317 lines
8.9 KiB
C
317 lines
8.9 KiB
C
/*
|
|
* Copyright 2019-2021 NXP
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "lvgl_support.h"
|
|
#include "lvgl.h"
|
|
#if defined(SDK_OS_FREE_RTOS)
|
|
#include "FreeRTOS.h"
|
|
#include "semphr.h"
|
|
#endif
|
|
|
|
#include "board.h"
|
|
#include "lvgl_support.h"
|
|
#include "fsl_gpio.h"
|
|
#include "fsl_debug_console.h"
|
|
#include "fsl_ili9341.h"
|
|
#include "fsl_ft6x06.h"
|
|
#include "fsl_spi_cmsis.h"
|
|
#include "fsl_i2c_cmsis.h"
|
|
|
|
/*******************************************************************************
|
|
* Definitions
|
|
******************************************************************************/
|
|
|
|
/* Port Me, Start. */
|
|
#define BOARD_TOUCH_I2C Driver_I2C4
|
|
#define BOARD_TOUCH_I2C_IRQ FLEXCOMM4_IRQn
|
|
#define BOARD_TOUCH_I2C_FREQ_FUNC I2C4_GetFreq
|
|
#define BOARD_TOUCH_I2C_FREQ CLOCK_GetFlexCommClkFreq(4U)
|
|
|
|
#define BOARD_LCD_SPI Driver_SPI8
|
|
#define BOARD_LCD_SPI_BAUDRATE 10000000U
|
|
#define BOARD_LCD_SPI_IRQ FLEXCOMM8_IRQn
|
|
#define BOARD_LCD_SPI_FREQ_FUNC SPI8_GetFreq
|
|
#define BOARD_LCD_SPI_FREQ CLOCK_GetHsLspiClkFreq()
|
|
#define BOARD_LCD_SPI_DMA_IRQ DMA0_IRQn
|
|
/* Port Me, End. */
|
|
|
|
/*******************************************************************************
|
|
* Prototypes
|
|
******************************************************************************/
|
|
static void DEMO_InitLcd(void);
|
|
static void DEMO_InitTouch(void);
|
|
static void DEMO_ReadTouch(lv_indev_drv_t *drv, lv_indev_data_t *data);
|
|
static void DEMO_FlushDisplay(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p);
|
|
/*******************************************************************************
|
|
* Variables
|
|
******************************************************************************/
|
|
static ft6x06_handle_t touch_handle;
|
|
static volatile uint32_t spi_event;
|
|
static volatile bool spi_event_received;
|
|
static ft6x06_handle_t touch_handle;
|
|
#if defined(SDK_OS_FREE_RTOS)
|
|
static SemaphoreHandle_t s_transferDone;
|
|
#else
|
|
static volatile bool s_transferDone;
|
|
#endif
|
|
SDK_ALIGN(static uint8_t s_frameBuffer[2][LCD_VIRTUAL_BUF_SIZE * LCD_FB_BYTE_PER_PIXEL], 4);
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
void lv_port_pre_init(void)
|
|
{
|
|
}
|
|
|
|
uint32_t BOARD_LCD_SPI_FREQ_FUNC(void)
|
|
{
|
|
return BOARD_LCD_SPI_FREQ;
|
|
}
|
|
|
|
uint32_t BOARD_TOUCH_I2C_FREQ_FUNC(void)
|
|
{
|
|
return BOARD_TOUCH_I2C_FREQ;
|
|
}
|
|
|
|
static void SPI_MasterSignalEvent(uint32_t event)
|
|
{
|
|
#if defined(SDK_OS_FREE_RTOS)
|
|
BaseType_t taskAwake = pdFALSE;
|
|
|
|
xSemaphoreGiveFromISR(s_transferDone, &taskAwake);
|
|
|
|
portYIELD_FROM_ISR(taskAwake);
|
|
#else
|
|
s_transferDone = true;
|
|
#endif
|
|
}
|
|
|
|
static void SPI_WaitEvent(void)
|
|
{
|
|
#if defined(SDK_OS_FREE_RTOS)
|
|
if (xSemaphoreTake(s_transferDone, portMAX_DELAY) != pdTRUE)
|
|
{
|
|
PRINTF("LCD SPI transfer error\r\n");
|
|
}
|
|
#else
|
|
while (false == s_transferDone)
|
|
{
|
|
}
|
|
s_transferDone = false;
|
|
#endif
|
|
}
|
|
|
|
static void DEMO_SPI_LCD_WriteCmd(uint8_t Data)
|
|
{
|
|
GPIO_PortClear(BOARD_LCD_DC_GPIO, BOARD_LCD_DC_GPIO_PORT, 1u << BOARD_LCD_DC_GPIO_PIN);
|
|
BOARD_LCD_SPI.Send(&Data, 1);
|
|
SPI_WaitEvent();
|
|
}
|
|
|
|
static void DEMO_SPI_LCD_WriteData(uint8_t Data)
|
|
{
|
|
GPIO_PortSet(BOARD_LCD_DC_GPIO, BOARD_LCD_DC_GPIO_PORT, 1u << BOARD_LCD_DC_GPIO_PIN);
|
|
BOARD_LCD_SPI.Send(&Data, 1);
|
|
SPI_WaitEvent();
|
|
}
|
|
|
|
static void DEMO_SPI_LCD_WriteMultiData(const uint8_t *pData, int NumItems)
|
|
{
|
|
GPIO_PortSet(BOARD_LCD_DC_GPIO, BOARD_LCD_DC_GPIO_PORT, 1u << BOARD_LCD_DC_GPIO_PIN);
|
|
while (NumItems > DMA_MAX_TRANSFER_COUNT)
|
|
{
|
|
BOARD_LCD_SPI.Send(pData, DMA_MAX_TRANSFER_COUNT);
|
|
SPI_WaitEvent();
|
|
NumItems -= DMA_MAX_TRANSFER_COUNT;
|
|
pData += DMA_MAX_TRANSFER_COUNT;
|
|
}
|
|
BOARD_LCD_SPI.Send(pData, NumItems);
|
|
SPI_WaitEvent();
|
|
}
|
|
|
|
static void DEMO_InitLcd(void)
|
|
{
|
|
/* Define the init structure for the data/command output pin */
|
|
gpio_pin_config_t dc_config = {
|
|
kGPIO_DigitalOutput,
|
|
1,
|
|
};
|
|
|
|
/* attach 12 MHz clock to SPI1 */
|
|
CLOCK_AttachClk(kEXT_CLK_to_PLL0);
|
|
|
|
/* Init data/command GPIO output . */
|
|
GPIO_PortInit(BOARD_LCD_DC_GPIO, BOARD_LCD_DC_GPIO_PORT);
|
|
GPIO_PinInit(BOARD_LCD_DC_GPIO, BOARD_LCD_DC_GPIO_PORT, BOARD_LCD_DC_GPIO_PIN, &dc_config);
|
|
|
|
#if defined(SDK_OS_FREE_RTOS)
|
|
s_transferDone = xSemaphoreCreateBinary();
|
|
if (NULL == s_transferDone)
|
|
{
|
|
PRINTF("Semaphore create failed\r\n");
|
|
assert(0);
|
|
}
|
|
#else
|
|
s_transferDone = false;
|
|
#endif
|
|
|
|
#if defined(SDK_OS_FREE_RTOS)
|
|
/* FreeRTOS kernel API is used in SPI ISR, so need to set proper IRQ priority. */
|
|
NVIC_SetPriority(BOARD_LCD_SPI_IRQ, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
|
|
NVIC_SetPriority(BOARD_LCD_SPI_DMA_IRQ, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
|
|
#endif
|
|
|
|
/* SPI master init */
|
|
BOARD_LCD_SPI.Initialize(SPI_MasterSignalEvent);
|
|
BOARD_LCD_SPI.PowerControl(ARM_POWER_FULL);
|
|
BOARD_LCD_SPI.Control(ARM_SPI_MODE_MASTER | ARM_SPI_CPOL1_CPHA1 | ARM_SPI_DATA_BITS(8), BOARD_LCD_SPI_BAUDRATE);
|
|
|
|
FT9341_Init(DEMO_SPI_LCD_WriteData, DEMO_SPI_LCD_WriteCmd);
|
|
/* Change to landscape view. */
|
|
DEMO_SPI_LCD_WriteCmd(ILI9341_CMD_MAC);
|
|
DEMO_SPI_LCD_WriteData(0x28);
|
|
}
|
|
|
|
void lv_port_disp_init(void)
|
|
{
|
|
static lv_disp_draw_buf_t disp_buf;
|
|
|
|
memset(s_frameBuffer, 0, sizeof(s_frameBuffer));
|
|
lv_disp_draw_buf_init(&disp_buf, s_frameBuffer[0], s_frameBuffer[1], LCD_VIRTUAL_BUF_SIZE);
|
|
|
|
/*-------------------------
|
|
* Initialize your display
|
|
* -----------------------*/
|
|
DEMO_InitLcd();
|
|
|
|
/*-----------------------------------
|
|
* Register the display in LittlevGL
|
|
*----------------------------------*/
|
|
|
|
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
|
|
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
|
|
|
/*Set the resolution of the display*/
|
|
disp_drv.hor_res = LCD_WIDTH;
|
|
disp_drv.ver_res = LCD_HEIGHT;
|
|
|
|
/*Used to copy the buffer's content to the display*/
|
|
disp_drv.flush_cb = DEMO_FlushDisplay;
|
|
|
|
/*Set a display buffer*/
|
|
disp_drv.draw_buf = &disp_buf;
|
|
|
|
/*Finally register the driver*/
|
|
lv_disp_drv_register(&disp_drv);
|
|
}
|
|
|
|
static void DEMO_FlushDisplay(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
|
|
{
|
|
lv_coord_t x1 = area->x1;
|
|
lv_coord_t y1 = area->y1;
|
|
lv_coord_t x2 = area->x2;
|
|
lv_coord_t y2 = area->y2;
|
|
|
|
uint8_t data[4];
|
|
const uint8_t *pdata = (const uint8_t *)color_p;
|
|
uint32_t send_size = (x2 - x1 + 1) * (y2 - y1 + 1) * LCD_FB_BYTE_PER_PIXEL;
|
|
|
|
/*Column addresses*/
|
|
DEMO_SPI_LCD_WriteCmd(ILI9341_CMD_COLADDR);
|
|
data[0] = (x1 >> 8) & 0xFF;
|
|
data[1] = x1 & 0xFF;
|
|
data[2] = (x2 >> 8) & 0xFF;
|
|
data[3] = x2 & 0xFF;
|
|
DEMO_SPI_LCD_WriteMultiData(data, 4);
|
|
|
|
/*Page addresses*/
|
|
DEMO_SPI_LCD_WriteCmd(ILI9341_CMD_PAGEADDR);
|
|
data[0] = (y1 >> 8) & 0xFF;
|
|
data[1] = y1 & 0xFF;
|
|
data[2] = (y2 >> 8) & 0xFF;
|
|
data[3] = y2 & 0xFF;
|
|
DEMO_SPI_LCD_WriteMultiData(data, 4);
|
|
|
|
/*Memory write*/
|
|
DEMO_SPI_LCD_WriteCmd(ILI9341_CMD_GRAM);
|
|
DEMO_SPI_LCD_WriteMultiData(pdata, send_size);
|
|
|
|
lv_disp_flush_ready(disp_drv);
|
|
}
|
|
|
|
void lv_port_indev_init(void)
|
|
{
|
|
static lv_indev_drv_t indev_drv;
|
|
|
|
/*------------------
|
|
* Touchpad
|
|
* -----------------*/
|
|
|
|
/*Initialize your touchpad */
|
|
DEMO_InitTouch();
|
|
|
|
/*Register a touchpad input device*/
|
|
lv_indev_drv_init(&indev_drv);
|
|
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
|
indev_drv.read_cb = DEMO_ReadTouch;
|
|
lv_indev_drv_register(&indev_drv);
|
|
}
|
|
|
|
static void I2C_MasterSignalEvent(uint32_t event)
|
|
{
|
|
/* Notify touch driver about status of the IO operation */
|
|
FT6X06_EventHandler(&touch_handle, event);
|
|
}
|
|
|
|
/*Initialize your touchpad*/
|
|
static void DEMO_InitTouch(void)
|
|
{
|
|
status_t status;
|
|
|
|
/* The FreeRTOS kernel APIs are not used in I2C ISR, so the
|
|
* interrupt priority could be set to 0.
|
|
*/
|
|
NVIC_SetPriority(BOARD_TOUCH_I2C_IRQ, 0);
|
|
|
|
/* attach 12 MHz clock to I2C0 */
|
|
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM4);
|
|
|
|
/*Init I2C1 */
|
|
BOARD_TOUCH_I2C.Initialize(I2C_MasterSignalEvent);
|
|
BOARD_TOUCH_I2C.PowerControl(ARM_POWER_FULL);
|
|
BOARD_TOUCH_I2C.Control(ARM_I2C_BUS_SPEED, ARM_I2C_BUS_SPEED_FAST);
|
|
|
|
status = FT6X06_Init(&touch_handle, &BOARD_TOUCH_I2C);
|
|
|
|
if (status != kStatus_Success)
|
|
{
|
|
PRINTF("Touch panel init failed\n");
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
/* Will be called by the library to read the touchpad */
|
|
static void DEMO_ReadTouch(lv_indev_drv_t *drv, lv_indev_data_t *data)
|
|
{
|
|
touch_event_t touch_event;
|
|
static int touch_x = 0;
|
|
static int touch_y = 0;
|
|
|
|
data->state = LV_INDEV_STATE_REL;
|
|
|
|
if (kStatus_Success == FT6X06_GetSingleTouch(&touch_handle, &touch_event, &touch_x, &touch_y))
|
|
{
|
|
if ((touch_event == kTouch_Down) || (touch_event == kTouch_Contact))
|
|
{
|
|
data->state = LV_INDEV_STATE_PR;
|
|
}
|
|
}
|
|
|
|
/*Set the last pressed coordinates*/
|
|
data->point.x = LCD_WIDTH - touch_y;
|
|
data->point.y = touch_x;
|
|
}
|