實(shí)戰(zhàn):從原理到代碼實(shí)現(xiàn))
1. 項(xiàng)目概述為什么GD32H75E的ADC值得深挖最近在做一個(gè)高精度數(shù)據(jù)采集的項(xiàng)目主控選型時(shí)盯上了兆易創(chuàng)新的GD32H75E。這顆基于Cortex-M7內(nèi)核的MCU性能參數(shù)很亮眼但真正讓我下決心用它還是因?yàn)槠鋬?nèi)置的ADC模塊。官方手冊里關(guān)于“同步模式”和“過采樣技術(shù)”的描述讓我覺得這不僅僅是又一個(gè)普通的模數(shù)轉(zhuǎn)換器而是為高性能實(shí)時(shí)信號(hào)處理量身打造的工具。在實(shí)際調(diào)通整個(gè)采集鏈路后我發(fā)現(xiàn)這里面門道不少從最基礎(chǔ)的通道配置、時(shí)鐘樹對齊到高級(jí)的同步觸發(fā)與過采樣降噪每一步都有需要注意的細(xì)節(jié)。這篇文章我就把自己從零開始折騰GD32H75E ADC的全過程包括踩過的坑和總結(jié)出的最佳實(shí)踐系統(tǒng)地梳理一遍。無論你是剛接觸GD32H75E還是正在為多通道同步采樣或提高分辨率發(fā)愁希望這些一手經(jīng)驗(yàn)?zāi)軒湍闵僮邚澛贰?. 核心模塊解析與設(shè)計(jì)思路2.1 ADC模塊架構(gòu)總覽與核心特性GD32H75E系列通常集成了多個(gè)ADC模塊具體數(shù)量需查閱對應(yīng)型號(hào)的數(shù)據(jù)手冊常見為2到3個(gè)獨(dú)立的ADC單元。每個(gè)ADC核心都是12位逐次逼近型SAR架構(gòu)但它的設(shè)計(jì)思路明顯偏向于滿足電機(jī)控制、數(shù)字電源、高端傳感器融合等復(fù)雜應(yīng)用場景。其核心特性可以概括為幾個(gè)方面首先是采樣速率在高速時(shí)鐘驅(qū)動(dòng)下單次轉(zhuǎn)換時(shí)間可以做得非常短這對于捕獲快速變化的信號(hào)至關(guān)重要。其次是多通道支持每個(gè)ADC通常有16個(gè)以上的外部模擬通道可以通過掃描模式依次轉(zhuǎn)換。但最吸引人的是硬件同步機(jī)制多個(gè)ADC單元可以在一個(gè)主觸發(fā)信號(hào)如定時(shí)器事件的驅(qū)動(dòng)下同時(shí)開始對各自指定的通道進(jìn)行采樣轉(zhuǎn)換這對于需要嚴(yán)格相位對齊的多路信號(hào)如三相電流測量是基礎(chǔ)保障。最后是過采樣與硬件平均功能它允許ADC在硬件層面進(jìn)行多次采樣并累加平均從而將有效分辨率提升到12位以上如16位同時(shí)抑制高頻噪聲這個(gè)功能如果軟件實(shí)現(xiàn)會(huì)消耗大量CPU時(shí)間而硬件實(shí)現(xiàn)則幾乎零開銷。我的設(shè)計(jì)思路是構(gòu)建一個(gè)雙ADC同步采樣系統(tǒng)ADC0和ADC1分別采集兩路相關(guān)的模擬信號(hào)例如一個(gè)采集電壓一個(gè)采集電流并利用過采樣技術(shù)將有效分辨率提升到16位最終通過DMA將數(shù)據(jù)搬運(yùn)到內(nèi)存中進(jìn)行實(shí)時(shí)處理。這個(gè)方案的關(guān)鍵在于精確的時(shí)序控制和資源配置。2.2 時(shí)鐘樹配置一切精度的起點(diǎn)ADC的精度和速度基石是時(shí)鐘。GD32H75E的ADC時(shí)鐘ADCCLK通常由高速的AHB時(shí)鐘HCLK經(jīng)過一個(gè)可編程的分頻器得到。這里第一個(gè)容易踩坑的點(diǎn)就出現(xiàn)了ADC時(shí)鐘頻率必須嚴(yán)格控制在數(shù)據(jù)手冊規(guī)定的范圍內(nèi)例如最大頻率可能是40MHz或60MHz具體需查證。超頻運(yùn)行會(huì)導(dǎo)致線性度下降、轉(zhuǎn)換結(jié)果不可靠。我的配置步驟如下首先確保系統(tǒng)時(shí)鐘SYSCLK和AHB時(shí)鐘HCLK已正確初始化。然后找到ADC的時(shí)鐘控制寄存器通常在RCU模塊中。假設(shè)HCLK為200MHz而ADC最大允許時(shí)鐘為40MHz那么分頻系數(shù)至少需要設(shè)置為5200/405。在代碼中這通常對應(yīng)設(shè)置一個(gè)預(yù)分頻器位域。注意分頻系數(shù)最好設(shè)置為2的整數(shù)次冪如2, 4, 8, 16。這是因?yàn)锳DC內(nèi)部的某些時(shí)序邏輯可能與時(shí)鐘邊沿對齊非2的冪次分頻可能導(dǎo)致微妙的時(shí)序抖動(dòng)在極高精度要求下會(huì)引入誤差。我通常選擇讓ADCCLK運(yùn)行在允許范圍內(nèi)的較低頻率如30MHz以換取更好的穩(wěn)定性和更低的功耗。此外ADC模塊還有一個(gè)獨(dú)立的“采樣保持時(shí)間”時(shí)鐘源用于控制對輸入信號(hào)電容充電的時(shí)間。這個(gè)時(shí)間必須足夠長以確保信號(hào)在采樣期間穩(wěn)定到所需的精度水平。時(shí)間長短與信號(hào)源內(nèi)阻和ADC輸入電容有關(guān)手冊會(huì)給出計(jì)算公式。對于內(nèi)阻較大的傳感器需要適當(dāng)延長這個(gè)時(shí)間。2.3 通道與掃描序列規(guī)劃GD32H75E的每個(gè)ADC都有多個(gè)規(guī)則通道Regular Channel和注入通道Injected Channel。規(guī)則通道用于常規(guī)的、按順序的掃描采樣而注入通道可以“插隊(duì)”在任何時(shí)候由特定觸發(fā)信號(hào)啟動(dòng)中斷當(dāng)前的規(guī)則轉(zhuǎn)換序列具有更高的優(yōu)先級(jí)。在我的同步采樣設(shè)計(jì)中我使用規(guī)則通道組。需要為ADC0和ADC1分別規(guī)劃要采樣的通道。例如ADC0規(guī)則序列通道5溫度傳感器通道11直流母線電壓。ADC1規(guī)則序列通道1A相電流通道2B相電流。規(guī)劃好后需要通過寄存器設(shè)置每個(gè)ADC的規(guī)則序列寄存器SQR定義轉(zhuǎn)換的總通道數(shù)和每個(gè)位置對應(yīng)的通道編號(hào)。這里需要注意的是規(guī)則通道的轉(zhuǎn)換順序嚴(yán)格按照SQR寄存器中定義的序列進(jìn)行。同時(shí)要啟用掃描模式SCAN位讓ADC自動(dòng)按序列轉(zhuǎn)換。實(shí)操心得在規(guī)劃序列時(shí)將轉(zhuǎn)換時(shí)間相近或需要同時(shí)關(guān)注的通道放在相鄰的序列位置有時(shí)可以簡化后續(xù)的數(shù)據(jù)處理邏輯。例如把三相電流的三個(gè)通道連續(xù)排列DMA搬運(yùn)到內(nèi)存后數(shù)據(jù)在數(shù)組里也是連續(xù)的便于進(jìn)行Park/Clarke變換等矩陣運(yùn)算。3. 同步采樣模式深度配置3.1 同步觸發(fā)源與主從模式設(shè)置同步采樣的精髓在于“同時(shí)開始”。GD32H75E的多個(gè)ADC可以工作在主從模式。通常選擇一個(gè)ADC作為主單元Master另一個(gè)或多個(gè)作為從單元Slave。主ADC的轉(zhuǎn)換啟動(dòng)事件會(huì)通過內(nèi)部硬件連線同步觸發(fā)所有從ADC。最常用且精準(zhǔn)的觸發(fā)源是高級(jí)定時(shí)器如TIMER0的捕獲/比較事件。配置步驟如下配置定時(shí)器初始化一個(gè)定時(shí)器設(shè)置其更新UEV或某個(gè)通道比較CCx事件作為觸發(fā)輸出TRGO。例如配置TIMER0每100us產(chǎn)生一次更新事件。配置主ADC的觸發(fā)源將主ADC例如ADC0的轉(zhuǎn)換觸發(fā)方式設(shè)置為“外部觸發(fā)”并選擇觸發(fā)源為對應(yīng)的定時(shí)器事件如EXTTRIG_EDGE_TIMER0_TRGO。配置從ADC的觸發(fā)源與同步模式將從ADC例如ADC1的觸發(fā)源也設(shè)置為同一個(gè)外部事件。關(guān)鍵在于需要啟用ADC的“同步模式”控制位例如SYNCMODE位并設(shè)置為“從模式”使其等待主ADC的硬件同步信號(hào)。使能觸發(fā)確保兩個(gè)ADC的“外部觸發(fā)使能”位都已打開。這樣每當(dāng)定時(shí)器事件到來主ADC0啟動(dòng)轉(zhuǎn)換的同時(shí)會(huì)立即發(fā)送一個(gè)同步脈沖給ADC1ADC1在接收到脈沖后也立即啟動(dòng)轉(zhuǎn)換。理論上兩個(gè)ADC的采樣保持動(dòng)作開始的時(shí)刻差異在納秒級(jí)滿足了同步性要求。3.2 同步時(shí)序細(xì)節(jié)與延遲補(bǔ)償盡管是硬件同步但細(xì)微的延遲仍然存在主要來源于ADC內(nèi)部模擬電路的路徑差異和數(shù)字邏輯的傳播延遲。對于大多數(shù)應(yīng)用這種延遲可以忽略。但在要求極端相位對齊如功率分析時(shí)需要考慮補(bǔ)償。GD32H75E的數(shù)據(jù)手冊中可能會(huì)提供一個(gè)參數(shù)稱為“同步延遲”或“觸發(fā)到采樣啟動(dòng)延遲”。這是一個(gè)固定值通常很小。更重要的實(shí)踐是確保兩個(gè)ADC的配置完全對稱使用相同的ADCCLK頻率和分頻系數(shù)。設(shè)置相同的采樣保持時(shí)間。如果可能使用相同類型的通道例如都使用規(guī)則通道組且序列長度相同。有時(shí)為了補(bǔ)償已知的固定延遲可以故意將從ADC的觸發(fā)極性設(shè)置為“上升沿”而主ADC設(shè)置為“下降沿”或者利用定時(shí)器產(chǎn)生略有錯(cuò)位的兩個(gè)脈沖分別觸發(fā)但這需要精確測量和反復(fù)調(diào)試屬于高階技巧。注意事項(xiàng)避免在同步轉(zhuǎn)換過程中頻繁切換ADC的配置如改變通道序列。最好在初始化階段就完成所有配置并在同步采樣期間保持穩(wěn)定。任何配置的更改都可能導(dǎo)致同步時(shí)序的短暫紊亂產(chǎn)生無效數(shù)據(jù)。3.3 DMA在同步采樣中的關(guān)鍵作用同步采樣會(huì)產(chǎn)生連續(xù)的數(shù)據(jù)流如果靠CPU中斷來讀取每個(gè)轉(zhuǎn)換結(jié)果開銷巨大且會(huì)引入不可控的抖動(dòng)破壞同步性。因此必須使用DMA。配置DMA的步驟外設(shè)到內(nèi)存模式每個(gè)ADC對應(yīng)一個(gè)DMA通道或請求流。將DMA源地址設(shè)置為ADC的規(guī)則數(shù)據(jù)寄存器如RDATA目標(biāo)地址設(shè)置為內(nèi)存中的一個(gè)數(shù)組如adc0_buffer[]。數(shù)據(jù)寬度與對齊外設(shè)和內(nèi)存的數(shù)據(jù)寬度都設(shè)置為半字16位因?yàn)?2位ADC結(jié)果通常右對齊存儲(chǔ)在16位寄存器中。循環(huán)模式與增量使能循環(huán)模式這樣當(dāng)DMA搬運(yùn)完設(shè)定的數(shù)據(jù)量后會(huì)自動(dòng)重置并等待下一輪數(shù)據(jù)。設(shè)置外設(shè)地址固定內(nèi)存地址遞增。數(shù)據(jù)數(shù)量設(shè)置DMA需要搬運(yùn)的數(shù)據(jù)數(shù)量NTRANS。這個(gè)數(shù)量等于每個(gè)ADC規(guī)則序列的長度。例如ADC0序列有2個(gè)通道那么NTRANS就設(shè)為2。DMA會(huì)在每次ADC轉(zhuǎn)換完成一個(gè)序列2個(gè)數(shù)據(jù)后自動(dòng)將這2個(gè)數(shù)據(jù)搬運(yùn)到內(nèi)存。雙緩沖技巧為了確保數(shù)據(jù)處理線程不會(huì)訪問正在被DMA寫入的內(nèi)存塊可以設(shè)置雙緩沖區(qū)。當(dāng)DMA寫滿緩沖區(qū)A時(shí)產(chǎn)生一個(gè)半傳輸完成或傳輸完成中斷在中斷服務(wù)程序中將數(shù)據(jù)處理的指針切換到緩沖區(qū)B同時(shí)DMA繼續(xù)向B或切換回A寫入。這樣可以實(shí)現(xiàn)無鎖、無丟失的數(shù)據(jù)流水線。4. 過采樣技術(shù)原理與實(shí)戰(zhàn)提升分辨率4.1 過采樣與噪聲整形的基本原理過采樣Oversampling是一種用采樣速率換取分辨率的信號(hào)處理技術(shù)。其核心原理基于一個(gè)假設(shè)ADC量化噪聲即由于有限分辨率產(chǎn)生的誤差是白噪聲并且在奈奎斯特帶寬內(nèi)均勻分布。如果我們以高于信號(hào)所需頻率Nyquist頻率的K倍進(jìn)行采樣那么量化噪聲的功率會(huì)分散到更寬的頻率范圍0 到 K*f_s/2。然后通過一個(gè)數(shù)字低通濾波器將信號(hào)帶寬以外的噪聲濾除再對數(shù)據(jù)進(jìn)行降采樣Decimation最終的有效分辨率就會(huì)提高。分辨率提升的公式為每增加4倍過采樣率有效分辨率提高1位。例如一個(gè)12位ADC進(jìn)行16倍4^2過采樣并處理后理論上可以得到14位有效分辨率進(jìn)行256倍4^4過采樣理論上可以得到16位有效分辨率。GD32H75E的硬件過采樣單元就是將“多次采樣累加”和“右移即降采樣”這兩個(gè)最耗CPU的操作用硬件實(shí)現(xiàn)了。你只需要配置過采樣倍數(shù)和右移位數(shù)硬件就會(huì)自動(dòng)完成N次采樣、累加、求平均通過右移實(shí)現(xiàn)并輸出一個(gè)結(jié)果大大減輕了CPU負(fù)擔(dān)。4.2 硬件過采樣寄存器配置詳解配置硬件過采樣主要涉及幾個(gè)寄存器過采樣使能位OVSEN置1以啟用硬件過采樣模式。過采樣倍數(shù)OVSS選擇過采樣率通常是2, 4, 8, 16, 32, 64, 128, 256倍可選。例如選擇OVSS[2:0] 4代表16倍過采樣。右移位數(shù)OVSR這個(gè)配置決定了如何從累加和得到最終結(jié)果。它實(shí)際上等價(jià)于除以2^OVSR。為了得到正確的平均值右移位數(shù)OVSR必須滿足2^OVSR 過采樣倍數(shù)OVSS。例如16倍過采樣OVSS4那么右移位數(shù)應(yīng)為4因?yàn)?^416。這樣硬件將16次采樣值累加后右移4位就得到了算術(shù)平均值。過采樣分辨率模式OVSMD有些ADC提供“常規(guī)模式”和“高分辨率模式”。高分辨率模式下ADC會(huì)進(jìn)行更多位的內(nèi)部累加防止在累加大量數(shù)據(jù)時(shí)溢出適合超高倍數(shù)的過采樣。配置示例目標(biāo)是將12位ADC提升至16位有效分辨率。需要256倍過采樣。那么設(shè)置OVSS為8代表256倍OVSR為8右移8位即除以256。這樣ADC硬件會(huì)自動(dòng)對每個(gè)通道進(jìn)行256次轉(zhuǎn)換將256個(gè)12位結(jié)果累加成一個(gè)20位12位 log2(256)8位的中間值然后右移8位最終輸出一個(gè)12位的“平均值”。但這個(gè)12位數(shù)值的噪聲遠(yuǎn)低于原始12位數(shù)據(jù)其有效位數(shù)ENOB接近16位。重要提示過采樣能抑制的是帶寬內(nèi)的隨機(jī)白噪聲如熱噪聲對于固定的偏移誤差Offset或增益誤差Gain Error是無效的。因此在使用過采樣前務(wù)必先進(jìn)行ADC的校準(zhǔn)消除固有的直流誤差。4.3 過采樣模式下的時(shí)序與性能權(quán)衡啟用過采樣后最直接的影響是單次轉(zhuǎn)換時(shí)間變長。因?yàn)橛布枰B續(xù)進(jìn)行N次采樣轉(zhuǎn)換。總轉(zhuǎn)換時(shí)間 ≈ 單次轉(zhuǎn)換時(shí)間 × 過采樣倍數(shù)。例如單次轉(zhuǎn)換時(shí)間為1us啟用256倍過采樣后得到一個(gè)有效數(shù)據(jù)點(diǎn)的周期就變成了256us等效采樣率從1MHz下降到了約3.9kHz。這是一個(gè)巨大的代價(jià)。因此過采樣技術(shù)的應(yīng)用場景非常明確用于轉(zhuǎn)換低頻或直流信號(hào)以極高的精度測量其幅度。比如測量溫度、壓力、慢變電壓、高精度電池電量檢測等。對于音頻信號(hào)或電機(jī)控制中的快速電流環(huán)過采樣通常不適用因?yàn)闀?huì)嚴(yán)重限制帶寬。在同步采樣模式下使用過采樣需要特別注意兩個(gè)ADC的過采樣配置倍數(shù)、右移必須完全相同否則它們輸出數(shù)據(jù)率的時(shí)序會(huì)錯(cuò)位導(dǎo)致后續(xù)數(shù)據(jù)處理無法對齊。同時(shí)觸發(fā)定時(shí)器的周期也要相應(yīng)調(diào)整必須大于等于ADC完成一次過采樣轉(zhuǎn)換所需的總時(shí)間。5. 完整代碼實(shí)現(xiàn)與配置流程5.1 系統(tǒng)初始化與ADC校準(zhǔn)任何高精度ADC應(yīng)用的第一步都是校準(zhǔn)。GD32H75E的ADC通常支持內(nèi)部自校準(zhǔn)功能用于修正電容陣列的誤差。// 偽代碼示例基于標(biāo)準(zhǔn)外設(shè)庫風(fēng)格 void ADC_Calibration(ADC_TypeDef* ADCx) { // 1. 確保ADC處于禁用狀態(tài)且穩(wěn)定 ADC_DISABLE(ADCx); delay_ms(1); // 2. 設(shè)置校準(zhǔn)模式通常為單端輸入校準(zhǔn) ADC_CALIBRATION_MODE_CONFIG(ADCx, ADC_CALIBRATION_SINGLE_ENDED); // 3. 啟動(dòng)校準(zhǔn) ADC_CALIBRATION_ENABLE(ADCx); // 4. 等待校準(zhǔn)完成 while(ADC_CALIBRATION_STATUS_GET(ADCx)); // 5. 可選讀取校準(zhǔn)因子并存儲(chǔ)用于后續(xù)軟件補(bǔ)償 // uint32_t calib_factor ADC_CALIBRATION_FACTOR_GET(ADCx); }系統(tǒng)時(shí)鐘初始化、GPIO將對應(yīng)引腳配置為模擬輸入模式和DMA的初始化在此省略這些都是標(biāo)準(zhǔn)操作。重點(diǎn)是校準(zhǔn)必須在ADC其他功能配置之前進(jìn)行且供電電壓穩(wěn)定。5.2 雙ADC同步與過采樣配置代碼以下是配置ADC0為主、ADC1為從并進(jìn)行16倍過采樣的核心代碼片段// 1. 配置ADC通用控制寄存器適用于所有ADC單元 // 設(shè)置ADCCLK分頻假設(shè)HCLK200MHz目標(biāo)ADCCLK25MHz RCU_CFG1 | RCU_CFG1_ADCPSC_8; // 8分頻200/825MHz // 2. 配置ADC0主 ADC_CTL0(ADC0) 0; // 先清零 ADC_CTL0(ADC0) | ADC_CTL0_ADCON; // 使能ADC // 設(shè)置掃描模式、連續(xù)轉(zhuǎn)換由外部觸發(fā)控制啟停 ADC_CTL0(ADC0) | ADC_CTL0_SCAN | ADC_CTL0_CONTINUOUS; // 配置外部觸發(fā)源為TIMER0的TRGO事件上升沿觸發(fā) ADC_CTL1(ADC0) | ADC_EXTTRIG_REGULAR_TIMER0_TRGO | ADC_CTL1_ETSRC; ADC_CTL1(ADC0) | ADC_CTL1_ETERC; // 使能外部觸發(fā) // 配置規(guī)則通道序列2個(gè)通道CH5, CH11 ADC_RSQ0(ADC0) (1 20); // 規(guī)則序列長度2 (RL[3:0]1表示2個(gè)轉(zhuǎn)換) ADC_RSQ2(ADC0) (5 0); // 序列第1個(gè)CH5 ADC_RSQ2(ADC0) | (11 5); // 序列第2個(gè)CH11 // 配置過采樣16倍右移4位 ADC_OVSAMPCTL(ADC0) | ADC_OVSAMPCTL_OVSEN; // 使能過采樣 ADC_OVSAMPCTL(ADC0) | (4 ADC_OVSAMPCTL_OVSS_OFFSET); // OVSS4 (16x) ADC_OVSAMPCTL(ADC0) | (4 ADC_OVSAMPCTL_OVSR_OFFSET); // OVSR4 (右移4位) // 3. 配置ADC1從 ADC_CTL0(ADC1) | ADC_CTL0_ADCON; ADC_CTL0(ADC1) | ADC_CTL0_SCAN | ADC_CTL0_CONTINUOUS; // 關(guān)鍵觸發(fā)源選擇與主ADC相同但工作模式設(shè)置為從同步模式 ADC_CTL1(ADC1) | ADC_EXTTRIG_REGULAR_TIMER0_TRGO | ADC_CTL1_ETSRC; ADC_CTL1(ADC1) | ADC_CTL1_ETERC; ADC_CTL1(ADC1) | ADC_CTL1_SYNCM; // 設(shè)置為同步模式從模式 // 規(guī)則通道序列CH1, CH2 ADC_RSQ0(ADC1) (1 20); // RL1 (2 conversions) ADC_RSQ2(ADC1) (1 0) | (2 5); // 過采樣配置必須與主ADC一致 ADC_OVSAMPCTL(ADC1) | ADC_OVSAMPCTL_OVSEN; ADC_OVSAMPCTL(ADC1) | (4 ADC_OVSAMPCTL_OVSS_OFFSET); ADC_OVSAMPCTL(ADC1) | (4 ADC_OVSAMPCTL_OVSR_OFFSET); // 4. 配置DMA for ADC0 ADC1 // 此處省略詳細(xì)的DMA初始化代碼重點(diǎn) // - 外設(shè)地址ADC_RDATA(ADC0) 和 ADC_RDATA(ADC1) // - 內(nèi)存地址各自的數(shù)據(jù)緩沖區(qū) // - 數(shù)據(jù)寬度半字16位 // - 循環(huán)模式外設(shè)地址固定內(nèi)存地址遞增 // - 數(shù)據(jù)數(shù)量2對應(yīng)規(guī)則序列長度 // 5. 使能ADC的DMA請求 ADC_CTL1(ADC0) | ADC_CTL1_DMA; ADC_CTL1(ADC1) | ADC_CTL1_DMA; // 6. 配置觸發(fā)定時(shí)器TIMER0 // 產(chǎn)生一個(gè)100us周期的更新事件作為TRGO TIMER_CAR(TIMER0) SystemCoreClock / 10000 - 1; // 10kHz - 100us TIMER_CTL0(TIMER0) | TIMER_CTL0_UPEN; // 使能更新事件 TIMER_CTL1(TIMER0) | TIMER_CTL1_MMC(0x20); // 選擇更新事件作為TRGO // 7. 最后使能定時(shí)器ADC開始等待觸發(fā) TIMER_CTL0(TIMER0) | TIMER_CTL0_CEN;5.3 數(shù)據(jù)讀取與處理流程配置完成后ADC會(huì)在每個(gè)定時(shí)器周期同步轉(zhuǎn)換DMA自動(dòng)將數(shù)據(jù)搬運(yùn)到指定數(shù)組。假設(shè)我們定義了雙緩沖區(qū)#define BUFFER_SIZE 2 volatile uint16_t adc0_buf_A[BUFFER_SIZE]; volatile uint16_t adc0_buf_B[BUFFER_SIZE]; volatile uint16_t adc1_buf_A[BUFFER_SIZE]; volatile uint16_t adc1_buf_B[BUFFER_SIZE]; volatile uint16_t *adc0_active_buf adc0_buf_A; volatile uint16_t *adc1_active_buf adc1_buf_A; volatile uint8_t buffer_ready 0;在DMA的半傳輸完成HT和傳輸完成TC中斷中切換活動(dòng)緩沖區(qū)指針并設(shè)置標(biāo)志位void DMA_ChannelX_IRQHandler(void) { if(DMA_INTF(DMAy, DMA_CHx) DMA_FLAG_HT) { // 半傳輸完成表示一個(gè)緩沖區(qū)已滿切換到另一個(gè) if(adc0_active_buf adc0_buf_A) { adc0_active_buf adc0_buf_B; adc1_active_buf adc1_buf_B; } else { adc0_active_buf adc0_buf_A; adc1_active_buf adc1_buf_A; } buffer_ready 1; // 通知主循環(huán)處理數(shù)據(jù) DMA_INTC(DMAy, DMA_CHx) | DMA_FLAG_HT; // 清除中斷標(biāo)志 } // ... 處理傳輸完成中斷如果需要 }主循環(huán)中檢測到buffer_ready標(biāo)志后即可處理非活動(dòng)緩沖區(qū)即剛被DMA寫滿的緩沖區(qū)中的數(shù)據(jù)。由于進(jìn)行了16倍過采樣此時(shí)adc0_buf_A[0]已經(jīng)是CH5信號(hào)16次采樣的平均值噪聲水平顯著降低。6. 調(diào)試技巧與常見問題排查6.1 同步性驗(yàn)證與診斷方法如何驗(yàn)證兩個(gè)ADC是否真正同步一個(gè)簡單的方法是讓它們采樣同一個(gè)直流電壓源。如果配置完全對稱且同步成功那么兩個(gè)ADC讀取到的數(shù)值應(yīng)該幾乎完全相同在1-2個(gè)LSB的誤差范圍內(nèi)。如果差值很大說明同步可能有問題。更嚴(yán)謹(jǐn)?shù)姆椒ㄊ怯靡粋€(gè)信號(hào)發(fā)生器產(chǎn)生一個(gè)方波同時(shí)輸入給兩個(gè)ADC的某個(gè)通道。用邏輯分析儀或示波器探測ADC的“轉(zhuǎn)換結(jié)束”EOC信號(hào)引腳如果MCU引出的話或者探測一個(gè)在EOC中斷中翻轉(zhuǎn)的GPIO。觀察兩個(gè)ADC的EOC信號(hào)是否同時(shí)出現(xiàn)。如果時(shí)間差在一個(gè)ADCCLK周期內(nèi)可以認(rèn)為是良好的同步。如果發(fā)現(xiàn)不同步檢查以下方面時(shí)鐘一致性確認(rèn)兩個(gè)ADC的ADCCLK來源和分頻設(shè)置完全一致。觸發(fā)源確認(rèn)主從ADC的觸發(fā)源選擇寄存器位是完全相同的編碼。同步模式位確認(rèn)從ADC的同步模式SYNCM已正確使能。軟件啟動(dòng)干擾確保沒有在循環(huán)中調(diào)用ADC_SOFTWARE_START_ENABLE這類函數(shù)它會(huì)覆蓋硬件觸發(fā)。6.2 過采樣效果不佳的可能原因過采樣后發(fā)現(xiàn)噪聲并沒有明顯降低或者有效位數(shù)提升不理想。可能的原因有噪聲非白噪聲過采樣對周期性噪聲如電源紋波或與采樣時(shí)鐘相關(guān)的噪聲抑制效果有限。需要先優(yōu)化硬件如加強(qiáng)電源濾波、使用屏蔽、在信號(hào)輸入端加入RC低通濾波器抗混疊濾波。采樣保持時(shí)間不足如果信號(hào)源內(nèi)阻較大ADC的采樣電容沒有足夠的時(shí)間充電到穩(wěn)定值每次采樣本身就有誤差過采樣只是平均了這些誤差無法提升精度。需要增加ADC采樣周期寄存器SMPT的值。校準(zhǔn)未做或不準(zhǔn)偏移和增益誤差會(huì)直接帶入過采樣結(jié)果。務(wù)必在初始化和溫度變化較大時(shí)執(zhí)行校準(zhǔn)。累加溢出在極高倍數(shù)過采樣時(shí)硬件累加器可能溢出。確保使能了“高分辨率模式”如果支持或者降低過采樣倍數(shù)。數(shù)字濾波不匹配硬件過采樣內(nèi)置的是簡單的移動(dòng)平均累加后右移。對于特定噪聲譜可能需要更復(fù)雜的數(shù)字濾波器如FIR進(jìn)行后處理。可以在MCU內(nèi)對過采樣后的數(shù)據(jù)流再進(jìn)行一次軟件濾波。6.3 DMA數(shù)據(jù)錯(cuò)位與緩沖區(qū)管理陷阱這是多通道同步采樣中最常見的問題?,F(xiàn)象是數(shù)據(jù)緩沖區(qū)中的通道順序混亂或者ADC0和ADC1的數(shù)據(jù)無法對應(yīng)。排查清單規(guī)則序列寄存器SQR配置反復(fù)核對ADC_RSQ2、ADC_RSQ1等寄存器確保通道編號(hào)和順序與預(yù)期完全一致。一個(gè)常見的錯(cuò)誤是忽略了寄存器中位域的位置。DMA傳輸數(shù)量NTRANS這個(gè)值必須等于規(guī)則序列轉(zhuǎn)換的通道總數(shù)。如果設(shè)為1DMA只搬運(yùn)第一個(gè)通道的數(shù)據(jù)后就停止了后續(xù)通道數(shù)據(jù)會(huì)丟失或覆蓋。內(nèi)存緩沖區(qū)對齊確保為每個(gè)ADC分配的緩沖區(qū)大小足夠容納一次完整掃描的所有數(shù)據(jù)。如果ADC0有2個(gè)通道DMA設(shè)置為傳輸2個(gè)半字那么緩沖區(qū)至少需要uint16_t buf[2]。數(shù)據(jù)對齊方式ADC數(shù)據(jù)可能是左對齊或右對齊。GD32H75E通常是右對齊。DMA搬運(yùn)時(shí)目標(biāo)內(nèi)存是uint16_t類型直接存儲(chǔ)即可。但在進(jìn)行數(shù)值計(jì)算時(shí)如果需要完整的12位數(shù)據(jù)可能需要將讀取的16位數(shù)右移4位如果結(jié)果是左對齊格式則需查手冊確認(rèn)。雙緩沖區(qū)指針管理在DMA中斷中切換緩沖區(qū)指針時(shí)務(wù)必確保操作是原子的或者中斷優(yōu)先級(jí)足夠高不會(huì)被其他中斷打斷防止指針在切換過程中被主程序訪問導(dǎo)致數(shù)據(jù)錯(cuò)亂。使用volatile關(guān)鍵字聲明緩沖區(qū)指針和標(biāo)志位是必須的。調(diào)試時(shí)可以先將過采樣倍數(shù)設(shè)為1即關(guān)閉過采樣用較低的采樣率在DMA完成中斷里通過串口打印出原始數(shù)據(jù)人工檢查每個(gè)通道的數(shù)據(jù)是否按預(yù)期順序出現(xiàn)數(shù)值是否合理。這是驗(yàn)證ADC基礎(chǔ)配置和DMA鏈路是否正常的最直接方法。