1. 程式人生 > >linux gpio模擬i2c的使用/用GPIO模擬I2C匯流排-3

linux gpio模擬i2c的使用/用GPIO模擬I2C匯流排-3

這個結構專門用於資料傳輸相關的addrI2C裝置地址,flags為一些標誌位,len為資料的長度,buf為資料。這裡巨集定義的一些標誌還是需要了解一下。

I2C_M_TEN表示10位裝置地址

I2C_M_RD讀標誌

I2C_M_NOSTART無起始訊號標誌

I2C_M_IGNORE_NAK忽略應答訊號標誌

回到for,這裡的num代表有幾個struct i2c_msg,進入for語句,接下來是個if語句,判斷這個裝置是否定義了I2C_M_NOSTART標誌,這個標誌主要用於寫操作時,不必重新發送起始訊號和裝置地址,但是對於讀操作就不同了,要呼叫i2c_repstart這個函式去重新發送起始訊號,呼叫bit_doAddress

函式去重新構造裝置地址位元組,來看這個函式。

  1. static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)  
  2. {  
  3.     unsigned short flags = msg->flags;  
  4.     unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;  
  5.     struct i2c_algo_bit_data *adap = i2c_adap->algo_data;  
  6.     unsigned char addr;  
  7.     int ret, retries;  
  8.     retries = nak_ok ? 0 : i2c_adap->retries;  
  9.     if (flags & I2C_M_TEN) {  
  10.         /* a ten bit address */  
  11.         addr = 0xf0 | ((msg->addr >> 7) & 0x03);  
  12.         bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);  
  13.         /* try extended address code...*/  
  14.         ret = try_address(i2c_adap, addr, retries);  
  15.         if ((ret != 1) && !nak_ok)  {  
  16.             dev_err(&i2c_adap->dev,  
  17.                 "died at extended address code\n");  
  18.             return -EREMOTEIO;  
  19.         }  
  20.         /* the remaining 8 bit address */  
  21.         ret = i2c_outb(i2c_adap, msg->addr & 0x7f);  
  22.         if ((ret != 1) && !nak_ok) {  
  23.             /* the chip did not ack / xmission error occurred */  
  24.             dev_err(&i2c_adap->dev, "died at 2nd address code\n");  
  25.             return -EREMOTEIO;  
  26.         }  
  27.         if (flags & I2C_M_RD) {  
  28.             bit_dbg(3, &i2c_adap->dev, "emitting repeated "  
  29.                 "start condition\n");  
  30.             i2c_repstart(adap);  
  31.             /* okay, now switch into reading mode */  
  32.             addr |= 0x01;  
  33.             ret = try_address(i2c_adap, addr, retries);  
  34.             if ((ret != 1) && !nak_ok) {  
  35.                 dev_err(&i2c_adap->dev,  
  36.                     "died at repeated address code\n");  
  37.                 return -EREMOTEIO;  
  38.             }  
  39.         }  
  40.     } else {        /* normal 7bit address  */  
  41.         addr = msg->addr << 1;  
  42.         if (flags & I2C_M_RD)  
  43.             addr |= 1;  
  44.         if (flags & I2C_M_REV_DIR_ADDR)  
  45.             addr ^= 1;  
  46.         ret = try_address(i2c_adap, addr, retries);  
  47.         if ((ret != 1) && !nak_ok)  
  48.             return -ENXIO;  
  49.     }  
  50.     return 0;  
  51. }  
這裡先做了一個判斷,10位裝置地址和7位裝置地址分別做不同的處理,通常一條I2C總線上不會掛那麼多I2C裝置,所以10位地址不常用,直接看對7位地址的處理。struct i2c_msgaddr中是真正的裝置地址,而這裡傳送的addr7位才是裝置地址,最低位為讀寫位,如果為讀,最低位為1,如果為寫,最低位為0。所以要將struct i2c_msgaddr向左移1位,如果定義了I2C_M_RD標誌,就將addr或上1,前面就說過,這個標誌就代表讀,如果是寫,這裡就不用處理,因為最低位本身就是0。最後呼叫try_address函式將這個地址位元組傳送出去。 [html] view plaincopyprint?
  1.  1. static int try_address(struct i2c_adapter *i2c_adap,    
  2.  2.                unsigned char addr, int retries)    
  3.  3. {    
  4.  4.     struct i2c_algo_bit_data *adap = i2c_adap->algo_data;    
  5.  5.     int i, ret = 0;    
  6.  6.     
  7.  7.     for (i = 0; i <= retries; i++) {    
  8.  8.         ret = i2c_outb(i2c_adap, addr);    
  9.  9.         if (ret == 1 || i == retries)    
  10. 10.             break;    
  11. 11.         bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");    
  12. 12.         i2c_stop(adap);    
  13. 13.         udelay(adap->udelay);    
  14. 14.         yield();    
  15. 15.         bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");    
  16. 16.         i2c_start(adap);    
  17. 17.     }    
  18. 18.     if (i && ret)    
  19. 19.         bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at "    
  20. 20.             "0x%02x: %s\n", i + 1,    
  21. 21.             addr & 1 ? "read from" : "write to", addr >> 1,    
  22. 22.             ret == 1 ? "success" : "failed, timeout?");    
  23. 23.     return ret;    
  24. 24. }    

最主要的就是呼叫i2c_outb傳送一個位元組,retries為重複次數,看前面adap->retries= 3;

如果傳送失敗,也就是裝置沒有給出應答訊號,那就傳送停止訊號,傳送起始訊號,再發送這個地址位元組,這就叫retries。來看這個具體的i2c_outb函式

[html] view plaincopyprint?
  1.  1. static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)    
  2.  2. {    
  3.  3.     int i;    
  4.  4.     int sb;    
  5.  5.     int ack;    
  6.  6.     struct i2c_algo_bit_data *adap = i2c_adap->algo_data;    
  7.  7.     
  8.  8.     /* assert: scl is low */    
  9.  9.     for (i = 7; i >= 0; i--) {    
  10. 10.         sb = (c >> i) & 1;    
  11. 11.         setsda(adap, sb);    
  12. 12.         udelay((adap->udelay + 1) / 2);    
  13. 13.         if (sclhi(adap) <0) { /* timed out */    
  14. 14.             bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "    
  15. 15.                 "timeout at bit #%d\n", (int)c, i);    
  16. 16.             return -ETIMEDOUT;    
  17. 17.         }    
  18. 18.         /* FIXME do arbitration here:   
  19. 19.          * if (sb && !getsda(adap)) -> ouch! Get out of here.   
  20. 20.          *   
  21. 21.          * Report a unique code, so higher level code can retry   
  22. 22.          * the whole (combined) message and *NOT* issue STOP.   
  23. 23.          */    
  24. 24.         scllo(adap);    
  25. 25.     }    
  26. 26.     sdahi(adap);    
  27. 27.     if (sclhi(adap) <0) { /* timeout */    
  28. 28.         bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "    
  29. 29.             "timeout at ack\n", (int)c);    
  30. 30.         return -ETIMEDOUT;    
  31. 31.     }    
  32. 32.     
  33. 33.     /* read ack: SDA should be pulled down by slave, or it may   
  34. 34.      * NAK (usually to report problems with the data we wrote).   
  35. 35.      */    
  36. 36.     ack = !getsda(adap);    /* ack: sda is pulled low -> success */    
  37. 37.     bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,    
  38. 38.         ack ? "A" : "NA");    
  39. 39.     
  40. 40.     scllo(adap);    
  41. 41.     return ack;    
  42. 42.     /* assert: scl is low (sda undef) */    
  43. 43. }    

這個函式有兩個引數,一個是structi2c_adapter代表I2C主機,一個是傳送的位元組資料。那麼I2C是怎樣將一個位元組資料傳送出去的呢,那再來看看協議。



首先是傳送位元組資料的最高位,在時鐘為高電平期間將一位資料傳送出去,最後是傳送位元組資料的最低位。傳送完成之後,我們需要一個ACK訊號,要不然我怎麼知道傳送成功沒有,ACK訊號就是在第九個時鐘週期時資料線為低,所以在一個位元組資料傳送完成後,還要將資料線拉高,我們看程式中就是這一句sdahi(adap);等待這個ACK訊號的到來,這樣一個位元組資料就傳送完成。

回到bit_xfer函式中,前面只是將裝置地址位元組傳送出去了,那麼接下來就是該傳送資料了。

注意:這裡的資料包括操作裝置的基地址

如果是讀則呼叫readbytes函式去讀,如果是寫則呼叫sendbytes去寫,先看readbytes函式

[html] view plaincopyprint?
  1.  1. static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)    
  2.  2. {    
  3.  3.     int inval;    
  4.  4.     int rdcount = 0;    /* counts bytes read */    
  5.  5.     unsigned char *temp = msg->buf;    
  6.  6.     int count = msg->len;    
  7.  7.     const unsigned flags = msg->flags;    
  8.  8.     
  9.  9.     while (count > 0) {    
  10. 10.         inval

    相關推薦

    linux gpio模擬i2c的使用/GPIO模擬I2C匯流排-3

    這個結構專門用於資料傳輸相關的addr為I2C裝置地址,flags為一些標誌位,len為資料的長度,buf為資料。這裡巨集定義的一些標誌還是需要了解一下。 I2C_M_TEN表示10位裝置地址 I2C_M_RD讀標誌 I2C_M_NOSTART無起始訊號標誌 I2

    Linux文件IO的方式操作GPIO(/sys/class/gpio)(轉)

    char include clu wro linux fcntl sysfs 查看 printf 通過sysfs方式控制GPIO,先訪問/sys/class/gpio目錄,向export文件寫入GPIO編號,使得該GPIO的操作接口從內核空間暴露到用戶空間,GPIO的操作接

    Linux內核調I2C驅動_以MPU6050為例

    匹配 獲取 inux error: sdn git alt 說明 時鐘 Linux內核調用I2C驅動_以MPU6050為例 0. 導語 最近一段時間都在惡補數據結構和C++,加上導師的事情比較多,Linux內核驅動的學習進程總是被阻礙、不過,十一假期終於沒有人打擾,有這個奢

    USB轉CAN匯流排介面卡/分析儀 模組 相容USB-I2C/SPI/GPIO/UART/ADC

    名稱:緯圖Ginkgo USB-CAN匯流排介面卡品牌:ViewTool/緯圖型號:VTG202A 典型應用:- 通過USB介面實現對CAN匯流排網路的傳送和接收 - CAN網路資料採集、資料分析 - USB介面轉CAN網路介面 - CAN程式除錯,延長CAN匯流排的網路通訊長度 - 工業現場C

    qemu模擬i386的linux核心,用於核心學習

    安裝 apt-get install qemu 下載http://kernel.org/  這裡也測試過4.5版本,但是無法啟動 wget http://www.kernel.org/pub/linux/kernel/v3.0/linux-3.7.4.tar.bz2 tar

    Fiddler模擬低速網絡環境(弱網)

    鏈接 一位 enter 所有 通過 repl rscript uic 限制 原文鏈接:http://caibaojian.com/fiddler.html 有時候寬頻網路用習慣了… 在開發的過程就比較少去考慮最佳化的問題… 但當有人反應說「你的網頁好慢」 甚至當網路速度慢,

    ES5模擬實現ES6中的Map類

    fun 遍歷 false 創建 per 映射 .get script 實例 ECMAScript6原生實現了Map類,即我們所說的字典,字典和集合很像,不過集合是以值值得形式存儲元素,字典則是以鍵值的形式存儲元素。字典也叫映射。 1. 創建一個字典 function M

    PostMan模擬Post請求時 模擬戶登錄狀態

    測試 .com cnblogs post請求 技術 head com post 調試 1.打開Chrome 登錄要測試的網站 2.打開開發者調試工具,點開NetWork,復制Cookie 3.將整段Cookie復制到PostMan的Headers裏 4.大功告成!可以開

    pythonGUI編程Canvas模擬畫板

    idt paint create -1 tkinter png height width ges 代碼如下: from tkinter import * import webbrowser root = Tk() w = Canvas(root,width=400,h

    chrome模擬微信瀏覽器訪問需要OAuth2.0網頁授權的頁面

    mil col cnblogs bre letter 型號 默認 刷新 build 現在很流行微信網頁小遊戲,用html5制作的小遊戲移過來,可以放到微信瀏覽器中打開,關鍵是可以做成微信分享朋友圈的形式,大大提高遊戲的傳播,增強好友的遊戲互動。 微信瀏覽器中打開網頁遊戲效

    Fiddler模擬低速網絡環境【轉】

    正在 www. itl rdl pro 存檔 url 資源 wid 原文鏈接:http://caibaojian.com/fiddler.html 我們為什麽要限速 限速對於web前端研發是非常重要的,由於開發者的機器一般配置都很高,並且是在localhost下來調試程

    RGBD模擬激光雷達數據:depthimage_to_laserscan

    功能 ati github 雷達 ack div color back continue 參考:http://wiki.ros.org/depthimage_to_laserscanhttps://github.com/ros-perception/depthimage_t

    【作業】模擬dfs

    模擬 clu AD string crt code warnings style cin 題意:一個迷宮,起點到終點的路徑,不用遞歸。 題解: #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include

    編寫一個模擬註冊戶和驗證戶登陸的程序

    一個 input bsp BE 不存在 == code AS ges import hashlib import loggin User_pass = {‘11‘:‘ e1942a04175fdbe80e7fea0c40f7bf54‘} def get_md5(self):

    自己ul模擬實現下拉多選框,

    ogg point shee index ati ref -m order nowrap 模擬實現下拉多選框 效果如下 <!DOCTYPE html> <html lang="en"> <head> <meta char

    PTS模擬海量戶訪問,助力懂球帝應對日增百萬

    應對 ima 訪問量 image 實現 tex 流量 col 客戶 摘要: 零門檻上手,可達千萬TPS的施壓能力,全球首家支持實時調速的能力,流量仿真能力全行業領先。 今年夏天刷遍各大社交網絡的除了世界杯期間的黑馬頻出、英雄遲暮、老帥離別、新人輩出,還有那一張張讓你禁不住轉

    vue專案json模擬資料

    基於node和express 1,先寫一個json檔案,例如data.json {  seller:[ ....... ],  goods: [ ...... ] } 2,自dev-server裡寫 var appData=requir

    postman模擬ajax傳送json資料的筆記

    header是這個: 但是你後臺,你知道嗎,用request.getParameter("sysName");是接受不到的, 因為json串在requset的body中。如果不用@RequsetBody註解,那就要寫方法從流中讀取引數。 public static String getRequ

    Linux應用層直接操作GPIO

    分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

    山科java實驗4-2 HashMap模擬一個網上購物車。

    用HashMap模擬一個網上購物車。要求:從鍵盤輸入n本書的名稱、單價、購買數量,將這些資訊存入一個HashMap,然後將該HashMap作為引數呼叫方法getSum(HashMap books),該方法用於計算書的總價並返回。【說明:鍵盤輸入可使用Scanner類】 package 作業2