From 3a44dbbf925c73e343d67529ad6dd6b23f1f1fcd Mon Sep 17 00:00:00 2001 From: Shicheng Chu <1468559561@qq.com> Date: Wed, 31 May 2023 11:40:19 +0800 Subject: [PATCH] [bsp][lpc55sxx]add: drv_lcd and drv_touch (#7569) --- bsp/lpc55sxx/Libraries/drivers/SConscript | 13 +- bsp/lpc55sxx/Libraries/drivers/drv_gt911.c | 198 ++++++++++ bsp/lpc55sxx/Libraries/drivers/drv_gt911.h | 75 ++++ bsp/lpc55sxx/Libraries/drivers/drv_i2c.c | 2 +- bsp/lpc55sxx/Libraries/drivers/drv_spi.h | 18 + bsp/lpc55sxx/Libraries/drivers/drv_st7796.c | 339 ++++++++++++++++++ bsp/lpc55sxx/Libraries/drivers/drv_st7796.h | 68 ++++ .../Libraries/drivers/sample/lcd_sample.c | 68 ++++ .../drivers/sample/lcd_touch_sample.c | 64 ++++ .../Libraries/drivers/sample/touch_sample.c | 47 +++ bsp/lpc55sxx/lpc55s69_nxp_evk/board/Kconfig | 39 ++ 11 files changed, 929 insertions(+), 2 deletions(-) create mode 100644 bsp/lpc55sxx/Libraries/drivers/drv_gt911.c create mode 100644 bsp/lpc55sxx/Libraries/drivers/drv_gt911.h create mode 100644 bsp/lpc55sxx/Libraries/drivers/drv_spi.h create mode 100644 bsp/lpc55sxx/Libraries/drivers/drv_st7796.c create mode 100644 bsp/lpc55sxx/Libraries/drivers/drv_st7796.h create mode 100644 bsp/lpc55sxx/Libraries/drivers/sample/lcd_sample.c create mode 100644 bsp/lpc55sxx/Libraries/drivers/sample/lcd_touch_sample.c create mode 100644 bsp/lpc55sxx/Libraries/drivers/sample/touch_sample.c diff --git a/bsp/lpc55sxx/Libraries/drivers/SConscript b/bsp/lpc55sxx/Libraries/drivers/SConscript index e5714da749..db8bd4d409 100644 --- a/bsp/lpc55sxx/Libraries/drivers/SConscript +++ b/bsp/lpc55sxx/Libraries/drivers/SConscript @@ -49,7 +49,18 @@ if GetDepend('BSP_USING_SOFT_I2C'): if GetDepend('BSP_USING_SOFT_SPI'): src += ['drv_soft_spi.c'] -path = [cwd,cwd + '/config'] +if GetDepend('BSP_USING_LCD'): + src += ['drv_st7796.c'] + src += ['sample/lcd_sample.c'] + +if GetDepend('BSP_USING_TOUCH'): + src += ['drv_gt911.c'] + src += ['sample/touch_sample.c'] + +if GetDepend('BSP_USING_NXP_LCDM_S'): + src += ['sample/lcd_touch_sample.c'] + +path = [cwd] group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path) diff --git a/bsp/lpc55sxx/Libraries/drivers/drv_gt911.c b/bsp/lpc55sxx/Libraries/drivers/drv_gt911.c new file mode 100644 index 0000000000..f2d9a509b4 --- /dev/null +++ b/bsp/lpc55sxx/Libraries/drivers/drv_gt911.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-05-26 Chushicheng the first version + */ + +#include "drv_gt911.h" + +#define LOG_TAG "drv.gt911" +#include + +#ifndef BSP_TOUCH_I2C_BUS +#define BSP_TOUCH_I2C_BUS "i2c1" +#endif +#define CAPT_I2C_ADDR (0x5D) + +#define GT911_REG_RT_CMD 0x8040U +#define GT911_REG_RT_CMD_SW_RST_Pos 2U +#define GT911_REG_RT_CMD_SW_RST_Msk (1U << GT911_REG_RT_CMD_SW_RST_Pos) +#define GT911_REG_RT_CMD_READ_Pos 0U +#define GT911_REG_RT_CMD_READ_Msk (1U << GT911_REG_RT_CMD_READ_Pos) + +#define GT911_REG_CONFIG_VERSION 0x8047U + +#define GT911_REG_MODULE_SW1 0x804DU +#define GT911_REG_MODULE_SW1_INT_Pos 0U +#define GT911_REG_MODULE_SW1_INT_Msk (3U << GT911_REG_MODULE_SW1_INT_Pos) + +#define GT911_REG_PRODUCT_ID 0x8140U + +#define GT911_REG_COORD 0x814EU +#define GT911_REG_COORD_STATUS_Pos 7U +#define GT911_REG_COORD_STATUS_Msk (1U << GT911_REG_COORD_STATUS_Pos) + +#define GT911_REG_POINT0 0x814FU + +static capt_t capt_obj; + +static rt_err_t gt911_ctp_read_reg(gt911_t *ctp, rt_uint16_t reg, rt_uint8_t *data, rt_uint16_t len); +static rt_err_t gt911_ctp_write_reg(gt911_t *ctp, rt_uint16_t reg, rt_uint8_t data); +static rt_err_t gt911_ctp_sw_reset(gt911_t *ctp); +static rt_err_t gt911_ctp_read_config(gt911_t *ctp); +static rt_err_t gt911_ctp_config_interrupt(gt911_t *ctp); +static rt_err_t gt911_ctp_init(gt911_t *ctp); +rt_err_t gt911_ctp_read(gt911_t *ctp, gt911_input_t *input); + +static rt_err_t gt911_ctp_init(gt911_t *ctp) +{ + if (ctp->ops.reset) + { + if (ctp->ops.reset(ctp->user_data) != RT_EOK) + { + return -RT_ERROR; + } + } + if (gt911_ctp_sw_reset(ctp) != RT_EOK) + { + return -RT_ERROR; + } + if (gt911_ctp_read_config(ctp) != RT_EOK) + { + return -RT_ERROR; + } + if (gt911_ctp_config_interrupt(ctp) != RT_EOK) + { + return -RT_ERROR; + } + return RT_EOK; +} + +rt_err_t gt911_ctp_read(gt911_t *ctp, gt911_input_t *input) +{ + rt_uint8_t rx_data[40] = {0}; + + if (gt911_ctp_read_reg(ctp, GT911_REG_COORD, rx_data, 1) != RT_EOK) + { + return -RT_ERROR; + } + if ((rx_data[0] & GT911_REG_COORD_STATUS_Msk) == 0) + { + input->num_pos = 0U; + return RT_EOK; + } + input->num_pos = rx_data[0] & 0x0F; + if (gt911_ctp_read_reg(ctp, GT911_REG_POINT0, rx_data, 40) != RT_EOK) + { + return -RT_ERROR; + } + for (rt_uint8_t i = 0; i < input->num_pos; i++) + { + rt_uint8_t point_offset = 8 * i; /* Each point has 8 bytes */ + + input->pos[i].id = rx_data[point_offset]; /* 0x00: Track ID */ + input->pos[i].pos_x = rx_data[point_offset + 1] | (rx_data[point_offset + 2] << 8U); /* 0x01-0x02: X coord */ + input->pos[i].pos_y = rx_data[point_offset + 3] | (rx_data[point_offset + 4] << 8U); /* 0x03-0x04: Y coord */ + input->pos[i].size = rx_data[point_offset + 5] | (rx_data[point_offset + 6] << 8U); /* 0x05-0x06: Size*/ + } + /* Clear buffer status latch, ready for new data */ + gt911_ctp_write_reg(ctp, GT911_REG_COORD, 0x00); + + return RT_EOK; +} + +static rt_err_t gt911_ctp_read_reg(gt911_t *ctp, rt_uint16_t reg, rt_uint8_t *data, rt_uint16_t len) +{ + rt_uint8_t tx_data[2] = {(reg >> 8U), (reg & 0xFFU)}; + gt911_i2c_xfer_t xfer = + { + .tx_data = tx_data, + .rx_data = data, + .tx_len = 2, + .rx_len = len, + }; + + return ctp->ops.xfer(ctp->user_data, &xfer); +} + +static rt_err_t gt911_ctp_write_reg(gt911_t *ctp, rt_uint16_t reg, rt_uint8_t data) +{ + rt_uint8_t tx_data[3] = {(reg >> 8U), (reg & 0xFFU), data}; + gt911_i2c_xfer_t xfer = + { + .tx_data = tx_data, + .rx_data = NULL, + .tx_len = 3, + .rx_len = 0, + }; + + return ctp->ops.xfer(ctp->user_data, &xfer); +} + +static rt_err_t gt911_ctp_sw_reset(gt911_t *ctp) +{ + return gt911_ctp_write_reg(ctp, GT911_REG_RT_CMD, (GT911_REG_RT_CMD_SW_RST_Msk)); +} + +static rt_err_t gt911_ctp_read_config(gt911_t *ctp) +{ + rt_uint8_t rx_data[7]; + if (gt911_ctp_read_reg(ctp, GT911_REG_CONFIG_VERSION, rx_data, 7) != RT_EOK) + { + return -RT_ERROR; + } + ctp->fw_version = rx_data[0]; /* 0x8047, Config Version */ + ctp->pos_x_max = rx_data[1] | (rx_data[2] << 8U); /* 0x8048-0x8049, Maximum X */ + ctp->pos_y_max = rx_data[3] | (rx_data[4] << 8U); /* 0x804A-0x804B, Maximum Y */ + ctp->pos_max = rx_data[5] & 0x0FU; /* 0x804C, Maximum positions */ + + return RT_EOK; +} + +static rt_err_t gt911_ctp_config_interrupt(gt911_t *ctp) +{ + rt_uint8_t mod_sw1 = 0x00U; + if (gt911_ctp_read_reg(ctp, GT911_REG_MODULE_SW1, &mod_sw1, 0x01) != RT_EOK) + { + return -RT_ERROR; + } + mod_sw1 &= ~(GT911_REG_MODULE_SW1_INT_Msk); + mod_sw1 |= (ctp->int_mode & GT911_REG_MODULE_SW1_INT_Msk); + + return gt911_ctp_write_reg(ctp, GT911_REG_MODULE_SW1, mod_sw1); +} + +static rt_err_t ctp_impl_xfer(void *handle, gt911_i2c_xfer_t *xfer) +{ + capt_t *capt = (capt_t*)handle; + + if(xfer->tx_len) rt_i2c_master_send(capt->bus, CAPT_I2C_ADDR, 0, xfer->tx_data, xfer->tx_len); + if(xfer->rx_len) rt_i2c_master_recv(capt->bus, CAPT_I2C_ADDR, 0, xfer->rx_data, xfer->rx_len); + + return RT_EOK; +} + +int drv_capt_hw_init(void) +{ + capt_obj.bus = (struct rt_i2c_bus_device*)rt_device_find(BSP_TOUCH_I2C_BUS); + if(capt_obj.bus == RT_NULL) + { + LOG_E("no %s device\r\n", BSP_TOUCH_I2C_BUS); + return -RT_ERROR; + } + + capt_obj.gt911.user_data = capt_obj.parent.user_data = &capt_obj; + capt_obj.gt911.ops.xfer = ctp_impl_xfer; + if(gt911_ctp_init(&capt_obj.gt911) != RT_EOK) + { + return -RT_ERROR; + } + rt_device_register(&capt_obj.parent, "capt", RT_DEVICE_FLAG_RDWR); + + return RT_EOK; +} +INIT_COMPONENT_EXPORT(drv_capt_hw_init); diff --git a/bsp/lpc55sxx/Libraries/drivers/drv_gt911.h b/bsp/lpc55sxx/Libraries/drivers/drv_gt911.h new file mode 100644 index 0000000000..2a9d2ce20a --- /dev/null +++ b/bsp/lpc55sxx/Libraries/drivers/drv_gt911.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-05-26 Chushicheng the first version + */ + +#ifndef __DRV_GT911_H +#define __DRV_GT911_H + +#include + +typedef enum +{ + GT911_INT_MODE_IRQ_RISE = 0x00U, + GT911_INT_MODE_IRQ_FALL = 0x01U, + GT911_INT_MODE_POLL = 0x03U, +} gt911_int_mode_t; + +typedef struct +{ + rt_uint8_t id; + rt_uint16_t pos_x; + rt_uint16_t pos_y; + rt_uint16_t size; +} gt911_point_t; + +typedef struct +{ + rt_uint8_t num_pos; + gt911_point_t pos[5]; +} gt911_input_t; + +typedef struct +{ + rt_uint8_t *tx_data; + rt_uint8_t *rx_data; + rt_uint16_t tx_len; + rt_uint16_t rx_len; +} gt911_i2c_xfer_t; + +typedef rt_err_t (*gt911_ops_reset_t)(void *handle); +typedef rt_err_t (*gt911_ops_i2c_xfer_t)(void *handle, gt911_i2c_xfer_t *xfer); + +typedef struct +{ + gt911_ops_reset_t reset; + gt911_ops_i2c_xfer_t xfer; +} gt911_ops_t; + +typedef struct +{ + rt_uint16_t pos_x_max; + rt_uint16_t pos_y_max; + rt_uint8_t pos_max; + rt_uint8_t fw_version; + gt911_int_mode_t int_mode; + gt911_ops_t ops; + void *user_data; +} gt911_t; + +typedef struct +{ + struct rt_device parent; + struct rt_i2c_bus_device *bus; + gt911_t gt911; +} capt_t; + +rt_err_t gt911_ctp_read(gt911_t *ctp, gt911_input_t *input); +int drv_capt_hw_init(void); + +#endif /* __DRV_GT911_H */ diff --git a/bsp/lpc55sxx/Libraries/drivers/drv_i2c.c b/bsp/lpc55sxx/Libraries/drivers/drv_i2c.c index 2a2e314024..128d53a9f7 100644 --- a/bsp/lpc55sxx/Libraries/drivers/drv_i2c.c +++ b/bsp/lpc55sxx/Libraries/drivers/drv_i2c.c @@ -55,7 +55,7 @@ struct lpc_i2c_bus lpc_obj[] = { .I2C = I2C1, .DMA = DMA0, - .dma_chl = 12, + .dma_chl = 7, .device_name = "i2c1", .baud = 100000U, .instance = 1U, diff --git a/bsp/lpc55sxx/Libraries/drivers/drv_spi.h b/bsp/lpc55sxx/Libraries/drivers/drv_spi.h new file mode 100644 index 0000000000..af668ac59d --- /dev/null +++ b/bsp/lpc55sxx/Libraries/drivers/drv_spi.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-05-18 Chushicheng The first version for LPC55S6x + */ + +#ifndef __DRV_SPI_H__ +#define __DRV_SPI_H__ + +#include + +rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin); + +#endif /*__DRV_SPI_H__ */ diff --git a/bsp/lpc55sxx/Libraries/drivers/drv_st7796.c b/bsp/lpc55sxx/Libraries/drivers/drv_st7796.c new file mode 100644 index 0000000000..cd306864f3 --- /dev/null +++ b/bsp/lpc55sxx/Libraries/drivers/drv_st7796.c @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-05-23 Chushicheng the first version + */ + +#include "drv_spi.h" +#include "drv_st7796.h" + +#define LOG_TAG "drv.st7796" +#include + +#ifndef ST7796_LCD_IPS_PANEL +#define ST7796_LCD_IPS_PANEL 1 +#else +#define ST7796_LCD_IPS_PANEL 0 +#endif + +#define ST7796_INIT_SEQ_NAME(x) st7796_init_seq_##x##_480_320 +#if ST7796_LCD_IPS_PANEL +#define ST7796_LCD_INIT_SEQ ST7796_INIT_SEQ_NAME(ips) +#else +#define ST7796_LCD_INIT_SEQ ST7796_INIT_SEQ_NAME(tft) +#endif + +static st7796_t lcd_spi_obj; + +static rt_err_t _st7796_init_seq(st7796_lcd_t *lcd); +static rt_err_t _st7796_window(st7796_lcd_t *lcd, rt_uint16_t x_start, rt_uint16_t x_end, rt_uint16_t y_start, rt_uint16_t y_end); +static rt_err_t _st7796_reset(st7796_lcd_t *lcd); +static rt_err_t st7796_lcd_load(st7796_lcd_t *lcd, void *data, rt_uint16_t x_start, rt_uint16_t x_end, rt_uint16_t y_start, rt_uint16_t y_end); +static rt_err_t st7796_lcd_sleep(st7796_lcd_t *lcd, rt_uint8_t sleep_mode); +static rt_err_t st7796_lcd_display(st7796_lcd_t *lcd, rt_uint8_t display_on); +static rt_err_t st7796_lcd_config(st7796_lcd_t *lcd, st7796_config_t *config); +void lcd_load(rt_uint16_t x_start, rt_uint16_t x_end, rt_uint16_t y_start, rt_uint16_t y_end, void *data); + +static rt_uint8_t st7796_init_seq_tft_480_320[] = +{ + 0x01, 0xF0, 0xC3, /* Enable command part 1 */ + 0x01, 0xF0, 0x96, /* Enable command part 2*/ + 0x08, 0xE8, 0x40, 0x82, 0x07, 0x18, 0x27, 0x0A, 0xB6, 0x33, /* DOCA */ + 0x01, 0xC5, 0x27, /* VCOM control */ + 0x01, 0xC2, 0xA7, /* Power control 3 */ + 0x0E, 0xE0, 0xF0, 0x01, 0x06, 0x0F, 0x12, 0x1D, 0x36, 0x54, 0x44, 0x0C, 0x18, 0x16, 0x13, 0x15, /* PGC */ + 0x0E, 0xE1, 0xF0, 0x01, 0x05, 0x0A, 0x0B, 0x07, 0x32, 0x44, 0x44, 0x0C, 0x18, 0x17, 0x13, 0x16, /* NGC */ + 0x01, 0xF0, 0x3C, /* Disable command part 1 */ + 0x01, 0xF0, 0x69, /* Disable command part 2 */ +}; + +static rt_uint8_t st7796_init_seq_ips_480_320[] = +{ + 0x01, 0xF0, 0xC3, /* Enable command part 1 */ + 0x01, 0xF0, 0x96, /* Enable command part 2 */ + 0x01, 0xB4, 0x01, /* Display inversion */ + 0x02, 0xB1, 0x80, 0x10, /* Frame rate control 1 */ + 0x04, 0xB5, 0x1F, 0x50, 0x00, 0x20, /* Blanking porch control */ + 0x03, 0xB6, 0x8A, 0x07, 0x3B, /* Display function control */ + 0x02, 0xC0, 0x80, 0x64, /* Power control 1 */ + 0x01, 0xC1, 0x13, /* Power control 2 */ + 0x01, 0xC2, 0xA7, /* Power control 3 */ + 0x01, 0xC5, 0x09, /* VCOM control */ + 0x08, 0xE8, 0x40, 0x8A, 0x00, 0x00, 0x29, 0x19, 0xA5, 0x33, /* DOCA */ + 0x0E, 0xE0, 0xF0, 0x06, 0x0B, 0x07, 0x06, 0x05, 0x2E, 0x33, 0x47, 0x3A, 0x17, 0x16, 0x2E, 0x31, /* PGC */ + 0x0E, 0xE1, 0xF0, 0x09, 0x0D, 0x09, 0x08, 0x23, 0x2E, 0x33, 0x46, 0x38, 0x13, 0x13, 0x2C, 0x32, /* NGC */ + 0x01, 0xF0, 0x3C, /* Disable command part 1 */ + 0x01, 0xF0, 0x69, /* Disable command part 2 */ +}; + +static rt_err_t _st7796_init_seq(st7796_lcd_t *lcd) +{ + rt_uint16_t i = 0; + + while (i < sizeof(ST7796_LCD_INIT_SEQ)) + { + if (lcd->cb.write_cmd_cb(lcd->user_data, &ST7796_LCD_INIT_SEQ[i + 1], ST7796_LCD_INIT_SEQ[i] + 1) != RT_EOK) + { + return -RT_ERROR; + }; + i += ST7796_LCD_INIT_SEQ[i] + 2; + } + + return RT_EOK; +} + +static rt_err_t _st7796_window(st7796_lcd_t *lcd, rt_uint16_t x_start, rt_uint16_t x_end, rt_uint16_t y_start, rt_uint16_t y_end) +{ + rt_uint16_t real_x_start, real_x_end, real_y_start, real_y_end; + rt_uint16_t x_offset, y_offset; + switch (lcd->config.direction) + { + case ST7796_DIR_0: + x_offset = 0; + y_offset = 0; + break; + case ST7796_DIR_90: + x_offset = 0; + y_offset = 0; + break; + case ST7796_DIR_180: + x_offset = 320; + y_offset = 480; + break; + case ST7796_DIR_270: + x_offset = 480; + y_offset = 320; + break; + default: + x_offset = 0; + y_offset = 0; + } + real_x_start = x_start + x_offset; + real_x_end = x_end + x_offset; + real_y_start = y_start + y_offset; + real_y_end = y_end + y_offset; + + rt_uint8_t tx_buf[5] = {0x2A, ((rt_uint8_t)(real_x_start >> 0x08U) & 0xFFU), (real_x_start & 0xFFU), + ((rt_uint8_t)(real_x_end >> 0x08U) & 0xFFU), (real_x_end & 0xFFU)}; + + if (lcd->cb.write_cmd_cb(lcd->user_data, tx_buf, 0x05) != RT_EOK) + { + return -RT_ERROR; + } + tx_buf[0] = 0x2B; + tx_buf[1] = ((rt_uint8_t)(real_y_start >> 0x08U) & 0xFFU); + tx_buf[2] = (real_y_start & 0xFFU); + tx_buf[3] = ((rt_uint8_t)(real_y_end >> 0x08U) & 0xFFU); + tx_buf[4] = (real_y_end & 0xFFU); + if (lcd->cb.write_cmd_cb(lcd->user_data, tx_buf, 0x05) != RT_EOK) + { + return -RT_ERROR; + } + + return RT_EOK; +} + +static rt_err_t _st7796_reset(st7796_lcd_t *lcd) +{ + return lcd->cb.reset_cb(lcd->user_data); +} + +static rt_err_t lcd_impl_reset(void *handle) +{ + rt_pin_write(BSP_LCD_RST_PIN, PIN_LOW); + rt_thread_mdelay(50); + rt_pin_write(BSP_LCD_RST_PIN, PIN_HIGH); + rt_thread_mdelay(50); + + return RT_EOK; +} + +static rt_err_t st7796_lcd_init(st7796_lcd_t *lcd) +{ + if (_st7796_reset(lcd) != RT_EOK) return -RT_ERROR; + if (_st7796_init_seq(lcd) != RT_EOK) return -RT_ERROR; + if (st7796_lcd_config(lcd, &lcd->config) != RT_EOK) return -RT_ERROR; + if (st7796_lcd_sleep(lcd, 0) != RT_EOK) return -RT_ERROR; + if (st7796_lcd_display(lcd, 1) != RT_EOK) return -RT_ERROR; + + return RT_EOK; +} + +static rt_err_t st7796_lcd_load(st7796_lcd_t *lcd, void *data, rt_uint16_t x_start, rt_uint16_t x_end, rt_uint16_t y_start, rt_uint16_t y_end) +{ + rt_uint32_t pixel_count = (y_end - y_start + 1) * (x_end - x_start + 1); + rt_uint32_t data_len = 0; + + switch (lcd->config.pix_fmt) + { + case ST7796_RGB444: + data_len = pixel_count * 3 / 2; + break; + case ST7796_RGB565: + data_len = pixel_count * 2; + break; + case ST7796_RGB666: + case ST7796_RGB888: + data_len = pixel_count * 3; + break; + default: + data_len = pixel_count; + break; + } + + /* Set cursor */ + if (_st7796_window(lcd, x_start, x_end, y_start, y_end) != RT_EOK) + { + return -RT_ERROR; + } + + rt_uint8_t command = 0x2C; /* Memory Write */ + if (lcd->cb.write_cmd_cb(lcd->user_data, &command, 0x01) != RT_EOK) + { + return -RT_ERROR; + } + /* Write pixel data */ + if (lcd->cb.write_data_cb(lcd->user_data, data, data_len) != RT_EOK) + { + return -RT_ERROR; + } + + return RT_EOK; +} + +void lcd_load(rt_uint16_t x_start, rt_uint16_t x_end, rt_uint16_t y_start, rt_uint16_t y_end, void *data) +{ + st7796_t *lcd_obj = (st7796_t *)rt_device_find("lcd"); + st7796_lcd_load(&lcd_obj->st7796, data, x_start, x_end, y_start, y_end); +} + +static rt_err_t st7796_lcd_sleep(st7796_lcd_t *lcd, rt_uint8_t sleep_mode) +{ + /* Write SLPIN or SLPOUT command */ + rt_uint8_t command = sleep_mode ? 0x10 : 0x11; + return lcd->cb.write_cmd_cb(lcd->user_data, &command, 0x01); +} + +static rt_err_t st7796_lcd_display(st7796_lcd_t *lcd, rt_uint8_t display_on) +{ + /* write display_on command */ + rt_uint8_t command = display_on ? 0x29 : 0x28; + if (lcd->cb.write_cmd_cb(lcd->user_data, &command, 0x01) != RT_EOK) + { + return -RT_ERROR; + } + if ((lcd->cb.backlight_cb != NULL) && (lcd->cb.backlight_cb(lcd->user_data, display_on) != RT_EOK)) + { + return -RT_ERROR; + } + + return RT_EOK; +} + +static rt_err_t st7796_lcd_config(st7796_lcd_t *lcd, st7796_config_t *config) +{ + lcd->config.direction = config->direction; + + /* Write inversion command */ + rt_uint8_t command[2] = {config->inversion ? 0x20 : 0x21, 0x00}; + if (lcd->cb.write_cmd_cb(lcd->user_data, command, 0x01) != RT_EOK) + { + return -RT_ERROR; + } + lcd->config.inversion = config->inversion; + + command[0] = 0x3A; + command[1] = config->pix_fmt; + if (lcd->cb.write_cmd_cb(lcd->user_data, command, 0x02) != RT_EOK) + { + return -RT_ERROR; + } + lcd->config.pix_fmt = config->pix_fmt; + + command[0] = 0x36; + command[1] = config->direction; + if (!config->bgr_mode) + { + command[1] &= ~0x08U; + } + + if (config->mirrored) + { + /* Invert X or Y bit */ + if (config->direction == ST7796_DIR_90 || config->direction == ST7796_DIR_270) + { + command[1] ^= 0x80U; + } + else + { + command[1] ^= 0x40U; + } + } + + return lcd->cb.write_cmd_cb(lcd->user_data, command, 0x02); +} + +static rt_err_t lcd_impl_write_cmd(void *handle, rt_uint8_t *cmd, rt_uint8_t len) +{ + st7796_t *nxp_lcd = (st7796_t*)handle; + + rt_pin_write(BSP_LCD_DC_PIN, PIN_LOW); + rt_spi_send(nxp_lcd->spi_dev, cmd, 1); + if (len > 1) + { + rt_pin_write(BSP_LCD_DC_PIN, PIN_HIGH); + rt_spi_send(nxp_lcd->spi_dev, &cmd[1], len-1); + } + + return RT_EOK; +} + +static rt_err_t lcd_impl_write_data(void *handle, void *data, rt_uint32_t len) +{ + st7796_t *nxp_lcd = (st7796_t*)handle; + + rt_pin_write(BSP_LCD_DC_PIN, PIN_HIGH); + rt_spi_send(nxp_lcd->spi_dev, data, len); + + return RT_EOK; +} + +int drv_st7796_init(void) +{ + rt_pin_mode(BSP_LCD_RST_PIN, PIN_MODE_OUTPUT); + rt_pin_mode(BSP_LCD_DC_PIN, PIN_MODE_OUTPUT); + rt_pin_write(BSP_LCD_RST_PIN, PIN_HIGH); + + lcd_spi_obj.st7796.config.direction = ST7796_DIR_90; + lcd_spi_obj.st7796.config.pix_fmt = ST7796_RGB565; + lcd_spi_obj.st7796.config.bgr_mode = 1; + lcd_spi_obj.st7796.config.inversion = 0; + lcd_spi_obj.st7796.config.mirrored = 1; + lcd_spi_obj.st7796.cb.reset_cb = lcd_impl_reset; + lcd_spi_obj.st7796.cb.write_cmd_cb = lcd_impl_write_cmd; + lcd_spi_obj.st7796.cb.write_data_cb = lcd_impl_write_data; + lcd_spi_obj.st7796.user_data = lcd_spi_obj.parent.user_data = &lcd_spi_obj; + + rt_hw_spi_device_attach(BSP_LCD_SPI_BUS, LCD_DEVICE_NAME, BSP_LCD_CS_PIN); + lcd_spi_obj.spi_dev = (struct rt_spi_device *)rt_device_find(LCD_DEVICE_NAME); + if (!lcd_spi_obj.spi_dev) + { + LOG_E("lcd init run failed! can't find %s device!\n", LCD_DEVICE_NAME); + return -RT_ERROR; + } + struct rt_spi_configuration cfg; + cfg.data_width = 8; + cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */ + cfg.max_hz = 10 * 1000 * 1000; /* 10M */ + rt_spi_configure(lcd_spi_obj.spi_dev, &cfg); + + st7796_lcd_init(&lcd_spi_obj.st7796); + rt_device_register(&lcd_spi_obj.parent, "lcd", RT_DEVICE_FLAG_RDWR); + + return RT_EOK; +} +INIT_ENV_EXPORT(drv_st7796_init); diff --git a/bsp/lpc55sxx/Libraries/drivers/drv_st7796.h b/bsp/lpc55sxx/Libraries/drivers/drv_st7796.h new file mode 100644 index 0000000000..22263d7016 --- /dev/null +++ b/bsp/lpc55sxx/Libraries/drivers/drv_st7796.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-05-23 Chushicheng the first version. + */ + +#ifndef DRV_ST7796_H__ +#define DRV_ST7796_H__ + +#include + +#define LCD_DEVICE_NAME "st7796" +typedef enum +{ + ST7796_DIR_0 = 0x08U, + ST7796_DIR_90 = 0x68U, + ST7796_DIR_180 = 0xC8U, + ST7796_DIR_270 = 0xA8U, +} st7796_direction_t; + +typedef enum +{ + ST7796_RGB444 = 3, + ST7796_RGB565 = 5, + ST7796_RGB666 = 6, + ST7796_RGB888 = 7 +} st7796_pixfmt_t; + +typedef struct +{ + rt_err_t (*reset_cb)(void *handle); + rt_err_t (*backlight_cb)(void *handle, rt_uint8_t on); + rt_err_t (*write_cmd_cb)(void *handle, rt_uint8_t *cmd, rt_uint8_t len); + rt_err_t (*write_data_cb)(void *handle, void *data, rt_uint32_t len); +} st7796_cb_t; + +typedef struct +{ + st7796_direction_t direction; + st7796_pixfmt_t pix_fmt; + rt_uint8_t inversion; + rt_uint8_t bgr_mode; + uint8_t mirrored; +} st7796_config_t; + +typedef struct +{ + void *user_data; + st7796_cb_t cb; + st7796_config_t config; +} st7796_lcd_t; + +typedef struct +{ + struct rt_device parent; + st7796_lcd_t st7796; + struct rt_spi_device *spi_dev; +} st7796_t; + +void lcd_load(rt_uint16_t x_start, rt_uint16_t x_end, rt_uint16_t y_start, rt_uint16_t y_end, void *data); +int drv_st7796_init(void); + +#endif /* DRV_ST7796_H__ */ + diff --git a/bsp/lpc55sxx/Libraries/drivers/sample/lcd_sample.c b/bsp/lpc55sxx/Libraries/drivers/sample/lcd_sample.c new file mode 100644 index 0000000000..25c97de26b --- /dev/null +++ b/bsp/lpc55sxx/Libraries/drivers/sample/lcd_sample.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-05-26 Chushicheng the first version + */ +/* + * Program Checklist: This is an LCD device usage routine + * The routine exports lcd_sample commands to the control terminal + * Command invocation format: lcd_sample + * Program function: Full screen refresh display +*/ +#include +#include "drv_st7796.h" + +static void lcd_sample(void) +{ + static rt_uint16_t orange[319*2]; + static rt_uint16_t green[319*2]; + static rt_uint16_t blue[319*2]; + st7796_t *lcd_obj = (st7796_t *)rt_device_find("lcd"); + + for (rt_uint32_t i = 0; i < 319*2; i++) + { + orange[i] = 0xFD; + } + for (rt_uint32_t i = 0; i < 319*2; i++) + { + green[i] = 0x07; + } + for (rt_uint32_t i = 0; i < 319*2; i++) + { + blue[i] = 0xFF1F; + } + + while (1) + { + for (rt_uint16_t i = 0; i < 159; i++) + { + lcd_load(i, i, 0, 319, orange); + } + for (rt_uint16_t i = 159; i < 318; i++) + { + lcd_load(i, i, 0, 319, blue); + } + for (rt_uint16_t i = 318; i < 479; i++) + { + lcd_load(i, i, 0, 319, green); + } + + for (rt_uint16_t i = 479; i > 318; i--) + { + lcd_load(i, i, 0, 319, blue); + } + for (rt_uint16_t i = 318; i > 159; i--) + { + lcd_load(i, i, 0, 319, orange); + } + for (rt_uint16_t i = 159; i > 0; i--) + { + lcd_load(i, i, 0, 319, green); + } + } +} +MSH_CMD_EXPORT(lcd_sample, lcd sample); diff --git a/bsp/lpc55sxx/Libraries/drivers/sample/lcd_touch_sample.c b/bsp/lpc55sxx/Libraries/drivers/sample/lcd_touch_sample.c new file mode 100644 index 0000000000..6325ef2f55 --- /dev/null +++ b/bsp/lpc55sxx/Libraries/drivers/sample/lcd_touch_sample.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-05-26 Chushicheng the first version + */ +/* + * Program Listing: This is an LCD device touch usage routine + * The routine exports lcd_touch_sample commands to the control terminal + * Command invocation format: lcd_touch_sample + * Program functions: draw the trajectory of the touch on the screen and print the coordinates of the touch point on the terminal +*/ +#include +#include "drv_st7796.h" +#include "drv_gt911.h" + +static void lcd_touch_sample(void) +{ + static rt_uint16_t white[319*2]; + rt_uint16_t green[4*4*2]; + st7796_t *lcd_obj = (st7796_t *)rt_device_find("lcd"); + rt_device_t dev = rt_device_find("capt"); + capt_t *capt = (capt_t*)dev->user_data; + gt911_input_t ctp_input; + + for (rt_uint32_t i = 0; i < 319*2; i++) + { + white[i] = 0xffff; + } + for (rt_uint32_t i = 0; i < 4*4*2; i++) + { + green[i] = 0x07; + } + for (rt_uint16_t i = 0; i < 159; i++) + { + lcd_load(i, i, 0, 319, white); + } + for (rt_uint16_t i = 159; i < 318; i++) + { + lcd_load(i, i, 0, 319, white); + } + for (rt_uint16_t i = 318; i < 479; i++) + { + lcd_load(i, i, 0, 319, white); + } + + while(1) + { + gt911_ctp_read(&capt->gt911, &ctp_input); + for (rt_uint8_t i = 0; i < ctp_input.num_pos; i++) + { + /* Found track ID #0 */ + if (ctp_input.pos[i].id == 0) + { + lcd_load(capt->gt911.pos_y_max - ctp_input.pos[i].pos_y, capt->gt911.pos_y_max - ctp_input.pos[i].pos_y+4, ctp_input.pos[i].pos_x, ctp_input.pos[i].pos_x+4, green); + rt_kprintf("x:%d, y:%d\r\n", capt->gt911.pos_y_max - ctp_input.pos[i].pos_y , ctp_input.pos[i].pos_x); + } + } + } +} +MSH_CMD_EXPORT(lcd_touch_sample, lcd sample); diff --git a/bsp/lpc55sxx/Libraries/drivers/sample/touch_sample.c b/bsp/lpc55sxx/Libraries/drivers/sample/touch_sample.c new file mode 100644 index 0000000000..1c649ad753 --- /dev/null +++ b/bsp/lpc55sxx/Libraries/drivers/sample/touch_sample.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-05-26 Chushicheng the first version + */ +/* + * Program listing: This is a touch device usage routine + * The routine exports touch_sample commands to the control terminal + * Command invocation format: touch_sample + * Program function: The terminal prints the coordinates of the touch point +*/ +#include +#include "drv_gt911.h" + +static int touch_sample(void) +{ + gt911_input_t ctp_input; + + rt_device_t dev = rt_device_find("capt"); + + RT_ASSERT(dev != RT_NULL); + + capt_t *capt = (capt_t*)dev->user_data; + while(1) + { + gt911_ctp_read(&capt->gt911, &ctp_input); + + for (rt_uint8_t i = 0; i < ctp_input.num_pos; i++) + { + /* Found track ID #0 */ + if (ctp_input.pos[i].id == 0) + { + rt_kprintf("x:%d, y:%d\r\n", capt->gt911.pos_y_max - ctp_input.pos[i].pos_y, ctp_input.pos[i].pos_x); + } + } + + rt_thread_mdelay(16); + } + + return RT_EOK; +} + +MSH_CMD_EXPORT(touch_sample, the capt touch test); diff --git a/bsp/lpc55sxx/lpc55s69_nxp_evk/board/Kconfig b/bsp/lpc55sxx/lpc55s69_nxp_evk/board/Kconfig index c02ced54e3..62da91b198 100644 --- a/bsp/lpc55sxx/lpc55s69_nxp_evk/board/Kconfig +++ b/bsp/lpc55sxx/lpc55s69_nxp_evk/board/Kconfig @@ -296,6 +296,45 @@ menu "Onboard Peripheral Drivers" endmenu menu "Board extended module Drivers" + menuconfig BSP_USING_NXP_LCDM_S + config BSP_USING_NXP_LCDM_S + bool "Enable NXP LCD" + select BSP_USING_LCD + select BSP_USING_TOUCH + select BSP_USING_I2C + select BSP_USING_SPI + default n + + menuconfig BSP_USING_LCD + config BSP_USING_LCD + bool "Enable LCD" + select BSP_USING_SPI + default n + if BSP_USING_LCD + config BSP_LCD_SPI_BUS + string "the spi bus for lcd" + default "spi3" + config BSP_LCD_CS_PIN + int "the pin of lcd cs" + default 5 + config BSP_LCD_RST_PIN + int "the pin of lcd rst" + default 55 + config BSP_LCD_DC_PIN + int "the pin of lcd dc" + default 3 + endif + + menuconfig BSP_USING_TOUCH + config BSP_USING_TOUCH + bool "Enable TOUCH" + select BSP_USING_I2C + default n + if BSP_USING_TOUCH + config BSP_TOUCH_I2C_BUS + string "the i2c bus for lcd" + default "i2c1" + endif endmenu