本文以增強I2C通訊的穩定性出發,介紹輪詢與中斷的差異,並給不熟悉通訊的讀者說明何謂I2C Bus及其工作原理。同時給進階的讀者以實際波形分析通訊失敗時的實際狀況,並將中斷服務(ISR)視覺化觀察中斷發生的時機以及時序,以利除錯。{alertInfo}
目錄
前言
這次的應用是要讓F280025C作為接收端,透過I2C回應其他裝置要求的資料,並傳送相關狀態給主機。為了達到裝置的高穩定度,想使用中斷的方式處理I2C Request,而非輪詢。
在通訊時使用中斷一直是停留在我腦中的一個設計方式,在這之前都還沒有機會實際應用,因為以前的專案簡單的輪詢就可以達成效果就一直沒有去精進程式。這篇文章會記錄輪詢與中斷在實際應用上會遇到的問題以及視覺化MCU在處理程式時佔用的時間,讓設計者能夠一目了然的知道問題出在哪。
可以參考我在TI E2E論壇所提問的兩篇文章:
- TMS320F280025C: I2C interrupt ARDYINT, AASINT clarification and TX FIFO question - C2000 microcontrollers forum - C2000™︎ microcontrollers - TI E2E support forums
- TMS320F280025C: I2C bus busy, unknow reason to occupy the bus - C2000 microcontrollers forum - C2000™︎ microcontrollers - TI E2E support forums
I2C通訊協議介紹
I2C是被廣泛應用在板間電路或短距離通訊的協議,他與SPI相比除了使用的資料線更少之外,更可以串聯最多1023組接收端(Slave, 10-bit address),讓他擁有許多衍伸通訊協議,如PMBus、SMBus等等。
要在C2000系列MCU使用I2C功能,需要先將GPIO設定成I2C模式,同時若是主控端(Master)則需要設定時脈、位址格式、資料位元數以及資料長度。若是將C2000,如 F280025C作為接收端(Slave),則是需要設定接收端自己的位址(I2COAR)。
由於I2C在工作上有四種模式,擔任控制端時,可以為控制傳輸模式(Master Transmitter)、控制接收模式(Master Receiver),擔任接收端時也可以擔任接收傳輸模式(Slave Transmitter)與接收傳輸模式(Slave Reviever)。以這次的例子,F280025C會需要扮演Slave Reciever與Slave Transmiter的角色,Mater則由其他裝置扮演。I2C的常見連如下圖1所示。
I2C最重要的核心精神在於他的資料線與時脈線是全部並聯再一起,以資料的角度看就是全部AND在一起。也就是說只要其中一個裝置把匯流排下拉至Low,整條線的訊號就都是Low。
而I2C的時脈訊號SCL只能由Master提供,但任一個Slave都可以將SCL下拉為Low告訴Master等等待回應,這個功能叫做Time stretching 時脈延展。這時候SCL訊號被拉到地,Master內部接收資料的位移暫存器也不會動作,讓Master得以等待Slave處理完成後釋放SCL線,Master的SCL訊號才可以被傳送到Slave繼續通訊。
|
圖1. I2C 匯流排連接圖 |
除此之外,新一點的I2C標準還允許多組主控端(Multi-Master),但這並不在本文的討論範圍,有興趣的讀者可以自行搜尋相關知識。
F280025C I2C工作原理說明
|
圖2. F280025C I2C模組方塊圖 |
在F280025C中,I2C模組方塊圖如圖2所示。本文暫且只討論MCU作為Slave時的工作原理。
當SCL收到時脈訊號後,CPU會在SCL為LOW時讀取SDA線的狀態,並將此位元(bit)放入I2CRSR中,再放置到I2CDRR。若FIFO開啟,則會將I2CDRR資料放置FIFO中,並依照I2CFFSTS暫存器的FIFO準位設定,產生FIFO
Full中斷。利用FIFO Full中斷我們可以將FIFO內部資料進行處理,執行對應動作。
而作為Slave要傳送資料時,要注意的是SCL只能由Master提供,如果Master沒有支援Time stretch功能,可能會讓Master不知道要等Slave處理,導致SDA線為空並解析出錯誤資料。因此在收到指令後,MCU要快速處理I2C指令,並將要傳送的資料放到I2C TXFIFO中。當I2C TXFIFO放滿資料後(機制如同RXFFSTS),在I2C模組收到SCL時脈時便會自動將暫存器中的資料轉移到SDA線上給Master讀取。
而0025的I2C中斷被OR在一起成兩個中斷,分別是I2C Interrupt與I2C FIFO
Interrupt。
I2C Interrupt可以在依照來源細分成ARBLINT,
NACKINT,ARDYINT,RRDYINT,XRDYINT,SCDINT,AASINT七個,而I2C FIFO則是TX
FIFO與RX FIFO兩個。
前者主要用於判斷I2C匯流排上的資料狀態,包含Master呼叫自己(Bus上傳送對應自己的Address),
Bus Busy,Stop Condition,ACK
Condition等等。後者則是針對FIFO狀態進行中斷通知,當RX
FIFO滿了就叫MCU把FIFO中的資料解碼/產生對應資料,TX
FIFO不為空就叫MCU把FIFO內的東西傳出去。
詳細的實作可以參考TI C2000 Library的I2C相關範例: I2c_ex6_eeprom_interrupt.c
|
圖3. F280025C I2C 中斷與中斷向量表 |
輪詢與中斷的主要區別
輪詢(Polling)一種概念簡單且編寫容易的通訊法,當輪詢應用在通訊上時只需要檢查通訊暫存器有沒有新的資料,若有就處理,沒有就繼續執行其他任務。這種方式在編寫上很線性,但是會有兩個大缺點,第一是當CPU再做其他事情的時候,不一定有足夠的資源去處理通訊訊息,會導致通訊不穩定;第二則是當通訊訊息發生異常(如暫存器溢位或有超時設定)時,CPU沒辦法及時處理通訊事件,造成通訊不穩定。
因此,需要改用另一種較穩定,但撰寫起來不線性化的中斷服務(Interrupt Service Routine (wikipedia)寫法。中斷的概念是當CPU在處理固定程序時,若有中斷發生會優先處理中斷內容,處理完畢再跳回原本的程式繼續執行。不同的中斷副程式都會有不同的優先權(priority),這對應到CPU要處理的優先順序,這個資料被記錄在中段向量服務表(Interrupt vector Table(wikipedia))
舉個生活上的例子來說,當你在滑手機的時候,同學叫你跟他一起玩遊戲,還有媽媽叫你去掃地兩件事情同時發生時,肯定是媽媽的要求優先。這個例子中,滑手機對應到的是 CPU固定處理程序,同學叫你看手機對應到低優先權的中斷副程式,而媽媽叫你去掃地則是對應到最高優先權的中斷程式。
那把這個概念套用到通訊處理中,就是當我用I2C介面向從端MCU發送訊息時,CPU會先放下手邊的工作優先處理I2C佔存器中的訊息,確保每次通訊都可以即時回應並傳輸資料。
中斷服務程式時序分析
從中可以看到當ISR2發生時,ISR1是被擠到後面去處理的,因此在資料傳輸過程中與ISR2產生碰撞,使得本該處理這串資料的ISR1被拖到後面去執行,變成SDA上Slave沒有回傳任何資料導致通訊不穩定(註1)。
張貼留言
留個言吧