1. 程式人生 > >荔枝派 V3S Linux 應用層 IIC 使用OLED

荔枝派 V3S Linux 應用層 IIC 使用OLED

ddr 開始 出現 驅動程序 line 但是 IE HR 手冊

1.開始

  我想在荔枝派上驅動oled屏,但是在內核中寫驅動對我來說肯定是非常麻煩的,所以我退而求其次,想在應用層中操作通用i2c接口來實現oled的驅動程序。

我買的OLED是中景園經典款,四針IIC接口oled。首先我參考了NanoPi的Matrix庫,參考他的IIC應用層函數。我發現他多include了一個i2c-dev.h 並且這個函數的內容是比我/usr/inlucde/linux/i2c-dev.h中的內容多的,他多了以下幾個函數

static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, 
                                     
int size, union i2c_smbus_data *data) static inline __s32 i2c_smbus_write_quick(int file, __u8 value) static inline __s32 i2c_smbus_read_byte(int file) static inline __s32 i2c_smbus_write_byte(int file, __u8 value) static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) static
inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value) static inline __s32 i2c_smbus_read_word_data(int file, __u8 command) static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value)
static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) /* Returns the number of read bytes */ static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values) static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, __u8 *values) /* Returns the number of read bytes */ static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, __u8 *values) static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, __u8 length, __u8 *values) /* Returns the number of read bytes */ static inline __s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length, __u8 *values)

  我在網上查詢了這些函數,這個是一種smbus協議,是對應用層i2c的進一步封裝。我可以使用這個快速的對i2c數據進行讀寫。

之後我就參考了別人的OLED代碼,開始了移植。

2.問題出現

  我發現我設置好了從機地址之後,進行讀寫一直出現No Such Device Or Addres 的錯誤。經過一天的尋找,我終於發現了錯誤所在。

在網上的那個oled程序,都是將0x78作為從機地址。並且數據手冊中也是這樣寫的,那麽我理所當然將0x78作為從機地址。但是接下來我們看數據手冊以及代碼片段

ssd1306:

數據手冊片段:

技術分享圖片

ssd1306的讀寫函數片段:

/*********************OLED寫數據************************************/ 
void OLED_WrDat(unsigned char IIC_Data)
{
    IIC_Start();
   IIC_Send_Byte(0x78);            //D/C#=0; R/W#=0
    IIC_Wait_Ack();    
   IIC_Send_Byte(0x40);            //write data
    IIC_Wait_Ack();    
   IIC_Send_Byte(IIC_Data);
    IIC_Wait_Ack();
    IIC_Stop();
}

mpu6050:

數據手冊

技術分享圖片

代碼片段:

//IIC讀一個字節 
//reg:寄存器地址 
//返回值:讀到的數據
u8 MPU_Read_Byte(u8 reg)
{
    u8 res;
    IIC_Start(); 
    IIC_Send_Byte((MPU_ADDR<<1)|0);//發送器件地址+寫命令    
    IIC_Wait_Ack();        //等待應答 
    IIC_Send_Byte(reg);    //寫寄存器地址
    IIC_Wait_Ack();        //等待應答
    IIC_Start();
    IIC_Send_Byte((MPU_ADDR<<1)|1);//發送器件地址+讀命令    
    IIC_Wait_Ack();        //等待應答 
    res=IIC_Read_Byte(0);//讀取數據,發送nACK 
    IIC_Stop();            //產生一個停止條件 
    return res;        
}

大家發現錯誤沒有? 那就是對兩個器件寫地址的時候,oled的地址沒有左移!那麽問題就出現在這裏,linux中設置好了從機地址後,他的發送時會自動根據讀寫來對地址進行左移後或上0、1的操作。

所以我這個0x78就是他的已經左移一位了的地址,那麽我給linux中設置的從機地址應該是0x78右移一位得出的0x3C!現在我就可以正常讀寫了。

3.代碼

  下面附上我修改的i2c代碼驅動地址

荔枝派 V3S Linux 應用層 IIC 使用OLED