Skocz do zawartości

Pilot multimedialny HID


Pomocna odpowiedź

W przypływie wolnego czasu chciałem przećwiczyć sobie obsługę USB w STM32 i przy okazji zrobić coś praktycznego do podłączenia do komputera. Ponieważ mam klawiaturę mechaniczną z przyciskami multimedialnymi ukrytymi pod mało praktyczną kombinacją z klawiszem FN (klawisz po prawej stronie - totalnie niepraktyczne w tym zastosowaniu) postanowiłem zrobić sobie dedykowany pilot do multimediów. Platforma STM32F103 bo mam mały zapas płytek BluePill. Jako sterowanie wybrałem joystick z enkoderem na wzór tych z systemów infotainment w samochodzie. Żeby doprecyzować joysticki ALPS RKJXT1F42001 zamówione jakiś czas temu na aliexpress i czekające na projekt jak ten.

joystick.thumb.PNG.6b4a8ed2be859541831f293bc05741a4.PNG

Kod na STM32 powstawał na bazie generowanego przez CubeIDE przy middleware USB_DEVICE z wybranym Human Interface Device Class (HID). W moim odczuciu generowany kod jest chyba bardziej demonstracją, ponieważ kod z definicjami deskryptorów jest stworzony dla myszy, i nie ma nigdzie znaczników USER_CODE_BEGIN/END. Próbowałem coś zadziałać z klasą Custom Human Interface Device ale mogłem znaleźć deskryptorów urządzenia, konfiguracji i interfejsu w kodzie, a deskryptor raportu HID był do napisania od zera, co jest raczej trudne przy pierwszym projekcie z USB. Zostałem przy przykładzie z myszką od ST, który sukcesywnie modyfikowałem, tworząc kopie zapasowe na wypadek potrzeby generowania kodu z Cube (przez brak znaczników USER_CODE wszystkie zmiany - głównie zmodyfikowany deskryptor raportu - byłyby nadpisane przez wygenerowany kod). Nie będę opisać tworzenia mojego deskryptora bo robiłem to raczej na czuja metodą prób i błędów. W skrócie chodzi o to, że deskryptor raportu HID informuje host(komputer) o możliwościach urządzenia oraz przypisuje funkcjonalności bajtom w raporcie HID - w moim przypadku każdy bit w drugim bajcie raportu niesie informacje o wciśnięciu przycisku z grupy consumer page (0x0C) (więcej o nich w dokumentacji USB HID - HID Usage Tables 1.12). Utworzenie deskryptora od zera jest raczej trudne dla początkującego ale w internecie jest sporo informacji - wielką pomocą był dla mnie raport z przykładowej implementacji (http://www2.ece.rochester.edu/~parihar/pres/Report_MultiMedia-KB.pdf) w którym o wiele lepiej wytłumaczono działanie USB, klas i deskryptorów, niż ja to jestem w stanie zrobić. Oprócz tego mój deskryptor raportu jest lekko zmodyfikowaną wersją tego spod linku. Deskryptory urządzenia, konfiguracji i interfejsu wykorzystałem w wersji wygenerowanej przez cube dla myszy - zmieniłem jedynie typ urządzenia na klawiaturę (0x01) w deskryptorze konfiguracji (Middlewares/ST/STM32_USB_Device_Library/Class/HID/Src/usbd_hid.c).

19372024_cfgdescriptor.thumb.PNG.680a073869e7ac3fbcac30dfac7c9767.PNG

Deskryptor raportu powstał na podstawie tego podlinkowanego. Mapowanie przycisków do bitów w raporcie jest tam zobrazowane na stronie 11. Dobry tutorial o deskryptorach raportów HID tutaj. Gotowy deskryptor raportu przedstawia się tak:

0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
		0x09, 0x01, // USAGE (Consumer Control)
		0xa1, 0x01, // COLLECTION (Application)
		0x85, 0x01, // REPORT_ID (1)
		0x15, 0x00, // LOGICAL_MINIMUM (0)
		0x25, 0x01, // LOGICAL_MAXIMUM (1)
		0x75, 0x01, // REPORT_SIZE (1)
		0x95, 0x10, // REPORT_COUNT (16)
		0x09, 0xe2, // USAGE (Mute) 0x01
		0x09, 0xe9, // USAGE (Volume Up) 0x02
		0x09, 0xea, // USAGE (Volume Down) 0x03
		0x09, 0xcd, // USAGE (Play/Pause) 0x04
		0x09, 0xb7, // USAGE (Stop) 0x05
		0x09, 0xb6, // USAGE (Scan Previous Track) 0x06
		0x09, 0xb5, // USAGE (Scan Next Track) 0x07
		0x0a, 0x8a, 0x01, // USAGE (Mail) 0x08
		0x0a, 0x92, 0x01, // USAGE (Calculator) 0x09
		0x0a, 0x21, 0x02, // USAGE (www search) 0x0a
		0x0a, 0x23, 0x02, // USAGE (www home) 0x0b
		0x0a, 0x2a, 0x02, // USAGE (www favorites) 0x0c
		0x0a, 0x27, 0x02, // USAGE (www refresh) 0x0d
		0x0a, 0x26, 0x02, // USAGE (www stop) 0x0e
		0x0a, 0x25, 0x02, // USAGE (www forward) 0x0f
		0x0a, 0x24, 0x02, // USAGE (www back) 0x10
		0x81, 0x62, // INPUT (Data,Var,Abs,NPrf,Null)
		0xc0

I definicje bitów dla przycisków oraz zmiennej przechowującej raport HID do wysłania

#define HID_REPORT_SIZE 3

#define MEDIA_MUTE 0
#define MEDIA_VOLUP 1
#define MEDIA_VOLDOWN 2
#define MEDIA_PLAY_PAUSE 3
#define MEDIA_STOP 4
#define MEDIA_PREV 5
#define MEDIA_NEXT 6
/* USER CODE END PD */

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim1;

/* USER CODE BEGIN PV */
extern USBD_HandleTypeDef hUsbDeviceFS;
uint8_t HID_report[HID_REPORT_SIZE] = {0x01,0,0}; //empty hid report

W celu zakomunikowania hostowi wciśnięcia przycisku wysyłamy raport HID z ustawionym bitem odpowiadającym wciśniętemu przyciskowi. Przykładowo dla przycisku VOL_UP ustawić należy drugi bit w drugim bajcie raportu. Ponieważ należy zasymulować wciśniecie i zwolnienie przycisku należy wysłać po chwili drugi raport z samymi zerami. Ważne jest też zachowanie co najmniej 10 ms odstępu między wysyłaniem raportów, by dać czas na przetworzenie informacji bibliotece USB na STMie oraz hostowi (komputerowi).

Poniżej kod w funkcji main() obsługujący wysyłanie raportów o wciśnięciu przycisków 

HID_report[1]=0; //0 means none of the buttons pressed

	  ////THIS CODE CAN SUPPORT ONLY 1 KEY AT A TIME, AND VERY SLOW REPEAT WITH LONG PRESS////

	  CheckButtonsState(); //check if any button is pressed and set appropriate bits in HID_report[1]
	  if(HID_report[1]!=0){
		  USBD_HID_SendReport(&hUsbDeviceFS, HID_report, HID_REPORT_SIZE); //send key-press and after 15 ms key-release reports
		  HAL_Delay(400);
		  HID_report[1]=0;
		  USBD_HID_SendReport(&hUsbDeviceFS, HID_report, HID_REPORT_SIZE);
		  HAL_Delay(15);
	  }

Funkcja CheckButtonsState() ustawia na podstawie stanów logicznych na wejściach uC, bity w 2 bajcie tablicy uint8_t przechowującej raport HID.

void CheckButtonsState(){
	if(!HAL_GPIO_ReadPin(PUSH_GPIO_Port, PUSH_Pin))	{ 							//push input is low when whichever button is pressed
		uint8_t isPushPressed=1;
		if(!HAL_GPIO_ReadPin(RIGHT_GPIO_Port, RIGHT_Pin))	{SetKeyPress(MEDIA_NEXT); isPushPressed=0; }
		if(!HAL_GPIO_ReadPin(LEFT_GPIO_Port, LEFT_Pin))		{SetKeyPress(MEDIA_PREV); isPushPressed=0; }
		if(!HAL_GPIO_ReadPin(UP_GPIO_Port, UP_Pin))			{SetKeyPress(MEDIA_MUTE); isPushPressed=0; }
		if(!HAL_GPIO_ReadPin(DOWN_GPIO_Port, DOWN_Pin))		{SetKeyPress(MEDIA_STOP); isPushPressed=0; }

		if(isPushPressed==1){SetKeyPress(MEDIA_PLAY_PAUSE);}
	}
}

void SetKeyPress(uint8_t key){
	HID_report[1] |= 1<<key;
}

Zastosowany joystick ALPS jest tak skonstruowany, że wciśnięcie jakiegokolwiek przycisku zwiera także wyprowadzenie PUSH odpowiadające wciśnięciu joysticka. Z tego powodu funkcja jest napisana tak, że jeżeli na wejściu PUSH jest 1 to na każdym innym musi być 1 (styki otwarte). Jeżeli wciśnięty jest PUSH (logiczne 0) ale też 0 jest na pinie od innego przycisku, oznacza to że wciśnięto inny przycisk, a stan na wejściu PUSH jest ignorowany. Jeżeli 0 jest tylko na wejściu PUSH, oznacza to że joystick rzeczywiście został wciśnięty. Takie rozwiązanie prosi się aż o generowanie przerwania z wejścia PUSH i wykonywania kodu wtedy. Ponieważ jestem leniwy i miałem już gotowy kod do wysyłania raportów HID kiedy to odkryłem, zostałem przy pollingu stanu na wejściach. Delay po wysłaniu raportu rozwiązuje mi także problem z debouncingiem przycisków (obserwowałem wejścia na oscyloskopie i stwierdzam że styki w tym joysticku drżą jak złe 😁).

Przechwytywanie.thumb.PNG.0e5d609bbe367f50fd316f5b171edb26.PNG

Regulację głośności obsługuję przez timer 1 w trybie enkodera (przydał się kurs zaawansowanych timerów na STM32 z waszego bloga 😁). Przy zmianie wartości licznika timera wartość jest porównywana z zapisaną w poprzednim przejściu głównej pętli while(1). Jeżeli się zmieniła na mniejszą lub większą wysyłany jest raport HID z ustawionym bitem odpowiadającym klawiszowi VOLUP/VOLDOWN a zmienna lastEncoderCount jest in/dekrementowana. Dopóki obie wartości nie są równe raporty są wysyłane co przejście głównej pętli while. Wartość licznika jest dzielona przez 2 gdyż przy poprawnej pracy enkodera o tyle zmienia się po przeskoczeniu "o jeden ząbek". Czasem miałem sytuację że wartość licznika była nieparzysta (może błąd połączeń/drżenie styków) i algorytm w kółko podnosił/obniżał głośność o 1 bo wartości encoderCount i lastEncoderCount nigdy nie były równe. Dzielenie przez 2 gwarantuje parzystość wartości zmiennej

///TE ZMIENNE SA GLOBALNE///
uint16_t encoderCount=32766; //half of timers resolution (16bit)
uint16_t lastEncoderCount=16383;
////////////////////////////

//TEN KOD WYKONUJE SIE W PETLI WHILE FUNKCJI MAIN()//
encoderCount=__HAL_TIM_GET_COUNTER(&htim1)/2; //get encoder absolute position

if(encoderCount!=lastEncoderCount){
		  if(encoderCount<lastEncoderCount){SetKeyPress(MEDIA_VOLDOWN);lastEncoderCount-=1;}  //set key press depending on encoder movement direction
		  else{SetKeyPress(MEDIA_VOLUP);lastEncoderCount+=1;}

		  USBD_HID_SendReport(&hUsbDeviceFS, HID_report, HID_REPORT_SIZE);
		  HAL_Delay(15);
		  HID_report[1]=0;
		  USBD_HID_SendReport(&hUsbDeviceFS, HID_report, HID_REPORT_SIZE);
		  HAL_Delay(15);
}

Kompletne oprogramowanie STMa dostępne na github.com/wiciu15/STM32-USBHID-MultimediaPilot

Po zweryfikowaniu działania prototypu zaprojektowałem i wytrawiłem prostą płytkę w KiCADzie żeby się pozbyć luźnych kabelków. Urządzenie zasilane jest z USB na BluePillu, programuje je z wyprowadzeń SWD po drugiej stronie płytki za pomocą ST-Linka V2.

boardview.thumb.PNG.9af0b04d2a62575423a59de189fbcaf7.PNGbottomview.thumb.PNG.e66d51394681328dba983c1cbb6e1625.PNG

Żeby urządzenie jakoś wyglądało zaprojektowałem i wydrukowałem obudowę oraz gałkę do joysticka. Od razu ostrzegam że na drukarce FDM ciężko jest osiągnąć taką precyzję żeby gniazdo w gałce ciasno siedziało na wałku joysticka - ja zaprojektowałem 0,1mm ciaśniej i przy montażu rozgrzałem plastik tak by się uplastycznił i dopasował do kształtu na końcu drążka joysticka. Nie jest to ciasne pasowanie ale wystarcza żeby sterować bez urywania gałki co drugie dotknięcie 😁.

USBHIDmultimediapilot.thumb.png.8ce806092d784e9337d411bf763012f2.png

I wydrukowane:

IMG_20200315_223604.thumb.jpg.3acd295b6c329c0d649b4a3b1b2a4e7b.jpg

Wszystkie pliki z kodem, płytka i obudowa dostępne na github.com/wiciu15/STM32-USBHID-MultimediaPilot.

Z racji że chciałbym dalej to rozwijać to zakupiłem moduł NRF51822 i będę próbował zrobić coś podobnego, ale na Bluetooth HID, i z zastosowaniem w aucie do sterowania tanim tabletem z emulatorem headunitu AndroidAuto (używam apki HeadUnit Reloaded która wspiera obsługę z klawiatury do sterowania API Androida Auto np. sterowanie jasny/ciemny tryb, multimedia, poruszanie się po interfejsie za pomocą enkodera - AA jest tak zaprojektowany bo piloty do systemów infotainment z reguły mają też enkodery). Jedyna moja obawa jest taka że pilocik będzie musiał działać cały czas ze stałej instalacji 12V, bo tablet z niewiadomych powodów po rozłączeniu z sparowanym urządzeniem BT wymaga ręcznego ponownego połączenia, więc po wyłączeniu i włączeniu pilocika czeka mnie wycieczka do ustawień tabletu by go z powrotem połączyć. 

Nie mam doświadczenia z programowaniem nRF więc zobaczymy jak mi pójdzie na raz z BT HID, przerwaniami, enkoderem i jeszcze minimalizacją poboru energii😁

IMG_20200310_213530.thumb.jpg.2fed2e16e9b31090752091022a57eafd.jpgIMG_20200310_231144.thumb.jpg.3362a8522d89903c72a64c362fc467de.jpg

Łatwiej by było dorobić drugie USB w tablecie i podłączyć taki pilot jak opisałem powyżej. Tu jest problem tej natury, że tablet który mam już zmodyfikowany i założony na bardzo mocną taśmę dwustronną (😁) nie chce działać na OTG z więcej niż jednym urządzeniem. Podłączałem do niego kilka HUBów USB, kupiłem nawet specjalną przejściówkę do OTG z paroma portami USB ale nic nie chce ruszyć.

Póki co moduł z NRF81 dopiero przyszedł, będę teraz się oswajał z SDK do niego, może jakiś hello world 😛. Nie jestem jeszcze pewny czy będę w stanie go programować i debugować bo mam tylko ST-Linka na stanie w tej chwili 😞 Podobno korzystając z OpenOCD można ST-Linka z tym połączyć ale to musiałbym przy wolnej chwili zrobić próby. Jak nie ruszy to będę szukać jakiegoś JTAGa ale ceny mnie trochę odstraszają.

Wszelkie sugestie, pochwały, krytyka i komentarze mile widziane 🙂 

Edytowano przez wiciu15
  • Lubię! 1
Link do komentarza
Share on other sites

Krytyki nie będzie bo te stmy, hidy i klawisze to moje klimaty z chęcią obejrzę każdy materiał, a Twój jest nawet kompletny, jest projekt, wykonanie, brakuje glutów jak w większości projektów arduino, a na końcu jeszcze obudowa w 3D.

Mam za to sugestie:

1. Skoro zapoznałeś się już USB w STM32 to zobacz sobie ciekawą alternatywę dla kodu od ST:

https://github.com/dmitrystu/libusb_stm32

Oprócz tego zapoznaj się z poradnikiem, który przygotował Kolega @Elvis 

https://forum.sunduino.pl/viewtopic.php?f=9&t=520

Mnie się udało z większym czy tez mniejszym zrozumieniem zrobić urządzenie HID na podstawie tego poradnika.

2. Co do wydruku 3d to warto przy precyzyjnych wydrukach używać PETG, który ma małą kurczliwość pod wpływem temperatury. Mnie się udało wykonać kilka nawet dość precyzyjnych modeli.

https://prusament.com/pl/materials/prusament-petg/

Zresztą na stronie Prusa są charakterystyki dla większości materiałów i warto się z nimi zapoznać przy wyborze filamentu.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

32 minuty temu, Zealota napisał:

Co do wydruku 3d to warto przy precyzyjnych wydrukach używać PETG

Bez przesady - na mojej Anetce drukowałem przeróżne gałki i suwaczki z najtańszego PLA od Colorfilla i bardzo dobrze się sprawują. A do tego typu wajchy powinna być gałka ze śrubką.

Link do komentarza
Share on other sites

(edytowany)

Pojawiło mi się parę innych tematów do załatwienia, więc pilocik poszedł na jakiś czas na bok. Jakoś dwa tygodnie temu miałem trochę wolnego czasu i owocem tego był pierwszy prototyp pilota na Bluetooth. Urządzenie na tym samym joysticku ALPSa, za mózg robi ESP32 Lite. Pod względem oprogramowania za wiele ciekawego nie stworzyłem, bo wszystko jest napisane w Arduino IDE i z gotową biblioteką do obsługi BLE-HID (https://github.com/T-vK/ESP32-BLE-Keyboard). Nie wiem czy ESP32 może hardware'owo obsługiwać enkoder tak jak timer w STM32, więc enkoder ogarniam przerwaniem z wejścia A i sprawdzaniem czy stan logiczny na A i B jest taki sam czy przeciwny, by ustalić kierunek obrotu. Korzystając z poprzednich doświadczeń z tym joystickiem napisałem implementację wychylania i wciskania joysticka, tym razem z przerwaniem od wejścia PUSH.

Oprócz przycisków multimedialnych wysyłam też zwykłe klawisze, pod którymi w emulatorze androida auto zaszyte są funkcje do nawigacji po UI (strzałki) i skróty np. Media (L), Nawigacja(D) itp.

Szkic wrzucam poniżej, dla innych płytek ESP32 mogą być potrzebne inne numery pinów. 

#include <BleKeyboard.h>

//definicje pinow
#define ENC_A 26
#define ENC_B 27
#define PUSH 33
#define ENC_RIGHT 14
#define ENC_LEFT 12
#define UP 32
#define DOWN 25

#define BTN_MIC 5
#define BTN_RIGHT 17
#define BTN_LEFT 16
#define BTN_NAV 4
#define BTN_MEDIA 0
#define BTN_HOME 2
#define BTN_NIGHT 15
#define BTN_PHONE 13

BleKeyboard bleKeyboard;

int8_t encMovement=0;
uint32_t lastEventMillis=0;
uint32_t lastJoystickEventMillis=0;
uint8_t encoderEventDetected=0;
uint8_t joystickEventDetected=0;
uint8_t nightModeToggler=0;

void IRAM_ATTR enc_isr(){  //przerwanie przy obracaniu enkoderem
  if(lastEventMillis+10<millis()){
    encoderEventDetected=1;
    lastEventMillis=millis();
  }
}

void IRAM_ATTR push_isr(){ //przerwanie z wejscia PUSH zwieranego przy kazdym ruchu joystickiem
  if(lastEventMillis+50<millis()){
    joystickEventDetected=1;
    lastEventMillis=millis();
  }
}

void setup() {
  pinMode(ENC_A,INPUT_PULLUP);
  pinMode(ENC_B,INPUT_PULLUP);
  attachInterrupt(ENC_A,enc_isr,CHANGE);
  
  initButtons();
  
  pinMode(PUSH,INPUT_PULLUP);
  attachInterrupt(PUSH,push_isr,FALLING);
  
  lastEventMillis=millis();
  
  Serial.begin(115200);
  Serial.println("Starting BLE keyboard!");
  bleKeyboard.begin();
}

void loop() {
  if(bleKeyboard.isConnected()) {
    if(encoderEventDetected){ 
      delay(3); //debounce  
      if(digitalRead(ENC_B) ^ digitalRead(ENC_A)){encMovement++;} //XOR - przy obrocie w prawo stan na pinach enkodera w momencie przerwania jest przeciwny
      else{encMovement--;}
      encoderEventDetected=0;
    }
    if(encMovement>0){
      Serial.printf("Wheel Right!\r\n");
      bleKeyboard.write(KEY_RIGHT_ARROW); //wysylamy raport HID
      encMovement--;
    }
    if(encMovement<0){
      Serial.printf("Wheel Left!\r\n");
      bleKeyboard.write(KEY_LEFT_ARROW);
      encMovement++;
  }
  if(joystickEventDetected){ //interrupt from PUSH input detected
    delay(30); //debouncing
    //check if any other input is low
    if(!digitalRead(ENC_RIGHT)){bleKeyboard.write(KEY_MEDIA_NEXT_TRACK);Serial.printf("Right\r\n");}
    else if(!digitalRead(ENC_LEFT)){bleKeyboard.write(KEY_MEDIA_PREVIOUS_TRACK);Serial.printf("Left\r\n");}
    else if(!digitalRead(UP)){bleKeyboard.write(KEY_UP_ARROW);Serial.printf("Up\r\n");}
    else if(!digitalRead(DOWN)){bleKeyboard.write(KEY_DOWN_ARROW);Serial.printf("Down\r\n");}
    else { //if only PUSH input is low, that means joystick really was pushed
      if(!digitalRead(PUSH) && lastJoystickEventMillis+350<millis()){ //PUSH can be low for a moment when releasing joystick lever to straight position, if PUSH is low for >350ms guarantees its intentional
        bleKeyboard.write(KEY_RETURN);Serial.printf("Return\r\n");}
      }
    joystickEventDetected=0;
    lastJoystickEventMillis=millis();
  }
  if(lastEventMillis+500<millis()){ //physical buttons handling
    if(!digitalRead(BTN_RIGHT)){bleKeyboard.press(KEY_LEFT_SHIFT);bleKeyboard.press(KEY_RIGHT_ARROW);delay(20);bleKeyboard.releaseAll();Serial.printf("Button Right\r\n");lastEventMillis=millis();}
    if(!digitalRead(BTN_LEFT)){bleKeyboard.press(KEY_LEFT_SHIFT);bleKeyboard.press(KEY_LEFT_ARROW);delay(20);bleKeyboard.releaseAll();Serial.printf("Button Left\r\n");lastEventMillis=millis();}
    if(!digitalRead(BTN_MIC)){bleKeyboard.write('M');Serial.printf("M (Mic)\r\n");lastEventMillis=millis();}
    if(!digitalRead(BTN_NAV)){bleKeyboard.write('D');Serial.printf("D (Nav)\r\n");lastEventMillis=millis();}
    if(!digitalRead(BTN_MEDIA)){bleKeyboard.write('L');Serial.printf("L (Media)\r\n");lastEventMillis=millis();}
    if(!digitalRead(BTN_HOME)){bleKeyboard.write('H');Serial.printf("H (Home)\r\n");lastEventMillis=millis();}    
    if(!digitalRead(BTN_PHONE)){bleKeyboard.write('4');Serial.printf("4 (Phone)\r\n");lastEventMillis=millis();}
    if(!digitalRead(BTN_NIGHT)){
      if(!nightModeToggler){bleKeyboard.press(KEY_LEFT_CTRL);bleKeyboard.press('N');delay(20);bleKeyboard.releaseAll();Serial.printf("CTRL+N (Night)\r\n");lastEventMillis=millis();nightModeToggler=1;}
      else{bleKeyboard.press(KEY_LEFT_SHIFT);bleKeyboard.press('N');delay(20);bleKeyboard.releaseAll();Serial.printf("SHIFT+N (Day)\r\n");lastEventMillis=millis();nightModeToggler=0;}
    }
  }
  delay(5);
}
}

void initButtons(){
  pinMode(ENC_RIGHT,INPUT_PULLUP);
  pinMode(ENC_LEFT,INPUT_PULLUP);
  pinMode(UP,INPUT_PULLUP);
  pinMode(DOWN,INPUT_PULLUP);
  pinMode(BTN_MIC,INPUT_PULLUP);
  pinMode(BTN_RIGHT,INPUT_PULLUP);
  pinMode(BTN_LEFT,INPUT_PULLUP);
  pinMode(BTN_NAV,INPUT_PULLUP);
  pinMode(BTN_MEDIA,INPUT_PULLUP);
  pinMode(BTN_HOME,INPUT_PULLUP);
  pinMode(BTN_NIGHT,INPUT_PULLUP);
  pinMode(BTN_PHONE,INPUT_PULLUP);  
}

Żeby projekt trzymał się kupy zaprojektowałem i wytrawiłem płytkę, tym razem zoptymalizowałem trochę przypisanie pinów żeby nie bawić się w przelotki/dwuwarstwowe płytki. Joystick jest na stronie z miedzią więc jest uniesiony odrobinę do góry żebym miał dojście lutownicą do padów. Jak ktoś potrzebuje symbol i footprint do ESP32Lite to jest w ZIPie z projektem, oszczędzi pół godziny życia które ja straciłem na pomiary i rysowanie, modelu 3D już nie miałem czasu ani ochoty robić 😄 .

IMG_20200419_200134.thumb.jpg.e0f1762e49aec68d77bd4e699ca55680.jpg

Płytka zamknięta jest w obudowie na wzór oryginalnego pilota od nawigacji z Renault Laguny 2 ph2 (nawigacja Carminat DVD)

IMG_20200422_190252.thumb.jpg.d79563e8c3e862dac8800a4a00086916.jpgpilot.thumb.PNG.7a153fcc908b20793d3630c51d48a34a.PNG

Nie zrobiłem jeszcze nakładki na górę z przyciskami, sam korpus też wymaga paru poprawek - jest za niski i trochę zbyt luźno spasowany z gniazdem w tunelu środkowym. Zatrzaski z PLA też zostawiają trochę do życzenia - nie są zbyt sztywne i przy mocnym naciśnięciu pilot wpada do tunelu środkowego bo zatrzaski puszczają. Trochę lepiej niż poprzednim razem poradziłem sobie z pasowaniem joystick-gałka:

Gniazdo w gałce zaprojektowałem na nominał, z moją drukarką z dyszą 0,5mm wyszło na mniejszy wymiar (wewnętrzny otworu). Tym razem nie grzałem wydrukowanej gałki by zmiękczyć plastik, tylko rozgrzałem hot-airem metalowy wałek joysticka (odpowiadam na potencjalne pytanie - nie, nie potopiłem plastików wewnątrz joysticka - pacjent przeżył zabieg i cały czas działa 😄 ). Póki wałek był gorący nasunąłem gałkę najbardziej jak się dało w prostej linii, w miarę możliwości bez przechylania. Gałkę na gorącym wałku zostawiłem do ostygnięcia nie dotykając jej by nie zmienić na gorąco kształtu otworu w gałce . Po ostygnięciu otrzymałem idealne pasowanie, nawet śrubka do zablokowania nie jest potrzebna jak zaproponował @ethanak .

Pilocik nie jest jeszcze w formie w jakiej chciałbym żeby był, ale przynajmniej jest to jakiś działający prototyp, plus mam czym już zmieniać muzykę w samochodzie bez szukania przycisków na dotykowym ekranie. Jak ktoś jest ciekaw jak działa nawigacja po AndroidAuto fizycznymi przyciskami, to mogę nagrać film. Na razie mam tylko szybkie demo które nagrałem na potrzebę zgłoszenia buga w apce emulującej headunit AndroidAuto (zmienia tryb tylko z dziennego na nocny, w drugą stronę już nie da rady)

https://photos.app.goo.gl/qiWeLANUxEqcUyDZA

Dalej chciałbym to kontynuować na nRF51822. Będzie nowa płytka, nowa obudowa i jakieś konkretne programowanie. Na tą chwilę robiłem próby na płytce https://www.waveshare.com/wiki/Core51822_(B) . Odpaliłem ją już w Arduino IDE z pomocą https://github.com/sandeepmistry/arduino-nRF5. Do programowania zamówiony mam z aliexpress klon J-Linka V8. Póki co używam ST-Linka V2 - działa z Arduino za pomocą OpenOCD. W Arduino IDE wszystko jest już gotowe po instalacji, wystarczy wgrać na płytkę softDevice (musiałem ręcznie pobrać ze strony Nordic i wkleić do folderu w AppData/Roaming/Arduino15 - link wbudowany w Arduino IDE umarł). Potem tylko otwieramy jakiś przykładowy kod, zamiast portu COM, wybieramy ST-Linka z menu Programator i wysyłamy program na płytkę. Używana przeze mnie płytka działa jako Generic nRF51. Mapowanie pinów do peryferiów jest tutaj - https://github.com/sandeepmistry/arduino-nRF5/blob/master/variants/Generic/variant.h - potrzebowałem do podłączenia UARTa.

Jak się mniej więcej zapoznałem z platformą to zacząłem kompletować toolchain do programowania oparty o SDK Nordica i Eclipse. Doszedłem już do momentu gdzie mogę z powodzeniem kompilować kod z pomocą gcc i make, wysłać hex/bin na płytkę przez ST-Linka za pomocą OpenOCD i debugować w eclipse (OpenOCD + GDB), tak jak robiłem to na STM32. Ponieważ weekend mi się skończył to nie miałem okazji nic pokodzić żeby się zapoznać z platformą - póki co odpalałem przykład z SDK ble_peripheral\ble_app_hids_keyboard. Nie będę się rozpisywał o stawianiu toolchaina na eclipse i gcc z makefile bo Nordic ma dobry poradnik który to wytłumaczy lepiej niż ja - https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/development-with-gcc-and-eclipse . Napotkałem parę problemów po drodze, ale większość była rozwiązywalna z pomocą internetu i podstawowej wiedzy o środowiskach programistycznych. Jedyną różnicą jest programowanie MCU - używam OpenOCD z ST-Linkiem zamiast ich narzędzia nrfjprog i J-Linka. Wymagane zmiany to parę ścieżek w eclipse i podmiana komend w makefile (dokładniej to komendy dla "make flash" i "make flash_softdevice" - wywołać trzeba openocd z potrzebnymi parametrami). O używaniu OpenOCD i ST-linka do programowania MCU Nordica tutaj - https://sudonull.com/post/955-Working-with-nRF51822-using-ST-Link-and-Clion-OpenOCD. O konfiguracji OpenOCD do debugowania w eclipse tutaj - https://gnu-mcu-eclipse.github.io/debug/openocd.

Jak się trochę lepiej zaznajomię z platformą i będzie na to popyt mogę zrobić jakiś poradnik (a może i serię??) jak zacząć z nRF i ogólnie Bluetooth BLE. Póki co będę działał dalej, nie obiecuje kiedy kolejna aktualizacja bo z wolnym czasem u mnie różnie 😄  Wszelkie sugestie ,komentarze i pomysły jak zwykle mile widziane 🙂 

BLE_AndroidAuto_Keyboard.zip

Edytowano przez wiciu15
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.