1401|1

328

帖子

5

TA的资源

纯净的硅(中级)

楼主
 

【ST NUCLEO-C031C6开发板测评】移植SSD1306 OLED显示库及支持中文显示 [复制链接]

一、驱动SSD1306 OLED遇到的问题

Zephyr提供的Display Interface,已经支持了SSD1306。

并且,在samples中,还提供了驱动演示:Display — Zephyr Project Documentation

也提供了LVGL演示,同样能够使用SSD1306:LVGL basic sample — Zephyr Project Documentation

然后,再实际编译的过程中,会遇到:

 

 

核心在于,STM32C0资源实在有限:

 

 

二、想办法解决问题

经过一番研究,最终使用Zephyr自身设备驱动功能,驱动SSD1306,然后外挂一个SSD1306显示库,用于实际显示处理。

系统显示部分的功能,最小化调用,其他需要的自己代码中处理。

 

三、实际操作过程

1. 硬件连接

我使用的是I2C接口的SSD1306,所以接线和 【ST NUCLEO-C031C6开发板测评】I2C获取温湿度传感器SHT30数据 中的一样I2C接口即可:

 

2. dts配置修改

修改 zephyr/boards/arm/nucleo_c031c6/arduino_r3_connector.dtsi,启用arduino_i2c支持:

 

 

3. 测试工程

参考 samples/drivers/display 这个实例进行,但是需要大刀阔斧的修改,贴出所有文件吧:

prj.conf

# CONFIG_HEAP_MEM_POOL_SIZE=16384
CONFIG_HEAP_MEM_POOL_SIZE=2048
CONFIG_LOG=n
CONFIG_DISPLAY=y
CONFIG_BOOT_BANNER=n
CONFIG_DEBUG=y

 

CMakeLists.txt

# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(display)

# set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")

target_sources(app PRIVATE src/main_ssd1306.c src/ssd1306_i2c/ssd1306_i2c.c src/ssd1306_i2c/ssd1306_addon.c)

 

main_ssd1306.c:

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(sample, LOG_LEVEL_INF);

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/display.h>

#include "ssd1306_i2c/ssd1306_i2c.h"
#include "ssd1306_i2c/ssd1306_addon.h"

extern int buffer[SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8];

const struct device *display_dev;
struct display_capabilities capabilities;
struct display_buffer_descriptor buf_desc;

void ssd1306_displayShow()
{
	display_write(display_dev, 0, 0, &buf_desc, buffer);
}

int main(void)
{
	size_t x;
	size_t y;
	size_t buf_size = 0;

	display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
	if (!device_is_ready(display_dev))
	{
		LOG_ERR("Device %s not found. Aborting sample.",
				display_dev->name);

		return 0;
	}

	LOG_INF("Display sample for %s", display_dev->name);
	display_get_capabilities(display_dev, &capabilities);


	buf_size = sizeof(buffer) / sizeof(buffer[0]);

	// 设置buf
	buf_desc.buf_size = buf_size;
	buf_desc.pitch = SSD1306_LCDWIDTH;
	buf_desc.width = SSD1306_LCDWIDTH;
	buf_desc.height = SSD1306_LCDHEIGHT;

	display_blanking_off(display_dev);

	x = 0;
	y = 0;

	ssd1306_displayShow();
	k_msleep(2000);

	ssd1306_clearDisplay();
	ssd1306_setCursor(50,20);
	char *text = "This is demo for SSD1306 i2c driver for Raspberry Pi";
	ssd1306_drawString(text);
	ssd1306_displayShow();
	k_msleep(2000);

	ssd1306_clearDisplay();
	ssd1306_drawChinese(20, 20, "祝大家龙年");
	ssd1306_drawChinese(30, 40, "大吉大利");
	ssd1306_displayShow();
	k_msleep(2000);

	bool status = true;
	ssd1306_clearDisplay();
	while (1)
	{
		for (y = 0; y < 64; y+=2)
		{
			for (x = 0; x < 128; x += 2)
			{
				ssd1306_drawPixel(x, y, WHITE);
				ssd1306_displayShow();
				k_msleep(1);
			}
		}
		status = !status;
	}

	return 0;
}

 

在上面的main代码中,调用了ssd1306_i2c库,可以从:HonestQiao/ssd1306_i2c at zephyr (github.com) 下载(zephyr分支),放到 samples/drivers/display/src/ssd1306_i2c。

该库来源于:iliapenev/ssd1306_i2c: SSD1306 i2c driver for Raspberry Pi (github.com),使用了buffer来处理来处理。

而zephry中的display,也使用了buffer进行处理,经过仔细研究,把两者的buffer关联到一起,就能够正常使用了。

另外:

  • 在 ssd1306_i2c/oled_fonts_cn.h 中,提供了仅包含“祝大家龙年吉利”的汉字字库,可以根据实际需要方便的定制。
  • 在 ssd1306_i2c/ssd1306_addon.c/h 中,提供了显示汉字字符串的处理。
  • 在 ssd1306_i2c/ssd1306_addon.c/h 中,还添加了 ssd1306_setCursor(),可以设置英文字符自动换行显示的起始坐标。

oled_fonts_cn.h:

#ifndef OLED_FONTS_CN_H
#define OLED_FONTS_CN_H

#define PROGMEM

/**
 * 汉字字模在线: https://www.23bei.com/tool-223.html
 * 数据排列:从左到右从上到下
 * 取模方式:横向8位左高位
 **/
#define FONT_CN_CHAR_NUM 7
#define FONT_CN_CHAR_WIDTH 3
#define FONT_CN_CHAR_BIT_NUM 32
static const char font_cn_chars[FONT_CN_CHAR_NUM * FONT_CN_CHAR_WIDTH] = "祝大家龙年吉利";
static const unsigned char font_cn_16x16[FONT_CN_CHAR_NUM * FONT_CN_CHAR_BIT_NUM] PROGMEM = {
	/* [字库]:[HZK1616宋体] [数据排列]:从左到右从上到下 [取模方式]:横向8点左高位 [正负反色]:否 [去掉重复后]共7个字符
	[总字符库]:"祝大家龙年吉利"*/

	/*-- ID:0,字符:"祝",ASCII编码:D7A3,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节*/
	0x20, 0x08, 0x13, 0xFC, 0x12, 0x08, 0x02, 0x08, 0xFE, 0x08, 0x0A, 0x08, 0x12, 0x08, 0x3B, 0xF8,
	0x56, 0xA8, 0x90, 0xA0, 0x10, 0xA0, 0x11, 0x20, 0x11, 0x22, 0x12, 0x22, 0x14, 0x1E, 0x18, 0x00,

	/*-- ID:1,字符:"大",ASCII编码:B4F3,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节*/
	0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x04, 0xFF, 0xFE, 0x01, 0x00, 0x02, 0x80,
	0x02, 0x80, 0x02, 0x40, 0x04, 0x40, 0x04, 0x20, 0x08, 0x10, 0x10, 0x0E, 0x60, 0x04, 0x00, 0x00,

	/*-- ID:2,字符:"家",ASCII编码:BCD2,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节*/
	0x02, 0x00, 0x01, 0x00, 0x7F, 0xFE, 0x40, 0x02, 0x80, 0x04, 0x3F, 0xF8, 0x04, 0x00, 0x1A, 0x10,
	0x63, 0x30, 0x05, 0x40, 0x19, 0x80, 0x63, 0x40, 0x05, 0x30, 0x19, 0x0E, 0x65, 0x04, 0x02, 0x00,

	/*-- ID:3,字符:"龙",ASCII编码:C1FA,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节*/
	0x02, 0x00, 0x02, 0x40, 0x02, 0x20, 0x02, 0x04, 0xFF, 0xFE, 0x02, 0x80, 0x02, 0x88, 0x04, 0x88,
	0x04, 0x90, 0x04, 0xA0, 0x08, 0xC0, 0x08, 0x82, 0x11, 0x82, 0x16, 0x82, 0x20, 0x7E, 0x40, 0x00,

	/*-- ID:4,字符:"年",ASCII编码:C4EA,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节*/
	0x08, 0x00, 0x08, 0x08, 0x1F, 0xFC, 0x11, 0x00, 0x21, 0x00, 0x41, 0x10, 0x1F, 0xF8, 0x11, 0x00,
	0x11, 0x00, 0x11, 0x04, 0xFF, 0xFE, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,

	/*-- ID:5,字符:"吉",ASCII编码:BCAA,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节*/
	0x01, 0x00, 0x01, 0x00, 0x01, 0x04, 0xFF, 0xFE, 0x01, 0x00, 0x01, 0x00, 0x01, 0x10, 0x3F, 0xF8,
	0x00, 0x00, 0x00, 0x10, 0x1F, 0xF8, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F, 0xF0, 0x10, 0x10,

	/*-- ID:6,字符:"利",ASCII编码:C0FB,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节*/
	0x01, 0x04, 0x07, 0x84, 0x7C, 0x04, 0x04, 0x24, 0x04, 0x24, 0x05, 0x24, 0xFF, 0xA4, 0x0C, 0x24,
	0x0E, 0x24, 0x15, 0xA4, 0x14, 0xA4, 0x24, 0x24, 0x44, 0x04, 0x04, 0x04, 0x04, 0x14, 0x04, 0x08
};
#endif

 

ssd1306_addon.c:

#include <stdio.h>
#include <string.h>

#include "ssd1306_i2c.h"
#include "oled_fonts_cn.h"

extern int cursor_y;
extern int cursor_x;

void ssd1306_setCursor(uint8_t x, uint8_t y)
{
	cursor_x = x;
	cursor_y = y;
}

void ssd1306_drawRegion(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *data, uint32_t size, uint32_t stride)
{
	if (x + w > SSD1306_LCDWIDTH || y + h > SSD1306_LCDHEIGHT || w * h == 0)
	{
		fprintf(stderr, "%dx%d @ %d,%d out of range or invalid!\r\n", w, h, x, y);
		return;
	}

	w = (w <= SSD1306_LCDWIDTH ? w : SSD1306_LCDWIDTH);
	h = (h <= SSD1306_LCDHEIGHT ? h : SSD1306_LCDHEIGHT);
	stride = (stride == 0 ? w : stride);

	uint8_t rows = size * 8 / stride;
	for (uint8_t i = 0; i < rows; i++)
	{
		uint32_t base = i * stride / 8;
		for (uint8_t j = 0; j < w; j++)
		{
			uint32_t idx = base + (j / 8);
			uint8_t byte = idx < size ? data[idx] : 0;
			uint8_t bit = byte & (0x80 >> (j % 8));
			ssd1306_drawPixel(x + j, y + i, bit ? WHITE : BLACK);
		}
	}
}

void ssd1306_drawChinese(uint8_t x, uint8_t y, char *str)
{
	const uint32_t W = 16, H = 16, S = 16;

	for (uint32_t i = 0, end=strlen(str); i < end; i += FONT_CN_CHAR_WIDTH)
	{
		for (uint32_t n = 0; n < FONT_CN_CHAR_NUM; n++)
		{
			if (strncmp(str+i, font_cn_chars+n*FONT_CN_CHAR_WIDTH, FONT_CN_CHAR_WIDTH)==0)
			{
				// 字符匹配成功,获取字体数据
				ssd1306_drawRegion(x + i / FONT_CN_CHAR_WIDTH * W, y, W, H, font_cn_16x16 + n * FONT_CN_CHAR_BIT_NUM, FONT_CN_CHAR_BIT_NUM, S);
				break;
			}
		}
	}
}

 

为了最小限度的减少对原库的侵入,在main中定义了一个显示函数:

void ssd1306_displayShow()
{
	display_write(display_dev, 0, 0, &buf_desc, buffer);
}

以替代原有的ssd1306_display()。

 

最终,编译出来的结果如下:

 

 

FLASH所剩无几,RAM还剩余不少。

 

四、实际效果

编译下载到开发板,运行效果如下:

4622_1708331393

 

五、参考资料

此帖出自stm32/stm8论坛

最新回复

本帖最后由 lugl4313820 于 2024-2-19 20:19 编辑 外挂128M的flash可以吗?帮主的再试一下DMA呗!体验飞一样的速度!   详情 回复 发表于 2024-2-19 20:17
点赞 关注(2)
 

回复
举报

6993

帖子

11

TA的资源

版主

沙发
 
本帖最后由 lugl4313820 于 2024-2-19 20:19 编辑

外挂128M的flash可以吗?帮主的再试一下DMA呗!体验飞一样的速度!

此帖出自stm32/stm8论坛
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表