本文介紹SPI通訊介面的電器特性、傳輸特性以及使用方式,並實際使用F280025C微處理機對EEPROM記憶體進行讀寫,深入探討使用時需要注意的項目以及與其他介面的優缺點。
目錄
前言
串列周邊線路,Serial Peripheral Interface,是一種常見的通訊協議,不只被應用在記憶體,也有針對顯示器產生的變種DSI(Display Serial Interface)或其他高速通訊協議上。
這次主要使用F280025C讀取ST M95640 EEPROM,仗著以前碩論用過SPI,想說這介面應該是設定好就可以直接傳輸,沒什麼困難的,殊不知又被SPI的FIFO跟ISR搞得不要不要的。
起初只是想把前輩的Code改得更精簡一點,同時舊的Code有個小問題就是沒辦法寫16bit。但這照理說不合理,因為16bit是非常基本的資料型態,包含C2000系列的微處理器int型態都是16bit。
這限制了我們的應用,同時要寫入16bit資料借一定要拆分成兩筆8bit,很沒效率。所以我決定研究官方C2000Ware提供的範例程式。
官方範例程式很精簡,使用很多內建API,我把它全改成我們用的EEPROM參數卻還是不能用,到這我已經搞一個禮拜了QQQQ 再這樣下去進度掛零我很不好意思...於是決定用示波器勾一勾看它到底吐了什麼訊號出來。
結果發現官方範例程式在切換不同指令時會把CS Pin拉High,這就不符合EEPROM Spec的規範。每次只要CS High,EEPROM的指令就會被重設,也就是說這顆EEPROM要正常執行指令需要把CS維持在Low的狀態。我嘗試把CS Pin指定成GPIO Function,但是迎來的還是奇怪的波型...
好吧,只能放棄官方API自己刻一個出來了。
EEPROM的SPI通訊協議
|
M95640寫入指令 |
使用SPI設備時要先依據設備定義的指令進行操作,如這顆EEPROM的操作,以寫入為例,當CS被拉下後,傳送寫入指令與記憶體位址,便可立刻傳送要寫入的資料,直到Master將CS拉High。
但我這就不懂了,我怎麼知道EEPROM會吐多少東西回來?
我要怎麼知道EEPROM剛好吐資料到我要的地方?總不可能用時間去計算,因為以"時間"當標準是最不準確的工具。
搞了好久才知道原來C2000系列MCU的SPI
Bus有個Register是SPIDAT,它是SPITX與SPIRX共用的,當這個站存器被寫進資料後,會透過底層邏輯電路馬上將資料轉為訊號傳送出去。
也就是說當我給它0x87,寫入的瞬間MCU的SPI模組便馬上把0x87透過MOSI腳傳送出去。
![]() |
SPIDAT與SPIRXBUF、SPITXBUF的關係 |
但這還有一個大重點!!!
只要有一個bit從SPIDAT Register推出去,就馬上會從MISO讀取一個bit回來。
也就是說SPIDAT根本是一個環形暫存器,喜歡保持內部是滿滿的狀態,喜歡被填滿>
<
傳一個bit,就要從外面拉一個bit。
那這就好辦了,要讀EEPROM回傳的東西就要傳送一些"垃圾"給它,這些"垃圾"(dummy
data)的目的只是要讀取EEPROM回傳的資料,所以一般會是0xff或者0x00之類的,喜歡0x87也可以用87當dummy
data。
那應該距離目標又更近了吧,就把CS Pull low,依照EEPROM datasheet傳送Read,
Address, dummy, dummy應該就可以得到16bit的資料了吧?
0 不行 甚麼都沒有,讀到的東西全部都是0xFF,WHYYYY???
示波器上傳送的訊號都正確,MISO腳接收到的資料也都對,問題出在哪呢?
Google了一番,要等SPI RX FIFO收到資料再進行讀取才能正確讀到資料。
因為MCU時脈都是以100MHz之類的高頻運作,SPIDAT在傳送出資料後馬上讀取,會重複讀到一個bit好幾次。這就是為甚麼幾乎所有的通訊界面都有FIFO做為緩衝,判斷資料的品質與狀態。
![]() |
SPI Interrupt 連接圖 |
我們可以簡單的用SPI RX
FIFO中斷將資料進行處理,FIFO滿到一定程度(最多16層)後便會觸發SPIRXINT中斷訊號,執行中斷副程式。
起初我也想用中斷進行處理,但後來發現讀取EEPROM是我們程式設計師可控的動作之一,不需要用中斷來切離目前的處理程序,因此用一個簡單的while迴圈等待SPI回傳完整資料並進行分析。
這樣做還有另一個好處是CPU資源可以分配給更高優先權的中斷來進行處理。
以上就是這兩個禮拜在SPI上的奮鬥與筆記嚕!!
張貼留言
留個言吧