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

相关推荐
逐步前行3 小时前
STM32_TIM_寄存器操作
stm32·单片机·嵌入式硬件
0南城逆流03 小时前
【STM32】知识点介绍七:PWM功能
stm32·单片机·嵌入式硬件
dashizhi20153 小时前
服务器共享禁止保存到本地磁盘、共享文件禁止另存为本地磁盘、移动硬盘等
运维·网络·stm32·安全·电脑
三佛科技-187366133977 小时前
FT32F030F6AP7高性能32位RISC内核MCU解析(兼容STM32F030K6TP7)
stm32·单片机·嵌入式硬件
LCMICRO-133108477468 小时前
长芯微LDC90810完全P2P替代ADC128D818,是一款八通道系统监控器,专为监控复杂系统状态而设计。
stm32·单片机·嵌入式硬件·fpga开发·硬件工程·模数转换芯片adc
csaaa200512 小时前
STM32F103 开发USB设备端点超过ENDP4以上时崩溃问题的解决
stm32·单片机·嵌入式硬件
LCG元12 小时前
故障预测与健康管理:STM32G4监控自身参数,早期预警
stm32·单片机·嵌入式硬件
ipod74112 小时前
STM32 GPIO控制器及其应用
stm32·单片机·嵌入式硬件
逐步前行12 小时前
STM32_USART_串口通信
stm32·单片机·嵌入式硬件
我不是程序猿儿12 小时前
【嵌入式】趣味理解“volatile”
stm32·单片机·嵌入式硬件·学习