piątek, 27 marca 2020

Som Labs - IMx6 ULL - Debian - Uart

W tym poście chciałbym opisać sposób obsługi interfejsu UART.

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

Device Tree:


Dla testowanego programu uruchomiłem interfejs UART3. W tym celu należy wprowadzić następujące zmiany w Device Tree:

  1. &uart4 {
  2.         pinctrl-names = "default";
  3.         pinctrl-0 = <&pinctrl_uart4>;
  4.         dma-names = """";
  5.         status = "okay";
  6. };
  7. pinctrl_uart4: uart3grp {
  8.     fsl,pins = <
  9.         MX6UL_PAD_UART4_TX_DATA__UART4_DCE_TX      0x1b0b1
  10.         MX6UL_PAD_UART4_RX_DATA__UART4_DCE_RX      0x1b0b1
  11.     >;                                              
  12. };

Podobnie będzie wyglądała konfiguracja pinów np. dla UART3. Natomiast z płytki VisonCB-STD linie RX i TX dla UART3 nie zostały wyprowadzone na złącza.

W przypadku wykorzystywania linii UART4 RX oraz TX należy zakomentować deklarację I2C1. Ponieważ oba interfejsy korzystają z tych samych wyprowadzeń.

Linie UART4 zostały wyprowadzone na złącze do nakładek Arduino (żółte 8 pinów):


Konwerter poziomów logicznych w standardowej konfiguracji nie zmienia sygnałów na 5V tylko utrzymuje poziom 3V3.


Minicom:


W celu wykonania testów połączenia można się posłużyć programem Minicom.

Najpierw jednak należy podłączyć konwerter UART->USB do linii AR-DIO-1 oraz AR-DIO-0 oraz GND (np. pin 6 złącza Raspberry Pi).

Przed uruchomieniem interfejsu należy zainstalować program Minicom:

  1. apt install minicom

Następnie w celu uruchomienia programu należy wpisać:

  1. minicom -D /dev/ttymxc3

Domyślne prędkość transmisji wynosi 115200, 8 bitów danych, brak kontroli parzystości oraz jeden bit stopu.

Po przesłanie danych z komputera do płytki Colibri powinny się one wyświetlić w następujący w oknie:


Aby wysłać dane należy je wpisać w oknie. Dane przesyłane są pojedynczo:


Dodatkowe ustawienia programu dostępne są po wpisaniu kombinacji CTRL + A po czym klawisz Z.

Aby wyłączyć program Minicom należy wpisać CTRL+A, Z oraz X;

Program C:


Aby uruchomić przykładowy program można wykorzystać informację udostępnione przez producenta pod tym linkiem: https://wiki.somlabs.com/index.php/How_to_use_VisionSOM-6ULL_UART_interface_in_command_line_and_C_programs

Program napisany w języku C pozwala na przesłanie oraz odbiór danych z prędkością 9600.

Poniżej rozwinę trochę powyższy przykład.

Konfiguracja UART'a:

  1. int configureUART(int fd, int speed)
  2. {
  3.         struct termios serialPortSett;
  4.  
  5.         memset (&serialPortSett, 0, sizeof serialPortSett);
  6.         /* Kopiowanie ustawień */
  7.         tcgetattr (fd, &serialPortSett);          
  8.  
  9.         /* Ustawienie prędkości odczytu UART */
  10.         cfsetispeed (&serialPortSett, speed);
  11.         /* Ustawienie prędkości zapisu UART */
  12.         cfsetospeed (&serialPortSett, speed);  //Ustaw prędkość zapisu UART
  13.  
  14.         /* Disables parity */
  15.         serialPortSett.c_cflag &= ~(PARENB | PARODD);
  16.  
  17.         /* CSTOPB oznacza dwa bity stopu tutaj zanegowane
  18.             czyli ustawiony jeden bit stopu*/
  19.         serialPortSett.c_cflag &= ~CSTOPB;  
  20.         /* Czyszczenie maski do zapisu rozmiaru danych */
  21.         serialPortSett.c_cflag &= ~CSIZE;
  22.         /* Ustawienie rozmiaru danych na 8 */
  23.         serialPortSett.c_cflag |=  CS8;
  24.  
  25.         /* Brak sprzętowej kontroli przepływu danych */
  26.         serialPortSett.c_cflag &= ~CRTSCTS;
  27.         /* Uruchomienie odbierania
  28.             Wyłączenie ang. modem control lines */
  29.         serialPortSett.c_cflag |= CREAD | CLOCAL;
  30.  
  31.         /* Wyłączenie XON/XOFF */
  32.         serialPortSett.c_iflag &= ~(IXON | IXOFF | IXANY);
  33.         /* Wyłączenie trybu kanonicznego oraz echa */
  34.         serialPortSett.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  35.         /* Output processing wyłączony */
  36.         serialPortSett.c_oflag &= ~OPOST;
  37.  
  38.         /* Timeout */
  39.         serialPortSett.c_cc[VMIN] = 0;
  40.         serialPortSett.c_cc[VTIME] = 0;
  41.  
  42.         /* Ustawienie danych */
  43.         if((tcsetattr(fd,TCSANOW,&serialPortSett)) != 0) {
  44.             printf("\n  UART init ERROR");
  45.         }
  46.         else{
  47.             printf("\n UART init OK");
  48.         }
  49.  
  50.         /* Usunięcie danych z bufora RX */
  51.         tcflush(fd, TCIFLUSH);
  52. }

Jako parametr speed czyli szybkość komunikacji można podać następujące wartości:

  1. B0
  2. B50
  3. B75
  4. B110
  5. B134
  6. B150
  7. B200
  8. B300
  9. B600
  10. B1200
  11. B1800
  12. B2400
  13. B4800
  14. B9600
  15. B19200
  16. B38400
  17. B57600
  18. B115200
  19. B230400

Poniżej cały program:

  1. #include <stdio.h>
  2. #include <errno.h>
  3. #include <fcntl.h>
  4. #include <string.h>
  5. #include <termios.h>
  6. #include <unistd.h>
  7.  
  8. int confUART(int fd, int speed)
  9. {
  10.         struct termios serialPortSett;
  11.         memset (&serialPortSett, 0, sizeof serialPortSett);
  12.         tcgetattr (fd, &serialPortSett);
  13.         cfsetispeed (&serialPortSett, speed);
  14.         cfsetospeed (&serialPortSett, speed);
  15.  
  16.         serialPortSett.c_cflag &= ~(PARENB | PARODD);
  17.         serialPortSett.c_cflag &= ~CSTOPB;
  18.         serialPortSett.c_cflag &= ~CSIZE;
  19.         serialPortSett.c_cflag |=  CS8;
  20.  
  21.         serialPortSett.c_cflag &= ~CRTSCTS;
  22.         serialPortSett.c_cflag |= CREAD | CLOCAL;
  23.         serialPortSett.c_iflag &= ~(IXON | IXOFF | IXANY);
  24.         serialPortSett.c_iflag &= ~IGNBRK;
  25.         serialPortSett.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  26.         serialPortSett.c_oflag &= ~OPOST;
  27.  
  28.         serialPortSett.c_cc[VMIN] = 0;
  29.         serialPortSett.c_cc[VTIME] = 0;
  30.  
  31.         if((tcsetattr(fd,TCSANOW,&serialPortSett)) != 0) {
  32.             printf("\n  UART init ERROR\n");
  33.         }
  34.         else{
  35.             printf("\n UART init OK\n");
  36.         }
  37.         tcflush(fd, TCIFLUSH);
  38. }
  39.  
  40. void main() {
  41.         char buf [50];
  42.         int bytesRead = 0;
  43.         int fd = open ("/dev/ttymxc3", O_RDWR | O_NOCTTY | O_SYNC);
  44.         confUART(fd, B115200);
  45.  
  46.         printf("Sending mesage...\n");
  47.  
  48.         sprintf(buf, "Test msg\n");
  49.         write (fd, buf, strlen(buf));
  50.         memset(buf, 0, sizeof(buf));
  51.  
  52.         printf("Receiving message...\n");
  53.  
  54.         while(1)
  55.         {
  56.                 bytesRead = read(fd, buf, sizeof(buf));
  57.                 printf("ReadBytes: %d\n", bytesRead);
  58.                 printf("Msg: %s\n", buf);
  59.         }
  60. }

W funkcji main uzyskujemy dostęp do interfejsu przez otwarcie pliku. Dołożone flagi oznaczają możliwość odczytu i zapisu, brak kontroli przez terminal oraz synchronizacja zapisu odczytu z pliku. 

Następnie przesyłana jest informacja po której następuje wejście do pętli while która odbiera dane i wyrzuca je w terminalu w postaci ilości odebranych danych oraz samego bufora. Przesłana ramka musi być zakończona znakiem CR.

Dokładne informacje o znaczeniu poszczególnych flag wartości można pobrać tutaj:
http://man7.org/linux/man-pages/man3/termios.3.html