動(dòng)開發(fā)實(shí)戰(zhàn):從寄存器配置到數(shù)據(jù)采集)
簡(jiǎn)介面向STM32等主流單片機(jī)平臺(tái)的ADS131M04四通道高精度ADC驅(qū)動(dòng)源碼幫助嵌入式開發(fā)者快速實(shí)現(xiàn)四通道同步采樣、數(shù)據(jù)校準(zhǔn)與寄存器配置并通過(guò)SPI完成通信控制。驅(qū)動(dòng)源碼以ads131m0x.c和ads131m0x.h為核心包含完整的初始化函數(shù)、數(shù)據(jù)讀取接口、狀態(tài)監(jiān)測(cè)邏輯和典型時(shí)序處理直接調(diào)用即可接入項(xiàng)目適配常見(jiàn)ADS131M04硬件電路設(shè)計(jì)無(wú)需額外依賴庫(kù)。壓縮包共6個(gè)文件除了驅(qū)動(dòng)源碼與頭文件還提供測(cè)試文件以演示調(diào)用方法整體約18KB輕量簡(jiǎn)潔結(jié)構(gòu)清晰便于按需修改。目前已有180人學(xué)習(xí)瀏覽適合電能計(jì)量、工業(yè)傳感器信號(hào)采集、精密電流電壓監(jiān)測(cè)等場(chǎng)景的工程師快速上手使用與調(diào)試。資源注釋詳實(shí)支持增益設(shè)置、通道使能、數(shù)據(jù)速率調(diào)整等關(guān)鍵配置便于二次開發(fā)和參數(shù)優(yōu)化。 從事單片機(jī)數(shù)據(jù)采集開發(fā)的朋友十有八九都被同一個(gè)問(wèn)題卡過(guò)傳感器輸出的信號(hào)明明是模擬世界里最干凈的微弱信號(hào)結(jié)果一進(jìn)MCU的片內(nèi)ADC分辨率不夠、噪聲奇高、通道之間還互相串?dāng)_最后讀出來(lái)的數(shù)據(jù)用來(lái)做功率分析或者高精測(cè)量根本不敢用。我之前做三相電能質(zhì)量監(jiān)測(cè)前端時(shí)就因?yàn)檫@個(gè)選了獨(dú)立ADC最終鎖定了TI的ADS131M04順手把整套驅(qū)動(dòng)源碼沉淀了一套比較穩(wěn)定的工程模板。這篇文章不聊芯片手冊(cè)里已經(jīng)寫清楚的東西而是把我從選型到驅(qū)動(dòng)調(diào)試、再到產(chǎn)線實(shí)測(cè)中真正踩過(guò)的坑和驗(yàn)證過(guò)的思路完整拆給你看。適合正在做工業(yè)采集、電能計(jì)量、精密儀器這類項(xiàng)目、想用ADS131M04又不想走彎路的工程師參考。ADS131M04是一顆四通道、24位分辨率、帶可編程增益放大器PGA的同步采樣Delta-Sigma ADCSPI接口輸出單芯片就能完成多通道高精度同步采集。相比用多顆ADC做同步的方案它的數(shù)據(jù)一致性天然好省掉了很多對(duì)齊邏輯。驅(qū)動(dòng)源碼的核心工作本質(zhì)上是三件事把SPI時(shí)序走對(duì)、把寄存器配置寫對(duì)、把數(shù)據(jù)幀解析對(duì)但真正讓數(shù)據(jù)“準(zhǔn)”的功夫還在硬件布局和信號(hào)處理上。1. 選型背景為什么繞開內(nèi)置ADC和常見(jiàn)16位芯片1.1 內(nèi)置ADC的局限與獨(dú)立ADC的意義單片機(jī)片內(nèi)ADC大多數(shù)是逐次逼近型SAR12位居多部分高端MCU有16位。如果只是做電池電壓監(jiān)測(cè)、按鍵檢測(cè)、溫度粗略讀值內(nèi)置ADC完全夠用這也是大部分項(xiàng)目的常態(tài)。但換到真正的精密測(cè)量場(chǎng)景內(nèi)置ADC的短板是硬傷一是分辨率不足12位理論最小量程只在滿量程4096分之一哪怕基準(zhǔn)電壓5V一個(gè)LSB就是1.22mV傳感器輸出如果只有幾毫伏根本沒(méi)法看二是參考電壓往往直接取自MCU電源電源紋波會(huì)以比例方式直接耦合進(jìn)測(cè)量結(jié)果三是多通道內(nèi)置ADC基本靠模擬開關(guān)切換做不到嚴(yán)格同步做三相電或者多相氣體分析時(shí)通道間時(shí)間差會(huì)讓計(jì)算結(jié)果失真。獨(dú)立ADC選型上也分兩類。一類是SAR型比如ADS8688這類速度快但外加PGA電路和抗混疊濾波也需要不少工夫。另一類是Delta-Sigma型精度高、內(nèi)置PGA、對(duì)前級(jí)抗混疊濾波要求低缺點(diǎn)是采樣率相對(duì)低。ADS131M04屬于后者24位分辨率在微弱信號(hào)場(chǎng)景下優(yōu)勢(shì)非常明顯而且它本來(lái)就是面向電能計(jì)量、電網(wǎng)監(jiān)測(cè)這類需要多通道同時(shí)采樣的場(chǎng)合設(shè)計(jì)的四個(gè)通道共用同一個(gè)時(shí)基各通道的采樣時(shí)刻是一致的這在做功率計(jì)算、相位分析時(shí)很關(guān)鍵。1.2 ADS131M04的關(guān)鍵特性與適用場(chǎng)景ADS131M04單通道最高采樣率32kSPS四通道同時(shí)工作也都能維持這個(gè)速率對(duì)絕大多數(shù)工業(yè)信號(hào)振動(dòng)、電壓電流、壓力、聲音都?jí)蛴?。?nèi)置的PGA增益可編程1、2、4、8、16、32、64、128倍等于把前端儀表放大器的活也包了傳感器差分輸出可以直接接進(jìn)來(lái)省掉一級(jí)運(yùn)放。SPI接口最高20MHz實(shí)際布線不好時(shí)跑不到這個(gè)后面說(shuō)支持CRC數(shù)據(jù)校驗(yàn)還支持菊花鏈級(jí)聯(lián)多顆芯片擴(kuò)展通道數(shù)非常方便這在設(shè)計(jì)多通道同步采集板時(shí)是實(shí)打?qū)嵉膬?yōu)勢(shì)。適用場(chǎng)景我總結(jié)大概這三類電能質(zhì)量與功率計(jì)量特別是三相電壓電流同時(shí)采樣做功率計(jì)算四通道剛好對(duì)應(yīng)A/B/C三相電流加一路零序或電壓。多通道壓力/溫度/應(yīng)變采集大量程變化小需要高分辨率分辨微小變化比如稱重、氣壓計(jì)、光纖應(yīng)變等。便攜式精密儀器低功耗模式做得好單顆芯片功耗在毫瓦級(jí)適合電池供電的數(shù)據(jù)記錄儀。如果你只是做單通道、低速、精度要求不極高的采集這顆芯片會(huì)有點(diǎn)性能溢出成本上也劃不來(lái)。但如果你遇到的是“多通道、要同步、信號(hào)微弱、精度要求高”這組需求同時(shí)出現(xiàn)那它基本就是為該場(chǎng)景設(shè)計(jì)的。2. 驅(qū)動(dòng)開發(fā)前的硬件準(zhǔn)備與SPI時(shí)序分析2.1 引腳連接與供電去耦細(xì)節(jié)不少人拿到芯片直接寫代碼結(jié)果發(fā)現(xiàn)讀出來(lái)的數(shù)據(jù)亂七八糟第一反應(yīng)是調(diào)SPI時(shí)鐘和寄存器但很多時(shí)候問(wèn)題出在硬件連接和去耦上。ADS131M04的電源規(guī)劃值得單獨(dú)說(shuō)。AVDD和DVDD我建議各自獨(dú)立供電中間用電感或者磁珠隔離模擬地和數(shù)字地在ADC底下單點(diǎn)連接不要直接大面積覆銅連通。參考電壓REFOUT/REFIN引腳的去耦電容要按照數(shù)據(jù)手冊(cè)的位置放離芯片引腳盡量近我用的是1μF陶瓷電容并聯(lián)0.1μF高頻電容的組合。引腳連接上SPI四根線加一根DRDY中斷線基本就夠了。DRDY是數(shù)據(jù)就緒指示新數(shù)據(jù)準(zhǔn)備好時(shí)會(huì)拉低這個(gè)引腳對(duì)完整性要求很高不要和別的GPIO共享中斷最好接到MCU的EXTI引腳并打開內(nèi)部上拉。MISO、MOSI、SCLK、CS根據(jù)MCU的SPI外設(shè)映射接CS用普通GPIO控制完全沒(méi)問(wèn)題還方便做多片級(jí)聯(lián)時(shí)的片選管理。2.2 命令格式與數(shù)據(jù)幀結(jié)構(gòu)ADS131M04的SPI是命令-響應(yīng)機(jī)制。主機(jī)發(fā)送一串命令字節(jié)同時(shí)從MISO讀回對(duì)應(yīng)長(zhǎng)度的數(shù)據(jù)。寫寄存器命令格式大致是發(fā)送命令頭包含R/W標(biāo)志、起始寄存器地址、寄存器數(shù)量后面跟要寫入的數(shù)據(jù)讀寄存器類似命令頭后面接任意字節(jié)以產(chǎn)生時(shí)鐘數(shù)據(jù)從MISO返回。讀數(shù)據(jù)時(shí)要特別注意所有讀操作都會(huì)返回當(dāng)前已轉(zhuǎn)換好的通道數(shù)據(jù)即使你發(fā)送的是寄存器寫命令MISO上也會(huì)吐數(shù)據(jù)。所以驅(qū)動(dòng)里每條命令的響應(yīng)長(zhǎng)度要嚴(yán)格匹配否則下一幀的數(shù)據(jù)就對(duì)不齊了。數(shù)據(jù)幀結(jié)構(gòu)默認(rèn)是狀態(tài)字 四通道各24位數(shù)據(jù) CRC如果開啟的話。狀態(tài)字里有每通道的過(guò)載標(biāo)志這個(gè)強(qiáng)烈建議解析出來(lái)因?yàn)樗苤苯痈嬖V你是不是輸入超量程導(dǎo)致數(shù)據(jù)飽和了而不是只看到滿碼值。24位數(shù)據(jù)格式是二進(jìn)制補(bǔ)碼實(shí)際值等于原始碼除以8388608再乘以量程。2.3 用示波器先看波形再寫代碼寫驅(qū)動(dòng)前我做了一件事在MCU主頻和SPI速率都配置好后先用示波器抓SCLK、CS、MISO三根線確認(rèn)時(shí)序是空閑高還是空閑低采樣沿是上升沿還是下降沿。ADS131M04默認(rèn)SPI模式需要確認(rèn)CPOL、CPHA我的經(jīng)驗(yàn)是結(jié)合數(shù)據(jù)手冊(cè)時(shí)序圖核對(duì)好再初始化HAL或標(biāo)準(zhǔn)庫(kù)否則后續(xù)所有寄存器讀寫都是錯(cuò)的排查起來(lái)非常隱蔽。具體波形分析時(shí)重點(diǎn)看CS拉低后到第一個(gè)SCLK上升沿之間有沒(méi)有足夠時(shí)間讓ADC準(zhǔn)備總線片選拉低后建議加一小段延時(shí)至少幾百納秒。很多原廠示例代碼里沒(méi)注意這個(gè)實(shí)際接到某些MCU上就會(huì)偶發(fā)數(shù)據(jù)錯(cuò)位是因?yàn)镃S下降沿到SCLK第一個(gè)時(shí)鐘來(lái)的太快。HAL庫(kù)的SPI傳輸函數(shù)在使能CS后立即發(fā)數(shù)據(jù)正好踩這個(gè)坑所以我在驅(qū)動(dòng)里把CS控制拆出來(lái)先拉低、再延時(shí)、再啟動(dòng)SPI收發(fā)。3. 寄存器配置與初始化流程從零到能讀到數(shù)據(jù)3.1 初始化步驟的先后順序很關(guān)鍵ADS131M04初始化有個(gè)隱藏邏輯芯片上電后默認(rèn)狀態(tài)是復(fù)位狀態(tài)必須先把CLOCK寄存器配置好讓它從內(nèi)部振蕩器或外部時(shí)鐘切換到目標(biāo)采樣時(shí)鐘再配置ADC_EN使能通道最后配置PGA和數(shù)字濾波器。順序搞反了通道使能了但時(shí)鐘不對(duì)數(shù)據(jù)可能完全無(wú)效而且還不報(bào)錯(cuò)。我當(dāng)時(shí)就是先寫了通道配置再配時(shí)鐘結(jié)果數(shù)據(jù)跳得很離譜排查了半個(gè)下午。我整理了一套比較穩(wěn)的初始化順序拉高CSDRDY配置為輸入并等待芯片上電穩(wěn)定至少10ms。復(fù)位芯片發(fā)送RESET命令命令字節(jié)按照手冊(cè)定義等待至少1ms。配置CLOCK寄存器選擇采樣時(shí)鐘源、期望的采樣率。ADS131M04內(nèi)部有時(shí)鐘振蕩器使用內(nèi)部時(shí)鐘時(shí)要把寄存器對(duì)應(yīng)位配好。配置PGA與通道使能增益根據(jù)傳感器量程和ADC滿量程范圍來(lái)確定使能實(shí)際用到的通道。配置數(shù)字濾波器選擇低延遲或?qū)掝l帶FIR濾波器或IIR濾波這個(gè)根據(jù)實(shí)時(shí)性和噪聲要求取舍。執(zhí)行一次全局校準(zhǔn)如果使用內(nèi)部校準(zhǔn)功能適配JESD標(biāo)準(zhǔn)路徑時(shí)也推薦做一次。讀取各寄存器回讀驗(yàn)證一遍防止SPI時(shí)序錯(cuò)誤導(dǎo)致配置沒(méi)寫進(jìn)去。3.2 關(guān)鍵寄存器配置參考寄存器的具體地址和位定義一定要以官方數(shù)據(jù)手冊(cè)為準(zhǔn)我這里給一個(gè)工程中最常用的配置思路代碼實(shí)現(xiàn)時(shí)按位填充即可配置項(xiàng)說(shuō)明典型值CLOCK采樣時(shí)鐘分頻、時(shí)鐘源選擇內(nèi)部時(shí)鐘目標(biāo)采樣率4kSPSADC_EN使能四通道CH0-CH3全使能PGA各通道增益電壓通道1倍電流通道8倍或16倍FILTER濾波器模式、抽取率低延遲FIR抽取率對(duì)應(yīng)采樣率CRCCRC使能與多項(xiàng)式模式開啟CRC校驗(yàn)整個(gè)幀OFFSET_CAL/GAIN_CAL各通道校準(zhǔn)系數(shù)全局校準(zhǔn)時(shí)自動(dòng)寫入增益選擇有個(gè)計(jì)算技巧。ADS131M04滿量程輸入范圍大約±1.2V內(nèi)部參考不同增益下滿量程有變化傳感器的最大輸出除以PGA增益后要讓最大輸出幅度在滿量程的80%左右留有裕量防削波又不浪費(fèi)分辨率。例如傳感器最大輸出±100mV選4倍增益后變成±400mV距離滿量程1.2V還有很大裕量這時(shí)可以選8倍變成±800mV。千萬(wàn)不要選到128倍那會(huì)把傳感器噪聲和失調(diào)一起放大滿量程范圍又小信號(hào)稍微多點(diǎn)就飽和。3.3 一個(gè)能跑通的最小讀數(shù)據(jù)循環(huán)下面這段是HAL庫(kù)版本的簡(jiǎn)化示例核心思想是“阻塞式讀一幀”方便先驗(yàn)證硬件通路。實(shí)際項(xiàng)目可以改成DMA或中斷版本但第一版務(wù)必讓它簡(jiǎn)單到?jīng)]有隱藏邏輯。#define ADS131M04_CS_LOW() HAL_GPIO_WritePin(ADC_CS_GPIO_Port, ADC_CS_Pin, GPIO_PIN_RESET) #define ADS131M04_CS_HIGH() HAL_GPIO_WritePin(ADC_CS_GPIO_Port, ADC_CS_Pin, GPIO_PIN_SET) void ADS131M04_ReadData(uint32_t *ch_samples) { uint8_t tx_buf[4 4 * 3]; // 命令字 4通道×3字節(jié) uint8_t rx_buf[4 4 * 3]; memset(tx_buf, 0x00, sizeof(tx_buf)); // 發(fā)送NULL命令觸發(fā)一次數(shù)據(jù)讀取 ADS131M04_CS_LOW(); for (int i 0; i 4; i) asm(nop); // CS建立時(shí)間 HAL_SPI_TransmitReceive(hspi1, tx_buf, rx_buf, sizeof(tx_buf), 10); ADS131M04_CS_HIGH(); for (int ch 0; ch 4; ch) { uint8_t *p rx_buf[1 ch * 3]; // 跳過(guò)狀態(tài)字 int32_t raw (int32_t)((p[0] 16) | (p[1] 8) | p[2]); if (raw 0x800000) raw | 0xFF000000; // 24位轉(zhuǎn)32位有符號(hào)數(shù) ch_samples[ch] (uint32_t)raw; } }這段代碼里忽略了狀態(tài)字解析但工程版要檢查狀態(tài)字的過(guò)載位。另外要注意發(fā)送的tx_buf全部為0等于發(fā)的是NULL命令A(yù)DS131M04不允許在高位CS期間有任何未完成命令所以每次讀數(shù)據(jù)命令前不需要額外配置發(fā)一幀全0命令即可讀出當(dāng)前數(shù)據(jù)幀。4. 數(shù)據(jù)讀取、CRC校驗(yàn)與信號(hào)處理4.1 24位數(shù)據(jù)轉(zhuǎn)有符號(hào)整型的陷阱24位ADC輸出是二進(jìn)制補(bǔ)碼最高位是符號(hào)位。把三個(gè)字節(jié)拼成一個(gè)32位整數(shù)時(shí)如果是正數(shù)沒(méi)問(wèn)題負(fù)數(shù)就會(huì)被錯(cuò)誤地當(dāng)成一個(gè)很大的正數(shù)比如0xFFFFFF其實(shí)是-1但直接拼完變成16777215。所以轉(zhuǎn)換代碼里那句“如果符號(hào)位為1則把高8位全置1”是關(guān)鍵。我見(jiàn)過(guò)不少剛接觸24位ADC的同事栽在這里表象是數(shù)據(jù)在某一個(gè)閾值附近突然跳變實(shí)際就是符號(hào)擴(kuò)展處理出錯(cuò)。更好的做法是做一個(gè)通用函數(shù)用算術(shù)右移一次到位但工程上上面的寫法最容易理解。4.2 CRC校驗(yàn)是有代價(jià)的高收益選項(xiàng)開啟數(shù)據(jù)CRC后每一幀數(shù)據(jù)多一個(gè)16位CRC字段主控端需要實(shí)現(xiàn)對(duì)應(yīng)的CRC多項(xiàng)式計(jì)算。好處是SPI線上的毛刺、字節(jié)錯(cuò)位都能被檢測(cè)出來(lái)這對(duì)工業(yè)現(xiàn)場(chǎng)長(zhǎng)距離傳輸或電機(jī)驅(qū)動(dòng)器附近等強(qiáng)干擾環(huán)境是救命級(jí)功能。但我建議在開發(fā)階段先不開CRC把數(shù)據(jù)通路調(diào)通了再開否則一個(gè)SPI波形問(wèn)題和一個(gè)CRC算法問(wèn)題混在一起排查難度是指數(shù)級(jí)上升的。CRC計(jì)算方式基于多項(xiàng)式0x1021或0x8005具體查閱手冊(cè)但要注意計(jì)算范圍是包含狀態(tài)字、通道數(shù)據(jù)和CRC本身之前的字節(jié)。很多參考代碼會(huì)在CRC上踩坑我建議按字節(jié)查表法實(shí)現(xiàn)速度足夠快代碼也簡(jiǎn)潔。開CRC后幀長(zhǎng)會(huì)變化DMA接收長(zhǎng)度和環(huán)形緩沖區(qū)設(shè)計(jì)都要同步修改。4.3 濾波器選用和等效噪聲分析ADS131M04的數(shù)字濾波器選擇直接決定了數(shù)據(jù)質(zhì)量。芯片內(nèi)置三種濾波器低延遲FIR、寬頻FIR和IIR。我的經(jīng)驗(yàn)是如果需要實(shí)時(shí)性比如閉環(huán)控制選低延遲FIR如果追求低噪聲、響應(yīng)速度不敏感選寬頻FIR如果還嫌噪聲大可以在MCU端再疊加一個(gè)簡(jiǎn)單的滑動(dòng)平均濾波代碼里那類ADC值濾波函數(shù)在這里就有用武之地了。等效分辨率的概念值得多說(shuō)一句。24位是數(shù)字輸出位數(shù)但實(shí)際無(wú)噪聲分辨率受PGA增益、采樣率、參考電壓噪聲影響典型情況下能做到18到20位。你打開濾波器的抽取率越大采樣率越低等效噪聲越小。以我的項(xiàng)目為例PGA增益16、采樣率4kSPS、寬頻濾波下短接輸入后讀數(shù)的峰峰值大約在3到5個(gè)LSB也就是等效無(wú)噪聲分辨率約21位這個(gè)水平足夠做0.1%級(jí)的測(cè)量了。如果你讀出來(lái)的數(shù)據(jù)短接輸入時(shí)峰峰值都幾十上百個(gè)LSB大概率不是ADC不給力而是電源紋波或者PCB布局引入了噪聲。5. 實(shí)測(cè)量產(chǎn)中遇到的幾個(gè)典型坑5.1 電源和地線布局直接影響有效位數(shù)第一次打樣回來(lái)我做了一個(gè)“置信度測(cè)試”把四個(gè)通道輸入同時(shí)短接到AGND按4kSPS連續(xù)采了1萬(wàn)幀統(tǒng)計(jì)每通道數(shù)據(jù)的峰峰值和標(biāo)準(zhǔn)差。結(jié)果發(fā)現(xiàn)CH0和CH1噪聲很低CH2明顯偏高CH3最高。三個(gè)通道用的是同一顆ADC問(wèn)題一定出在PCB布局上。檢查后發(fā)現(xiàn)CH2和CH3的模擬輸入走線穿過(guò)了一個(gè)DC-DC電感的正下方開關(guān)噪聲被耦合進(jìn)了差分線。改版時(shí)把輸入走線繞開電感區(qū)域并把差分線間距拉開等長(zhǎng)走線CH2/CH3的噪聲立刻回到和CH0/CH1同一水平。這件事給我的教訓(xùn)是無(wú)論驅(qū)動(dòng)代碼寫得多好PCB布局上的一個(gè)疏忽會(huì)讓所有精度努力白費(fèi)。測(cè)量差分輸入時(shí)芯片內(nèi)部PGA對(duì)共模電壓有要求輸入信號(hào)不能完全懸空必須提供共模偏置通路。在傳感器是電橋或電流互感器這類本身就提供共模電壓的場(chǎng)景問(wèn)題不大但如果你直接接一個(gè)浮空熱電偶讀數(shù)會(huì)漂到懷疑人生。正確做法是在每個(gè)模擬輸入引腳對(duì)AGND各加一個(gè)1μF電容并且通過(guò)一個(gè)大電阻100kΩ級(jí)別建立共模參考點(diǎn)。5.2 DRDY邊沿和SPI傳輸?shù)臅r(shí)序競(jìng)爭(zhēng)DRDY引腳在數(shù)據(jù)準(zhǔn)備好時(shí)拉低主機(jī)可以在上升沿觸發(fā)中斷讀取。但有一個(gè)隱蔽問(wèn)題如果你在中斷里直接調(diào)用阻塞式SPI傳輸而SPI傳輸期間又有更高優(yōu)先級(jí)中斷插入剛好錯(cuò)過(guò)下一個(gè)DRDY周期那就會(huì)讀到新舊數(shù)據(jù)混幀。我在驅(qū)動(dòng)里用了一個(gè)簡(jiǎn)單的乒乓緩沖DRDY中斷只置一個(gè)標(biāo)志位并記錄時(shí)間戳主循環(huán)檢測(cè)到標(biāo)志后再執(zhí)行SPI讀取讀取完成后把數(shù)據(jù)放進(jìn)DMA環(huán)形緩沖區(qū)。這樣中斷耗時(shí)極短主循環(huán)讀取也永遠(yuǎn)不會(huì)和DRDY競(jìng)爭(zhēng)。如果是高速采樣大于8kSPS建議直接用SPI DMA傳輸并在DMA完成中斷里處理數(shù)據(jù)。HAL庫(kù)里要注意DMA接收長(zhǎng)度必須和幀長(zhǎng)嚴(yán)格匹配否則尾部會(huì)殘留上一幀數(shù)據(jù)。我把幀長(zhǎng)定義為一個(gè)宏所有DMA配置和緩沖計(jì)算都引用它改配置時(shí)只改一處這樣能少踩很多坑。5.3 多片級(jí)聯(lián)時(shí)CS管理和數(shù)據(jù)對(duì)齊問(wèn)題當(dāng)項(xiàng)目需要8通道、16通道時(shí)兩顆或四顆ADS131M04做菊花鏈級(jí)聯(lián)非常方便。級(jí)聯(lián)模式下所有芯片共用SCLK、MOSI、MISO每顆芯片把數(shù)據(jù)從它的DOUT引腳轉(zhuǎn)發(fā)到下一顆的DIN一次SPI讀取就能拿到所有芯片的數(shù)據(jù)。但這個(gè)模式下最強(qiáng)的坑是字節(jié)對(duì)齊主機(jī)必須一次讀完所有芯片的數(shù)據(jù)幀總長(zhǎng)度中間不能片選拉高否則數(shù)據(jù)錯(cuò)位。我的做法是固定初始化順序先配置所有芯片為級(jí)聯(lián)模式再對(duì)每顆芯片單獨(dú)寫配置CS單獨(dú)控制最后才進(jìn)入級(jí)聯(lián)讀取模式讀取全部數(shù)據(jù)。級(jí)聯(lián)讀取時(shí)所有CS接到同一個(gè)GPIO上一次拉低、一次性發(fā)送總幀長(zhǎng)個(gè)字節(jié)。級(jí)聯(lián)讀取還有一個(gè)細(xì)節(jié)每顆芯片在級(jí)聯(lián)模式下會(huì)把當(dāng)前通道數(shù)據(jù)放進(jìn)幀里第一顆芯片的數(shù)據(jù)在幀的末尾最后一顆在最前面。也就是反向時(shí)序別按物理連接順序去解析否則通道標(biāo)識(shí)會(huì)全亂。我在解析循環(huán)里加了一個(gè)REVERSE_ORDER宏定義了數(shù)據(jù)排列順序調(diào)試時(shí)對(duì)比已知參考電壓一眼就能看到有沒(méi)有反。5.4 采樣率配置與實(shí)際輸出不符的檢查思路癥狀是數(shù)據(jù)有意義但頻率完全不對(duì)正弦波信號(hào)讀出來(lái)頻率是設(shè)置值的一半或者四分之一。通常原因有兩類一是CLOCK寄存器里的分頻系數(shù)理解錯(cuò)誤沒(méi)有按手冊(cè)里的計(jì)算公式核實(shí)實(shí)際采樣率二是數(shù)字濾波器的抽取率配置后輸出數(shù)據(jù)率是調(diào)制器時(shí)鐘除以抽取率而不是調(diào)制器時(shí)鐘本身。檢查時(shí)往輸入端加一個(gè)1kHz正弦波采集一段數(shù)據(jù)做FFT看頻譜峰值位置是否正確這個(gè)方法能快速定位采樣率配置錯(cuò)誤。如果FFT峰值出現(xiàn)在預(yù)期位置附近但有明顯歪斜一般是PGA增益設(shè)置導(dǎo)致削波或者信號(hào)源阻抗太高需要分別排查。另外多通道同時(shí)采樣時(shí)如果要驗(yàn)證通道間同步性可以把同一個(gè)正弦波同時(shí)接到兩個(gè)通道讀取后做互相關(guān)相位差應(yīng)該接近零。這個(gè)測(cè)試對(duì)電能計(jì)量場(chǎng)景尤其重要我曾經(jīng)就遇到一個(gè)案例兩顆芯片級(jí)聯(lián)后CH0和CH4的相位差有0.3度排查了半天發(fā)現(xiàn)是其中一顆芯片的時(shí)鐘源選擇了外部晶體而另一顆用了內(nèi)部振蕩器頻率偏移導(dǎo)致相位緩慢漂移。同一塊板子上所有ADC芯片的時(shí)鐘源必須統(tǒng)一否則同步性無(wú)從談起。最后再分享一個(gè)調(diào)試習(xí)慣每次修改寄存器配置后都做一次回歸測(cè)試——把某個(gè)通道短接到GND讀1000幀看均值是不是在0附近偏離不大且比較穩(wěn)定把某個(gè)通道接一個(gè)穩(wěn)定的2.5V參考電壓看讀數(shù)是否在期望值附近。兩個(gè)測(cè)試都過(guò)了再動(dòng)下一項(xiàng)配置。ADC驅(qū)動(dòng)這種東西最怕的就是一次改多個(gè)參數(shù)出問(wèn)題根本不知道是哪一步導(dǎo)致的。ADS131M04的驅(qū)動(dòng)源碼本質(zhì)上不難難點(diǎn)全在“確認(rèn)每一步確實(shí)按預(yù)期工作”的驗(yàn)證方法上這套方法建立起來(lái)之后不管是換MCU還是加通道數(shù)基本都是一兩個(gè)小時(shí)就能搞定的事情。本文還有配套的精品資源點(diǎn)擊獲取