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) 的优化路线。

相关推荐
A9better4 小时前
嵌入式开发学习日志50——任务调度与状态
stm32·嵌入式硬件·学习
草丛中的蝈蝈6 小时前
STM32向FLASH写入数据后,重新读出的数据和原写入数据不一致
stm32
DLGXY6 小时前
STM32——EXTI外部中断(六)
stm32·单片机·嵌入式硬件
LCG米9 小时前
开发环境搭建:告别Keil,用CLion+STM32CubeMX打造智能嵌入式IDE
ide·stm32·嵌入式硬件
Hello_Embed9 小时前
Modbus 协议报文解析
笔记·stm32·单片机·学习·modbus
WD1372980155711 小时前
30V降12V,8A大功率高集成同步降压IC,工业电源WD5030K
stm32·单片机·嵌入式硬件·电脑
愈心凌11 小时前
知识碎片——STM32的定时器时钟解读
stm32·单片机·嵌入式硬件
bai54593613 小时前
STM32 CubeIDE 控制OLED显示屏
stm32·单片机·嵌入式硬件
独处东汉13 小时前
freertos开发空气检测仪之延迟函数设计:DWT软件实现
人工智能·stm32·单片机·嵌入式硬件