MCUXpresso_LPC54102/boards/lpcxpresso54102/littlevgl_examples/littlevgl_support.c
2022-05-14 22:28:55 +08:00

286 lines
8.2 KiB
C

/*
* Copyright 2019 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "littlevgl_support.h"
#include "lvgl.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "board.h"
#include "littlevgl_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_I2C0
#define BOARD_TOUCH_I2C_IRQ I2C0_IRQn
#define BOARD_TOUCH_I2C_FREQ_FUNC I2C0_GetFreq
#define BOARD_TOUCH_I2C_FREQ CLOCK_GetI2cClkFreq()
#define BOARD_LCD_SPI Driver_SPI1
#define BOARD_LCD_SPI_BAUDRATE 10000000U
#define BOARD_LCD_SPI_IRQ SPI1_IRQn
#define BOARD_LCD_SPI_FREQ_FUNC SPI1_GetFreq
#define BOARD_LCD_SPI_FREQ CLOCK_GetSpiClkFreq()
#define BOARD_LCD_SPI_DMA_IRQ DMA0_IRQn
/* Port Me, End. */
/*******************************************************************************
* Prototypes
******************************************************************************/
static void DEMO_InitLcd(void);
static void DEMO_InitTouch(void);
static bool DEMO_ReadTouch(lv_indev_data_t *data);
static void DEMO_FlushDisplay(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const 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;
static SemaphoreHandle_t s_transferDone;
static uint8_t s_frameBuffer[2][LCD_VIRTUAL_BUF_SIZE * LCD_FB_BYTE_PER_PIXEL];
/*******************************************************************************
* Code
******************************************************************************/
void lv_port_pre_init(void)
{
/*
* Pass in the frame buffer address to LittlevGL manually, the LV_VDB_ADR
* and LV_VDB2_ADR should be defined to LV_VDB_ADR_INV in lv_conf.h
*/
memset(s_frameBuffer, 0, sizeof(s_frameBuffer));
lv_vdb_set_adr(s_frameBuffer[0], s_frameBuffer[1]);
}
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)
{
BaseType_t taskAwake = pdFALSE;
xSemaphoreGiveFromISR(s_transferDone, &taskAwake);
portYIELD_FROM_ISR(taskAwake);
}
static void SPI_WaitEvent(void)
{
if (xSemaphoreTake(s_transferDone, portMAX_DELAY) != pdTRUE)
{
PRINTF("LCD SPI transfer error\r\n");
}
}
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(kIRC12M_to_SPI);
/* Init data/command GPIO output . */
GPIO_PinInit(BOARD_LCD_DC_GPIO, BOARD_LCD_DC_GPIO_PORT, BOARD_LCD_DC_GPIO_PIN, &dc_config);
s_transferDone = xSemaphoreCreateBinary();
if (NULL == s_transferDone)
{
PRINTF("Semaphore create failed\r\n");
assert(0);
}
/* 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);
/* 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_CPHA0 | 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)
{
/*-------------------------
* Initialize your display
* -----------------------*/
DEMO_InitLcd();
/*-----------------------------------
* Register the display in LittlevGL
*----------------------------------*/
lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
/*Used in buffered mode (LV_VDB_SIZE != 0 in lv_conf.h)*/
disp_drv.disp_flush = DEMO_FlushDisplay;
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
}
static void DEMO_FlushDisplay(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t *color_p)
{
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_flush_ready();
}
void lv_port_indev_init(void)
{
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 = 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(kIRC12M_to_I2C);
/*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 bool DEMO_ReadTouch(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;
/*Return `false` because we are not buffering and no more data to read*/
return false;
}