【STM32WB5MM-DK | Zephyr】3、OLED驱动
本文将介绍如何使用zephyr的display来驱动开发板的OLED屏
1. 硬件与原理图分析
开发板上的OLED通过spi1连接。

通过分析整理,开发板与OLED的连接如下表:

2. 设备树
使用shell的基础工程,创建boards\stm32wb5mm_dk.overlay,内容如下:
/{
chosen {
zephyr,display = &oled; /* display API 通过 chosen 找默认屏 */
};
};
&spi1 {
status = "okay";
pinctrl-0 = <&spi1_sck_pa1 &spi1_mosi_pa7>;
pinctrl-names = "default";
cs-gpios = <&gpioh 0 GPIO_ACTIVE_LOW>; /* 片选引脚 PH0 */
oled: ssd1306@0 {
compatible = "solomon,ssd1306";
reg = <0>; /* 片选为 0 */
spi-max-frequency = <10000000>;
width = <128>;
height = <64>;
segment-offset = <0>;
page-offset = <0>;
display-offset = <0>;
multiplex-ratio = <63>;
segment-remap;
com-invdir;
prechargep = <0x22>;
data-cmd-gpios = <&gpioc 9 GPIO_ACTIVE_HIGH>; /* 数据命令选择引脚 PC9 */
reset-gpios = <&gpioc 8 GPIO_ACTIVE_LOW>; /* 复位引脚 PC8 */
};
};
说明:开发板上的显示屏,根据官方的手册他的芯片为SSD1315,但是zephyr没有这个驱动,他的大多数与ssd1306都是通用的,因此先用ssd1306来驱动。
在这里根据原理图,定义的sck mosi,cs,rst,dc这几个重要的选择。
4. 配置文件prj.conf
CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_SERIAL=y
# 串口控制台、日志
CONFIG_CONSOLE=y
CONFIG_LOG=y
CONFIG_UART_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_LOG_DEFAULT_LEVEL=3
# shell 增强(tab补全、历史命令、命令别名)
CONFIG_SHELL_TAB=y
CONFIG_SHELL_HISTORY=y
CONFIG_SHELL_HISTORY_BUFFER=512
# 栈大小
CONFIG_MAIN_STACK_SIZE=2048
CONFIG_SHELL_STACK_SIZE=1024
# reboot 命令需要内核的复位支持
CONFIG_REBOOT=y
CONFIG_DISPLAY=y
CONFIG_SPI=y
CONFIG_CHARACTER_FRAMEBUFFER=y
# CFB 使用 k_malloc 分配帧缓冲,需要内核堆
CONFIG_HEAP_MEM_POOL_SIZE=2048
在prj.conf中开启了DISPLAY与SPI,特别注意的是需要添加cfb的k_malloc帖缓冲。
5. main.c的测试代码
#include <zephyr/kernel.h>
#include <zephyr/shell/shell.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/reboot.h>
#include <zephyr/drivers/display.h>
#include <zephyr/display/cfb.h>
const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
static int cmd_hello(const struct shell *shell, size_t argc, char **argv)
{
shell_print(shell, "Hello from shell demo, stm32wb5mm_dk!");
return 0;
}
static int cmd_reboot(const struct shell *shell, size_t argc, char **argv)
{
shell_print(shell, "Rebooting the system...");
sys_reboot(SYS_REBOOT_COLD);
return 0;
}
SHELL_CMD_REGISTER(hello, NULL, "Print hello message", cmd_hello);
SHELL_CMD_REGISTER(reboot, NULL, "Reboot the system", cmd_reboot);
int main(void)
{
printk("OLED demo application started.\n");
if (!device_is_ready(dev)) {
printk("Display device not ready\n");
return -ENODEV;
}
display_set_pixel_format(dev, PIXEL_FORMAT_MONO01);
display_blanking_off(dev);
if (cfb_framebuffer_init(dev)) {
printk("cfb_framebuffer_init failed\n");
return -EIO;
}
cfb_framebuffer_clear(dev, true);
cfb_print(dev, "hello Zephyr", 0, 0);
cfb_print(dev, "OLED demo", 0, 16);
cfb_framebuffer_finalize(dev);
return 0;
}
在测试代码主,先引入头文件
#include <zephyr/drivers/display.h>
#include <zephyr/display/cfb.h>
再定义设备句柄:const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
如果顺利的拿到设备ssd1306,则使用cfb_print+cfb_framebuffer_finalize进行输出。
实现效果:

总结
zephyr提供了display,我们只需要配置spi以及dc/rst就可以轻松实现OLED的驱动。