关键词不能为空

当前您在: 主页 > 英语 >

linux gpio模拟i2c的使用用GPIO模拟I2C总线

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-02-08 21:03
tags:

-

2021年2月8日发(作者:queensize)


linux gpio


模拟


i2c


的使用用


GPIO


模拟


I2 C


总线








这个结 构专门用于数据传输相关的


addr



I2C


设备地


址,


flags


为一些标志位,


len


为数据的长度,


buf


为数据。


这里宏定义的一些标志还是需要 了解一下。



I2C_M_TEN


表示


10


位设备地址



I2C_M_RD


读标志


< p>
I2C_M_NOSTART


无起始信号标志


< /p>


I2C_M_IGNORE_NAK


忽略应答信号标志

< p>


回到


for


,这里的< /p>


num


代表有几个


struct


i2c_msg



进入


for


语句,


接下来是个


if


语句,


判断这个设备


是否定义了


I2C_M_NOSTART


标志,这个标志主要用于写

操作时,不必重新发送起始信号和设备地址,但是对于读操


作就不同了,要调用


i2c_repstart


这个函数去重新发送起始


信号,调用


bit_doAddress


函数去重新构 造设备地址字节,


来看这个函数。




static int bit_doAddress(struct i2c_adapter *i2c_adap,


struct i2c_msg *msg)



{







unsigned short flags =


msg->flags;







unsigned short nak_ok =


msg->flags & I2C_M_IGNORE_NAK;







struct


i2c_algo_bit_data *adap = i2c_adap->algo_data;









unsigned char addr;







int ret, retries;









retries =


nak_ok ? 0 : i2c_adap->retries;









if (flags &


I2C_M_TEN) {











/* a ten bit address */











addr = 0xf0 | ((msg->addr >> 7) & 0x03);











bit_dbg(2, &i2c_adap->dev,











/* try extended address code...*/











ret =


try_address(i2c_adap, addr, retries);











if ((ret != 1)


&& !nak_ok)



{















dev_err(&i2c_adap->dev,

































return


-EREMOTEIO;











}











/* the remaining 8


bit address */











ret = i2c_outb(i2c_adap,


msg->addr & 0x7f);











if ((ret != 1)


&& !nak_ok) {















/* the chip did not


ack / xmission error occurred */















dev_err(&i2c_adap->dev,


coden















return -EREMOTEIO;











}











if (flags & I2C_M_RD) {















bit_dbg(3,


&i2c_adap->dev,

































i2c_repstart(adap);















/* okay, now switch into reading mode */















addr |= 0x01;















ret = try_address(i2c_adap,


addr, retries);















if ((ret != 1)


&& !nak_ok)


{



















dev_err(&i2c_adap->dev,



































return -EREMOTEIO;















}











}







}


else {









/* normal 7bit address



*/











addr =


msg->addr << 1;











if (flags &


I2C_M_RD)















addr |= 1;











if (flags


& I2C_M_REV_DIR_ADDR)















addr ^= 1;











ret = try_address(i2c_adap, addr, retries);











if


((ret != 1) && !nak_ok)















return


-ENXIO;







}









return 0;



}




< /p>


这里先做了一个判断,


10


位设备地址和


7


位设备地址分别做


不同的处理,通常 一条


I2C


总线上不会挂那么多


I2C


设备,


所以


10


位地址不常用,直接看对


7


位地址的处理。

< br>struct


i2c_msg



addr


中是真正的设备地址,而这里发送的


addr



7


位才是设备地址,最低位为读写位,如果 为读,最低位



1


,如果为写,最低位 为


0


。所以要将


struct


i2c_msg



addr

< br>向左移


1


位,


如果定义了


I2C_M_RD


标志,


就将


addr


或上


1


,前面就说过 ,这个标志就代表读,


如果是


写,这里就不用处理,因为最低位 本身就是


0


。最后调用


try_add ress


函数将这个地址字节发送出去。


[html] view


plaincopyprint? 1. static int try_address(struct i2c_adapter


*i2c_adap,







2.

















unsigned char addr, int retries)







3. {







4.






struct i2c_algo_bit_data *adap =


i2c_adap->algo_data;







5.






int i, ret = 0;







6.








7.






for (i = 0; i <= retries; i++) {







8.










ret = i2c_outb(i2c_adap, addr);







9.










if (ret == 1 || i == retries)






10.














break;






11.










bit_dbg(3, &i2c_adap->dev,


stop conditionn






12.










i2c_stop(adap);






13.










udelay(adap->udelay);






14.










yield();






15.










bit_dbg(3, &i2c_adap->dev,


start conditionn






16.










i2c_start(adap);






17.






}






18.






if (i && ret)






19.










bit_dbg(1, &i2c_adap->dev,







20.



















21.














addr & 1 ?


addr >> 1,






22.














ret == 1 ?






23.






return ret;






24. }





最主要 的就是调用


i2c_outb


发送一个字节,

< br>retries


为重复次数,看前面


adap-> retries=


3;


如果发送失败,也就是设备没有给出 应答信号,那就发送停


止信号,


发送起始信号,


再发送这个地址字节,


这就叫


retries



来看这个具体的


i2c_outb

< p>
函数


[html] view


plaincopyprint? 1. static int i2c_outb(struct i2c_adapter


*i2c_adap, unsigned char c)







2. {







3.






int i;







4.






int sb;







5.






int ack;







6.






struct i2c_algo_bit_data *adap =


i2c_adap->algo_data;







7.








8.






/* assert: scl is low */







9.






for (i = 7; i >= 0; i--) {






10.










sb = (c >> i) & 1;






11.










setsda(adap, sb);






12.










udelay((adap->udelay + 1) / 2);






13.










if (sclhi(adap) < 0) { /* timed out */






14.














bit_dbg(1, &i2c_adap->dev,







15.























16.














return -ETIMEDOUT;






17.










}






18.










/* FIXME do arbitration here:





19.











* if (sb && !getsda(adap)) ->


ouch! Get out of here.





20.











*





21.











* Report a unique code, so higher level code


can retry





22.











* the whole (combined) message and *NOT*


issue STOP.





23.











*/






24.










scllo(adap);






25.






}






26.






sdahi(adap);






27.






if (sclhi(adap) < 0) { /* timeout */






28.










bit_dbg(1, &i2c_adap->dev,


0x%02x,






29.



















30.










return -ETIMEDOUT;






31.






}






32.







33.






/* read ack: SDA should be pulled down by slave,


or it may





34.







* NAK (usually to report problems with the data


we wrote).





35.







*/






36.






ack = !getsda(adap);





/* ack: sda is pulled low


-> success */






37.






bit_dbg(2, &i2c_adap->dev,


0x%02x %sn






38.










ack ?






39.







40.






scllo(adap);






41.






return ack;






42.






/* assert: scl is low (sda undef) */






43. }







这个函数有两个参数,


一个是


structi2c_adapter


代表


I 2C



机,一个是发送的字节数据。那么


I2C


是怎样将一个字节数


据发送出去的呢,那再来看看协议 。首先是发送字节数据的


最高位,在时钟为高电平期间将一位数据发送出去,最后是


发送字节数据的最低位。


发送完成之后,


我 们需要一个


ACK


信号,


要不然我怎么 知道发送成功没有,


ACK


信号就是在第


九个时钟周期时数据线为低,所以在一个字节数据传送完成


后,还要将数据线拉高,我 们看程序中就是这一句


sdahi(adap);


等待这个


ACK


信号的到来,


这样一个字节数据


就发送完成。



回到


bit_xfer


函数中,


前面只是将设备地址字节发送出去 了,


那么接下来就是该发送数据了。



注意:这里的数据包括操作设备的基地址


如果是读则调用


readbytes


函数去读,如果是写则 调用


sendbytes


去写,先看


r eadbytes


函数


[html] view


plaincopyprint? 1. static int readbytes(struct i2c_adapter


*i2c_adap, struct i2c_msg *msg)







2. {







3.






int inval;







4.






int rdcount = 0;





/* counts bytes read */







5.






unsigned char *temp = msg->buf;







6.






int count = msg->len;







7.






const unsigned flags = msg->flags;







8.








9.






while (count > 0) {






10.










inval = i2c_inb(i2c_adap);






11.










if (inval >= 0) {






12.














*temp = inval;






13.














rdcount++;






14.










} else {




/* read timed out */






15.














break;






16.










}






17.







18.










temp++;






19.










count--;






20.







21.










/* Some SMBus transactions require that we


receive the





22.













transaction length as the first read byte. */






23.










if (rdcount == 1 && (flags &


I2C_M_RECV_LEN)) {






24.














if (inval <= 0 || inval >


I2C_SMBUS_BLOCK_MAX) {






25.


















if (!(flags &


I2C_M_NO_RD_ACK))






26.






















acknak(i2c_adap, 0);






27.


















dev_err(&i2c_adap->dev,







28.



























29.


















return -EREMOTEIO;






30.














}






31.














/* The original count value accounts for


the extra





32.

















bytes, that is, either 1 for a regular


transaction,





33.

















or 2 for a PEC transaction. */






34.














count += inval;






35.














msg->len += inval;






36.










}






37.







38.










bit_dbg(2, &i2c_adap->dev,







39.














inval,






40.














(flags & I2C_M_NO_RD_ACK)






41.


















?






42.


















: (count ?






43.







44.










if (!(flags & I2C_M_NO_RD_ACK)) {






45.














inval = acknak(i2c_adap, count);






46.














if (inval < 0)






47.


















return inval;






48.










}






49.






}






50.






return rdcount;






51. }







其中一个大的


while

< p>
循环,


调用


i2c_inb


去读一个字节,


count


为数据的长度,单位为多少个字节 ,



那就来看


i2c_inb


函数。




static int i2c_inb(struct i2c_adapter *i2c_adap)



{







/*


read byte via i2c port, without start/stop sequence



*/







/* acknowledge is sent in i2c_read.










*/







int i;







unsigned char indata = 0;







struct i2c_algo_bit_data


*adap = i2c_adap->algo_data;









/* assert: scl is


low */







sdahi(adap);







for (i = 0; i < 8; i++)


{











if (sclhi(adap) < 0) { /* timeout */















bit_dbg(1, &i2c_adap->dev,


































return


-ETIMEDOUT;











}











indata *= 2;











if (getsda(adap))















indata |= 0x01;











setscl(adap, 0);











udelay(i == 7 ? adap->udelay


/ 2 : adap->udelay);







}







/* assert: scl is low */







return indata;



}





再来看


sendbytes


函数


[html] view


plaincopyprint? 1. static int sendbytes(struct i2c_adapter


*i2c_adap, struct i2c_msg *msg)







2. {







3.






const unsigned char *temp = msg->buf;







4.






int count = msg->len;







5.






unsigned short nak_ok = msg->flags &


I2C_M_IGNORE_NAK;







6.






int retval;







7.






int wrcount = 0;







8.








9.






while (count > 0) {






10.










retval = i2c_outb(i2c_adap, *temp);






11.







12.










/* OK/ACK; or ignored NAK */






13.










if ((retval > 0) || (nak_ok &&


(retval == 0))) {






14.














count--;






15.














temp++;






16.














wrcount++;






17.







18.










/* A slave NAKing the master means the


slave didn't like





19.











* something about the data it saw.



For


example, maybe





20.











* the SMBus PEC was wrong.





21.











*/






22.










} else if (retval == 0) {






23.














dev_err(&i2c_adap->dev,







24.














return -EIO;






25.







26.










/* Timeout; or (someday) lost arbitration





27.











*





28.











* FIXME Lost ARB implies retrying the


transaction from





29.











* the first message, after the


master issues





30.











* its STOP.



As a rule, upper layer code has


no reason





31.











* to know or care about this ... it is *NOT* an


error.





32.











*/






33.










} else {






34.














dev_err(&i2c_adap->dev,







35.






















retval);






36.














return retval;






37.










}






38.






}






39.






return wrcount;






40. }







也是一个大的


while

< p>
循环,同发送地址字节一样,也是调用


i2c_outb

< br>去发送一个字节,


count


也是数据长度,由于


i2c_outb


函数在前面发送设备地址那里已经介绍了,这里也< /p>

-


-


-


-


-


-


-


-



本文更新与2021-02-08 21:03,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/616966.html

linux gpio模拟i2c的使用用GPIO模拟I2C总线的相关文章