用于 OLED 屏幕的 Debian I2C 驱动程序无法正常工作。 [ssd1306]

Posted

技术标签:

【中文标题】用于 OLED 屏幕的 Debian I2C 驱动程序无法正常工作。 [ssd1306]【英文标题】:Debian I2C driver for OLED screen not working. [ssd1306] 【发布时间】:2017-04-10 22:07:34 【问题描述】:

我有一些驱动程序代码,我正在测试它们与 SSD1306 驱动的 128x32 OLED 屏幕(与 OLED adafruit 型号相同)一起使用。我需要它在 debian 中运行(我使用的是Linario-4.4.9

我已按照 Debian 指南开始为设备创建文件处理程序,如下所示。 oled.h 中唯一的内容是设备地址 (0x3C) 和原型类型。我遵循在 adafruit github 上采用的初始化方法(因为我首先在 Ardunio 上尝试了他们的代码,以确保屏幕确实有效)。我相信我可能做错了什么,但我不完全确定我做错了什么。我还在下面列出了我的初始化过程。

#include <errno.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <linux/i2c-dev.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>

#include "oled.h"

int oled;

int  lcd_driver_init(void)

        ///< Begin the init proc.
        int dloc = open("/dev/i2c-1", O_RDWR);
        if (dloc < 0 )
        
                fprintf(stderr, "Error opening i2c device\n");
                return -1;
        


        if(ioctl(dloc, I2C_SLAVE, SCR_ADDR) < 0)
        
                fprintf(stderr, "Error in ioctl. Errno :%i\n",errno);
                return -2;
        

        oled = dloc;
        fprintf(stderr, "init success, device open and local\n");   
        return EXIT_SUCCESS;


int oled_command( uint8_t cmd)

        char command[2]= 0;
        command[1] = cmd;
        int check = (write(oled, command, 2));

        return check;


void oled_cmd_start()

        int check = (write(oled, 0x00, sizeof(uint8_t)));
        if(check<0)
                fprintf(stderr, "Errno set:: %i\n", errno);
        return;

void oled_data_start()

        uint8_t _data_start_[1] = 0x40 ;
        int check = (write(oled, _data_start_, sizeof(uint8_t)));
        if(check<0)
                fprintf(stderr, "Errno set oled_data_start:: %i\n", errno);
        return;


int oled_data (uint8_t xmit)


        int check = (write(oled, &xmit, (sizeof(uint8_t))));
        if(check<0)
                fprintf(stderr, "Errno set oled_data:: %i\n", errno);
        return check;

初始化进程

void sendcommand(unsigned char payload)

    oled_data(0x00);        //Control Byte - Command
    oled_data(payload);     //payload

void lcd_init(void)


    sendcommand(0xAE);//--Set Display off

    sendcommand(0x00);//--set low column address

    sendcommand(0x10);//--set high column address

    sendcommand(0x81);//--set contrast control register
    sendcommand(0x7f);

    sendcommand(0xa1);//--set segment re-map 95 to 0

    sendcommand(0xA6);//--set normal display

    sendcommand(0xa8);//--set multiplex ratio(1 to 16)
    sendcommand(0x1f);//--duty 1/32

    sendcommand(0xd3);//--set display offset
    sendcommand(0x00);//--not offset

    sendcommand(0xd5);//--set display clock divide ratio/oscillator frequency
    sendcommand(0xf0);//--set divide ratio

    sendcommand(0xd9);//--set pre-charge period
    sendcommand(0x22);

    sendcommand(0xda);//--set com pins hardware configuration
    sendcommand(0x02);//disable left/right remap and set for sequential

    sendcommand(0xdb);//--set vcomh
    sendcommand(0x49);//--0.83*vref

    sendcommand(0x8d);//--set DC-DC enable
    sendcommand(0x14);//

    sendcommand(0xAF);//--turn on oled panel

    sendcommand(0xA4);//--Entire Display ON


之后,我交替发送0xFF 尝试在屏幕上制作条纹。唯一出现的是随机像素。没有什么连贯的。

我已连接逻辑分析仪以嗅探 I2C 线路,当我连接 LA 时,I2C 线路似乎不再起作用,ERRNO 返回 IO 故障 (#5)。 但是,打开设备以获取文件指针似乎从来没有问题。

我确实有时会收到 ERRNO 超时,但我已经读到这只是使用协议的 I2C 设备的问题,因为 write 期望比 I2C 更快的响应。

我还在使用-std=c99 -O0 进行编译,以确保所有内联函数都在那里,并确保循环变量可用。

如果有人能指出我正确的方向并指出我的方法中的一些缺陷,我将不胜感激。谢谢。

编辑

我检查了设备树并且 i2c 设备已正确启用。但是,似乎没有启用任何i2c_freq 速度。这会导致超时和垃圾数据传输吗?

【问题讨论】:

对了,如果能提供I2C版本的fbtft驱动就好了。这对很多人来说都是有益的。并且内核驱动程序比用户空间驱动程序好得多(我有像这样的 sparkfun OLED 显示器,虽然它是 SPI 连接的)。 我的 debian 内核没有 fbtft 模块,所以我正在尝试编写一个可加载的内核模块,它可以接受请求并将它们写入屏幕。我以前从未真正这样做过,所以这可能进展缓慢。不过,当我完成它时,我可以将你链接到它的回购! 【参考方案1】:

我已连接逻辑分析仪来嗅探 I2C 线路,当我连接 LA 时,I2C 线路似乎不再起作用,ERRNO 返回 IO 故障 (#5)。

逻辑分析仪只是一种测量设备。它将捕获的数据转换为时序图,解码您设置的协议。因此它不会对任何 I2C 读写错误负责(直到您的接地和硬件连接正确)。

对于超时问题,您可以尝试减小 i2c clock-frequency 或 ioctl I2C_TIMEOUT

【讨论】:

LA 是为了确保数据格式正确并以正确的顺序传输等。这里有趣的一点是,当 LA 连接时,我什至没有在OLED,它只是保持空白,直到我断开 LA 并重新运行我的程序。根据我的阅读,超时并不意味着写入失败。它只是设置errno,因为计时器已过期。对吗? 我不知道为什么在连接洛杉矶时会发生这种奇怪的事情。对我来说,它看起来只是硬件问题。当 I2C 总线被认为忙时会产生超时。我认为 I2C 支持two type of timeout。可能是您在编写时缺少一些注册设置或序列(假设您的硬件连接正确)。所以你可以尝试一件事:通过 I2C 工具设置这些寄存器并验证它们的更新值 我尝试通过i2cset 工具运行命令,但没有任何结果。该设备也不再出现在i2cdetect 上。这似乎是一个硬件问题,因为我的代码没有错,而且我正确使用了 ioctl。 好吧,我从一开始就假设了。顺便说一句,如果您甚至没有通过 i2cdetect 看到您的设备(确保您使用的是正确的 i2c 总线编号),请咨询您的硬件工程师。 完全重置后设备显示备份。 (不幸的是我是硬件工程师!)【参考方案2】:

事实证明,SOM 有一个内部调节器,用于 I2C 线路为 1V8,而 SSD1306 芯片以 3V3 运行,导致信息处理不当。 SOM 中未记录此行为。

在设计中应用电平转换芯片可实现正确通信。

如果有人遇到同样的问题,请检查您的原理图以了解电压不匹配水平。

【讨论】:

以上是关于用于 OLED 屏幕的 Debian I2C 驱动程序无法正常工作。 [ssd1306]的主要内容,如果未能解决你的问题,请参考以下文章

STC单片机驱动ssd1306 I2C oled屏幕

Arduino RP2040 驱动ssd1306 I2C OLED屏幕

STM32F103VET6基于STM32CubeMX 配置硬件I2C驱动SH1106 OLED屏幕

Arduino ESP32 0.96OLED I2C屏幕驱动显示

使用U8g2库驱动I2C 0.96“or1.3“OLED屏幕相关接口函数选择

Arduino框架下轻量级ssd1306 I2C屏幕驱动库