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:
- static void SPI_Init(void)
- {
- hspi1.Instance = SPI1;
- hspi1.Init.Mode = SPI_MODE_MASTER;
- hspi1.Init.Direction = SPI_DIRECTION_2LINES;
- hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
- hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
- hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
- hspi1.Init.NSS = SPI_NSS_SOFT;
- hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;//SPI_BAUDRATEPRESCALER_2;
- hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
- hspi1.Init.TIMode = SPI_TIMODE_DISABLED;
- hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
- hspi1.Init.CRCPolynomial = 10;
- HAL_SPI_Init(&hspi1);
- }
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:
- static void MX_USART2_UART_Init(void)
- {
- huart2.Instance = USART2;
- huart2.Init.BaudRate = 115200;
- huart2.Init.WordLength = UART_WORDLENGTH_8B;
- huart2.Init.StopBits = UART_STOPBITS_1;
- huart2.Init.Parity = UART_PARITY_NONE;
- huart2.Init.Mode = UART_MODE_TX_RX;
- huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
- huart2.Init.OverSampling = UART_OVERSAMPLING_16;
- if (HAL_UART_Init(&huart2) != HAL_OK)
- {
- Error_Handler();
- }
- }
Następnym elementem jest uruchomienie kilku dodatkowych pinów jako wyjścia.
Chip Select dla SPI1 (PB6):
- GPIO_InitStruct.Pin = FT800_CS_N;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
- 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:
- GPIO_InitStruct.Pin = GPIO_PIN_8;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Pin odpowiedzialny za reset i uruchomienie układu w tryb pracy czyli PD (PA9):
- GPIO_InitStruct.Pin = FT800_PD_PIN;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
- 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:
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.
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().
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).
Kolejnym elementem jest ustawienie stanu wysokiego na linii PD oraz sprowadzenie jej na chwilę w stan niski co pozwala na reset układu.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).
- static void FT801_SelectSPIInterface(void)
- {
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
- CS_SET();
- }
- static void FT801_SetPDPin(void)
- {
- HAL_GPIO_WritePin(GPIOA, FT800_PD_PIN, GPIO_PIN_SET);
- HAL_Delay(30);
- HAL_GPIO_WritePin(GPIOA, FT800_PD_PIN, GPIO_PIN_RESET);
- HAL_Delay(30);
- HAL_GPIO_WritePin(GPIOA, FT800_PD_PIN, GPIO_PIN_SET);
- HAL_Delay(30);
- }
Następnym elementem jest uzyskanie dostępu do adresu 0x00. Powoduje to wybudzenie układu FT. Po czym należy przejść do ustawienia zegara:
- static void FT801_StartChip(void)
- {
- //Access adress 0 to wake up FTChip
- FT801_CommandWrite(FT800_ACTIVE);
- HAL_Delay(20);
- }
- static void FT801_ConfigClock(void)
- {
- FT801_CommandWrite(FT800_CLKEXT);
- HAL_Delay(20);
- FT801_CommandWrite(FT800_CLK48M);
- HAL_Delay(20);
- }
Dalej sprawdzam czy zostało podłączone odpowiednie urządzenie i wgrywam dodatkowe ustawienia:
- static void FT801_ReadDeviceId(uint8_t expectedID)
- {
- uint8_t readedRegId = FT801_Read8BitData(REG_ID);
- if (readedRegId != expectedID) {
- while(1); {
- /* Infinite loop when different device id than expected */
- }
- }
- }
- FT801_Write8BitData(REG_PCLK, 0); //PCLK to 0
- FT801_Write8BitData(REG_PWM_DUTY, 0); //Backlight to 0
Sprawdzenie czy koprocesor wystartował:
- static void FT801_CheckIfEngineIsReady(void)
- {
- uint8_t engineReadyStatus = FT801_Read8BitData(REG_CPURESET);
- while(engineReadyStatus != 0x00)
- {
- engineReadyStatus = FT801_Read8BitData(REG_CPURESET);
- HAL_Delay(100);
- }
- }
Po inicjalizacji SPI i ustawieniu kierunku na pinach można przejść do wgrywania parametrów wyświetlacza do sterownika FT801:
- #define FT_DispWidth 480L
- #define FT_DispHeight 272L
- #define FT_DispHCycle 548L
- #define FT_DispHOffset 43L
- #define FT_DispHSync0 0L
- #define FT_DispHSync1 41L
- #define FT_DispVCycle 292L
- #define FT_DispVOffset 12L
- #define FT_DispVSync0 0L
- #define FT_DispVSync1 10L
- #define FT_DispPCLK 5
- #define FT_DispSwizzle 0
- #define FT_DispPCLKPol 1
- #define FT_DispCSpread 0
- #define FT_DispDither 1
- static void FT801_SetConfigurationParameters(void)
- {
- LCD_Width = FT_DispWidth;
- LCD_Height = FT_DispHeight;
- LCD_Hcycle = FT_DispHCycle;
- LCD_Hoffset = FT_DispHOffset;
- LCD_Hsync0 = FT_DispHSync0;
- LCD_Hsync1 = FT_DispHSync1;
- LCD_Vcycle = FT_DispVCycle;
- LCD_Voffset = FT_DispVOffset;
- LCD_Vsync0 = FT_DispVSync0;
- LCD_Vsync1 = FT_DispVSync1;
- LCD_PCLK = FT_DispPCLK;
- LCD_Swizzle = FT_DispSwizzle;
- LCD_Pclkpol = FT_DispPCLKPol;
- LCD_DispCSpread = FT_DispCSpread;
- LCD_DispDither = FT_DispDither;
- }
- static void FT801_WriteInitialSettings(void)
- {
- FT801_Write16BitData(REG_HCYCLE, LCD_Hcycle);
- FT801_Write16BitData(REG_HOFFSET, LCD_Hoffset);
- FT801_Write16BitData(REG_HSYNC0, LCD_Hsync0);
- FT801_Write16BitData(REG_HSYNC1, LCD_Hsync1);
- FT801_Write16BitData(REG_VCYCLE, LCD_Vcycle);
- FT801_Write16BitData(REG_VOFFSET, LCD_Voffset);
- FT801_Write16BitData(REG_VSYNC0, LCD_Vsync0);
- FT801_Write16BitData(REG_VSYNC1, LCD_Vsync1);
- FT801_Write8BitData(REG_SWIZZLE, LCD_Swizzle);
- FT801_Write8BitData(REG_PCLK_POL, LCD_Pclkpol);
- FT801_Write16BitData(REG_HSIZE, LCD_Width);
- FT801_Write16BitData(REG_VSIZE, LCD_Height);
- FT801_Write16BitData(REG_CSPREAD, LCD_DispCSpread);
- FT801_Write16BitData(REG_DITHER, LCD_DispDither);
- }
Za uruchomienie wyświetlacza wygląda następująco:
- static void FT801_StartDisplay(void)
- {
- ramDisplayList = RAM_DL;
- FT801_Write32BitData(ramDisplayList, DL_CLEAR_RGB);
- ramDisplayList += 4;
- FT801_Write32BitData(ramDisplayList, (DL_CLEAR | CLR_COL | CLR_STN | CLR_TAG));
- ramDisplayList += 4;
- FT801_Write32BitData(ramDisplayList, DL_DISPLAY);
- FT801_Write32BitData(REG_DLSWAP, DLSWAP_FRAME);
- ramDisplayList = RAM_DL;
- ft800Gpio = FT801_Read8BitData(REG_GPIO);
- ft800Gpio = ft800Gpio | 0x80;
- FT801_Write8BitData(REG_GPIO, ft800Gpio);
- FT801_Write8BitData(REG_PCLK, LCD_PCLK);
- for(int duty = 0; duty <= 128; duty++)
- {
- FT801_Write8BitData(REG_PWM_DUTY, duty);
- HAL_Delay(10);
- }
- }
Komunikacja z wyświetlaczem:
W celu komunikacji z wyświetlaczem wykorzystuje interfejs SPI. Funkcje przesyłające i odbierająca dane to:
- uint8_t FT801_Read8BitData(unsigned long AddressToRead);
- uint16_t FT801_Read16BitData(unsigned long AddressToRead);
- uint32_t FT801_Read32BitData(unsigned long AddressToRead);
- void FT801_CommandWrite(unsigned char CommandToSend);
- void FT801_Write8BitData(unsigned long AddressToWrite, unsigned char DataToWrite);
- void FT801_Write16BitData(unsigned long AddressToWrite, unsigned int DataToWrite);
- 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:
- HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
- 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:
- uint8_t FT801_Read8BitData(unsigned long AddressToRead)
- {
- uint8_t readedData = 0;
- uint8_t dummyByte = 0;
- uint8_t memmoryAddresToRead[3] = {0x00};
- memmoryAddresToRead[2] = (uint8_t)(AddressToRead >> 16) | MEM_READ;
- memmoryAddresToRead[1] = (uint8_t)(AddressToRead >> 8);
- memmoryAddresToRead[0] = (uint8_t)(AddressToRead);
- CS_CLEAR();
- HAL_SPI_Transmit(&hspi1, &memmoryAddresToRead[2], 1, 0);
- HAL_SPI_Transmit(&hspi1, &memmoryAddresToRead[1], 1, 0);
- HAL_SPI_Transmit(&hspi1, &memmoryAddresToRead[0], 1, 0);
- HAL_SPI_Transmit(&hspi1, &dummyByte, 1, 10);
- HAL_SPI_Receive(&hspi1, &readedData, 1, 10);
- CS_SET();
- return readedData;
- }
Funkcje przesyłające komendę oraz jeden bajt danych do wyświetlacza:
- void FT801_CommandWrite(unsigned char CommandToSend)
- {
- uint8_t dummyByte = 0x00;
- CS_CLEAR();
- HAL_SPI_Transmit(&hspi1, &CommandToSend, 1, 0);
- HAL_SPI_Transmit(&hspi1, &dummyByte, 1, 0);
- HAL_SPI_Transmit(&hspi1, &dummyByte, 1, 0);
- CS_SET();
- }
- void FT801_Write8BitData(uint32_t AddressToWrite, unsigned char DataToWrite)
- {
- uint8_t memmoryAddresToWrite[3] = {0x00};
- memmoryAddresToWrite[2] = (char) (AddressToWrite >> 16) | MEM_WRITE;
- memmoryAddresToWrite[1] = (char) (AddressToWrite >> 8);
- memmoryAddresToWrite[0] = (char) (AddressToWrite);
- CS_CLEAR();
- HAL_SPI_Transmit(&hspi1, &memmoryAddresToWrite[2], 1, 0);
- HAL_SPI_Transmit(&hspi1, &memmoryAddresToWrite[1], 1, 0);
- HAL_SPI_Transmit(&hspi1, &memmoryAddresToWrite[0], 1, 0);
- HAL_SPI_Transmit(&hspi1, &DataToWrite, 1, 0);
- CS_SET();
- }
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:
- void FT801_TouchpadReadCalibration8(uint8_t *array)
- {
- for (uint8_t i = 0; i < 24; i++)
- {
- *(array + i) = FT801_Read8BitData(REG_TOUCH_TRANSFORM_A + i);
- }
- }
- void FT801_TouchSetCalibration8(void)
- {
- uint8_t array[] = { REG_TOUCH_TRANSFORM_A_1, REG_TOUCH_TRANSFORM_A_2, REG_TOUCH_TRANSFORM_A_3, REG_TOUCH_TRANSFORM_A_4,
- REG_TOUCH_TRANSFORM_B_1, REG_TOUCH_TRANSFORM_B_2, REG_TOUCH_TRANSFORM_B_3, REG_TOUCH_TRANSFORM_B_4,
- REG_TOUCH_TRANSFORM_C_1, REG_TOUCH_TRANSFORM_C_2, REG_TOUCH_TRANSFORM_C_3, REG_TOUCH_TRANSFORM_C_4,
- REG_TOUCH_TRANSFORM_D_1, REG_TOUCH_TRANSFORM_D_2, REG_TOUCH_TRANSFORM_D_3, REG_TOUCH_TRANSFORM_D_4,
- REG_TOUCH_TRANSFORM_E_1, REG_TOUCH_TRANSFORM_E_2, REG_TOUCH_TRANSFORM_E_3, REG_TOUCH_TRANSFORM_E_4,
- REG_TOUCH_TRANSFORM_F_1, REG_TOUCH_TRANSFORM_F_2, REG_TOUCH_TRANSFORM_F_3, REG_TOUCH_TRANSFORM_F_4
- };
- for (uint8_t i = 0; i < 24; i++)
- {
- FT801_Write8BitData(REG_TOUCH_TRANSFORM_A + i, *(array + i));
- }
- }
Tutaj można też wykorzystać informację zapisane przez producenta w projekcie dla płyty Revelation Board:
- /* Value from Revelation_Board_FT80X_demo_firmware_source_Rev.1.3 */
- #define REG_TOUCH_TRANSFORM_A_VALUE 0x0000640F
- #define REG_TOUCH_TRANSFORM_B_VALUE 0xFFFFFc25
- #define REG_TOUCH_TRANSFORM_C_VALUE 0xFFF73909
- #define REG_TOUCH_TRANSFORM_D_VALUE 0x0000014B
- #define REG_TOUCH_TRANSFORM_E_VALUE 0x00006125
- #define REG_TOUCH_TRANSFORM_F_VALUE 0xFFF56FDB
- void FT801_TouchSetCalibration32(uint32_t *array)
- {
- FT801_Write32BitData(REG_TOUCH_TRANSFORM_A, *(array + 0));
- FT801_Write32BitData(REG_TOUCH_TRANSFORM_B, *(array + 1));
- FT801_Write32BitData(REG_TOUCH_TRANSFORM_C, *(array + 2));
- FT801_Write32BitData(REG_TOUCH_TRANSFORM_D, *(array + 3));
- FT801_Write32BitData(REG_TOUCH_TRANSFORM_E, *(array + 4));
- FT801_Write32BitData(REG_TOUCH_TRANSFORM_F, *(array + 5));
- }
Funkcje rysujące:
Poniżej wykaz funkcji wykonujących rysowanie obiektów na ekranie:
- 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]);
- void FT801_DrawRectangle(uint32_t *commandOffset, Ft801_Rectangle_Typedef rectStruct);
- 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]);
- void FT801_DrawLine(uint32_t *commandOffset, Ft801_Line_Typedef lineStruct);
- void FT801_DrawPoint_Simple(uint32_t *commandOffset, uint16_t x, uint16_t y, uint16_t size, uint8_t color_RGB_tab[3]);
- void FT801_DrawPoint(uint32_t *commandOffset, Ft801_Point_Typedef pointStruct);
Poniżej funkcja rysująca prostokąt na ekranie:
- 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])
- {
- uint32_t cmdOffset;
- cmdOffset =*commandOffset;
- FT801_SetRGBColor(&cmdOffset, color_RGB_tab[0],
- color_RGB_tab[1],
- color_RGB_tab[2]);
- FT801_Write32BitData(RAM_CMD + cmdOffset, (DL_LINE_WIDTH | (1*16)));
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
- FT801_Write32BitData(RAM_CMD + cmdOffset, (DL_BEGIN | RECTS));
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
- FT801_Write32BitData(RAM_CMD + cmdOffset, DL_VERTEX2F |
- ((x1 *16)<<15) |
- (y1 *16)<<0);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
- FT801_Write32BitData(RAM_CMD + cmdOffset, DL_VERTEX2F |
- ((x2 *16)<<15) |
- (y2 *16)<<0);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
- FT801_Write32BitData(RAM_CMD + cmdOffset, (DL_END));
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
- FT801_SetRGBColor(&cmdOffset, 0xFF, 0xFF, 0xFF);
- *commandOffset = cmdOffset;
- }
Obsługa przycisków:
Poniżej funkcja odpowiedzialna za wyświetlenie przycisku na ekranie:
- 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[],
- const uint32_t gradient, const char *text, uint8_t btnTag)
- {
- uint32_t cmdOffset;
- cmdOffset = *commandOffset;
- Ft801_Btn_Typedef buttonStruct;
- buttonStruct.x = x;
- buttonStruct.y = y;
- buttonStruct.siz_w = sizeWidth;
- buttonStruct.siz_h = sizeHeight;
- buttonStruct.font = font;
- buttonStruct.options = displayOptions;
- buttonStruct.fgcolor = foreGroundColor;
- buttonStruct.color_RGB_tab[0] = rgbTxtColor[0];
- buttonStruct.color_RGB_tab[1] = rgbTxtColor[1];
- buttonStruct.color_RGB_tab[2] = rgbTxtColor[2];
- buttonStruct.gradcolor = gradient;
- buttonStruct.s = text;
- FT801_Write32BitData(RAM_CMD + cmdOffset, (DL_TAG | btnTag));
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
- FT801_Display_Btn(&cmdOffset, buttonStruct);
- *commandOffset =cmdOffset;
- }
- void FT801_Display_Btn(uint32_t *commandOffset, Ft801_Btn_Typedef btnStruct)
- {
- uint32_t cmdOffset;
- cmdOffset =*commandOffset;
- FT801_SetRGBColor(&cmdOffset, btnStruct.color_RGB_tab[0],
- btnStruct.color_RGB_tab[1],
- btnStruct.color_RGB_tab[2]);
- FT801_Write32BitData(RAM_CMD + cmdOffset, CMD_FGCOLOR);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
- FT801_Write32BitData(RAM_CMD + cmdOffset, btnStruct.fgcolor);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
- FT801_Write32BitData(RAM_CMD + cmdOffset, CMD_GRADCOLOR);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
- FT801_Write32BitData(RAM_CMD + cmdOffset, btnStruct.gradcolor);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
- FT801_Write32BitData(RAM_CMD + cmdOffset, CMD_BUTTON);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
- FT801_Write16BitData(RAM_CMD + cmdOffset, btnStruct.x);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 2);
- FT801_Write16BitData(RAM_CMD + cmdOffset, btnStruct.y);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 2);
- FT801_Write16BitData(RAM_CMD + cmdOffset, btnStruct.siz_w);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 2);
- FT801_Write16BitData(RAM_CMD + cmdOffset, btnStruct.siz_h);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 2);
- FT801_Write16BitData(RAM_CMD + cmdOffset, btnStruct.font);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 2);
- FT801_Write16BitData(RAM_CMD + cmdOffset, btnStruct.options);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 2);
- while (1)
- {
- FT801_Write8BitData(RAM_CMD + cmdOffset, *btnStruct.s);
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 1);
- if (*btnStruct.s =='\0') {
- break;
- }
- btnStruct.s++;
- }
- while ((cmdOffset %4) !=0)
- {
- FT801_Write8BitData(RAM_CMD + cmdOffset, '\0');
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 1);
- }
- //Set the bitmap color to White
- FT801_SetRGBColor(&cmdOffset, 0xFF, 0xFF, 0xFF);
- *commandOffset = cmdOffset;
- }
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:
- uint16_t FT801_TouchpadReadTag(void)
- {
- return (uint16_t)(FT801_Read32BitData(REG_TOUCH_TAG) & 0xFFFF);
- }
Odczytane z rejestru informację należy jeszcze delikatnie obrobić:
- 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:
- switch (reg_tag)
- {
- case TEST_BTN_TAG:
- {
- if(test == 0)
- {
- test = 1;
- test2 = 1;
- size = sprintf(Data, "BUTTON_NASTAW_TAG %u\n\r", 1);
- HAL_UART_Transmit(&huart2, Data, size, 200);
- }
- break;
- }
- default:
- {
- break;
- }
- }
Wyświetlanie zdjęć na ekranie jest możliwe za pomocą funkcji
- void FT801_DisplayImage_NoRAMG(uint32_t *commandOffset, const unsigned char *arrayPtr, uint16_t sizeWidth,
- uint16_t sizeHeight, uint16_t x, uint16_t y)
- {
- uint32_t cmdOffset;
- cmdOffset = *commandOffset;
- Ft801_Picture_Typedef picStruct;
- picStruct.pictureDataBuffer = (unsigned char *)arrayPtr;
- picStruct.sizeHeight = sizeHeight;
- picStruct.sizeWidth = sizeWidth;
- picStruct.x = x;
- picStruct.y = y;
- FT801_DisplayPicture_RGB565(&cmdOffset, picStruct);
- FT801_Write32BitData(RAM_CMD + cmdOffset, (DL_RESTORE_CONTEXT));
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
- FT801_Write32BitData(RAM_CMD + cmdOffset, (DL_SAVE_CONTEXT));
- cmdOffset = FT801_UpdateCommandPointer(cmdOffset, 4);
- *commandOffset = cmdOffset;
- }
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:
- void FT801_DisplayPicture_RGB565(uint32_t *commandOffset, Ft801_Picture_Typedef pictureStruct);
- void FT801_DisplayPicture_RGB565_RAMGLoad(uint32_t *commandOffset, Ft801_Picture_Typedef pictureStruct);
- void FT801_DisplayImage_WithRAMGLoadControl(uint32_t *commandOffset, const unsigned char *arrayPtr, uint16_t sizeWidth, uint16_t sizeHeight, uint16_t x, uint16_t y);
- void FT801_DisplayImage_NoRAMG(uint32_t *commandOffset, const unsigned char *arrayPtr, uint16_t sizeWidth, uint16_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:
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