1. 程式人生 > >STM32 I2C 難點

STM32 I2C 難點

I2C 匯流排在所有嵌入式系統中用得極廣, 是一個工業級別的匯流排, 但由於STM32 是一個32位的MCU, 註定了他的I2C硬體介面將會功能強大, 但同時也會較難於控制,不象8位機,如AVR8位機的TWI(實際完全符合 I2C標準) 那麼易用. 以下是我的STM32 I2C硬體介面程式設計的一些心得體會.

    如果你選擇了STM32, 說明了你的專案的需求是比較複雜的,使用EMBEDDED OS 和大量地運用中斷+DMA的程式設計模型是必然的選擇, 如果你的專案中用STM32,而你用模擬的I2C的話, 說明了兩點: 一是浪費了STM32; 二, 如果你的專案很複雜的話,你會發現在專案的開發後期,好象STM32也比8位機快不了多少, WHY!! ,但這不是STM32的問題,而是你沒有最有效地利用上STM32.

    很多朋友在搞STM32的I2C介面程式設計時總是時不時“當在某處”(GOOGLE時你會發現這個問題很普遍), 一些朋友這時就會用軟體來模擬I2C,然後,很快發現和I2C裝置能很好地通訊了(但當機還是可能隨機出現), 這些朋友于是大罵STM32的I2C硬體介面是個”杯具”(呵呵,我有時也會突然想罵罵,但我知道,99.999%的原因還是自已對於STM32硬體介面的熟悉程度不夠,或者說,是我沒有揚STM32 I2C的長,而總是捉住他的短不發。)。

    固然,STM32 I2C硬體介面有設計不完善的地方,例如下面就是我從STM32最新的Errata sheet中總結出的,關於STM32 I2C介面設計上的一些缺陷和如何避開這些缺陷的推薦程式模型:

(1)把I2C的中斷優先順序提升到最高

(2)把傳送多於2個位元組的傳送與接收封裝成利用DMA收發的函式,而把對某I2C裝置接收和傳送一個位元組的函式單獨封裝為一個POLLING (輪詢)函式。

(3)在定址某一I2C DEVICE時要先CHECK I2C BUS 是否BUSY,如果忙,則等待指定時間,如果還是忙就說明I2C BUS 掛了(原因99.9%是由於我們的I2C通訊時序並不十分尊守I2C規約,或者我們所封裝的I2C通訊模組沒有加上防守程式碼(出錯恢復程式碼)),這時要呼叫一個專門的用於通知 I2C BUS上的所有device,讓他們結束當前內部的工作,重新準備好(下雨了,收衣服啦)。如下面的我的I2C模組的FUN 切片:

image

該函式一定要用在主MCU的啟動模組上,因為I2C匯流排在充當Master的MCU啟動時,SDA和SCL有可能組合出剛好符合I2C規約的時序組合,比如一個開始位(START CONDITION),使得I2C BUS 立即當在那裡(因為當主MCU真正需要發出一個START CONDITION時,發現I2C BUS 正處於BUS狀態,而根據STM32 手冊的START CONDITION說明可知,一個起始條件將會使得I2C BUS處於BUSY 狀態, 下面的I2C2_Free_Buf fun 的基本用法:
image

(注: I2C2_Free_Bus Fun 應放線上程中,而不是放在上圖中的位置,這樣會觸發並進入一個硬體錯誤處理向量中斷中)

提示:摘自STM32 手冊:
    I2C.SR1.Bit 0 位(SB)- Start bit(Master mode)
    - Set when a Start condition generated.
    - Cleared by software by reading the SR1 register followed by writing the DR register, or by hardware when PE=0.

(4) 不要讓I2C工作在88KHz的頻率上,低於或者使用Fast-mode(400KHz)頻率,這是STM32 I2C真正的一個硬體BUG(99.999%機率),但是也是可以程式設計避免的。

(5)Programming the bit NOSTRETCH=0  in the I2C_CR1 register. 這樣也可避免一個STM32 I2C硬體設計的一個小BUG(2。9。5節)

(6)大部分的MCU的硬體I2C介面的工作模式是中斷(高階的會用DMA)+狀態機;因此狀態機的程式設計概念要熟悉

(7)STM32 I2C的硬體介面負責實現滿足I2C匯流排的的規約,而我們(嵌入式程式設計開發者)則是通過I2C 控制暫存器和I2C的事件標誌組合來啟動狀態機,然後讓狀態機按照由I2C SR1 和SR2所組合志來的事件自動工作,並在傳送或接收完成後通過FLAG的方式或訊號量的方式通知我們所寫的讀寫函式,操作已經完成,或者在操作中出現了錯誤,如最常見的AF錯誤(device 在第9位上沒有拉低SDA應答Master。)

(8)I2C SR1 和SR2的功能分配(這是一個極易忽視的思考死角

    從STM32 手冊的I2C register map 中可以看到, I2C的SR1,主要是反映I2C通訊的最基本的標誌,要清除SR1的某個標誌可以直接清除,而I2C的SR2即是輔助SR1的,他一般反映了I2C總一當前的工作狀態,如BUSY,是主機模式還是從機模式,等等。關於SR2的很重要的一個程式設計模型是:要清除SR1的某些指定的標誌位時,比如ADDR,先讀SR1然後再讀SR2將會清除掉已置位的ADDR。

(9)Master在操作slave device時要先和他握一下手是很好的防守程式設計模型:

image