środa, 18 grudnia 2019

[40] STM32F4 - Wyświetlacz Riverdi FT801

W tym poście chciałbym opisać sposób obsługi wyświetlacza ze sterownikiem FT801 za pomocą STM32F4 oraz bibliotek HAL'a.


Projekt HAL:


Poniżej zawarty opis konfiguracyjny projektu w środowisku HAL.

Na samym początku interfejs SPI służący do komunikacji z wyświetlaczem. Tutaj, w związku z wykorzystywaniem płytki rozszerzeń w postaci nakładki od Riverdi, należy wykorzystać SPI1 (PA5, PA6, PA7). 


Poniżej fragment kodu uruchamiający SPI:

  1. static void SPI_Init(void)
  2. {
  3.   hspi1.Instance = SPI1;
  4.   hspi1.Init.Mode = SPI_MODE_MASTER;
  5.   hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  6.   hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  7.   hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  8.   hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  9.   hspi1.Init.NSS = SPI_NSS_SOFT;
  10.   hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;//SPI_BAUDRATEPRESCALER_2;
  11.   hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  12.   hspi1.Init.TIMode = SPI_TIMODE_DISABLED;
  13.   hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
  14.   hspi1.Init.CRCPolynomial = 10;
  15.   HAL_SPI_Init(&hspi1);
  16. }

Do przesyłania wiadomości przez UART najlepiej wykorzystać USART2 (PA2, PA3) ponieważ jest on podłączony pod USB zamontowane na płytce Nucleo.


Poniżej fragment wygenerowanego kodu przez program:

  1. static void MX_USART2_UART_Init(void)
  2. {
  3.   huart2.Instance = USART2;
  4.   huart2.Init.BaudRate = 115200;
  5.   huart2.Init.WordLength = UART_WORDLENGTH_8B;
  6.   huart2.Init.StopBits = UART_STOPBITS_1;
  7.   huart2.Init.Parity = UART_PARITY_NONE;
  8.   huart2.Init.Mode = UART_MODE_TX_RX;
  9.   huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  10.   huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  11.   if (HAL_UART_Init(&huart2) != HAL_OK)
  12.   {
  13.     Error_Handler();
  14.   }
  15. }

Następnym elementem jest uruchomienie kilku dodatkowych pinów jako wyjścia.

Chip Select dla SPI1 (PB6):

  1. GPIO_InitStruct.Pin = FT800_CS_N;
  2. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  3. GPIO_InitStruct.Pull = GPIO_NOPULL;
  4. GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  5. HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

Następnie pin odpowiedzialny za wybranie interfejsu. Pin PA8. Ustawienie go w stan niski powoduje wybranie interfejsu SPI. Gdy ustawiony będzie wysoko obsługiwany będzie interfejs I2C:

  1. GPIO_InitStruct.Pin = GPIO_PIN_8;
  2. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  3. GPIO_InitStruct.Pull = GPIO_NOPULL;
  4. GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  5. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


Pin odpowiedzialny za reset i uruchomienie układu w tryb pracy czyli PD (PA9):

  1. GPIO_InitStruct.Pin = FT800_PD_PIN;
  2. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  3. GPIO_InitStruct.Pull = GPIO_NOPULL;
  4. GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  5. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

Projekt przygotowany jest dla płytki Nucleo. Głównie dlatego, że łatwiej podłączyć Riverdi Shield. Natomiast nic nie stoi na przeszkodzie aby użyć płytki Discovery. W takim przypadku nakładkę trzeba podłączyć na kablach do odpowiednich pinów.

Hardware:


Do testów wykorzystałem wyświetlacz firmy Riverdi RVT43ULFNWC00 V3, shield dla Arduino z możliwością wpięcia karty SD itp. oraz płytkę Nucleo z STM32F4. Natomiast korzystając z bibliotek HAL'a projekt może zostać łatwo przeniesiony na inny mikrokontroler.

Opis wyprowadzeń Shielda dla Arduino:

  • VDD - Zasilanie 3V3;
  • GND - Masa;
  • SCL - Linia zegara I2C;
  • SDA - Linia danych I2C;
  • SCK - Zegar SPI;
  • MISO - Linia danych SPI;
  • MOSI - Linia danych SPI;
  • CS - Linia wybrania urządzenia dla SPI;
  • INT - Wywołanie przerwania, aktywowana stanem niskim;
  • PD - Linia Power Down, aktywna stanem niskim;
  • MODE - Wybranie trybu pracy wyświetlacza;
  • SDCARD CD - Linia detekcji karty;
  • SDCARD CS - Wybranie urządzenia SPI;

Domyślnie linia MODE podpięta jest pod VCC. Co oznacza, że bez zmiany stanu linii MODE na niski domyślnym interfejsem do komunikacji z wyświetlaczem będzie I2C.

Biblioteka:


Projekt biblioteki bazuje na przykładowych rozwiązaniach zastosowanych przy projektach dla Arduino umieszczonych na serwisie Github().

Ustawienia:


Na samym początku w konfiguracji wyświetlacza należy wybrać interfejs komunikacyjny do komunikacji z wyświetlaczem na SPI. Wykonuje się to poprzez podciągnięcie pinu MODE do masy (Odpowiada on wyprowadzeniu GPIOA8 na złączach Arduino w STM32Nucleo).

  1. static void FT801_SelectSPIInterface(void)
  2. {
  3.     HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
  4.     CS_SET();
  5. }

Kolejnym elementem jest ustawienie stanu wysokiego na linii PD oraz sprowadzenie jej na chwilę w stan niski co pozwala na reset układu.

  1. static void FT801_SetPDPin(void)
  2. {
  3.     HAL_GPIO_WritePin(GPIOA, FT800_PD_PIN, GPIO_PIN_SET);
  4.     HAL_Delay(30);
  5.     HAL_GPIO_WritePin(GPIOA, FT800_PD_PIN, GPIO_PIN_RESET);
  6.     HAL_Delay(30);
  7.     HAL_GPIO_WritePin(GPIOA, FT800_PD_PIN, GPIO_PIN_SET);
  8.     HAL_Delay(30);
  9. }

Następnym elementem jest uzyskanie dostępu do adresu 0x00. Powoduje to wybudzenie układu FT. Po czym należy przejść do ustawienia zegara:

  1. static void FT801_StartChip(void)
  2. {
  3.     //Access adress 0 to wake up FTChip
  4.     FT801_CommandWrite(FT800_ACTIVE);
  5.     HAL_Delay(20);
  6. }
  7. static void FT801_ConfigClock(void)
  8. {
  9.     FT801_CommandWrite(FT800_CLKEXT);
  10.     HAL_Delay(20);
  11.     FT801_CommandWrite(FT800_CLK48M);
  12.     HAL_Delay(20);
  13. }

Dalej sprawdzam czy zostało podłączone odpowiednie urządzenie i wgrywam dodatkowe ustawienia:

  1. static void FT801_ReadDeviceId(uint8_t expectedID)
  2. {
  3.     uint8_t readedRegId = FT801_Read8BitData(REG_ID);
  4.     if (readedRegId != expectedID) {
  5.         while(1); {
  6.             /* Infinite loop when different device id than expected */
  7.         }
  8.     }
  9. }
  10. FT801_Write8BitData(REG_PCLK, 0);       //PCLK to 0
  11. FT801_Write8BitData(REG_PWM_DUTY, 0);   //Backlight to 0

Sprawdzenie czy koprocesor wystartował:

  1. static void FT801_CheckIfEngineIsReady(void)
  2. {
  3.     uint8_t engineReadyStatus = FT801_Read8BitData(REG_CPURESET);
  4.     while(engineReadyStatus != 0x00)
  5.     {
  6.         engineReadyStatus = FT801_Read8BitData(REG_CPURESET);
  7.         HAL_Delay(100);
  8.     }
  9. }

Po inicjalizacji SPI i ustawieniu kierunku na pinach można przejść do wgrywania parametrów wyświetlacza do sterownika FT801:

  1. #define FT_DispWidth      480L
  2. #define FT_DispHeight     272L
  3. #define FT_DispHCycle     548L
  4. #define FT_DispHOffset    43L
  5. #define FT_DispHSync0     0L
  6. #define FT_DispHSync1     41L
  7. #define FT_DispVCycle     292L
  8. #define FT_DispVOffset    12L
  9. #define FT_DispVSync0     0L
  10. #define FT_DispVSync1     10L
  11. #define FT_DispPCLK       5
  12. #define FT_DispSwizzle    0
  13. #define FT_DispPCLKPol    1
  14. #define FT_DispCSpread    0
  15. #define FT_DispDither     1
  16. static void FT801_SetConfigurationParameters(void)
  17. {
  18.     LCD_Width   = FT_DispWidth;
  19.     LCD_Height  = FT_DispHeight;
  20.     LCD_Hcycle  = FT_DispHCycle;
  21.     LCD_Hoffset = FT_DispHOffset;
  22.     LCD_Hsync0  = FT_DispHSync0;
  23.     LCD_Hsync1  = FT_DispHSync1;
  24.     LCD_Vcycle  = FT_DispVCycle;
  25.     LCD_Voffset = FT_DispVOffset;
  26.     LCD_Vsync0  = FT_DispVSync0;
  27.     LCD_Vsync1  = FT_DispVSync1;
  28.     LCD_PCLK    = FT_DispPCLK;
  29.     LCD_Swizzle = FT_DispSwizzle;
  30.     LCD_Pclkpol = FT_DispPCLKPol;
  31.     LCD_DispCSpread = FT_DispCSpread;
  32.     LCD_DispDither = FT_DispDither;
  33. }
  34. static void FT801_WriteInitialSettings(void)
  35. {
  36.     FT801_Write16BitData(REG_HCYCLE,  LCD_Hcycle);
  37.     FT801_Write16BitData(REG_HOFFSET, LCD_Hoffset);
  38.     FT801_Write16BitData(REG_HSYNC0,  LCD_Hsync0);
  39.     FT801_Write16BitData(REG_HSYNC1,  LCD_Hsync1);
  40.     FT801_Write16BitData(REG_VCYCLE,  LCD_Vcycle);
  41.     FT801_Write16BitData(REG_VOFFSET, LCD_Voffset);
  42.     FT801_Write16BitData(REG_VSYNC0,  LCD_Vsync0);
  43.     FT801_Write16BitData(REG_VSYNC1,  LCD_Vsync1);
  44.     FT801_Write8BitData(REG_SWIZZLE,  LCD_Swizzle);
  45.     FT801_Write8BitData(REG_PCLK_POL, LCD_Pclkpol);
  46.     FT801_Write16BitData(REG_HSIZE,   LCD_Width);
  47.     FT801_Write16BitData(REG_VSIZE,   LCD_Height);
  48.     FT801_Write16BitData(REG_CSPREAD, LCD_DispCSpread);
  49.     FT801_Write16BitData(REG_DITHER,   LCD_DispDither);
  50. }

Za uruchomienie wyświetlacza wygląda następująco:

  1. static void FT801_StartDisplay(void)
  2. {
  3.     ramDisplayList = RAM_DL;
  4.     FT801_Write32BitData(ramDisplayList, DL_CLEAR_RGB);
  5.     ramDisplayList += 4;
  6.     FT801_Write32BitData(ramDisplayList, (DL_CLEAR | CLR_COL | CLR_STN | CLR_TAG));
  7.     ramDisplayList += 4;
  8.     FT801_Write32BitData(ramDisplayList, DL_DISPLAY);
  9.     FT801_Write32BitData(REG_DLSWAP, DLSWAP_FRAME);
  10.     ramDisplayList = RAM_DL;
  11.     ft800Gpio = FT801_Read8BitData(REG_GPIO);
  12.     ft800Gpio = ft800Gpio | 0x80;
  13.     FT801_Write8BitData(REG_GPIO, ft800Gpio);
  14.     FT801_Write8BitData(REG_PCLK, LCD_PCLK);
  15.     for(int duty = 0; duty <= 128; duty++)
  16.     {
  17.         FT801_Write8BitData(REG_PWM_DUTY, duty);
  18.         HAL_Delay(10);
  19.     }
  20. }

Komunikacja z wyświetlaczem:


W celu komunikacji z wyświetlaczem wykorzystuje interfejs SPI. Funkcje przesyłające i odbierająca dane to:

  1. uint8_t FT801_Read8BitData(unsigned long AddressToRead);
  2. uint16_t FT801_Read16BitData(unsigned long AddressToRead);
  3. uint32_t FT801_Read32BitData(unsigned long AddressToRead);
  4. void FT801_CommandWrite(unsigned char CommandToSend);
  5. void FT801_Write8BitData(unsigned long AddressToWrite, unsigned char DataToWrite);
  6. void FT801_Write16BitData(unsigned long AddressToWrite, unsigned int DataToWrite);
  7. void FT801_Write32BitData(unsigned long AddressToWrite, unsigned long DataToWrite);

Każda z powyższych funkcji do komunikacji z wyświetlaczem wykorzystuje funkcje z bibliteki HAL'a tzn:

  1. HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
  2. HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);

Funkcja odczytująca jeden bajt danych z podanej lokalizacji:

  1. uint8_t FT801_Read8BitData(unsigned long AddressToRead)
  2. {
  3.   uint8_t readedData = 0;
  4.   uint8_t dummyByte = 0;
  5.   uint8_t memmoryAddresToRead[3] = {0x00};
  6.   memmoryAddresToRead[2] = (uint8_t)(AddressToRead >> 16) | MEM_READ;
  7.   memmoryAddresToRead[1] = (uint8_t)(AddressToRead >> 8);
  8.   memmoryAddresToRead[0] = (uint8_t)(AddressToRead);
  9.   CS_CLEAR();
  10.   HAL_SPI_Transmit(&hspi1, &memmoryAddresToRead[2], 1, 0);
  11.   HAL_SPI_Transmit(&hspi1, &memmoryAddresToRead[1], 1, 0);
  12.   HAL_SPI_Transmit(&hspi1, &memmoryAddresToRead[0], 1, 0);
  13.   HAL_SPI_Transmit(&hspi1, &dummyByte, 1, 10);
  14.   HAL_SPI_Receive(&hspi1, &readedData, 1, 10);
  15.   CS_SET();
  16.   return readedData;
  17. }

Funkcje przesyłające komendę oraz jeden bajt danych do wyświetlacza:

  1. void FT801_CommandWrite(unsigned char CommandToSend)
  2. {
  3.     uint8_t dummyByte = 0x00;
  4.     CS_CLEAR();
  5.     HAL_SPI_Transmit(&hspi1, &CommandToSend, 1, 0);
  6.     HAL_SPI_Transmit(&hspi1, &dummyByte, 1, 0);
  7.     HAL_SPI_Transmit(&hspi1, &dummyByte, 1, 0);
  8.     CS_SET();
  9. }
  10. void FT801_Write8BitData(uint32_t AddressToWrite, unsigned char DataToWrite)
  11. {
  12.     uint8_t memmoryAddresToWrite[3] = {0x00};
  13.     memmoryAddresToWrite[2] = (char) (AddressToWrite >> 16) | MEM_WRITE;
  14.     memmoryAddresToWrite[1] = (char) (AddressToWrite >> 8);
  15.     memmoryAddresToWrite[0] = (char) (AddressToWrite);
  16.     CS_CLEAR();
  17.     HAL_SPI_Transmit(&hspi1, &memmoryAddresToWrite[2], 1, 0);
  18.     HAL_SPI_Transmit(&hspi1, &memmoryAddresToWrite[1], 1, 0);
  19.     HAL_SPI_Transmit(&hspi1, &memmoryAddresToWrite[0], 1, 0);
  20.     HAL_SPI_Transmit(&hspi1, &DataToWrite, 1, 0);
  21.     CS_SET();
  22. }

Ustawienie dotyku wykonuję poprzez przeprowadzenie standardowej procedury polegającej na kliknięciu w trzy punkty wyświetlane na ekranie. Następnie po wprowadzeniu tych danych do sterownika wykonują odczytanie i zapisanie ich jako wartości kalibrujących wyświetlacz:

  1. void FT801_TouchpadReadCalibration8(uint8_t *array)
  2. {
  3.     for (uint8_t i = 0; i < 24; i++)
  4.     {
  5.         *(array + i) = FT801_Read8BitData(REG_TOUCH_TRANSFORM_A + i);
  6.     }
  7. }
  8. void FT801_TouchSetCalibration8(void)
  9. {
  10.     uint8_t array[] = { REG_TOUCH_TRANSFORM_A_1, REG_TOUCH_TRANSFORM_A_2, REG_TOUCH_TRANSFORM_A_3, REG_TOUCH_TRANSFORM_A_4,
  11.                      REG_TOUCH_TRANSFORM_B_1, REG_TOUCH_TRANSFORM_B_2, REG_TOUCH_TRANSFORM_B_3, REG_TOUCH_TRANSFORM_B_4,
  12.                      REG_TOUCH_TRANSFORM_C_1, REG_TOUCH_TRANSFORM_C_2, REG_TOUCH_TRANSFORM_C_3, REG_TOUCH_TRANSFORM_C_4,
  13.                      REG_TOUCH_TRANSFORM_D_1, REG_TOUCH_TRANSFORM_D_2, REG_TOUCH_TRANSFORM_D_3, REG_TOUCH_TRANSFORM_D_4,
  14.                      REG_TOUCH_TRANSFORM_E_1, REG_TOUCH_TRANSFORM_E_2, REG_TOUCH_TRANSFORM_E_3, REG_TOUCH_TRANSFORM_E_4,
  15.                      REG_TOUCH_TRANSFORM_F_1, REG_TOUCH_TRANSFORM_F_2, REG_TOUCH_TRANSFORM_F_3, REG_TOUCH_TRANSFORM_F_4
  16.     };
  17.     for (uint8_t i = 0; i < 24; i++)
  18.     {
  19.         FT801_Write8BitData(REG_TOUCH_TRANSFORM_A + i, *(array + i));
  20.     }
  21. }

Tutaj można też wykorzystać informację zapisane przez producenta w projekcie dla płyty Revelation Board:

  1. /* Value from Revelation_Board_FT80X_demo_firmware_source_Rev.1.3 */
  2. #define REG_TOUCH_TRANSFORM_A_VALUE 0x0000640F
  3. #define REG_TOUCH_TRANSFORM_B_VALUE 0xFFFFFc25
  4. #define REG_TOUCH_TRANSFORM_C_VALUE 0xFFF73909
  5. #define REG_TOUCH_TRANSFORM_D_VALUE 0x0000014B
  6. #define REG_TOUCH_TRANSFORM_E_VALUE 0x00006125
  7. #define REG_TOUCH_TRANSFORM_F_VALUE 0xFFF56FDB
  8. void FT801_TouchSetCalibration32(uint32_t *array)
  9. {
  10.     FT801_Write32BitData(REG_TOUCH_TRANSFORM_A, *(array + 0));
  11.     FT801_Write32BitData(REG_TOUCH_TRANSFORM_B, *(array + 1));
  12.     FT801_Write32BitData(REG_TOUCH_TRANSFORM_C, *(array + 2));
  13.     FT801_Write32BitData(REG_TOUCH_TRANSFORM_D, *(array + 3));
  14.     FT801_Write32BitData(REG_TOUCH_TRANSFORM_E, *(array + 4));
  15.     FT801_Write32BitData(REG_TOUCH_TRANSFORM_F, *(array + 5));
  16. }

Funkcje rysujące:


Poniżej wykaz funkcji wykonujących rysowanie obiektów na ekranie:

  1. void FT801_DrawRectangle_Simple(uint32_t *commandOffset, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t color_RGB_tab[3]);
  2. void FT801_DrawRectangle(uint32_t *commandOffset, Ft801_Rectangle_Typedef rectStruct);
  3. void FT801_DrawLine_Simple(uint32_t *commandOffset, uint16_t x_start, uint16_t y_start, uint16_t x_stop, uint16_t y_stop, uint16_t size, uint8_t color_RGB_tab[3]);
  4. void FT801_DrawLine(uint32_t *commandOffset, Ft801_Line_Typedef lineStruct);
  5. void FT801_DrawPoint_Simple(uint32_t *commandOffset, uint16_t x, uint16_t y, uint16_t size, uint8_t color_RGB_tab[3]);
  6. void FT801_DrawPoint(uint32_t *commandOffset, Ft801_Point_Typedef pointStruct);

Poniżej funkcja rysująca prostokąt na ekranie:

  1. void FT801_DrawRectangle_Simple(uint32_t *commandOffset, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t color_RGB_tab[3])
  2. {
  3.     uint32_t cmdOffset;
  4.     cmdOffset =*commandOffset;
  5.     FT801_SetRGBColor(&cmdOffset, color_RGB_tab[0],
  6.                                 color_RGB_tab[1],
  7.                                 color_RGB_tab[2]);
  8.     FT801_Write32BitData(RAM_CMD + cmdOffset, (DL_LINE_WIDTH | (1*16)));
  9.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
  10.     FT801_Write32BitData(RAM_CMD + cmdOffset, (DL_BEGIN | RECTS));
  11.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
  12.     FT801_Write32BitData(RAM_CMD + cmdOffset, DL_VERTEX2F |
  13.                                    ((x1 *16)<<15) |
  14.                                    (y1 *16)<<0);
  15.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
  16.     FT801_Write32BitData(RAM_CMD + cmdOffset, DL_VERTEX2F |
  17.                                    ((x2 *16)<<15) |
  18.                                    (y2 *16)<<0);
  19.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
  20.     FT801_Write32BitData(RAM_CMD + cmdOffset, (DL_END));
  21.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
  22.     FT801_SetRGBColor(&cmdOffset, 0xFF, 0xFF, 0xFF);
  23.     *commandOffset = cmdOffset;
  24. }

Obsługa przycisków:


Poniżej funkcja odpowiedzialna za wyświetlenie przycisku na ekranie:

  1. void FT801_ConfigAndDisplay_BtnTag(uint32_t *commandOffset, const uint16_t x, const uint16_t y, const uint16_t sizeWidth, const uint16_t sizeHeight, const uint16_t font, const uint16_t displayOptions, const uint32_t foreGroundColor, const uint8_t rgbTxtColor[],
  2. const uint32_t gradient, const char *text, uint8_t btnTag)
  3. {
  4.     uint32_t cmdOffset;
  5.     cmdOffset = *commandOffset;
  6.     Ft801_Btn_Typedef buttonStruct;
  7.     buttonStruct.x = x;
  8.     buttonStruct.y = y;
  9.     buttonStruct.siz_w = sizeWidth;
  10.     buttonStruct.siz_h = sizeHeight;
  11.     buttonStruct.font = font;
  12.     buttonStruct.options = displayOptions;
  13.     buttonStruct.fgcolor = foreGroundColor;
  14.     buttonStruct.color_RGB_tab[0] = rgbTxtColor[0];
  15.     buttonStruct.color_RGB_tab[1] = rgbTxtColor[1];
  16.     buttonStruct.color_RGB_tab[2] = rgbTxtColor[2];
  17.     buttonStruct.gradcolor = gradient;
  18.     buttonStruct.s = text;
  19.     FT801_Write32BitData(RAM_CMD + cmdOffset, (DL_TAG | btnTag));
  20.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
  21.     FT801_Display_Btn(&cmdOffset, buttonStruct);
  22.     *commandOffset =cmdOffset;
  23. }

  1. void FT801_Display_Btn(uint32_t *commandOffset, Ft801_Btn_Typedef btnStruct)
  2. {
  3.     uint32_t cmdOffset;
  4.     cmdOffset =*commandOffset;
  5.     FT801_SetRGBColor(&cmdOffset, btnStruct.color_RGB_tab[0],
  6.                                     btnStruct.color_RGB_tab[1],
  7.                                     btnStruct.color_RGB_tab[2]);
  8.     FT801_Write32BitData(RAM_CMD + cmdOffset, CMD_FGCOLOR);
  9.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
  10.     FT801_Write32BitData(RAM_CMD + cmdOffset, btnStruct.fgcolor);
  11.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
  12.     FT801_Write32BitData(RAM_CMD + cmdOffset, CMD_GRADCOLOR);
  13.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
  14.     FT801_Write32BitData(RAM_CMD + cmdOffset, btnStruct.gradcolor);
  15.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
  16.     FT801_Write32BitData(RAM_CMD + cmdOffset, CMD_BUTTON);
  17.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
  18.     FT801_Write16BitData(RAM_CMD + cmdOffset, btnStruct.x);
  19.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 2);
  20.     FT801_Write16BitData(RAM_CMD + cmdOffset, btnStruct.y);
  21.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 2);
  22.     FT801_Write16BitData(RAM_CMD + cmdOffset, btnStruct.siz_w);
  23.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 2);
  24.     FT801_Write16BitData(RAM_CMD + cmdOffset, btnStruct.siz_h);
  25.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 2);
  26.     FT801_Write16BitData(RAM_CMD + cmdOffset, btnStruct.font);
  27.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 2);
  28.     FT801_Write16BitData(RAM_CMD + cmdOffset, btnStruct.options);
  29.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 2);
  30.     while (1)
  31.     {
  32.         FT801_Write8BitData(RAM_CMD + cmdOffset, *btnStruct.s);
  33.         cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 1);
  34.         if (*btnStruct.s =='\0') {
  35.             break;
  36.         }
  37.         btnStruct.s++;
  38.     }
  39.     while ((cmdOffset %4) !=0)
  40.     {
  41.         FT801_Write8BitData(RAM_CMD + cmdOffset, '\0');
  42.         cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 1);
  43.     }
  44.     //Set the bitmap color to White
  45.     FT801_SetRGBColor(&cmdOffset, 0xFF, 0xFF, 0xFF);
  46.     *commandOffset = cmdOffset;
  47. }

W celu identyfikacji klikniętego przycisku wykorzystuje opcje btnTag. Oznacza ona dodanie specjalnego numeru identyfikującego danych przycisk.

Aby odczytać informację który przycisk został wciśnięty należy odczytać jeden z rejestrów:

  1. uint16_t FT801_TouchpadReadTag(void)
  2. {
  3.     return (uint16_t)(FT801_Read32BitData(REG_TOUCH_TAG) & 0xFFFF);
  4. }

Odczytane z rejestru informację należy jeszcze delikatnie obrobić:

  1. ReadValue = (FT801_TouchpadReadTag() >> 8);

Tak przygotowane dane pozwolą na odczytanie kodu wciśniętego przycisku. Do tego można użyć instrukcji warunkowych jak switch bądź if:

  1. switch (reg_tag)
  2. {
  3.     case TEST_BTN_TAG:
  4.     {
  5.         if(test == 0)
  6.         {
  7.             test = 1;
  8.             test2 = 1;
  9.             size = sprintf(Data, "BUTTON_NASTAW_TAG %u\n\r", 1);
  10.             HAL_UART_Transmit(&huart2, Data, size, 200);
  11.         }
  12.         break;
  13.     }
  14.     default:
  15.     {
  16.         break;
  17.     }
  18. }

Wyświetlanie zdjęć na ekranie jest możliwe za pomocą funkcji

  1. void FT801_DisplayImage_NoRAMG(uint32_t *commandOffset, const unsigned char *arrayPtr, uint16_t sizeWidth,
  2.                                                 uint16_t sizeHeight, uint16_t x, uint16_t y)
  3. {
  4.     uint32_t cmdOffset;
  5.     cmdOffset = *commandOffset;
  6.     Ft801_Picture_Typedef picStruct;
  7.     picStruct.pictureDataBuffer = (unsigned char *)arrayPtr;
  8.     picStruct.sizeHeight = sizeHeight;
  9.     picStruct.sizeWidth = sizeWidth;
  10.     picStruct.x = x;
  11.     picStruct.y = y;
  12.     FT801_DisplayPicture_RGB565(&cmdOffset, picStruct);
  13.     FT801_Write32BitData(RAM_CMD + cmdOffset, (DL_RESTORE_CONTEXT));
  14.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
  15.     FT801_Write32BitData(RAM_CMD + cmdOffset, (DL_SAVE_CONTEXT));
  16.     cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
  17.     *commandOffset = cmdOffset;
  18. }

Zdjęcia muszą być przygotowane w formacie binarnym. Do przygotowania grafik służą odpowiednie programy. Najprostszym rozwiązaniem wydaję się być EVE Asset Builder.


Wygenerowany przez ten program obraz można wrzucić bezpośrednio do kodu z pliku rawh do tablicy z danymi. 

W celu wyświetlenia zdjęcia należy skorzystać z jednej z następujących funkcji:

  1. void FT801_DisplayPicture_RGB565(uint32_t *commandOffset, Ft801_Picture_Typedef pictureStruct);
  2. void FT801_DisplayPicture_RGB565_RAMGLoad(uint32_t *commandOffset, Ft801_Picture_Typedef pictureStruct);
  3. void FT801_DisplayImage_WithRAMGLoadControl(uint32_t *commandOffset, const unsigned char *arrayPtr, uint16_t sizeWidthuint16_t sizeHeight, uint16_t x, uint16_t y);
  4. void FT801_DisplayImage_NoRAMG(uint32_t *commandOffset, const unsigned char *arrayPtr, uint16_t sizeWidthuint16_t sizeHeight, uint16_t x, uint16_t y);

Jeśli chodzi o wyświetlanie czcionek to są one dostępne z ograniczonej puli. W celu ich wywołania należy wprowadzić jej numer do funkcji. Zakres domyślnych czcionek to od 16 do 31. 

Czcionki o numerach 16, 18 oraz od 20 do 31 są czcionkami podstawowymi. Zawierają one znaki ASCII z zakresu od 0 do 127. Czcionki o numerach 17 oraz 19 zawierają rozszerzoną tabelę znaków ASCII. Co oznacza, że zawierają one znaki umieszczone w tabeli poniżej:

[1] - Strona 24

Dodatkowo użytkownik może zdefiniować własne czcionki które będą zapisywane w pamięci RAM_G układu. 

W celu obsługi niestandardowej czcionki z pomocą przychodzi program EVE Asset Builder, zakładka Generate Font:


Tak przygotowane czcionki należy wkleić do programu w postaci L1, L4, L8. Instrukcje postępowania można znaleźć w tym dokumencie:

https://www.ftdichip.com/Support/Documents/AppNotes/AN_277_FT800_Custom_Font_Implement.pdf

Biblioteka:


[1] Datasheet - https://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT801.pdf