20260125 - Linu驱动学习笔记:SPI-OLED测试

SPI-OLED测试

OLED的D/C引脚电平逻辑:

电平状态 模式名称 作用描述 例子
低电平 (Low / 0) Command (命令) 写入控制寄存器,设置屏幕的工作状态。 设置亮度、开启滚动、设置起始页。
高电平 (High / 1) Data (数据) 写入显存 (GDDRAM),直接改变屏幕显示的图像。 发送图片点阵、发送字符字模。

设备树定义:

c 复制代码
&ecspi1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_ecspi1>;

    fsl,spi-num-chipselects = <2>;
    cs-gpios = <&gpio4 26 GPIO_ACTIVE_LOW>, <&gpio4 24 GPIO_ACTIVE_LOW>;
    status = "okay";

    oled: oled {
        compatible = "spidev";
        reg = <0>;
        spi-max-frequency = <10000000>;
    };
};

D/C引脚接在了GPIO4_20,即116号引脚,在APP程序中控制即可,不需要写进驱动。

因此可直接使用内核通用SPI驱动spidev.c。

首先,在内核目录中打开menuconfig:

c 复制代码
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88$ make menuconfig

搜索SPIDEV:

搜索结果:

之前已经被设置为了M,因此会被编译成模块:

c 复制代码
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88$ make modules

然后上传到开发板的/root目录下:

c 复制代码
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88$ adb push drivers/spi/spidev.ko /root

在APP程序中D/C引脚初始化及控制函数:

c 复制代码
void dc_pin_init(int number)
{
	char cmd[100];
	sprintf(cmd, "echo %d > /sys/class/gpio/export", number);
	system(cmd);
	sprintf(cmd, "echo out > /sys/class/gpio/gpio%d/direction", number);
	system(cmd);	
}

void oled_set_dc_pin(int val)
{
	char cmd[100];
	sprintf(cmd, "echo %d > /sys/class/gpio/gpio%d/value", val, dc_pin_num);
	system(cmd);	
}

void dc_pin_exit(int number)
{
    char cmd[100];
    sprintf(cmd, "echo %d > /sys/class/gpio/unexport", number);
    system(cmd);![image-20260116135634897](C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20260116135634897.png)
}

实验结果:

屏幕显示数据的速率肉眼可见地缓慢,性能太差。原因分析:

**设置位置 (OLED_DIsp_Set_Pos)**时:

  • 它内部调用了 3 次 oled_write_cmd_data
  • 每次 oled_write_cmd_data 都会:
    • 执行 system("echo ...")创建进程,很慢
    • 执行 write(fd_spidev, &uc_data, 1)1 字节写入
  • 小计:发 3 字节命令,却搞了 3 次进程创建 + 3 次 1 字节写。

发送数据 (oled_write_datas)时

  • 执行 oled_set_dc_pin(1):又是一次 system()创建进程)。
  • 执行 write(fd, buf, 8)8 字节写

总计 :显示一个 8bitx16bit 字符,一共执行了:

  • 8 次进程创建 (system 调用)
  • 6 次 1 字节写入 (设置坐标)
  • 2 次 8 字节写入 (实际像素数据)

优化 OLED 性能的核心思路:减少系统调用次数消除高开销操作

目前代码中, 导致性能低的最大原因是system() 函数,其次是碎片化的 write() 操作

system() 函数优化步骤:

  1. 修改 dc_pin_init,提前打开文件。
  2. 修改 oled_set_dc_pin,直接写文件描述符。
c 复制代码
static int fd_dc_value; // 定义为静态全局变量

void dc_pin_init(int number) {
    char cmd[100];
    char path[100];
    dc_pin_num = number;

    sprintf(cmd, "echo %d > /sys/class/gpio/export", number);
    system(cmd);
    sprintf(cmd, "echo out > /sys/class/gpio/gpio%d/direction", number);
    system(cmd);

    // 【关键优化】提前打开 value 文件
    sprintf(path, "/sys/class/gpio/gpio%d/value", number);
    fd_dc_value = open(path, O_WRONLY);
}

void oled_set_dc_pin(int val) {
    if (val) write(fd_dc_value, "1", 1);
    else     write(fd_dc_value, "0", 1);
}

其次是 oled_write_cmd_data,目前每写 1 字节就要切换一次 DC 引脚并执行一次 write。

优化逻辑:尽量将连续的命令或连续的数据打包在一起发送。

优化 Set_Pos 函数:

原函数执行了 3 次 write,可以合并为 1 次。

c 复制代码
void OLED_DIsp_Set_Pos(int x, int y) {
    unsigned char buf[3];
    buf[0] = 0xb0 + y;
    buf[1] = (x & 0x0f);
    buf[2] = ((x & 0xf0) >> 4) | 0x10;

    oled_set_dc_pin(0);       // 只切换一次 DC
    spi_write_datas(buf, 3);  // 一次性发送 3 字节命令
}

优化后,瞬间显示一整帧字符,无卡顿、无闪烁。

之后再试试显存缓冲区 (Frame Buffer) 的优化路线。

相关推荐
kebidaixu22 分钟前
FreeRTOS 移植到 STM32F407VETX 记录(四)
stm32
结城明日奈是我老婆1 小时前
基于stm32f103c8t6最小系统板俩块版通讯
stm32·单片机·嵌入式硬件
fengfuyao9852 小时前
STM32F030 SD卡文件系统读取实例
stm32·单片机·嵌入式硬件
kebidaixu2 小时前
FreeRTOS 移植到 STM32F407VETX 记录(三)
stm32·单片机·嵌入式硬件
普中科技12 小时前
【普中STM32F1xx开发攻略--标准库版】-- 第 45 章 FSMC-外扩 SRAM 实验
stm32·单片机·嵌入式硬件·fsmc·普中科技·外扩sram·is62wv51216
嵌入式ZYXC15 小时前
第3篇:《面试题:I2C为什么要加上拉电阻?阻值怎么选?》
stm32·单片机·嵌入式硬件·面试·职场和发展
你疯了抱抱我16 小时前
【STM32】使用 STM32CubeMX 生成项目,LED测试;上位机:STM32F411CEU6
stm32·单片机·嵌入式硬件
嵌入式小站19 小时前
STM32 零基础可移植教程 24:SPI Flash 读数据,先从指定地址读几个字节
chrome·stm32·嵌入式硬件
guygg8820 小时前
基于C# + Halcon的通用ROI绘制工具
stm32·单片机·c#