7.1.I2C 基礎知識
I2C(Inter-Integrated Circuit)總線是一種由Philips公司開發(fā)的兩線式串行總線,用于內部IC控制的具有多端控制能力的雙線雙向串行數(shù)據(jù)總線系統(tǒng),能夠用于替代標準的并行總線,連接各種集成 電路和功能模塊。I2C器件能夠減少電路間的連接,減少電路板的尺寸,降低硬件成本并提高系統(tǒng)的可靠性。I2C總線傳輸模式具有向下兼容性,傳輸速率標準模式下可達100kbps,快速模式下可 達400kbps,高速模式下可達3.4Mbps。
為了清楚起見,在此對I2C通信中關于設備的基本概念進行簡要講解。
① 發(fā)送設備:發(fā)送數(shù)據(jù)到總線上的設備。
② 接收設備:從總線上接收數(shù)據(jù)的設備。
③ 主設備:啟動數(shù)據(jù)傳輸并產生時鐘信號的設備。
④ 從設備:被主設備尋址的設備。
多主:多個主設備可以嘗試在不破壞信息的前提下同時控制線。
同步:同步兩個或更多設備之間的時鐘信號的過程。
仲裁:如果超過一個主設備同時試圖控制總線,只有一個主設備被允許,且獲勝主設備的信息不被破壞。
(1)I2C設備連接原理 I2C設備連接示意圖如設備連接示意圖所示。I2C總線是由數(shù)據(jù)線SDA和時鐘線SCL構成的串行總線,可發(fā)送和接收數(shù)據(jù)。在GD32 MCU與被控IC(集成電路)之間、IC與IC之間進行雙向傳送,最高傳送速率1Mbps。各種設備均并聯(lián)在總線上,兩條總線都被上拉電阻上拉到VCC,所有設備地位對等,都可作為主機或從機,就像電話機一樣只要撥通各自的號碼就能正常工作,所以,每個設備都有唯一的地址。在信息的傳輸過程中,I2C總線上并接的每個設備既是主設備(或從設備),又是發(fā)送設備(或接收設備),這取決于它所要完成的功能。每個設備都可以把總線接地拉低,卻不允許把總線電平直接連到VCC上置高。把總線電平拉低稱為占用總線,總線電平為高等待被拉低則稱為總線被釋放。
I2C 設備連接示意圖
由于SDA和SCL均為雙向I/O線,都是開漏極端(輸出1時,為高阻狀態(tài)),因此I2C總線上的所有設備的SDA和SCL引腳都要外接上拉電阻。
(2)I2C數(shù)據(jù)通信協(xié)議
I2C數(shù)據(jù)通信時序圖如I2C數(shù)據(jù)通信時序圖所示。下面首先介紹起始位和停止位,起始位和停止位都是由主設備產生的,如圖中虛線所示。當SCL時鐘線為高電平時,SDA數(shù)據(jù)線上由高到低的跳變,產生一個開始信號,即起始位。當SCL時鐘線為高電平時,SDA數(shù)據(jù)線上由低到高的跳變,將產生一個停止信號,即停止位。起始位之后,總線被認為忙,即有數(shù)據(jù)在傳輸,傳輸?shù)牡谝粋€字節(jié),即7位從地址和R/ ̄W 位。當R/ ̄W位為0時,主機向從機發(fā)送數(shù)據(jù);當R/ ̄W位為1時,主機接收來自從機的數(shù)據(jù)。在每個字節(jié)后的第九個SCL時鐘上,接收機發(fā)送ACK位。停止位之后,總線被認為閑,空閑狀態(tài)時,SDA和SCL都是高電平。
注意:當SCL位為高電平時,SDA的數(shù)據(jù)必須保持穩(wěn)定,否則,由于起始位和停止位的電氣邊沿特性,SDA上數(shù)據(jù)發(fā)生改變將被識別為起始位或停止位。所以,只有當SCL為低電平時才允許SDA上的數(shù)據(jù)改變。
I2C 數(shù)據(jù)通信時序圖
I2C總線上每位數(shù)據(jù)傳輸?shù)氖疽鈭D
(3)I2C的尋址方式 GD32 MCU的I2C模塊支持7位和10位兩種尋址模式,7位尋址模式最多尋址128個設備,10位尋址模式最多尋址1024個設備。I2C總線理論上可以允許的最大設備數(shù)是以總線上所有器件的電容總和不超過400pF為限(其中,包括連線本身的電容和其連接端的引出等效電容),總線上所有器件要依靠SDA發(fā)送的地址信號尋址,不需要片選信號。
① 7位尋址模式
如圖下圖所示為7位地址方式下的I2C數(shù)據(jù)傳輸格式,第一個字節(jié)由7位從地址和R/ ̄W讀/寫位組成。不論總線上傳送的是地址還是數(shù)據(jù)信息,每個字節(jié)傳輸完畢,接收設備都會發(fā)送響應位(ACK)。地址類信息傳輸之后是數(shù)據(jù)信息,直到接收到停止信息。
7 位尋址模式數(shù)據(jù)格式
② 10位尋址模式
如下圖所示為10位地址方式下的I2C數(shù)據(jù)傳輸格式。第一個字節(jié)由二進制位11110、從地址的最高兩位及R/ ̄W讀/寫控制位組成。第一個字節(jié)傳輸完畢后是ACK響應位。第二個字節(jié)就是10位從地址的低8位,后面是響應位和數(shù)據(jù)。
10 位尋址模式數(shù)據(jù)格式
③ 二次發(fā)送從地址模式(重復產生起始條件)
主機可以在不停止數(shù)據(jù)傳輸?shù)那闆r下,通過產生重復的起始條件,改變SDA上數(shù)據(jù)流的方向,這稱為RESTART。再次發(fā)送起始信號后,需重新發(fā)送從地址和R/ ̄W讀/寫控制位。重新產生起始條件數(shù)據(jù)傳輸格式如圖所示。
7.2.GD32 I2C 外設原理簡介
因篇幅有限,本文無法詳細介紹GD32所有系列I2C外設接口,下面以GD32F30x為列,著重介紹下GD32F30x的I2C外設簡介和結構框圖,后介紹下各個系列的差異。
GD32 I2C 主要特性
GD32F30X系列I2C 接口模塊實現(xiàn)了 I2C 協(xié)議的標速模式,快速模式以及快速+ 模式,具備CRC 計算和校驗功能、支持 SMBus(系統(tǒng)管理總線) 和 PMBus(電源管理總線),此外還支持多主機 I2C 總線架構。 I2C 接口模塊也支持 DMA 模式,可有效減輕 CPU 的負擔。
GD32 MCU I2C模塊主要特性描述如下:
? 并行總線至 I2C 總線協(xié)議的轉換及接口;
? 同一接口既可實現(xiàn)主機功能又可實現(xiàn)從機功能;
? 主從機之間的雙向數(shù)據(jù)傳輸;
? 支持 7 位和 10 位的地址模式和廣播尋址;
? 支持 I2C 多主機模式;
? 支持標速(最高 100 KHz),快速(最高 400 KHz) 和快速+ 模式(最高 1MHz);
? 從機模式下可配置的 SCL 主動拉低;
? 支持 DMA 模式;
? 兼容 SMBus 2.0 和 PMBus;
? 兩個中斷:字節(jié)成功發(fā)送中斷和錯誤事件中斷;
? 可選擇的 PEC(報文錯誤校驗) 生成和校驗;
I2C 結構框圖介紹
I2C內部結構框圖如下圖所示,該結構框圖可分為五個部分:
1、用于產生I2C通信時序;
2、用于收發(fā)I2C數(shù)據(jù),當有數(shù)據(jù)需要發(fā)送時,會首先將數(shù)據(jù)填充到數(shù)據(jù)寄存器,然后數(shù)據(jù)被自動移位到移位寄存器,通過SDA引腳發(fā)送出去,當有數(shù)據(jù)需要接受時,首先會根據(jù)SCL選擇的時鐘邊沿在移位寄存器中鎖存SDA數(shù)據(jù),當數(shù)據(jù)接受到后,數(shù)據(jù)被移到數(shù)據(jù)緩沖寄存器,并置位接受緩沖區(qū)非空標志;
3、用于收發(fā)數(shù)據(jù)CRC計算;
4、用于I2C模塊控制及相關標志位查詢;
5、系統(tǒng)通過APB總線對I2C數(shù)據(jù)寄存器及控制寄存器進行操作。
各系列 I2C 功能差異
GD32各系列MCU有關IIC功能差異如各系列I2C功能差異表所示。
7.3.硬件連接說明
如AT24C02C EEPROM IIC接口參考電路圖所示,AT24C02C為IIC接口的EEPROM,該電路圖為其典型參考電路,其中5腳為I2C SDA引腳,6腳為I2C SCL引腳,I2C總線需要通過4.7K歐姆電阻上拉。
7.4.軟件配置說明
本小節(jié)講解I2C_Example下的I2C0主機歷程,本例程講解IIC作為主機情況下對從機的讀寫,并引入超時恢復機制。
IIC 初始化配置
IIC初始化配置代碼如代碼清單I2C初始化配置所示,首先進行GPIO初始化,然后對IIC外設進行初始化。注意本例程僅講解IIC0的外設引腳及模塊初始化,若其他IIC模塊可參考修改。
void I2C_init(uint32_t I2Cx) { GPIO_Configuration_I2C(I2Cx); i2c_clock_config(I2Cx, 400000, I2C_DTCY_2); /* I2C address configure */ i2c_mode_addr_config(I2Cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0); /* enable acknowledge */ i2c_ack_config(I2Cx, I2C_ACK_DISABLE); /* enable I2Cx */ i2c_enable(I2Cx); }
時鐘及 GPIO 引腳配置
時鐘及GPIO引腳配置如代碼清單I2C時鐘及GPIO引腳配置所示,在例程中PB6、PB7引腳需要配置為復用開漏模式。
void GPIO_Configuration_I2C(uint32_t I2Cx) { uint32_t GPIO_SDA; uint32_t GPIO_SCL; uint32_t GPIO_Pin_SDA,GPIO_Pin_SCL; rcu_periph_reset_enable(RCU_I2C0RST); rcu_periph_reset_disable(RCU_I2C0RST); #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X /* enable GPIOB clock */ rcu_periph_clock_enable(RCU_GPIOB); /* enable I2C0 clock */ rcu_periph_clock_enable(RCU_I2C0); #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X rcu_periph_clock_enable(RCU_AF); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X #endif GPIO_SCL=GPIOB; GPIO_Pin_SCL=GPIO_PIN_6; GPIO_SDA=GPIOB; GPIO_Pin_SDA=GPIO_PIN_7; #endif /* Reset I2C1 IP */ // I2C_DeInit(I2Cx); #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X /* I2C0 GPIO ports */ /* connect PB6 to I2C0_SCL */ gpio_init(GPIO_SCL, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SCL); /* connect PB7 to I2C0_SDA */ gpio_init(GPIO_SDA, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SDA); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X #if defined GD32F1X0 || GD32F3X0 || GD32E23X /* I2C GPIO ports */ /* connect I2C_SCL_GPIO_PIN to I2C_SCL */ gpio_af_set(GPIO_SCL, GPIO_AF_1, GPIO_Pin_SCL); /* connect I2C_SDA_GPIO_PIN to I2C_SDA */ gpio_af_set(GPIO_SDA, GPIO_AF_1, GPIO_Pin_SDA); #elif defined GD32F4XX gpio_af_set(GPIO_SCL, GPIO_AF_4, GPIO_Pin_SCL); gpio_af_set(GPIO_SDA, GPIO_AF_4, GPIO_Pin_SDA); #endif gpio_mode_set(GPIO_SCL, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_Pin_SCL); gpio_output_options_set(GPIO_SCL, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SCL); gpio_mode_set(GPIO_SDA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_Pin_SDA); gpio_output_options_set(GPIO_SDA, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SDA); #endif }
I2C 多字節(jié)寫操作
I2C多字節(jié)寫操作如代碼清單IIC寫多字節(jié)操作所示,該函數(shù)接口實現(xiàn)IIC外設對IIC從機的多字節(jié)寫操作。
/*! \brief I2Cx Write NBytes \param[in] i2c_periph : I2Cx(x=0,1) \param[in] addr : slave address \param[in] start_Addr : reg \param[in] number_Bytes: number to Write \param[in] ADDR_Length : number of the addr */ I2C_Status I2Cx_Write_NBytes(uint32_t I2Cx,uint8_t driver_Addr, uint16_t start_Addr, uint8_t number_Bytes, uint8_t *write_Buffer,uint8_t ADDR_Length) { uint32_t I2C_Timeout = I2C_SHORT_TIMEOUT; i2c_ack_config(I2Cx,I2C_ACK_ENABLE); while(i2c_flag_get(I2Cx, I2C_FLAG_I2CBSY)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_start_on_bus(I2Cx); I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_SBSEND)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_master_addressing(I2Cx, driver_Addr, I2C_TRANSMITTER); I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_ADDSEND)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_flag_clear(I2Cx,I2C_FLAG_ADDSEND); I2C_Timeout = I2C_SHORT_TIMEOUT; while(SET != i2c_flag_get( I2Cx , I2C_FLAG_TBE )) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_enable(I2Cx); if(ADDR_Length)//á?×??úμ??· { i2c_data_transmit(I2Cx, (uint8_t)((start_Addr & 0xFF00) >> 8)); I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_data_transmit(I2Cx, (uint8_t)(start_Addr & 0x00FF)); } else { i2c_data_transmit(I2Cx, start_Addr); } I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } while(number_Bytes) { i2c_data_transmit(I2Cx, *write_Buffer); I2C_Timeout = I2C_SHORT_TIMEOUT; //while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))//5 // while(!i2c_flag_get(I2Cx, I2C_BTC))// while(!i2c_flag_get(I2Cx, I2C_FLAG_TBE)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } /* point to the next location where the byte read will be saved */ write_Buffer++; /* decrement the read bytes counter */ number_Bytes--; } // while(!i2c_flag_get(I2C1, I2C_BTC)) // { // if((I2C_Timeout--) == 0) // { // Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); // return I2C_FAIL; // } // } /* send a stop condition to I2C bus */ i2c_stop_on_bus(I2Cx); I2C_Timeout = I2C_SHORT_TIMEOUT; while (I2C_CTL0(I2Cx) & 0x0200) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_ack_config(I2Cx,I2C_ACK_ENABLE); return I2C_OK; }
IIC 多字節(jié)讀操作
IIC多字節(jié)讀操作如代碼清單IIC多字節(jié)讀操作所示,該函數(shù)接口可實現(xiàn)對IIC從機的多字節(jié)讀功能。
I2C_Status I2Cx_Read_NBytes(uint32_t I2Cx,uint8_t driver_Addr, uint16_t start_Addr, uint8_t number_Bytes, uint8_t *read_Buffer,uint8_t ADDR_Length) { uint32_t I2C_Timeout = I2C_SHORT_TIMEOUT; i2c_ack_config(I2Cx,I2C_ACK_ENABLE); while(i2c_flag_get(I2Cx, I2C_FLAG_I2CBSY)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } if(number_Bytes==2) { i2c_ackpos_config(I2Cx,I2C_ACKPOS_NEXT); } i2c_start_on_bus(I2Cx); I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_SBSEND)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_master_addressing(I2Cx, driver_Addr, I2C_TRANSMITTER); I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_ADDSEND)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } /* clear the ADDSEND bit */ i2c_flag_clear(I2Cx,I2C_FLAG_ADDSEND); I2C_Timeout = I2C_SHORT_TIMEOUT; while(SET != i2c_flag_get( I2Cx , I2C_FLAG_TBE )) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_enable(I2Cx); if(ADDR_Length)//á?×??úμ??· { i2c_data_transmit(I2Cx, (uint8_t)((start_Addr & 0xFF00) >> 8)); I2C_Timeout = I2C_SHORT_TIMEOUT; //while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING)) while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_data_transmit(I2Cx, (uint8_t)(start_Addr & 0x00FF)); } else { i2c_data_transmit(I2Cx, start_Addr); } I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_start_on_bus(I2Cx); I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_SBSEND)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_master_addressing(I2Cx, driver_Addr, I2C_RECEIVER); I2C_Timeout = I2C_SHORT_TIMEOUT; if(number_Bytes<3) { i2c_ack_config(I2Cx,I2C_ACK_DISABLE); } while(!i2c_flag_get(I2Cx, I2C_FLAG_ADDSEND)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } /* clear the ADDSEND bit */ i2c_flag_clear(I2Cx,I2C_FLAG_ADDSEND); if(number_Bytes==1) { i2c_stop_on_bus(I2Cx); } while(number_Bytes) { if(3 == number_Bytes){ /* wait until BTC bit is set */ I2C_Timeout = I2C_LONG_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } /* disable acknowledge */ /* disable acknowledge */ i2c_ack_config(I2Cx,I2C_ACK_DISABLE); } if(2 == number_Bytes){ /* wait until BTC bit is set */ I2C_Timeout = I2C_LONG_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } /* send a stop condition to I2C bus */ i2c_stop_on_bus(I2Cx); I2C_Timeout = I2C_SHORT_TIMEOUT; while (I2C_CTL0(I2Cx) & 0x0200) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } } /* wait until the RBNE bit is set and clear it */ if(i2c_flag_get(I2Cx, I2C_FLAG_RBNE)){ /* read a byte from the EEPROM */ *read_Buffer = i2c_data_receive(I2Cx); /* point to the next location where the byte read will be saved */ read_Buffer++; /* decrement the read bytes counter */ number_Bytes--; } } while(I2C_CTL0(I2Cx)&0x0200) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } /* enable acknowledge */ i2c_ack_config(I2Cx,I2C_ACK_ENABLE); i2c_ackpos_config(I2Cx,I2C_ACKPOS_CURRENT); return I2C_OK; }
IIC 超時恢復機制
IIC超時恢復機制實現(xiàn)如代碼清單IIC超時恢復機制所示。
uint32_t I2C_Timeout; void Delay_I2C(uint32_t i) { while(i--); } void Resume_IIC(uint32_t Timeout,uint32_t I2Cx ) { uint32_t GPIO_SDA; uint32_t GPIO_SCL; uint32_t GPIO_Pin_SDA,GPIO_Pin_SCL; #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X /* enable GPIOB clock */ rcu_periph_clock_enable(RCU_GPIOB); /* enable I2C0 clock */ rcu_periph_clock_enable(RCU_I2C0); #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X rcu_periph_clock_enable(RCU_AF); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X #endif #endif GPIO_SCL=GPIOB; GPIO_Pin_SCL=GPIO_PIN_6; GPIO_SDA=GPIOB; GPIO_Pin_SDA=GPIO_PIN_7; do{ #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X /* I2C0 GPIO ports */ /* connect PB6 to I2C0_SCL */ gpio_init(GPIO_SCL, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SCL); /* connect PB7 to I2C0_SDA */ gpio_init(GPIO_SDA, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SDA); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X #if defined GD32F1X0 || GD32F3X0 || GD32E23X /* I2C GPIO ports */ /* connect I2C_SCL_GPIO_PIN to I2C_SCL */ gpio_af_set(GPIO_SCL, GPIO_AF_1, GPIO_Pin_SCL); /* connect I2C_SDA_GPIO_PIN to I2C_SDA */ gpio_af_set(GPIO_SDA, GPIO_AF_1, GPIO_Pin_SDA); #elif defined GD32F4XX gpio_af_set(GPIO_SCL, GPIO_AF_4, GPIO_Pin_SCL); gpio_af_set(GPIO_SDA, GPIO_AF_4, GPIO_Pin_SDA); #endif gpio_mode_set(GPIO_SCL, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_Pin_SCL); gpio_output_options_set(GPIO_SCL, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SCL); gpio_mode_set(GPIO_SDA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_Pin_SDA); gpio_output_options_set(GPIO_SDA, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SDA); #endif gpio_bit_reset(GPIO_SCL, GPIO_Pin_SCL); Delay_I2C(20); gpio_bit_reset(GPIO_SDA, GPIO_Pin_SDA); Delay_I2C(20); gpio_bit_set(GPIO_SCL, GPIO_Pin_SCL); Delay_I2C(20); gpio_bit_set(GPIO_SDA, GPIO_Pin_SDA); Delay_I2C(20); if(Timeout-- == 0) return; }while((!gpio_input_bit_get(GPIO_SDA, GPIO_Pin_SDA))&(!gpio_input_bit_get(GPIO_SCL, GPIO_Pin_SCL))); I2C_init(I2Cx); }
主函數(shù)說明
本例程主函數(shù)如代碼清單I2C例程主函數(shù)所示。
int main(void) { I2C_init(I2C0); I2Cx_Write_NBytes(I2C0,0xA0, 0,8, Write_Buf,0); I2Cx_Read_NBytes(I2C0,0xA0, 0,8, Read_Buf,0); while (1) { }
7.5.I2C 使用注意事項
1、I2C總線需要上拉;
2、I2C引腳需要配置為復用開漏模式;
3、若采用查詢方式進行I2C數(shù)據(jù)傳輸,有可能會由于總線干擾,導致I2C卡死,可以在查詢方式上增加超時機制,如果超時重配IIC恢復總線通信(注意重配IIC時,建議先將I2C模塊Deinit,然后 在調用Init函數(shù)進行初始化)。
4、若采用軟件模擬IIC的方式,在移植過程中出現(xiàn)問題,可能是由于代碼執(zhí)行效率的問題,可以排查軟件延遲時間和其他芯片上的軟件延遲時間是否相同,可以通過調整軟件延遲時間進行測試;或者有可能是由于初始化配置IO端口的時候可能會引入干擾,可以先配置IO口輸出高,然后再配置為推挽或開漏模式。
本教程由GD32 MCU方案商聚沃科技原創(chuàng)發(fā)布,了解更多GD32 MCU教程,關注聚沃科技官網
-
單片機
+關注
關注
6035文章
44554瀏覽量
634590 -
mcu
+關注
關注
146文章
17123瀏覽量
350973 -
嵌入式
+關注
關注
5082文章
19104瀏覽量
304780 -
I2C
+關注
關注
28文章
1484瀏覽量
123616 -
GD32
+關注
關注
7文章
403瀏覽量
24326
發(fā)布評論請先 登錄
相關推薦
評論