linux下的I2c 和展锐8310下的I2c
I2C物理層
它是一個支持設(shè)備的總線。“總線”指多個設(shè)備共用的信號線。在一個I2C通訊總線中,可連接多個I2C通訊設(shè)備,支持多個通訊主機(jī)及多個通訊從機(jī)。
·一個I2C總線只使用兩條總線線路,一條雙向串行數(shù)據(jù)線(SDA),一條串行時鐘線(SCL)。數(shù)據(jù)線即用來表示數(shù)據(jù),時鐘線用于數(shù)據(jù)收發(fā)同步。
·每個連接到總線的設(shè)備都有一個獨(dú)立的地址,主機(jī)可以利用這個地址進(jìn)行不同設(shè)備之間的訪問。
·總線通過上拉電阻接到電源。當(dāng)I2C設(shè)備空閑時,會輸出高阻態(tài),而當(dāng)所有設(shè)備都空閑,都輸出高阻態(tài)時,由上拉電阻把總線拉成高電平。
·多個主機(jī)同時使用總線時,為了防止數(shù)據(jù)沖突,會利用仲裁方式?jīng)Q定由哪個設(shè)備占用總線。
·具有三種傳輸模式:標(biāo)準(zhǔn)模式傳輸速率為100kbit/s,快速模式為400kbit/s,高速模下可達(dá)3.4Mbit/s,但目前大多I2C設(shè)備尚不支持高速模式。
I2C協(xié)議層
以主機(jī)向從機(jī)寫數(shù)據(jù)為例,其基本結(jié)構(gòu)如圖所示,依次為:
起始信號——從機(jī)地址——讀寫信號——數(shù)據(jù)位——應(yīng)答位——… … ——停止位
?
起始信號(S):當(dāng) SCL 線是高電平時,SDA 線從高電平向低電平切換;停止信號(P):當(dāng) SCL 是高電平時,SDA 線由低電平向高電平切換。
?
?
應(yīng)答信號
I2C最大的一個特點(diǎn)就是有完善的應(yīng)答機(jī)制,從機(jī)接收到主機(jī)的數(shù)據(jù)時,會回復(fù)一個應(yīng)答信號來通知主機(jī)表示“我收到了”。
應(yīng)答信號出現(xiàn)在1個字節(jié)傳輸完成之后,即第9個SCL時鐘周期內(nèi),此時主機(jī)需要釋放SDA總線,把總線控制權(quán)交給從機(jī),由于上拉電阻的作用,此時總線為高電平,如果從機(jī)正確的收到了主機(jī)發(fā)來的數(shù)據(jù),會把SDA拉低,表示應(yīng)答響應(yīng)。
非應(yīng)答信號
當(dāng)?shù)?個SCL時鐘周期時,SDA保持高電平,表示非應(yīng)答信號。
幀地址:I2C總線上的每個設(shè)備都有自己的獨(dú)立地址,主機(jī)發(fā)起通訊時,通過SDA信號線發(fā)送設(shè)備地址(SLAVE_ADDRESS)來查找從機(jī)。I2C協(xié)議規(guī)定設(shè)備地址可以是7位或10位,實(shí)際中7位的地址應(yīng)用比較廣泛。
I2C使用SDA信號線來傳輸數(shù)據(jù),使用SCL信號線進(jìn)行數(shù)據(jù)同步。SDA數(shù)據(jù)線在SCL的每個時鐘周期傳輸一位數(shù)據(jù)。傳輸時,SCL為高電平的時候SDA表示的數(shù)據(jù)有效,即此時的SDA為高電平時表示數(shù)據(jù)“1”,為低電平時表示數(shù)據(jù)“0”。當(dāng)SCL為低電平時,SDA的數(shù)據(jù)無效,一般在這個時候SDA進(jìn)行電平切換,為下一次表示數(shù)據(jù)做好準(zhǔn)備。
I2C的數(shù)據(jù)和地址傳輸都帶響應(yīng)。響應(yīng)包括“應(yīng)答(ACK)”和“非應(yīng)答(NACK)”兩種信號。
作為數(shù)據(jù)接收端時,當(dāng)設(shè)備(無論主從機(jī))接收到I2C傳輸?shù)囊粋€字節(jié)數(shù)據(jù)或地址后,若希望對方繼續(xù)發(fā)送數(shù)據(jù),則需要向?qū)Ψ桨l(fā)送“應(yīng)答(ACK)”信號,發(fā)送方會繼續(xù)發(fā)送下一個數(shù)據(jù);若接收端希望結(jié)束數(shù)據(jù)傳輸,則向?qū)Ψ桨l(fā)送“非應(yīng)答(NACK)”信號,發(fā)送方接收到該信號后會產(chǎn)生一個停止信號,結(jié)束信號傳輸。
?
?Linux代碼
int linux_common_i2c_write(struct i2c_client *client, uint8_t *reg_addr, uint8_t *txbuf, int count) {int ret = -1;int ii = 0;uint8_t buf[MAX_XFER_SIZE + 1] = {0};struct i2c_msg msg[1];if(count > HX9031A_MAX_XFER_SIZE) {count = HX9031A_MAX_XFER_SIZE;PRINT_ERR("block write over size!!!\n");}buf[0] = *reg_addr;memcpy(buf + 1, txbuf, count);msg[0].addr = client->addr; //要寫的寄存器地址和數(shù)據(jù)msg[0].flags = 0;//write //讀寫操作,讀為1 寫為0msg[0].len = count + 1; // 要讀的字節(jié)數(shù)msg[0].buf = buf; //數(shù)據(jù)存放的地址ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));if (ARRAY_SIZE(msg) != ret) {PRINT_ERR("linux_common_i2c_write failed. ret=%d\n", ret);ret = -1;for(ii = 0; ii < msg[0].len; ii++) {PRINT_ERR("msg[0].addr=0x%04X, msg[0].flags=0x%04X, msg[0].len=0x%04X, msg[0].buf[%02d]=0x%02X\n",msg[0].addr,msg[0].flags,msg[0].len,ii,msg[0].buf[ii]);}} else {ret = 0;}return ret; }lin linux_common_i2c_read(struct i2c_client *client, uint8_t *reg_addr, uint8_t *rxbuf, int count) {int ret = -1;int ii = 0;struct i2c_msg msg[2];if(count > MAX_XFER_SIZE) {count = MAX_XFER_SIZE;PRINT_ERR("block read over size!!!\n");}//先寫需要讀的寄存器地址msg[0].addr = client->addr; //要讀的寄存器地址msg[0].flags = 0;//write //讀寫操作,讀為1 寫為0msg[0].len = 1;msg[0].buf = reg_addr;//再讀數(shù)據(jù)msg[1].addr = client->addr;msg[1].flags = I2C_M_RD;//readmsg[1].len = count;msg[1].buf = rxbuf;ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));if (ARRAY_SIZE(msg) != ret) {PRINT_ERR("linux_common_i2c_read failed. ret=%d\n", ret);ret = -1;PRINT_ERR("msg[0].addr=0x%04X, msg[0].flags=0x%04X, msg[0].len=0x%04X, msg[0].buf[0]=0x%02X\n",msg[0].addr,msg[0].flags,msg[0].len,msg[0].buf[0]);if(msg[1].len >= 1) {for(ii = 0; ii < msg[1].len; ii++) {PRINT_ERR("msg[1].addr=0x%04X, msg[1].flags=0x%04X, msg[1].len=0x%04X, msg[1].buf[%02d]=0x%02X\n",msg[1].addr,msg[1].flags,msg[1].len,ii,msg[1].buf[ii]);}}} else {ret = 0;}return ret; }8310代碼
struct i2c_msg {uint16 addr;/* slave address */uint16 flags;#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */#define I2C_M_RD 0x0001 /* read data, from slave to master */#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */uint16 len; /* msg length */uint8 *buf; /* pointer to msg data */ }; struct SPRD_I2C sprd_i2c[I2C_DEVICE_MAX] = {{/*i2c0*/CTL_I2C0_BASE,400000,0,12,1,TB_I2C0_INT,REG_AP_CLK_CORE_CGM_I2C0_CFG,I2C_26M,REG_AP_APB_APB_EB,BIT_AP_APB_I2C0_EB,REG_AP_APB_APB_RST,BIT_AP_APB_I2C0_SOFT_RST,1,DMA_I2C0_TX,DMA_I2C0_RX,},{/*i2c1*/CTL_I2C1_BASE,100000,1,12,1,TB_I2C1_INT,REG_AP_CLK_CORE_CGM_I2C1_CFG,I2C_26M,REG_AP_APB_APB_EB,BIT_AP_APB_I2C1_EB,REG_AP_APB_APB_RST,BIT_AP_APB_I2C1_SOFT_RST,0, //DMA使能位打開可能會影響讀的正確性DMA_I2C1_TX,DMA_I2C1_RX,},{/*i2c2*/CTL_I2C2_BASE,400000,1,12,1,TB_I2C2_INT,REG_AP_CLK_CORE_CGM_I2C2_CFG,I2C_26M,REG_AP_APB_APB_EB,BIT_AP_APB_I2C2_EB,REG_AP_APB_APB_RST,BIT_AP_APB_I2C2_SOFT_RST,1,DMA_I2C2_TX,DMA_I2C2_RX,},}; int i2c_write(uint8_t addr, uint8_t *txbuf, int count) {int ret = -1, transfer = -1, config_msg = -1, close = -1;uint8_t buf[32 + 1] = {0};buf[0] = addr;memcpy(buf + 1, txbuf, count);struct i2c_client MEIG_IIC;MEIG_IIC.index = 1;struct i2c_msg msgs[2];ret = I2C_Open(&MEIG_IIC);if(ret == -1){return -1;}MG_LOGD( "mg_i2c_write ret =%d", ret );msgs[0].buf = buf; //寄存器地址加要寫的數(shù)據(jù)msgs[0].len = count + 1 ;msgs[0].flags = 0; //讀寫為似乎不起作用msgs[0].addr = 0x50; //寄存器地址左移一位,最后一位為讀寫位 寄存器地址為0x28 即00101000 左移一位最后一位為讀寫位 即01010000transfer = i2c_transfer((uint32)MEIG_IIC.i2c, msgs, 1);MG_LOGD( "mg_i2c_write transfer =%d", transfer );close = I2C_Close((uint32)(&MEIG_IIC));if(close == -1){return -1;}MG_LOGD( "mg_i2c_write close =%d", close );return 0; };int i2c_read(uint8_t addr, uint8_t *rxbuf, int count) {int ret = -1, transfer = -1, config_msg = -1, close = -1;struct i2c_client MEIG_IIC;MEIG_IIC.index = 1; //i2c設(shè)備struct i2c_msg msgs[2];ret = I2C_Open(&MEIG_IIC);if(ret == -1){return -1;}MG_LOGD( "mg_i2c_read ret =%d", ret );msgs[0].buf = &addr;msgs[0].len = 1; //讀寫為似乎不起作用msgs[0].flags = 0;msgs[0].addr = 0x50; //寄存器地址左移一位,最后一位為讀寫位 寄存器地址為0x28 即00101000 左移一位最后一位為讀寫位 即01010000msgs[1].buf = rxbuf; msgs[1].len = count;msgs[1].flags = I2C_M_RD; //讀寫為似乎不起作用msgs[1].addr = 0x51; //寄存器地址左移一位,最后一位為讀寫位 寄存器地址為0x28 即00101000 左移一位最后一位為讀寫位 即01010001transfer = i2c_transfer((uint32)MEIG_IIC.i2c, msgs ,2);uint8_t reg_value = *(msgs[1].buf);MG_LOGD( "mg_i2c_read transfer =%d ,reg_value = %x", transfer ,rxbuf[0] );close = I2C_Close((uint32)(&MEIG_IIC));if(close == -1){return -1;}MG_LOGD( "mg_i2c_read close =%d", close );return 0; };總結(jié)
以上是生活随笔為你收集整理的linux下的I2c 和展锐8310下的I2c的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C/C++智能指针
- 下一篇: android 点对点 通信,将 WLA