本节将主要通过显示&触控综合Sample来介绍基于CSK6 SDK的显示屏和触控屏的基本使用。通过本章节学习,您将了解到:
csk6 sdk 驱动模型中定义了可供上层应用调用的关键接口,如 读/写framebuffer 、开/关屏幕 、获取屏幕设备信息 、 设置亮度/对比度/像素格式/方向等。
在csk6 sdk的\drivers\display
目录中可看到sdk已完成了屏显设备驱动的适配,其中包含本示例中使用的ST7789V (display_st7789v.c/.h)
,只需要在示例中完成驱动的配置即可使用该显示屏。
在display_kscan这个例程中,主程序对显示屏进行了初始化,并依次展示简单图形的绘制和图形的动态灰度调整功能,其主要流程如下(暂不包含触摸屏KSCAN相关):
如上,此例程调用了display驱动模型中若干核心的显示接口进行内容显示,开发者可根据自己需要,绘制自己的UI页面。
获取显示功能
void display_get_capabilities(const struct device *dev, struct display_capabilities *capabilities)
参数说明
字段 | 说明 |
---|---|
dev | 指向display设备实例的指针 |
capabilities | 指向要填充功能结构的指针 |
写入要显示的数据
int display_write(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, const void *buf)
字段 | 说明 |
---|---|
dev | 指向display设备实例的指针 |
x | x坐标点 |
y | y坐标点 |
desc | 指向描述显示区布局缓存的指针 |
buf | 指向显示区数组的指针 |
关闭显示消隐
int display_blanking_off(const struct device *dev)
参数说明
字段 | 说明 |
---|---|
dev | 指向display设备实例的指针 |
更详细的显示驱动API接口请查阅zephyr官网 Display Interface。
NOTE
显示消隐:动态显示过程中,若进行片选切换时没有对上一片显示的内容进行清空,则会导致当前数码管中出现上一片内容的余影,从而使显示模糊,影响了整个显示效果。
Zephyr具备kscan(keyboard scan matrix)驱动模型,其驱动程序用于检测矩阵键盘或带有按钮的设备中的按键。由于kscan驱动模型并不定义键值,而是通过按键的行列坐标来标识按键,而用户触碰触摸屏本质上也是生成一个行列坐标,因此kscan驱动模型也适用于触摸屏。csk6sdk中默认适配的触摸IC:BL6XXX(kscan_bl6xxx.c)
与display驱动类似,kscan驱动模型位于SDK的 \zephyr\include\zephyr\drivers\kscan.h
文件,kscan驱动模型中定义了一组很简洁的接口和回调。
注册一个callback,当按键发生时通过callback通知应用
int kscan_config(struct device *dev,kscan_callback_t callback);
参数说明
字段 | 说明 |
---|---|
dev | 指向kcan设备实例的指针 |
callback | 按键回调函数 |
使能callback回调
int kscan_enable_callback(struct device *dev);
参数说明
字段 | 说明 |
---|---|
dev | 指向kcan设备实例的指针 |
关闭callback回调
int kscan_disable_callback(struct device *dev);
参数说明
字段 | 说明 |
---|---|
dev | 指向kcan设备实例的指针 |
触摸回调函数
typedef void (*kscan_callback_t)(struct device *dev, u32_t row, u32_t column, bool pressed);
参数说明
字段 | 说明 |
---|---|
dev | 指向kcan设备实例的指针 |
row | 触摸点所在行 |
column | 触摸点所在列 |
pressed | true=触摸按下, false=触摸松开 |
更详细的kscan API接口请查阅zephyr官网 Keyboard Scan Driver APIs。
SDK 中提供了 display_kscan 的示例。
{SDK}\.sdk\csk\samples\driver\display_kscan
适用开发板:大模型开发套件
编译版型:csk6_duomotai_devkit
本示例基于 csk6_duomotai_devkit
开发板实现,开发板配备一块触控显示屏(使用 ST7789V
显示芯片的LCD屏及 FT6336U(FT5336)
触控芯片的TP),把触控显示屏接到csk6_duomotai_devkit
开发板上。
演示如何在Zephyr RTOS中使用显示驱动和键盘扫描设备。运行该代码后,将在屏幕上显示图形,并通过日志输出响应触摸按键事件。
在 SDK 根目录(duomotai_ap
)下可通过执行以下指令进行对该示例工程的编译:
lisa zep build -b csk6_duomotai_devkit .sdk/csk/samples/driver/display_kscan/ -p
编译完成后,编译产物二进制文件位于 build\zephyr\zephyr.bin
使用 Type-C 数据线连接开发套件的 DAP_USB
接口,选中以下其中一种方式对固件进行烧录:
cskburn desktop
是一款聆思推出的桌面烧录工具,在下载并安装 cskburn desktop 烧录工具后,双击图标运行软件:
1.点击串口下拉框,选择连接开发套件后识别到的串口编号;
2.将编译输出的.bin
文件拖拽进烧录区域;
3.点击开始烧录,等待烧录完成。
若您已按照 《环境搭建》 教程完成开发环境的安装,可在编译完成后执行 lisa zep exec cskburn
指令完成烧录。
lisa zep exec cskburn -s \\.\COMxx -C 6 -b 1500000 0x000000 --verify-all .\build\zephyr\zephyr.bin
请将命令行中的的 COMx 替换为开发套件在 PC 上对应的串口号(可通过设备管理器查看)。例如:
COM3
。
lisa zep exec cskburn -s PORT -C 6 0x000000 --verify-all ./build/zephyr/zephyr.bin -b 1500000
请将命令行中的 PORT 替换为开发套件连接在 PC 上对应的串口号。例如:
/dev/ttyUSB0
。
烧录完成后,可观察到设备显示屏出现【白色背景+三静态方块+一动态方块】的图像,如图:
日志串口接到PC端,通过串口终端可看到输出日志,当用手触摸屏幕时,屏幕会实时输出触摸点的坐标与状态,日志信息如下:
以下代码与注释已省略一部分非关键接口代码,主要呈现示例的主业务流程与主要接口的使用。
CONFIG_HEAP_MEM_POOL_SIZE=16384
CONFIG_LOG=y
CONFIG_GPIO=y
# 显示功能配置
CONFIG_DISPLAY=y
CONFIG_SPI=y
# ST7789V显示屏驱动配置
CONFIG_ST7789V=y
CONFIG_KSCAN=y
CONFIG_I2C=y
# 触摸屏驱动配置
CONFIG_KSCAN_FT5336=y
CONFIG_KSCAN_FT5336_INTERRUPT=y
本示例显示屏使用到了csk6_duomotai_devkit
开发板的SPI0接口,因此需要在 .overlay
中完成外设接口的配置,具体实现如下:
&pinctrl {
pinctrl_spi0_sclk_default: spi0_sclk_default {
pinctrls = <&pinmuxb 1 6>;
};
pinctrl_spi0_mosi_default: spi0_mosi_default {
pinctrls = <&pinmuxb 10 6>;
};
pinctrl_spi0_miso_default: spi0_miso_default {
pinctrls = <&pinmuxa 17 6>;
};
pinctrl_spi0_cs_default: spi0_cs_default {
pinctrls = <&pinmuxb 0 6>;
};
};
触摸屏使用到了i2c0接口,因此需要在 .overlay
中完成外设接口的配置,具体实现如下:
&csk6002_9s_nano_pinctrl{
// ...
/* 触摸屏I2C接口配置 */
pinctrl_i2c0_scl_default: i2c0_scl_default{
pinctrls = <I2C0_SCL_GPIOB_04>;
};
pinctrl_i2c0_sda_default: i2c0_sda_default{
pinctrls = <I2C0_SDA_GPIOB_03>;
};
};
&i2c0 {
status = "okay";
pinctrl-0 = <&pinctrl_i2c0_scl_default &pinctrl_i2c0_sda_default>;
pinctrl-names = "default";
ft5336@0 {
compatible = "focaltech,ft5336";
reg = <56>;
status = "okay";
int-gpios = <&gpiob 11 0>;
};
};
1. 获取显示设备句柄
display_dev = DEVICE_DT_GET(DT_INST(0, sitronix_st7789v));
2. 获取显示设备能力
display_get_capabilities(display_dev, &capabilities);
3. 初始化键盘扫描设备
kscan_init();
4. 填充缓冲区并写入显示设备
fill_buffer_fnc(TOP_LEFT, 0, buf, buf_size);
display_write(display_dev, x, y, &buf_desc, buf);
5. 打开显示设备的显示
display_blanking_off(display_dev);
按下开发板复位按钮,运行程序。程序将初始化显示设备和键盘扫描设备,在显示屏上绘制彩色方块,并响应触摸按键事件。
int main(void)
{
size_t x;
size_t y;
size_t rect_w;
size_t rect_h;
size_t h_step;
size_t scale;
size_t grey_count;
uint8_t *buf;
int32_t grey_scale_sleep;
const struct device *display_dev;
struct display_capabilities capabilities;
struct display_buffer_descriptor buf_desc;
size_t buf_size = 0;
fill_buffer fill_buffer_fnc = NULL;
/* kscan初始化 */
kscan_init();
/* 获取display设备实例 */
display_dev = DEVICE_DT_GET(DT_INST(0, sitronix_st7789v));
if (display_dev == NULL) {
LOG_ERR("Device not found. Aborting sample.");
RETURN_FROM_MAIN(-1);
}
/* 获取显示功能 */
display_get_capabilities(display_dev, &capabilities);
if (capabilities.screen_info & SCREEN_INFO_MONO_VTILED) {
rect_w = 16;
rect_h = 8;
} else {
rect_w = 2;
rect_h = 1;
}
h_step = rect_h;
scale = (capabilities.x_resolution / 8) / rect_h;
rect_w *= scale;
rect_h *= scale;
if (capabilities.screen_info & SCREEN_INFO_EPD) {
grey_scale_sleep = 10000;
} else {
grey_scale_sleep = 100;
}
buf_size = rect_w * rect_h;
if (buf_size < (capabilities.x_resolution * h_step)) {
buf_size = capabilities.x_resolution * h_step;
}
/* 色块配置 */
switch (capabilities.current_pixel_format) {
case PIXEL_FORMAT_ARGB_8888:
fill_buffer_fnc = fill_buffer_argb8888;
buf_size *= 4;
break;
case PIXEL_FORMAT_RGB_888:
fill_buffer_fnc = fill_buffer_rgb888;
buf_size *= 3;
break;
case PIXEL_FORMAT_RGB_565:
fill_buffer_fnc = fill_buffer_rgb565;
buf_size *= 2;
break;
case PIXEL_FORMAT_BGR_565:
fill_buffer_fnc = fill_buffer_bgr565;
buf_size *= 2;
break;
case PIXEL_FORMAT_MONO01:
case PIXEL_FORMAT_MONO10:
fill_buffer_fnc = fill_buffer_mono;
buf_size /= 8;
break;
default:
LOG_ERR("Unsupported pixel format. Aborting sample.");
RETURN_FROM_MAIN(-1);
}
buf = k_malloc(buf_size);
if (buf == NULL) {
LOG_ERR("Could not allocate memory. Aborting sample.");
RETURN_FROM_MAIN(-1);
}
(void)memset(buf, 0xFFu, buf_size);
buf_desc.buf_size = buf_size;
buf_desc.pitch = capabilities.x_resolution;
buf_desc.width = capabilities.x_resolution;
buf_desc.height = h_step;
/*整屏填充白色背景*/
for (int idx = 0; idx < capabilities.y_resolution; idx += h_step) {
display_write(display_dev, 0, idx, &buf_desc, buf);
}
buf_desc.pitch = rect_w;
buf_desc.width = rect_w;
buf_desc.height = rect_h;
/*左上角填充红色块*/
fill_buffer_fnc(TOP_LEFT, 0, buf, buf_size);
x = 0;
y = 0;
display_write(display_dev, x, y, &buf_desc, buf);
/*右上角填充绿色块*/
fill_buffer_fnc(TOP_RIGHT, 0, buf, buf_size);
x = capabilities.x_resolution - rect_w;
y = 0;
display_write(display_dev, x, y, &buf_desc, buf);
/*右下角填充蓝色块*/
fill_buffer_fnc(BOTTOM_RIGHT, 0, buf, buf_size);
x = capabilities.x_resolution - rect_w;
y = capabilities.y_resolution - rect_h;
display_write(display_dev, x, y, &buf_desc, buf);
/* 关闭显示消隐 */
display_blanking_off(display_dev);
grey_count = 0;
x = 0;
y = capabilities.y_resolution - rect_h;
/*左下角灰色动态色块*/
while (1) {
fill_buffer_fnc(BOTTOM_LEFT, grey_count, buf, buf_size);
display_write(display_dev, x, y, &buf_desc, buf);
++grey_count;
k_msleep(grey_scale_sleep);
#if CONFIG_TEST
if (grey_count >= 1024) {
break;
}
#endif
}
RETURN_FROM_MAIN(0);
}
Kscan使用比较简单,在固件代码中配置好后,注册callback函数,当触摸事件触发时在callback回调函数获取坐标点,在display_kscan这个例程中,关键的操作与注释如下:
/* 触摸回调函数,打印坐标 */
static void k_callback(const struct device *dev, uint32_t row, uint32_t col, bool pressed)
{
ARG_UNUSED(dev);
printk("row = %u col = %u, pressed:%s\n", row, col, pressed ? "TRUE" : "FLASE");
}
void kscan_init(void)
{
/* 获取kscan设备实例 */
const struct device *kscan_dev = DEVICE_DT_GET(DT_INST(0, focaltech_ft5336));
if (!device_is_ready(kscan_dev)) {
LOG_ERR("kscan device %s not ready", kscan_dev->name);
return;
}
/* 注册回调,在k_callback中可看到对应的坐标与状态printk输出操作 */
kscan_config(kscan_dev, k_callback);
/* 使能回调 */
kscan_enable_callback(kscan_dev);
}
void main(void)
{
kscan_init();
...
}
如上,仅需增加回调配置,即可在一个应用中注册触摸屏回调,开发者可根据实际业务需要,处理callback中的设备数据。