piątek, 24 stycznia 2020

Som Labs - IMx6 ULL - Debian - Obsługa przycisków z podsystemu GPIO Buttons

W tym poście chciałbym opisać sposób przygotowanie sterownika odpowiedzialnego za sterowanie przyciskami.

Znalezione obrazy dla zapytania som labs 6ull
[Źródło: https://somlabs.com/product/visionsom-6ull/]

W płytce VisionCB-STD przyciski są podłączone w następujący sposób:


Podobnie jak w poprzednim przypadku należy odpowiednio skonfigurować jądro systemu.

Aby skonfigurować sterowniki należy przejść do pobranego obrazu somlabs-debian.

Następnie w celu modyfikacji sterowników należy uruchomić go na systemie:

  1. sudo ./somlabs-debian/chtoolchain
  2. cd /home/developer/source/kernel/linux-rel_imx_4.1.15_2.1.0_ga
  3. make ARCH=arm menuconfig

Na samym początku należy uruchomić sterownik GPIO Buttons w jądrze systemu. W kompilacji systemu umieszczonej przez producenta te sterowniki powinny zostać już włączone. W innym przypadku należy uruchomić te sterownik (make menuconfig):

  1. Device Drivers -> Input device support -> [*] Keyboards -> <*>GPIO Buttons

Ta sama sytuacja dotyczy interfejsu zdarzeń:

  1. Device Drivers -> Input device support -> <*> Event interface

W przygotowanym obrazie przez producenta powyższe ustawienia powinny być już przygotowane. Więc prawdopodobnie wystarczy jedynie edycja Device Tree.

Konfiguracja przycisków wygląda następująco:

  1. gpio-keys {
  2.     compatible = "gpio-keys";
  3.     pinctrl-0 = <&pinctrl_gpio_keys>;
  4.     pinctrl-names = "default";
  5.     btn3 {
  6.         label = "btn3";
  7.         gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
  8.         linux,code = <103>; /* <KEY_UP> */
  9.     };
  10.     btn4 {
  11.         label = "btn4";
  12.         gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
  13.         linux,code = <108>; /* <KEY_DOWN> */
  14.     };
  15. };
  16. &iomuxc {
  17.     pinctrl-names = "default";
  18.     pinctrl-0 = <&pinctrl_hog_1>;
  19.     imx6ul-evk {
  20.         pinctrl_gpio_keys: gpio-keys {
  21.             fsl,pins = <
  22.                 MX6UL_PAD_GPIO1_IO08__GPIO1_IO08 0x1b0b0
  23.                 MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x1b0b0
  24.             >;
  25.         };
  26.     };
  27. };

Dostęp do przycisków jest możliwy przez plik /dev/input/event2.  Odczytu nie można zrealizować za pomocą instukcji cat:

  1. cat /dev/input/event2

Pod niego zostały podłączone przyciski IO08 oraz IO09. Po odczytaniu powyższą instrukcją zostaną przesłane następujące informacje:


Dziwne odczyty podczas klikania przycisków wynikają z zapisu danych do struktury. Wygląda ona następująco:

  1. struct input_event {
  2. #if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__)
  3.     struct timeval time;
  4. #define input_event_sec time.tv_sec
  5. #define input_event_usec time.tv_usec
  6. #else
  7.     __kernel_ulong_t __sec;
  8. #if defined(__sparc__) && defined(__arch64__)
  9.     unsigned int __usec;
  10.     unsigned int __pad;
  11. #else
  12.     __kernel_ulong_t __usec;
  13. #endif
  14. #define input_event_sec  __sec
  15. #define input_event_usec __usec
  16. #endif
  17.     __u16 type;
  18.     __u16 code;
  19.     __s32 value;
  20. };

Poszczególne pola zawierają takie informacje jak:


  • struct timeval time - czas zdarzenia,
  • unsigned short type - rodzaj zdarzenia,
  • unsigned short code - kod przycisku,
  • unsigned int value - aktualna wartość.


Rodzaje zdarzeń zawarte w polu type to:


  • EV_REL - Relative Movement - np. poruszenie myszką.
  • EV_ABS - Absolute Position - pozycja kliknięcia na wyświetlaczu przy wykorzystaniu ekranu dotykowego.
  • EV_SYN - Event Separator - używany przy ekranach dotykowych dla dotyku wielopunktowego.
  • EV_KEY - Key Event - wciśnięcie przycisku itp.

Obsługa przycisków w C


Odczyt pliku oraz wyświetlenie potrzebnych danych na ekranie za pomocą programu napisanego w języku C może wyglądać następująco:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <linux/input.h>
  6.  
  7. int main (void)
  8. {
  9.         struct input_event ev_input;
  10.         int size = sizeof(ev_input), fd;
  11.  
  12.         fd = open("/dev/input/event2", O_RDONLY);
  13.  
  14.         if (fd < 0)
  15.         {
  16.                 printf("Open event2 failed!\n");
  17.                 return EXIT_FAILURE;
  18.         }
  19.         else
  20.         {
  21.                 printf("Open event2 OK\n");
  22.         }
  23.         while (1)
  24.         {
  25.                 if (read(fd, &ev_input, size) < size)
  26.                 {
  27.                         printf ("Reading from /dev/input/event1 failed!\n");
  28.                         close(fd);
  29.                         return(EXIT_FAILURE);
  30.                 }
  31.                 if (ev_input.type == EV_KEY) //ev_input.type == 0x01
  32.                 {
  33.                         printf("----------Btn Click------\n");
  34.                         printf("type - %u\n", ev_input.type);
  35.                         printf("code - %u\n", ev_input.code);
  36.                         printf("value - %d\n", ev_input.value);
  37.                 }
  38.         }
  39.         close (fd);
  40.         return EXIT_FAILURE;
  41. }

Na samym początku następuje otwarcie pliku. Po nim w pętli dane są odczytywane i sprawdzane jest czy został przycisk wciśnięty i jakie informację są zapisane do struktury po jego kliknięciu. Program nie zawiera żadnego mechanizmu filtrującego fałszywe kliknięcia. Wobec tego mogą pojawiać się dodatkowe kliknięcia przycisków.


Bez wprowadzania dodatkowych ustawień można odczytać dane zapisane w pliku event1. Tym razem po kliknięciu przycisku oznaczonego jako IO4 (należy zmienić nazwę pliku do otwarcia z event2 na event1).


W celu uruchomienia pozostałych przycisków w Device Tree należy wprowadzić drobne zmiany.

  1. gpio-keys {
  2.     compatible = "gpio-keys";
  3.     pinctrl-0 = <&pinctrl_gpio_keys>;
  4.     pinctrl-names = "default";
  5.  
  6.     btn1 {
  7.         label = "btn1";
  8.         gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
  9.         linux,code = <106>; /* <KEY_RIGHT> */
  10.     };
  11.  
  12.     btn2 {
  13.         label = "btn2";
  14.         gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
  15.         linux,code = <105>; /* <KEY_LEFT> */
  16.     };
  17.  
  18.     btn3 {
  19.         label = "btn3";
  20.         gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
  21.         linux,code = <103>; /* <KEY_UP> */
  22.     };
  23.  
  24.     btn4 {
  25.         label = "btn4";
  26.         gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
  27.         linux,code = <108>; /* <KEY_DOWN> */
  28.     };
  29. };
  30.  
  31.  
  32.  
  33. &iomuxc {
  34.     pinctrl-names = "default";
  35.     pinctrl-0 = <&pinctrl_hog_1>;
  36.     imx6ul-evk {
  37.         pinctrl_gpio_keys: gpio-keys {
  38.             fsl,pins = <
  39.                 MX6UL_PAD_GPIO1_IO08__GPIO1_IO03 0x1b0b0
  40.                 MX6UL_PAD_GPIO1_IO09__GPIO1_IO04 0x1b0b0
  41.                 MX6UL_PAD_GPIO1_IO08__GPIO1_IO08 0x1b0b0
  42.                 MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x1b0b0
  43.             >;
  44.         };
  45.     };
  46. };

Powyżej zostają uruchomione wszystkie cztery przyciski. Dodatkowo należy usunąć następujące elementy. Ponieważ blokują one dwie ostatnie linie przycisków.

  1. /*
  2. pinctrl_tsc: tscgrp {
  3.     fsl,pins = <
  4.                 MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0
  5.                 MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0xb0
  6.                 MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0xb0
  7.                 MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0xb0
  8. };
  9. */
  10. /*
  11. &tsc {
  12.     pinctrl-names = "default;
  13.     pinctrl-0=<&pinctrl_tsc>;
  14.     xnur-gpio = <&gpio 1 3 GPIO_ACTIVE_LOW>;
  15.     measure-delay-time = <0xffff>;
  16.     status="okay";
  17. };
  18. */

Po wgraniu na płytę przygotowanych plików i uruchomieniu wcześniej przygotowanego programu w C można z event2 odczytać informację o kliknięciu z wszystkich przycisków.