[bsp][lpc55sxx]add: drv_lcd and drv_touch (#7569)
This commit is contained in:
parent
31ede54ac7
commit
3a44dbbf92
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 <drv_log.h>
|
||||
|
||||
#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);
|
|
@ -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 <rtdevice.h>
|
||||
|
||||
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 */
|
|
@ -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,
|
||||
|
|
|
@ -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 <rtdevice.h>
|
||||
|
||||
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__ */
|
|
@ -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 <drv_log.h>
|
||||
|
||||
#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);
|
|
@ -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 <rtdevice.h>
|
||||
|
||||
#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__ */
|
||||
|
|
@ -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 <rtdevice.h>
|
||||
#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);
|
|
@ -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 <rtdevice.h>
|
||||
#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);
|
|
@ -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 <rtdevice.h>
|
||||
#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);
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue