Zephyr设备树保姆级上手教程(下)
  m9kCQSVmQX0i 2023年11月12日 14 0

背景简介

本文主要是通过以下实例来讲解设备树节点如何编写

  1. 给项目增加一个UART输出接口
  2. 给项目增加一个LCD显示屏

Zephyr设备树理论知识请参考:【Zephyr设备树教程(上) 】 实战中使用的是聆思命令行指令,可以参考《聆思CSK6开发工具简介》进行一键部署

实战1:如何编写UART1的串口节点

使用lisa zep creat创建UART 的Sample

sample选择路径:/samples/boards/csk6/driver/uart/[uart_polling] WXWorkCapture_16795638963396.png image.png

重新定义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目录路径

image.png

修改主程序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节点

image.png

3、打开驱动加载设备 st7789会抛出如下截图的API,应用层使用伪代码调用对应的API就可以调用st7789外设

image.png

伪代码调用:

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 成功点亮屏幕并显示如下界面 image.png

更多学习资源

 Zephyr系列相关分享 | 51CTO  环境搭建  芯片介绍

如果需要获取本教程相关的学习资源、代码, 或者了解更多与嵌入式开发、AI芯片相关的其他课程,可以点击查看 目录导航

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月12日 0

暂无评论

推荐阅读
  ff1CyeNEm5RT   2023年11月12日   20   0   0 Linux引脚设备树
m9kCQSVmQX0i
最新推荐 更多