DMA發(fā)送MISO輸出0xFF的排查與解決)
Nucleo-H753ZI 上SPI 從機(jī)打開 DMA 準(zhǔn)備發(fā)數(shù)據(jù)結(jié)果主機(jī)那邊一讀回來四個(gè)字節(jié)全是 0xFF 0xFF 0xFF 0xFF。這不是個(gè)例STM32 社區(qū)里隔三差五就有人貼出這個(gè)問題。別急著懷疑線接錯(cuò)了先把 MISO 為什么會(huì)一直是高電平這件事想明白再往下查。先說結(jié)論SPI 從機(jī)的 MISO 在空閑狀態(tài)下就是高電平主機(jī)讀到 0xFF 意味著“這條線上沒有有效數(shù)據(jù)”。連續(xù) 0xFF 說明從機(jī)已經(jīng)被選中、SCK 時(shí)鐘也進(jìn)來了但發(fā)送路徑上根本沒數(shù)據(jù)可移出去。問題基本鎖定在三個(gè)方向DMA 配置沒有真正生效、H7 平臺(tái)特有的傳輸長(zhǎng)度設(shè)置沒做、或者發(fā)送緩沖區(qū)放到了 DMA 夠不到的內(nèi)存區(qū)域。這篇文章把原理、配置和排錯(cuò)流程完整講一遍照著做基本一次能通。1. 先搞清楚 0xFF 是怎么來的1.1 從機(jī) MISO 的空閑狀態(tài)SPI 是同步全雙工協(xié)議主機(jī)提供 SCK 時(shí)鐘從機(jī)在時(shí)鐘邊沿把數(shù)據(jù)一位一位移出到 MISO。站在主機(jī)側(cè)的視角MISO 上有兩種情況都會(huì)表現(xiàn)為高電平第一種是 NSS 為高、從機(jī)沒有被選中。此時(shí)從機(jī)的 MISO 引腳是高阻態(tài)主機(jī)側(cè)如果沒有下拉電阻線上被上拉或者空載讀數(shù)自然就是 1。第二種是從機(jī)被選中了SCK 也在跑但 TX 移位寄存器里沒有有效數(shù)據(jù)。此時(shí) H7 的 SPI 外設(shè)會(huì)保持 MISO 的默認(rèn)輸出電平主機(jī)讀到的還是 0xFF。所以看到 0xFF不要去懷疑“數(shù)據(jù)被干擾成 FF 了”它更可能是“從機(jī)壓根沒發(fā)數(shù)據(jù)”。1.2 TX 路徑上的數(shù)據(jù)是怎么流動(dòng)的從機(jī)發(fā)送不是主動(dòng)把數(shù)據(jù)推出去而是配合主機(jī)的時(shí)鐘往外供數(shù)據(jù)。主機(jī)來一個(gè)字節(jié)的時(shí)鐘從機(jī)把 TX FIFO 的頭一個(gè)字節(jié)搬進(jìn)移位寄存器再?gòu)?MISO 一位一位移出去。這里有個(gè)關(guān)鍵點(diǎn)SPI 外設(shè)只有在 TX FIFO 里有數(shù)據(jù)時(shí)才會(huì)啟動(dòng)內(nèi)部發(fā)送邏輯。如果你沒開 DMA、沒開 TXE 中斷、也沒手動(dòng)往發(fā)送寄存器寫數(shù)據(jù)TX FIFO 就是空的。主機(jī)來的每個(gè)字節(jié)時(shí)鐘從機(jī)都只能輸出空數(shù)據(jù)。H7 的 SPI 在這種情況下會(huì)置起 UDRUnderrun欠載標(biāo)志MISO 輸出默認(rèn)電平也就是 0xFF。1.3 先把 DMA 摘掉用輪詢做定位遇到這個(gè)問題第一步不是去調(diào) DMA 參數(shù)而是把 DMA 整個(gè)摘掉用最笨的阻塞式發(fā)送驗(yàn)證鏈路。uint8_t tx_buf[4] {0xA5, 0x5A, 0x01