I2C是一種多主從的串行通訊協議。STM32F1的I2C模塊支持標速(最高100kHz)和高速(最高400kHz)兩種工作模式。
一、I2C協議簡介
標準的IIC接口有數據線SDA、時鐘線SCL兩條總線,只能工作于半雙工模式,在設計中,對總線的負載電容有一定的要求,具體請查閱元件的技術手冊確定。
IIC的通訊時序如圖,通訊電平為正邏輯:
※數據發送的起始和終止信號為:SCL為高時,
起始:SDA下降沿 終止:SDA上升沿
※當總線空閑時,SDA和SCL均為高電平,總線需要外接上拉電阻,阻值5-10k。
※每次發送一字節(8bits)信號,MSB高位先發。
二、I2C通訊時序(使用時以具體被控芯片手冊為準)
通訊時序(主機發送若干數據):
※主機引腳配置為open Drain,務必不要內部上拉、下拉
***①保持SCL=1,拉低SDA,產生起始信號。
***②拉低SCL,準備發送數據;
***③將數據高位Shift Out(SDA上),隨后拉高SCL。在SCL=1期間SDA電平不能變動。
***④將數據依次輸出
***⑤輸出最后一位數據且SCL變為低電平后,主機接SDA引腳立即變換為高阻輸入模式。
⑥主機向SCL輸出一個時鐘方波,在方波高位檢測從機是否將SDA拉低(即發送ACK);若未收到表明發送未成功。
***⑦當主機檢測到SDA被拉低時,表明從機準備好接收下一字節數據。隨后主機拉高SCL,從機釋放SDA,形成終止信號。若錯誤,主機也拉高SCL并記錄錯誤。此時SCL=1,SDA=1。***
⑧準備下一次傳輸。
通訊時序(從機接收若干數據):
①從機引腳均配置為輸入模式
***②檢測開始信號,隨后接收數據(可以通過SCL上升、下降沿觸發方式檢測校驗)
③若接收沒有出現錯誤,從機將SDA配置為開漏,在定義的數據長度(數據位+1ACK)的前一個時鐘方波之后(時鐘下降沿)拉低SDA發出ACK。若接受錯誤(例如一個時鐘信號上升下降沿SDA數據不同)則不下拉。
④檢測到SCL出現上升后,釋放SDA。
⑤準備下一次傳輸。
※IIC數據以1個數據包(主機)+1位ACK(從機)格式傳送:
發送地址的最后一位是數據方向位(R/W位),該位用“0”表示主機發送數據,“1”表示主機接收數據(R)。
※當STM32做主機時,在發送地址位后(10位地址模式為首序列最后一位)會根據方向位自動判斷進入主發送器模式或主接收器模式**。**
三、STM32 LL庫IIC驅動
STM32的I2C模塊可以配置為從機輸出、從機輸入、主機輸出、主機輸入四種模式。
■主模式時,I2C接口啟動數據傳輸并產生時鐘信號。串行數據傳輸總是以起始條件開始并以停止條件結束。起始條件和停止條件都是在主模式下由軟件控制產生。
■從模式時,I2C接口能識別它自己的地址(7位或10位)和廣播呼叫地址。軟件能夠控制開啟或禁止廣播呼叫地址的識別。
※ SCL時鐘信號、起始終止信號由主機輸出 , 應答始終由從機應答 ;從機由主機發送地址選中(主機和從機的區別)。
1.IIC時鐘配置:
在I2C_CR2寄存器中Freq[5:0]設定該模塊的輸入時鐘( APH1旁路時鐘輸入,最高36MHz )。輸入時鐘的頻率至少為:
● 標準模式下為:2MHz ● 快速模式下為:4MHz
若使用CubeMX進行模塊的配置,則生成的模塊初始化函數中自動設置
2.相關寄存器
①自身地址寄存器(I2C_OAR1):
STM32的IIC模塊支持雙地址模式,即 可以設置兩個自身地址 :
自身地址寄存器2(I2C_OAR2):
*②時鐘控制寄存器(I2C_CCR): * (CubeMX自動配置)
在I2C_CR2中設置完成模塊輸入時鐘后對SCL輸出時鐘進行配置
③控制寄存器(I2C_CR1)
④控制寄存器(I2C_CR2)
⑤數據寄存器(I2C_DR)
⑥狀態寄存器(I2C_SR1)
PEC校驗的使用較為復雜,使用時請具體參看手冊
對包序號的判斷(第幾個包?)從起始條件開始計算。
⑦狀態寄存器(I2C_SR2)
3.傳輸時序(請參考傳輸時序進行開發)
** ①主發送器模式**
※7位地址最后一位為R/W位,10位幀頭最后一位為R/W,此時設置為"0",由本機發送
** ②主接收器模式(主模式下起始、終止條件都由本機發出)**
※7位地址最后一位為R/W位,10位幀頭最后一位為R/W,此時設置為"1",由本機發送
** ③從接收器模式**
※地址R/W位非本機發送,由硬件自動比對本機地址判斷是否被選中。此時R/W位為"0"
** ④從發送器模式**
※地址R/W位非本機發送,由硬件自動比對本機地址判斷是否被選中。此時R/W位為"0"
關于主從模式:
*** ■模塊默認處于從模式***
*** ■當本機通過START位主動發送起始條件時,進入主模式***
*** ■當主模式最后一字節傳輸完成后,由本機置STOP位發送停止條件,進入從模式***
*** ■從模式下模塊自動檢測總線上的電平變化***
*** ■發送/接收模式的選擇通過硬件自動判斷R/W實現***
■注意發送/接收地址后,讀ADDR才能進入主/從模式下一步的數據傳輸
LL庫函數:
1、初始化結構體LL_I2C_InitTypeDef
typedef struct
{
uint32_t PeripheralMode;/*
選擇模塊工作模式,通過LL_I2C_SetMode()實現
@ref LL_I2C_MODE_I2C //I2C模式
LL_I2C_MODE_SMBUS_HOST //
LL_I2C_MODE_SMBUS_DEVICE //
LL_I2C_MODE_SMBUS_DEVICE_ARP //
*/
uint32_t ClockSpeed;/*
配置時鐘頻率(< 400kHz(高速);< 100kHz(標準));通過LL_I2C_SetClockPeriod()、LL_I2C_SetDutyCycle()、
LL_I2C_SetClockSpeedMode()、LL_I2C_ConfigSpeed()實現
//示例: 若需要100kHz時鐘,則輸入100000
*/
uint32_t DutyCycle;/*
設置高速模式(僅)下信號占空比;通過LL_I2C_SetDutyCycle()實現
@ref LL_I2C_DUTYCYCLE_2 //低:高=2
LL_I2C_DUTYCYCLE_16_9 //低:高=16:9
*/
uint32_t OwnAddress1;/*
設置自身的主地址,通過 LL_I2C_SetOwnAddress1()實現
//10位模式最大為0x3FF, 7位最大為0x7F
※該結構體及模塊初始化函數不提供設置第二地址(副地址)的方式
*/
uint32_t TypeAcknowledge;/*
配置ACK使能;通過LL_I2C_AcknowledgeNextData()實現
@ref LL_I2C_ACK //在接收到一個字節后返回一個應答(匹配的地址或數據)
LL_I2C_NACK //無應答
*/
uint32_t OwnAddrSize;/*
設置自身地址長度;通過LL_I2C_SetOwnAddress1()實現
※在雙地址模式下只能設置為7位長度
@ref LL_I2C_OWNADDRESS1_7BIT //7位長度
LL_I2C_OWNADDRESS1_10BIT //10位長度
*/
} LL_I2C_InitTypeDef;
2、工作模式設置
void LL_I2C_SetMode(I2C_TypeDef *I2Cx, uint32_t PeripheralMode);/*
設置模塊工作模式
@reg CR1- >SMBUS、SMBTYPE、ENARP
@ref LL_I2C_MODE_I2C //I2C模式
LL_I2C_MODE_SMBUS_HOST //
LL_I2C_MODE_SMBUS_DEVICE //
LL_I2C_MODE_SMBUS_DEVICE_ARP //
*/
uint32_t LL_I2C_GetMode(I2C_TypeDef *I2Cx);
3、模塊開啟/關閉函數
void LL_I2C_Enable(I2C_TypeDef *I2Cx);/*
使能(開啟)I2C模塊
@reg CR1- >PE
*/
void LL_I2C_Disable(I2C_TypeDef *I2Cx);/*
禁用(關閉)I2C模塊
@reg CR1- >PE
*/
uint32_t LL_I2C_IsEnabled(I2C_TypeDef *I2Cx);/*
檢測I2C模塊是否開啟
@retval: 1//開啟
0//關閉
*/
4.時鐘延長控制(ClockStretching)
參考https://blog.csdn.net/happygaohualei/article/details/52864694
通過將SCL線拉低來暫停一個傳輸.直到釋放SCL線為高電平,傳輸才繼續進行。一般情況是從機在發送過程中將SCL接地,主機無法拉高電平后暫停傳輸,從機處理完成任務后釋放SCL,傳輸繼續。 大多數外設不支持時鐘延長功能。
※STM32默認允許時鐘延長
void LL_I2C_EnableClockStretching(I2C_TypeDef *I2Cx);/*
使能時鐘延長。
@reg CR1- >NOSTRETCH
*/
void LL_I2C_DisableClockStretching(I2C_TypeDef *I2Cx);/*
禁用時鐘延長
@reg CR1- >NOSTRETCH
*/
uint32_t LL_I2C_IsEnabledClockStretching(I2C_TypeDef *I2Cx);/*
檢測是否啟用時鐘延長
@retval 1//啟用
*/
5.自身地址設置
地址在從模式下由硬件自動比較
void LL_I2C_SetOwnAddress1(I2C_TypeDef *I2Cx, uint32_t OwnAddress1, uint32_t OwnAddrSize);/*
設置自身主地址,并設置地址模式(7位或10位)
@reg ADD0 ADD1_7 ADD8_9 ADDMODE
@param OWnAddress//自身主地址
OwnAddrSize//地址模式(7位或10位),@ref LL_I2C_OWNADDRESS1_7BIT
LL_I2C_OWNADDRESS1_10BIT
※若啟用第二地址,設置為7位地址模式
*/
void LL_I2C_EnableOwnAddress2(I2C_TypeDef *I2Cx);/*
雙地址模式(啟用第二地址),啟用后只支持7位地址模式
@reg OAR2- >ENDUAL
*/
void LL_I2C_SetOwnAddress2(I2C_TypeDef *I2Cx, uint32_t OwnAddress2);/*
設置第二地址(7位)
*/
void LL_I2C_DisableOwnAddress2(I2C_TypeDef *I2Cx);/*
禁用雙地址模式
@reg OAR2- >ENDUAL
*/
6.廣播呼叫控制(General Call)
當本機作為從機接收到地址0x00時,將被選中并發ACK(如果使能ACK),0x00即廣播地址。
void LL_I2C_EnableGeneralCall(I2C_TypeDef *I2Cx);/*
使能廣播呼叫。
@reg CR1- >ENGC
*/
void LL_I2C_DisableGeneralCall(I2C_TypeDef *I2Cx);/*
禁用廣播呼叫.
@reg CR1- >ENGC
*/
uint32_t LL_I2C_IsEnabledGeneralCall(I2C_TypeDef *I2Cx);/*
檢測是否啟用了廣播呼叫。
@retval 1//啟用
*/
7.模塊時鐘配置
- 請在模塊關閉的狀態下配置*
void LL_I2C_SetClockPeriod(I2C_TypeDef *I2Cx, uint32_t ClockPeriod);/*
配置SCL時鐘周期;
@reg CCR- >CCR
@note 具體配置參見MANUAL的CCR寄存器(前有)
*/
uint32_t LL_I2C_GetClockPeriod(I2C_TypeDef *I2Cx);/*
讀取CCR- >CCR的值
*/
void LL_I2C_SetClockSpeedMode(I2C_TypeDef *I2Cx, uint32_t ClockSpeedMode);/*
設置速度模式(標準/高速)
@reg CCR- >FS
@ref LL_I2C_CLOCK_SPEED_STANDARD_MODE //標準模式(最高100kHz)
LL_I2C_CLOCK_SPEED_FAST_MODE //高速模式(最高400kHz)
@note ※高速模式下可設置信號占空比
*/
void LL_I2C_SetPeriphClock(I2C_TypeDef *I2Cx, uint32_t PeriphClock);/*
設置模塊的輸入時鐘(e.g.36Mhz,84Mhz...);單位Hz,函數自動與10MHz對齊;
@reg CR2- >FREQ
*/
uint32_t LL_I2C_GetPeriphClock(I2C_TypeDef *I2Cx);/*
讀取模塊的輸入時鐘(由上一函數設置)
@reg CR2- >FREQ =@retval
*/
void LL_I2C_SetDutyCycle(I2C_TypeDef *I2Cx, uint32_t DutyCycle);/*
設置信號占空比(※僅高速模式)
@reg CCR- >DUTY
@ref LL_I2C_DUTYCYCLE_2 //低:高=2
LL_I2C_DUTYCYCLE_16_9 //低:高=16:9
*/
uint32_t LL_I2C_GetDutyCycle(I2C_TypeDef *I2Cx);/*
獲取信號占空比(僅高速模式);
@reg CCR- >DUTY
*/
void LL_I2C_SetRiseTime(I2C_TypeDef *I2Cx, uint32_t RiseTime);/*
設置主模式下SCL的最大上升時間。
@reg TRISE- >TRISE[5:0]
@note 默認值0x02 計算方法請詳細參看MANUAL
*/
uint32_t LL_I2C_GetRiseTime(I2C_TypeDef *I2Cx);/*
獲取主模式下SCL的最大上升時間。
@retval = TRISE[5:0]
*/
時鐘配置整合函數(優先使用):
void LL_I2C_ConfigSpeed(I2C_TypeDef I2Cx, uint32_t PeriphClock, uint32_t ClockSpeed,
uint32_t DutyCycle);/
配置輸入時鐘、時鐘周期、占空比(高速模式下)
*/
8.SMbus部分
暫不補充
9.關鍵控制
①ACK控制(接收時)
void LL_I2C_AcknowledgeNextData(I2C_TypeDef I2Cx, uint32_t TypeAcknowledge);/
配置應答使能(是否接收到一個數據(地址或數據)后返回一個應答)
@reg CR1->ACK
@ref LL_I2C_ACK //返回應答
LL_I2C_NACK //不返回應答
*/
②生成起始條件與終止條件
void LL_I2C_GenerateStartCondition(I2C_TypeDef I2Cx);/
生成起始條件(S),可與SB配合檢測起始條件的生成狀況
@reg CR1->START
@note 起始條件發送后START位自動清除
*/
void LL_I2C_GenerateStopCondition(I2C_TypeDef I2Cx);/
發送終止條件(P)
@reg CR1->STOP
@note 終止條件發送后STOP位自動清除
*/
③讀取/發送操作
uint8_t LL_I2C_ReceiveData8(I2C_TypeDef I2Cx);/
接收8位數據。
讀取一次DR,獲得8位數據
*/
void LL_I2C_TransmitData8(I2C_TypeDef I2Cx, uint8_t Data);/
發送8位數據。
向DR寫入一個字節
*/
I2C中斷
(摘自RM008)
從中可以看出,I2C模塊的中斷掩碼非常少,一旦開啟可靠性將大大降低,因此一般不使用中斷功能
中斷總共有兩個入口,條件檢測、中斷配置類似UART和SPI
中斷掩碼控制:
void LL_I2C_EnableIT_BUF(I2C_TypeDef I2Cx);/
置位ITBUFEN
*/
void LL_I2C_DisableIT_BUF(I2C_TypeDef I2Cx);/
清零ITBUFEN
*/
void LL_I2C_EnableIT_ERR(I2C_TypeDef I2Cx);/
置位ITERREN
*/
void LL_I2C_DisableIT_ERR(I2C_TypeDef I2Cx);/
清零ITERREN
*/
void LL_I2C_EnableIT_EVT(I2C_TypeDef I2Cx);/
置位ITEVTEN
*/
void LL_I2C_DisableIT_EVT(I2C_TypeDef I2Cx);/
清零ITEVTEN
*/
I2C狀態判斷 ※在軟件方式使用I2C時非常重要
讀取狀態位判斷的格式為 LL_I2C_IsActiveFlag_XXX()
使用請參見前面的時序圖。
DMA控制
I2C模塊同樣可以配置DMA傳輸,這通常使用在主模式下傳輸大量數據的情況。
但LL庫使用DMA時容易發生通訊錯誤,因此不推薦使用。
評論
查看更多