議詳解:從時序原理到多設(shè)備實戰(zhàn))
SPI 這玩意兒我玩了快十年見過太多人把它寫成“玄學通信”——波形不對就甩鍋“干擾”速率上不去就怪“芯片不行”。說實話SPI 是嵌入式里最耿直的兄弟不像 I2C 有地址和 ACK也不像 UART 有幀格式和波特率誤差。它就是一根時鐘線拉著兩根數(shù)據(jù)線跑誰拉低片選誰上場。只要你會按時序圖辦事SPI 能做到非常優(yōu)雅代碼量比 I2C 少、速度比 UART 快甚至能在一條總線上掛七八個設(shè)備還互不打擾。這篇文章我準備了很久從時序原理到硬件片選與軟件片選的博弈從 W25Q64 的讀寫到 ESP32 屏幕與 SD 卡共享總線的坑從 STM32 的 HAL 配置到 FPGA 的 Verilog 實現(xiàn)全部懟在一篇里。不論你是剛點亮第一個 LED 的新人還是正被多設(shè)備共享總線折磨的老兵這篇都能給你點新東西。1. 內(nèi)容整體設(shè)計與思路拆解1.1 為什么說 SPI 是“四根線走天下”先說點最核心的。很多新人一上來就背“SPI 是四線制接口”但其實理解它最好的方式是從“角色分工”去看。SPI 總線上永遠有一個主設(shè)備Master和若干個從設(shè)備Slave主設(shè)備負責產(chǎn)生時鐘 SCK從設(shè)備只能被動接受時鐘驅(qū)動。四根線分別是SCK 時鐘線、MOSI 主出從入、MISO 主入從出以及 CS 片選線有的也叫 SS、NSS、CSN。這里的優(yōu)雅之處在于只要把 CS 拉低這根線上那個從設(shè)備就被“點名”上場其他沒被選中的設(shè)備全部把 MOSI 輸出口置為高阻徹底閉嘴。這種工作模式天然適合一主多從所以 SPI 在 Flash、SD 卡、LCD 屏幕、傳感器這些外設(shè)里滿地都是。那 SPI 和 IIC 到底差在哪我用一句話給你講透IIC 是公共汽車車上有站牌地址大家都排隊上車SPI 是專線電話主設(shè)備撥號拉低 CS直接點名不需要地址這一層。所以 SPI 的幀結(jié)構(gòu)比 IIC 干凈得多沒有地址字節(jié)、沒有 ACK 位一個時鐘周期就是一位數(shù)據(jù)簡單、粗暴、快。但代價就是引腳更多。IIC 兩根線能掛 127 個設(shè)備SPI 每加一個從設(shè)備就必須占一個片選引腳。這是 SPI 最核心的“短板”也是后面要討論的“硬件片選 vs 軟件片選”問題的根源。1.2 數(shù)據(jù)總是在時鐘沿上跳舞——弄懂時序才是優(yōu)雅的前提SPI 之所以被很多人覺得難其實是被“四種模式”這個概念嚇住了。CPOL時鐘極性和 CPHA時鐘相位這兩個參數(shù)看起來像數(shù)學題本質(zhì)上就是回答兩個問題空閑時 SCK 是高點平還是低點平數(shù)據(jù)是在 SCK 上升沿采樣還是下降沿采樣CPOL0 表示空閑時 SCK 拉低CPOL1 表示空閑時 SCK 拉高。CPHA0 表示第一個時鐘沿就采樣CPHA1 表示第二個時鐘沿才采樣。四個組合就是模式 0/1/2/3。我的經(jīng)驗是絕大多數(shù) SPI 外設(shè)默認配置都是模式 0CPOL0CPHA0也就是 SCK 空閑為低、第一個上升沿采樣數(shù)據(jù)。遇到傳感器芯片或顯示屏驅(qū)動 IC 時才需要去查手冊確認。實話說為了這幾個模式去死記硬背真沒必要。我自己的方法是直接用邏輯分析儀抓默認配置的波形看看數(shù)據(jù)在哪個沿變穩(wěn)定、哪個沿被鎖存如果不穩(wěn)就換模式試。畢竟每個外設(shè)手冊里都會把時序圖畫得清清楚楚你照著它的時序圖配置對應模式就行。像 W25Q64 這種 Flash 手冊里就明確寫了支持 SPI Mode 0 和 Mode 3其他模式不用想。1.3 這次博文的整體路線聊完了原理思路就順了。我打算從時序和物理層開始然后進入“軟件模擬 vs 硬件 SPI”的實現(xiàn)拆解接著重點聊片選信號這個最容易栽跟頭的環(huán)節(jié)再往上掛資源共享總線的實戰(zhàn)玩法中間穿插 STM32、ESP32 和 FPGA 三個平臺的實現(xiàn)對照最后整理一份問題排查手冊。整個邏輯就是從點單個設(shè)備時序到線一根總線掛多設(shè)備再到面跨平臺實戰(zhàn)循序漸進盡量讓你看完就能上手干活。2. 核心細節(jié)解析與實操要點2.1 四種模式上手指南不要死記要學會“看圖說話”SPI 模式這種東西理解比記憶重要。我建議每個做單片機的朋友都學會讀時序圖而不是去背一堆表格。以 W25Q64 讀數(shù)據(jù)為例時序圖的橫軸是時間縱軸是各路信號的電平。圖上會用虛線箭頭標出“數(shù)據(jù)建立時刻”和“數(shù)據(jù)采樣時刻”你只要看數(shù)據(jù)在那個沿穩(wěn)定下來、又在哪個沿被主機鎖存就自然知道該配哪個模式。入門的技巧是這樣的先用邏輯分析儀抓設(shè)備在默認配置下的輸出觀察 MISO 上的數(shù)據(jù)跳變沿。如果 MISO 在 SCK 上升沿前后有足夠穩(wěn)定的窗口說明主機應該在上升沿采樣配 CPHA0如果數(shù)據(jù)在下降沿附近才穩(wěn)定就配 CPHA1。這樣一輪下來你就不需要去翻成堆的芯片手冊了。不過有一點必須強調(diào)時鐘極性必須完全一致否則傳輸立刻亂掉。我見過有人把 CPOL 設(shè)反結(jié)果是屏幕也不亮、Flash 讀出來全 0xFF折騰了一下午才發(fā)現(xiàn)是模式 3 和模式 0 混了。2.2 硬件片選與軟件片選的博弈看似小問題實則大講究片選信號是 SPI 最容易“隱形翻車”的地方。硬件片選是指用 MCU 上專門的 NSS 引腳或者由 SPI 外設(shè)自動控制某個 GPIO在每次傳輸開始時由硬件自動拉低、結(jié)束時自動拉高。軟件片選是自己用 GPIO 手動拉低/拉高。聽起來軟件片選又土又麻煩實際上絕大多數(shù)項目里我反而推薦軟件片選。原因很簡單硬件片選引腳往往被固定在一個特定管腳上而 SPI 從設(shè)備的 CS 時序五花八門。有些 Flash 要求 CS 拉低后要等一個 tCS 時間才能開始傳數(shù)據(jù)有些芯片則在 CS 拉高后還需要保持高電平一段時間才允許下一次操作。硬件自動片選在這些場景里面非常死板你不容易插入延時或調(diào)整時序軟件片選則完全可控。軟件片選還有一個額外好處你有多少 GPIO 就能掛多少從設(shè)備。不管 MCU 的 SPI 外設(shè)支持幾個片選引腳軟件片選都不受限制。我在一塊 STM32F103 上曾經(jīng)同時掛了 6 個 SPI 從設(shè)備片選引腳全是普通 GPIO跑得穩(wěn)穩(wěn)當當。那硬件片選什么時候有用只有一種場景建議用當你做高速、大批量、連續(xù)傳輸時硬件片選能最大限度減少驅(qū)動時序的誤差。但前提是你用的 MCU 片選引腳支持引腳重映射和極性配置且時序完全匹配。2.3 SPI 管腳初始化最容易踩的坑復用功能不是你想開就能開STM32 上初始化 SPI最常見的新手錯誤是把 MOSI/MISO/SCK 配成普通推挽輸出然后發(fā)現(xiàn)數(shù)據(jù)傳輸卡死。SPI 作為外設(shè)復用功能GPIO 必須設(shè)置成復用推挽模式AF_PP而且 MISO 引腳必須配置為上拉輸入或浮空輸入。更隱蔽的坑是 MISO 引腳忘記開啟上拉/下拉結(jié)果從設(shè)備 MISO 驅(qū)動能力弱時主設(shè)備讀到的全是雜散電平。另外很多 STM32 型號的 SPI 引腳不是隨意映射的需要參考數(shù)據(jù)手冊里的 AFIO 重映射表。比如 STM32F103 的 SPI1默認引腳是 PA5、PA6、PA7部分封裝支持重映射到 PB3、PB4、PB5。如果你的 PCB 走線把引腳連到了 PB3卻沒開啟重映射那程序?qū)懙教旎牡乩弦餐ú涣?。配置完外設(shè)時鐘和 GPIO 時鐘之后別忘了一條先初始化 GPIO再初始化 SPI 外設(shè)。順序反了很容易在后續(xù)調(diào)試里出現(xiàn)奇怪的問題。2.4 SPI Flash 讀寫 W25Q64 的經(jīng)典套路W25Q64 是幾乎每個嵌入式工程師都摸過的芯片8MB 容量SPI 接口用來做字庫存儲、固件升級備份、日志記錄都非常順手。用 SPI 讀寫 W25Q64 的套路其實就四步發(fā)命令、發(fā)地址、傳數(shù)據(jù)、收尾。比如讀芯片 ID就是拉低 CS發(fā)送 0x9F 命令然后讀三個字節(jié)分別是廠商 ID 和設(shè)備 ID最后拉高 CS。W25Q64 的廠商 ID 固定是 0xEF設(shè)備 ID 是 0x4014能對上說明 SPI 通了。寫入操作就比較講究了。Flash 寫入前必須先擦除擦除以扇區(qū)為單位。W25Q64 一個扇區(qū) 4KB擦除命令是 0x20。擦除一次大約需要 150ms 到 400ms期間芯片會拉低 BUSY 位你要通過讀狀態(tài)寄存器 0x05 不斷查詢 WIP 位等它變 0 才能繼續(xù)下一步。很多機器人車項目里 Flash 寫入突然失敗十有八九就是擦除還沒完成就開始寫。讀數(shù)據(jù)時最快的方式是連續(xù)讀先發(fā)送 0x03 命令再發(fā) 24 位地址之后主設(shè)備持續(xù)產(chǎn)生時鐘W25Q64 就會一個字節(jié)接著一個字節(jié)往外吐讀完整片 8MB 也就一眨眼的功夫。這里要注意W25Q64 的單次頁編程最多寫 256 字節(jié)跨頁寫必須手動處理地址對齊偷懶直接跨頁寫大概率會寫飛。3. 實操過程與核心環(huán)節(jié)實現(xiàn)3.1 軟件模擬 SPIGPIO 翻轉(zhuǎn)也能很優(yōu)雅很多人覺得軟件模擬 SPI 是“性能不足”的無奈之舉我倒覺得這是一種最優(yōu)雅的底層能力。它不依賴任何硬件外設(shè)任何兩個 GPIO 就能“徒手”搓一個 SPI 主機出來。在硬件 SPI 引腳被占用、或者你用的芯片壓根沒有 SPI 外設(shè)時軟件模擬就是救命的稻草。軟件模擬 SPI 的核心是別把時序?qū)懙锰珕?。以模?0 為例發(fā)送一位的邏輯是這樣的先把 MOSI 置成要發(fā)送的位然后把 SCK 拉高等一小段時間再把 SCK 拉低。重復 8 次就是一個字節(jié)。代碼一共不到二十行但是有一個關(guān)鍵細節(jié)在循環(huán)里不要調(diào)用任何帶延時的庫函數(shù)最好是用__nop()或者空循環(huán)制造幾個時鐘周期的延時否則頻率一高整個時序就變形了。我之前在 STM32F0 上做過一次軟件模擬用 GPIO 翻轉(zhuǎn)模擬三線 SPI——也就是沒有 MISO只有 SCK、MOSI、片選。因為那是一個只需要單向?qū)憯?shù)據(jù)的 LED 驅(qū)動芯片三線完全夠用。當時把主頻拉到 48MHz軟件模擬 SPI 的時鐘能跑到 1MHz 左右控制幾十個 LED 燈帶綽綽有余。所以“軟件模擬慢”其實是個相對概念在低速外設(shè)場景下它完全夠用。需要特別注意的一個問題軟件模擬 SPI 讀數(shù)據(jù)時MISO 引腳要在 SCK 下降沿之后去讀而不是上升沿。因為很多從設(shè)備是在上升沿輸出數(shù)據(jù)數(shù)據(jù)要等一小段傳播延遲才穩(wěn)定。你在上升沿立刻去讀 GPIO很容易讀到上一個 bit 的殘留值。我自己就因為這個問題在讀取傳感器時出過數(shù)據(jù)錯位后來改成下降沿讀問題立刻消失。3.2 硬件 SPI 實戰(zhàn)STM32 的 CubeMX 配置與避坑在 STM32 上搞硬件 SPI我強烈建議用 CubeMX 先做圖形化配置。原因很簡單SPI 外設(shè)的寄存器位太多手寫初始化代碼容易漏。你用 CubeMX 把 SPI 模式選為 Full-Duplex Master速率設(shè)為 18MHz 或更低CPOL/CPHA 按芯片手冊填好它會自動把 GPIO 復用、外設(shè)時鐘、DMA 請求這些瑣碎的東西全部配好比手寫省事太多。配置時會遇到一個經(jīng)典問題分頻系數(shù)和實際總線時鐘算不對。STM32F103 的 APB1 最大 36MHzAPB2 最大 72MHz而 SPI1 掛在 APB2 上、SPI2 掛在 APB1 上。如果 SPI1 配 18M 波特率那分頻就是 4但 SPI2 想配 18M 就不行了因為 APB1 只有 36MHz最大只能到 36/218MHz而且預分頻必須是 2 的冪。很多同學的開發(fā)板跑 SPI2 莫名其妙速率上不去其實就是沒意識到這個時鐘域的差別。CubeMX 生成的初始化代碼只是第一步別忘了在實時操作系統(tǒng)里使用 SPI 還要做好互斥保護。如果是裸機用查詢方式倒沒什么問題一旦跑 FreeRTOS多個任務同時訪問同一個 SPI 外設(shè)不加互斥量就會出現(xiàn)數(shù)據(jù)交叉錯亂。我當時第一次在 RTOS 下調(diào) W25Q64 時寫進 Flash 的數(shù)據(jù)總是偶發(fā)性損壞查了兩天才意識到是兩個任務在搶總線。后面加了一把互斥鎖問題瞬間歸零。硬件 SPI 的另一種優(yōu)雅姿勢是 DMA。配置好 DMA 通道、把外設(shè)地址指向 SPI 的 DR 寄存器、內(nèi)存地址指向你的數(shù)據(jù)緩沖區(qū)然后啟動一次傳輸CPU 就可以去干別的事。傳完以后在 DMA 中斷里做收尾清理比如拉高片選、置標志位。大塊數(shù)據(jù)的搬運效果立竿見影尤其是 LCD 刷屏配合 DMA 之后幀率能提升一倍還多。3.3 ESP32 實戰(zhàn)屏幕與 SD 卡共享 SPI到底哪個優(yōu)先級高ESP32 上跑 SPI 是個高頻場景大部分時候是屏幕和 SD 卡一起掛在同一根 SPI 總線上。很多人在網(wǎng)上問“用哪個 SPI 好”其實問題的核心不是用哪個硬件 SPI而是總線上匹配不同速率的外設(shè)怎么做仲裁。屏幕刷新往往需要十幾 MHz 甚至更高而 SD 卡在 SPI 模式下一般跑到 20MHz 就到頂了互相遷就會造成兩頭不討好。我的方案是屏幕用硬件 SPI 優(yōu)先級拉滿因為刷屏對實時性要求高SD 卡的讀寫可以稍后插入。實現(xiàn)上把 CS 分給屏幕和 SD 卡兩個不同的 GPIO兩個設(shè)備都掛在同一組 MOSI/MISO/SCK 上軟件層通過分別控制 CS 來分時復用。這樣屏幕在刷新時就不會被 SD 卡的慢速操作拖累SD 卡讀寫的時候屏幕則暫時停一下、等一個垂直消隱周期再切回來。實測下來 2.4 寸 240x320 的屏加一張普通 TF 卡在 ESP32 上刷圖、存日志、讀配置文件完全沒問題。這里有個關(guān)鍵坑切換 CS 之后總線不是立刻就能用的。因為被選中的設(shè)備在 CS 拉低后往往需要一小段時間穩(wěn)定內(nèi)部邏輯立刻開始發(fā)數(shù)據(jù)有概率丟掉第一個字節(jié)。我的習慣是在每次 CS 拉低后插入幾個空時鐘周期的延時代價極低但穩(wěn)定性好了很多。另外不同設(shè)備模式不同也沒關(guān)系因為模式是在每一次傳輸前配置的切換設(shè)備時重新配置 SPI 模式即可不會有硬件沖突。還有一個非常不起眼但會咬人的細節(jié)當兩種設(shè)備都掛在一條總線上時千萬不要讓多個設(shè)備的 CS 同時為低。否則它們的行為無法預測輕則數(shù)據(jù)錯亂重則漏電損壞 IO 口。我在驅(qū)動代碼里寫了一個斷言每次切換前都檢查當前是否有設(shè)備占用總線一旦檢測到重復選中就立刻報錯。這個小機制后來救了我很多次。3.4 FPGA 視角Verilog 實現(xiàn) SPI 協(xié)議帶你拆解狀態(tài)機FPGA 下的 SPI 和單片機完全是兩種思維。單片機是用外設(shè)寄存器去控制時序FPGA 是你自己當“時序的上帝”。用 Verilog 實現(xiàn) SPI最核心的就是狀態(tài)機的架構(gòu)。我常用的狀態(tài)劃分是IDLE、發(fā)送命令、發(fā)送地址、讀/寫數(shù)據(jù)、結(jié)束。每個狀態(tài)之間用計數(shù)器精確控制 SCK 的翻轉(zhuǎn)字節(jié)傳輸按位進行位計數(shù)器到 8 就跳到下一個狀態(tài)。比如實現(xiàn)一個模式 0 的 SPI MasterSCK 空閑為低上升沿輸出數(shù)據(jù)、采樣輸入。Verilog 邏輯大概是在偶數(shù)周期翻轉(zhuǎn) SCK在 SCK 上升沿之前把 MOSI 更新為當前發(fā)送位在 SCK 下降沿附近鎖存 MISO。看起來簡單但如果你的位寬、地址寬度、命令序列都是可配置參數(shù)這個模塊的可復用性就很強。用 FPGA 做 SPI 最大的好處是你可以把片選時序做得非常精確甚至能在一個 SPI 事務中間插入自定義的等待周期。這是 MCU 的硬件 SPI 外設(shè)做不到的。但代價是調(diào)試難度更高因為硬件波形錯了沒法像單片機那樣打斷點。所以我的建議是先用邏輯分析儀抓波形再用 ILA集成邏輯分析儀看內(nèi)部信號兩手都要抓。凡是遇到時序問題先看 SCK 是不是穩(wěn)定、CS 有沒有毛刺、數(shù)據(jù)是否在采樣沿保持穩(wěn)定這三個點查完90% 的問題都能定位。4. 常見問題與排查技巧實錄4.1 一張問題速查表解決 90% 的 SPI 故障平時在群里幫人看 SPI 問題來來回回就是那幾類。我整理了一張速查表按出現(xiàn)頻率排序癥狀可能原因解決辦法MISO 一直讀到 0xFF從設(shè)備沒被正確選中檢查 CS 引腳極性配置確認是否真正拉低MISO 讀到全 0x00MOSI 或時鐘沒通用示波器/邏輯分析儀看 SCK 有無時鐘翻轉(zhuǎn)數(shù)據(jù)錯位前兩個字節(jié)正常CPHA 配置反了切換 CPHA調(diào)整數(shù)據(jù)采樣沿數(shù)據(jù)對但偶發(fā)亂碼速率太高時序余量不足降低 SPI 分頻系數(shù)減小總線電容多個設(shè)備互相干擾片選信號控制邏輯有bug檢查是否有兩個 CS 同時拉低寫入 Flash 失敗沒有先擦除或擦除超時未等待確認發(fā)送 0x20 擦除命令后輪詢狀態(tài)寄存器我對速查表的使用邏輯是先懷疑片選因為片選錯了影響最大且最隱蔽再看時鐘和數(shù)據(jù)線最后才懷疑從設(shè)備本身。很多人在 SPI 調(diào)不通時第一反應是換芯片、換板子其實認真查一下時序和片選問題往往出在自己眼皮底下。4.2 用邏輯分析儀抓波形從一大堆雜波中找出真兇調(diào)試 SPI 絕對不能靠肉眼猜邏輯分析儀是嵌入式工程師最值得投資的工具。便宜的 USB 邏輯分析儀支持 8 通道、采樣率 24MHz 起步抓 SPI 綽綽有余。抓的時候把采樣率設(shè)到 SPI 時鐘的 4 倍以上否則波形不夠光滑看不出數(shù)據(jù)采樣沿是否安全。抓完波形以后解碼是基本功。打開邏輯分析儀自帶的 SPI 解碼器設(shè)置好 CPOL/CPHA 和位序一般是 MSB First它會自動幫你解析出 MOSI 和 MISO 上的字節(jié)流。對比期望值一目了然。分享一個我印象很深的案例之前調(diào)試一塊 LCD 屏程序邏輯看著都對但屏幕老是閃花。我抓了波形后發(fā)現(xiàn)SPI 數(shù)據(jù)線上的下降沿毛刺極其嚴重尤其在 CS 切換的瞬間。追查之下才發(fā)現(xiàn)是 SPI 總線上掛的 FPC 線太長寄生電容太大在 20MHz 時產(chǎn)生了振鈴。最后把 SPI 速率降到 10MHz同時在 SCK 和 MOSI 上串了 33 歐姆的電阻做阻尼屏幕馬上就穩(wěn)定了。所以有時候波形不好別急著改代碼先看看硬件走線和阻抗匹配。4.3 極限性能調(diào)優(yōu)SPI 屏刷新率到底怎么算SPI 屏幕刷新率是很多做 UI 的人關(guān)心的重點。刷新率的理論計算公式是刷新率 SPI 時鐘頻率 /每像素位數(shù) × 總像素數(shù)。比如一塊 240x320 的屏共 76800 像素RGB565 格式下每像素 16 位SPI 時鐘 40MHz理論視頻幀率 40000000 /16 × 76800≈ 32.5 幀每秒再加上幀消隱、命令開銷實際有 20 多幀就不錯了。所以如果屏幕卡頓關(guān)鍵瓶頸往往在 SPI 時鐘頻率而非主頻。想把刷新率提上去優(yōu)先做三件事第一把 SPI 速率拉滿到外設(shè)支持的上限第二用 DMA 搬數(shù)據(jù)避免 CPU 逐字節(jié)搬運第三盡量減少發(fā)送前的準備時間比如提前把一幀數(shù)據(jù)拼好再用一塊連續(xù)內(nèi)存一次性發(fā)出去。我實測過一次升級從普通輪詢發(fā)送改到 DMA 雙緩沖刷新率直接提升了接近兩倍。需要注意的另一個點是屏幕驅(qū)動 IC 的數(shù)據(jù)寫入速率通常高于實際顯示刷新率所以真正決定絲滑程度的是 MCU 到驅(qū)動 IC 的搬運效率而不是屏幕面板本身的刷新率。這話可能有點繞但你只要記住“優(yōu)化搬運而不是優(yōu)化面板”這個大方向就對了。4.4 編程下載算法與工具鏈的小眾痛點關(guān)于 STM32F429 下載算法里 SPI Flash 的配置這里值得單獨提一句。很多人會在 Keil 里給外部 SPI Flash 做下載算法卻反復出現(xiàn)RM1135 step 01 clear DL tag and setting in SPI - read reg(0xbfc7ffe0) fail這類報錯。這類問題絕大多數(shù)出現(xiàn)在 Flash 型號與下載算法不匹配或者 SPI 模式配置錯誤的場景。解決辦法是確認 W25Q256 的 ID0xEF 0x40 0x19與算法里的定義完全一致同時把 SPI 模式設(shè)為 Mode 0速率先降到 5MHz 試一下。燒進去之后如果校驗能過再逐步提速。工具鏈層面我常用的調(diào)試裝備是“USB 轉(zhuǎn) SPI/I2C 適配器”這類便宜的模塊能讓你在 PC 端直接對著寄存器讀寫省去反復編譯下載的時間。特別適合調(diào)試傳感器初始化序列這種要反復試的場景。把寄存器配置用腳本寫成序列一鍵跑看反饋比在 MCU 上改代碼重燒快一個數(shù)量級。5. 跨平臺對照總結(jié)STM32、ESP32、FPGA 三路并進5.1 STM32 平臺功能最全最適合系統(tǒng)性學習STM32 的 SPI 外設(shè)非常經(jīng)典包含硬件片選、DMA、FIFO、CRC 等特性最適合初學者把這些特性吃透。STM32H743 這類高性能芯片的 SPI 甚至能跑到 100MHz 以上做高速采集都沒壓力。但高性能意味著更多寄存器要配所以用 HAL 庫時除了初始化結(jié)構(gòu)體還得留意SPI_TIMode和NSSP這些冷門配置項在普通場景下別去動它們。5.2 ESP32 平臺外設(shè)少而精自由度高ESP32 只有兩到三個硬件 SPI但它的優(yōu)點在于引腳幾乎可以任意映射。尤其在 Arduino 環(huán)境下SPI.begin()一行代碼就能啟用默認 SPI對于想快速上手的用戶非常友好。工程上如果遇到“引腳不夠、外設(shè)不夠”的死局ESP32 的 GPIO 矩陣還能讓你用任意引腳模擬任意外設(shè)這種靈活性很值錢。5.3 FPGA 平臺萬物可控但代價是復雜度FPGA 上的 SPI 是唯一能真正實現(xiàn)“引腳級精確控制時序”的載體。不管你要反向?qū)崿F(xiàn)一個奇怪的從設(shè)備協(xié)議還是想同時驅(qū)動多個沒有標準 SPI 接口的傳感器FPGA 都能搞定。但代價是開發(fā)周期明顯拉長Verilog 的調(diào)試也沒那么直觀。所以如果你的產(chǎn)品功能就是板級通信優(yōu)先考慮 MCU如果你的板子就是用來做協(xié)議轉(zhuǎn)換、接口擴展的“膠水芯片”FPGA 值得一上。5.4 選型建議別盲目追求外設(shè)數(shù)量最終選型不是看哪個平臺的 SPI 外設(shè)多而是看整個系統(tǒng)的總擁有成本。STM32 生態(tài)成熟、資料多適合量產(chǎn)和學習ESP32 網(wǎng)絡和藍牙集成度高適合 IoT 項目FPGA 靈活可控適合做接口級定制。SPI 本身只是一種承載數(shù)據(jù)的物理機制真正重要的是你如何組織這些數(shù)據(jù)、如何管理總線上的設(shè)備以及如何讓代碼在任何平臺上都保持結(jié)構(gòu)清晰。6. 寫在最后的幾個實在建議文章寫到這兒我最后再掏幾句壓箱底的心得。第一方向永遠比努力重要。調(diào)試 SPI 的時候不要上來就對著代碼逐行看先接邏輯分析儀抓波形把“電平時序”和“數(shù)據(jù)結(jié)果”對應起來找到證據(jù)鏈再動刀。第二片選信號是 SPI 的“靈魂”。很多玄學問題最后都落回到 CS 的時序、極性、毛刺這三點上。第三不要死守一種方式。硬件 SPI 不行就軟件模擬頂一下阻塞傳輸不行就換 DMASPI 最大的優(yōu)點就是靈活靈活的資源就該被靈活地用。如果你照著這篇文章的思路把一個 SPI 設(shè)備從零調(diào)通再成功在一條總線上掛了多個設(shè)備那我相信你已經(jīng)能體會到“SPI 這么玩就很優(yōu)雅”到底是什么感覺——那是一種從底層掌控了節(jié)奏而不是被時序追著跑的自由。