背景简介
本文主要是通过以下实例来讲解设备树节点如何编写
- 给项目增加一个UART输出接口
- 给项目增加一个LCD显示屏
Zephyr设备树理论知识请参考:【Zephyr设备树教程(上) 】 实战中使用的是聆思命令行指令,可以参考《聆思CSK6开发工具简介》进行一键部署
实战1:如何编写UART1的串口节点
使用lisa zep creat创建UART 的Sample
sample选择路径:/samples/boards/csk6/driver/uart/[uart_polling]
重新定义UART1
打开/uart_polling/boards路径下的csk6011a_nano.overlay文件进行串口配置,设置好rx和tx,以及波特率,配置代码信息如下:
&pinctrl{ pinctrl_uart1_rx_default: uart1_rx_default{ pinctrls = <UART1_RXD_GPIOA_05>; //rx pin }; pinctrl_uart1_tx_default: uart1_tx_default{ pinctrls = <UART1_TXD_GPIOA_04>; //tx pin }; }; &uart1{ status = "okay"; current-speed = <9600>; //配置波特率 pinctrl-0 = <&pinctrl_uart1_rx_default &pinctrl_uart1_tx_default>; pinctrl-names = "default"; };
想了解更多串口配置信息可以参考样本配置文件,配置讲解视频可通过导读说明获取。 串口样本配置文件在聆思CSK6开发工具的安装目录下可以找到,路径为:开发工具安装目录/LISA/csk-sdk/zephyr/boards/arm/csk6011a_nano/csk6011a_nano.dts 修改串口后,相关配置项关联文件也需要修改:
*/zephyr/dts/arm/csk/csk6.dtsi */zepbyr/dts/bindings/serial/uart-controller.yaml */zepbyr/dts/bindings/pinctrl/pinctrl-device.yaml */zepbyr/dts/bindings/serial/listenai,csk-uart.yaml */zephyr/include/zephyr/dt-bindings/pinctrl/csk6-pinctrl.h
注意:/zephy让为ZEPHYR_BASE目录,可通过lisa info zep获得ZEPHYR_BASE目录路径
修改主程序main.c
将main.c中配置为“uart0”修改为“uart1”,配置修改后的信息参考如下:
主程序main.c路径:/uart_polling/src/main.c ,配置详解请参考讲解视频
#include <kernel.h>
#include <zephyr.h>
#include <sys/printk.h>
#include <string.h>
#include <devicetree.h>
#include <logging/log.h>
#include <drivers/uart.h>
LOG_MODULE_REGISTER(sample, LOG_LEVEL_INF);
#define UART1 DT_NODELABEL(uart1)
void main(void)
{
char rx_char;
const struct device *uart = device_get_binding("UART_1");
if(!device_is_ready(uart)){
LOG_ERR("device:%s is not ready!", uart->name);
return;
}
LOG_INF("devices %s is ready", uart->name);
while(1){
if(uart_poll_in(uart, &rx_char) == 0){/*read a char*/
uart_poll_out(uart, rx_char); /*send a char*/
}
}
return;
}
编译/烧录
进入实例目录:cd uart_polling 执行编译:lisa zep build -b csk6011a_nano 烧录指令:lisa zep flash
实战2:如何编写LCD显示屏节点(屏幕型号st7789)
实现路径参考
1、查看zephyr已有的LCD支持列表,确定可行性 2、根据yaml要求的硬件节点信息,结合实际硬件电路给出dts节点
3、打开驱动加载设备 st7789会抛出如下截图的API,应用层使用伪代码调用对应的API就可以调用st7789外设
伪代码调用:
display_dev = device_get_binding(“sitronix_st7789v”); display_get_capabilities(display_dev, &capabilities); display_write(display_dev, x, y, &desc, buf);
基于sample模板实现驱动显示屏
1、选择同类设备的sample模板 创建命令:lisa zep create 此处使用的显示器模板选择路径:sample→boards→csk6→driver→display→ili9488
2、修改设备树文件 打开工程/ili9488/boards/路径,只保留一个overlay文件并填入以下的配置信息,修改名称为csk6011a_nano.overlay文件。
&csk6011a_nano_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>;
};
};
&spi0 {
status = "okay";
pinctrl-0 = <&pinctrl_spi0_sclk_default &pinctrl_spi0_mosi_default &pinctrl_spi0_miso_default &pinctrl_spi0_cs_default>;
pinctrl-names = "default";
st7789v@0 {
compatible = "sitronix,st7789v";
label = "ST7789V";
status = "okay";
spi-max-frequency = <20000000>;
reg = <0>;
cmd-data-gpios = <&gpiob 2 1>;
reset-gpios = <&gpioa 15 1>;
width = <320>;
height = <240>;
x-offset = <0>;
y-offset = <0>;
// reg: 0xBB
vcom = <0x1e>;
// reg: 0xB7
gctrl = <0x35>;
// reg: 0xC3
vrhs = <0x0b>;
// reg: 0xC4
vdvs = <0x20>;
// reg: 0x36
mdac = <0xA3>;
// reg: 0x26
gamma = <0x01>;
// reg: 0x3a
colmod = <0x05>;
// reg: 0xc0
lcm = <0x2c>;
// reg: 0xb2
porch-param = [ 0c 0c 00 33 33 ];
// reg: 0xDF
cmd2en-param = [ 5a 69 02 01 ];
// reg: 0xD0
pwctrl1-param = [ a4 a1 ];
// reg: 0xE0
pvgam-param = [ d0 06 0b 07 07 24 2e 32 46 37 13 13 2d 33 ];
// reg: 0xE1
nvgam-param = [ d0 02 06 09 08 05 29 44 42 38 14 14 2a 30 ];
// reg: b0
ram-param = [ 00 F0 ];
// reg: b1
rgb-param = [ CD 08 14 ];
};
};
3、修改prj.con 路径为/ili9488/prj.conf
CONFIG_HEAP_MEM_POOL_SIZE=102400
#hardware
CONFIG_DISPLAY=y
CONFIG_ST7789V=y
CONFIG_SPI=y
CONFIG_GPIO=y
4、修改主程序main.c
/*
* Based on ili9488 sample:
* SPDX-License-Identifier: Apache-2.0
*/
#include <logging/log.h>
LOG_MODULE_REGISTER(sample, LOG_LEVEL_INF);
#include <zephyr.h>
#include <device.h>
#include <drivers/display.h>
#define DISPLAY_DEV_NAME DT_LABEL(DT_INST(0, sitronix_st7789v))
enum corner {
TOP_LEFT,
TOP_RIGHT,
BOTTOM_RIGHT,
BOTTOM_LEFT
};
typedef void (*fill_buffer)(enum corner corner, uint8_t grey, uint8_t *buf,
size_t buf_size);
static void fill_buffer_argb8888(enum corner corner, uint8_t grey, uint8_t *buf,
size_t buf_size)
{
uint32_t color = 0;
switch (corner) {
case TOP_LEFT:
color = 0x00FF0000u;
break;
case TOP_RIGHT:
color = 0x0000FF00u;
break;
case BOTTOM_RIGHT:
color = 0x000000FFu;
break;
case BOTTOM_LEFT:
color = grey << 16 | grey << 8 | grey;
break;
}
for (size_t idx = 0; idx < buf_size; idx += 4) {
*((uint32_t *)(buf + idx)) = color;
}
}
static void fill_buffer_rgb888(enum corner corner, uint8_t grey, uint8_t *buf,
size_t buf_size)
{
uint32_t color = 0;
switch (corner) {
case TOP_LEFT:
color = 0x00FF0000u;
break;
case TOP_RIGHT:
color = 0x0000FF00u;
break;
case BOTTOM_RIGHT:
color = 0x000000FFu;
break;
case BOTTOM_LEFT:
color = grey << 16 | grey << 8 | grey;
break;
}
for (size_t idx = 0; idx < buf_size; idx += 3) {
*(buf + idx + 0) = color >> 16;
*(buf + idx + 1) = color >> 8;
*(buf + idx + 2) = color >> 0;
}
}
static uint16_t get_rgb565_color(enum corner corner, uint8_t grey)
{
uint16_t color = 0;
uint16_t grey_5bit;
switch (corner) {
case TOP_LEFT:
color = 0xF800u;
break;
case TOP_RIGHT:
color = 0x07E0u;
break;
case BOTTOM_RIGHT:
color = 0x001Fu;
break;
case BOTTOM_LEFT:
grey_5bit = grey & 0x1Fu;
/* shift the green an extra bit, it has 6 bits */
color = grey_5bit << 11 | grey_5bit << (5 + 1) | grey_5bit;
break;
}
return color;
}
static void fill_buffer_rgb565(enum corner corner, uint8_t grey, uint8_t *buf,
size_t buf_size)
{
uint16_t color = get_rgb565_color(corner, grey);
for (size_t idx = 0; idx < buf_size; idx += 2) {
*(buf + idx + 0) = (color >> 8) & 0xFFu;
*(buf + idx + 1) = (color >> 0) & 0xFFu;
}
}
static void fill_buffer_bgr565(enum corner corner, uint8_t grey, uint8_t *buf,
size_t buf_size)
{
uint16_t color = get_rgb565_color(corner, grey);
for (size_t idx = 0; idx < buf_size; idx += 2) {
*(uint16_t *)(buf + idx) = color;
}
}
static void fill_buffer_mono(enum corner corner, uint8_t grey, uint8_t *buf,
size_t buf_size)
{
uint16_t color;
switch (corner) {
case BOTTOM_LEFT:
color = (grey & 0x01u) ? 0xFFu : 0x00u;
break;
default:
color = 0;
break;
}
memset(buf, color, buf_size);
}
void 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;
LOG_INF("Display sample for %s", DISPLAY_DEV_NAME);
display_dev = device_get_binding(DISPLAY_DEV_NAME);
if (display_dev == NULL) {
LOG_ERR("Device %s not found. Aborting sample.",
DISPLAY_DEV_NAME);
return;
}
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;
}
buf = k_malloc(buf_size);
if (buf == NULL) {
LOG_ERR("Could not allocate memory. Aborting sample.");
return;
}
(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;
LOG_INF("init success");
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
}
}
5、编译/烧录
- 编译指令:lisa zep build -b csk6011a_nano
- 烧录指令:lisa zep flash --runner pyocd 成功点亮屏幕并显示如下界面
更多学习资源
Zephyr系列相关分享 | 51CTO 环境搭建 芯片介绍
如果需要获取本教程相关的学习资源、代码, 或者了解更多与嵌入式开发、AI芯片相关的其他课程,可以点击查看 目录导航。