據(jù)流追蹤:從傳感器到屏幕的完整旅程)
www.z-linear.com一個(gè)ADC采樣值從傳感器到上位機(jī)屏幕顯示需要經(jīng)過(guò)AD7606采集→FPGA緩沖→QSPI四線傳輸→DMA搬運(yùn)→雙緩沖打包→CRC校驗(yàn)→USB發(fā)送→C#解析→ScottPlot繪制。本文追蹤一個(gè)數(shù)據(jù)點(diǎn)的完整旅程。一、全鏈路全景圖傳感器 ──→ 信號(hào)調(diào)理 ──→ AD7606 ──→ FPGA FIFO ──→ QSPI四線 ──→ DMA ──→ 雙緩沖 ① ② ③ ④ ⑤ ⑥ ⑦ 雙緩沖 ──→ 幀打包 ──→ CRC16 ──→ USB CDC ──→ C#接收 ──→ 幀解析 ──→ ScottPlot ⑦ ⑧ ⑨ ⑩ ? ? ?二、階段①②傳感器與信號(hào)調(diào)理2.1 傳感器輸出溫度傳感器 Pt100 → 4-20mA變送器 → 240Ω取樣電阻 → 0.96~4.8V電壓參數(shù)值說(shuō)明傳感器類型Pt100 變送器溫度→電流輸出范圍4-20mA工業(yè)標(biāo)準(zhǔn)取樣電阻240ΩD223電流型輸入阻抗轉(zhuǎn)換后電壓0.96~4.8VI×R2.2 信號(hào)調(diào)理0.96~4.8V → 1MΩ限流電阻 → TVS箝位 → RC低通濾波(16kHz) → AD7606輸入環(huán)節(jié)參數(shù)作用限流電阻1MΩ過(guò)壓保護(hù)TVS6.4V擊穿瞬態(tài)保護(hù)RC濾波1kΩ10nF16kHz抗混疊三、階段③AD7606 ADC采樣3.1 采樣過(guò)程CONVST信號(hào) → AD7606啟動(dòng)轉(zhuǎn)換 → 8通道同步采樣 → 轉(zhuǎn)換完成 → BUSY拉低參數(shù)值A(chǔ)DC類型AD7606BBSTZ16位SAR采樣率500KSPSD223最高通道數(shù)8通道同步轉(zhuǎn)換時(shí)間~2μs量程±5V/±10V可配輸入阻抗1MΩ電壓/ 240Ω電流基準(zhǔn)電壓REF5050 5.000V ± 0.005V3.2 數(shù)據(jù)輸出AD7606并行總線 → FPGA讀取16位數(shù)據(jù) → 存入FPGA內(nèi)部FIFOAD7606輸出16位補(bǔ)碼5V → 0x7FFF (32767) 0V → 0x0000 (0) -5V → 0x8000 (-32768)四、階段④FPGA FIFO緩沖4.1 FIFO寫入AD7606 BUSY↓ → FPGA讀取8通道數(shù)據(jù) → 寫入FIFO[writeIndex] FIFO格式: [index(4B)] [CH1_0][CH1_1][CH1_2][CH1_3] ... [CH8_0]...[CH8_3] 共66字節(jié)4字節(jié)索引 8通道×4組×2字節(jié)4.2 FIFO讀取時(shí)機(jī)// TIM13中斷中voidqspiAdcTimTask(){// 計(jì)算FIFO新數(shù)據(jù)量_uadc.adc_BufIndex_qspiAdcBuf.index0xff;_uadc.adc_BufIndexGap計(jì)算索引差值;_uadc.adc_BufIndexGapmin(_uadc.adc_BufIndexGap,4);// 最多4組// 讀取DIN狀態(tài)搭便車_dioParam.dinAll(_qspiAdcBuf.index8)0xff;// 觸發(fā)QSPI DMA讀取QSPI_ReadDatas_DMA(0x81,2,(u8*)_qspiAdcBuf,0,66);}FPGA在FIFO數(shù)據(jù)中嵌入了DIN狀態(tài)索引高8位STM32讀取ADC數(shù)據(jù)時(shí)同時(shí)獲取DIN狀態(tài)無(wú)需單獨(dú)SPI讀取。五、階段⑤QSPI四線傳輸5.1 QSPI命令[CS↓] [0x81命令] [地址(2B)] [數(shù)據(jù)(66B)] [CS↑] ←─單線─→ ←─單線─→ ←─四線──→ 50MHz時(shí)鐘階段線數(shù)時(shí)鐘數(shù)耗時(shí)50MHz命令1線8160ns地址1線16320ns數(shù)據(jù)4線1322.64μsCS切換—~5100ns合計(jì)—~1613.22μs5.2 傳輸效率有效數(shù)據(jù)率 66字節(jié) / 3.22μs 20.5 MB/s 需求帶寬 500K × 8通道 × 2B 8 MB/s 余量 20.5 / 8 2.56倍 ?六、階段⑥D(zhuǎn)MA搬運(yùn)6.1 DMA配置QSPI外設(shè) → DMA1 Stream5 → 內(nèi)存_qspiAdcBuf 方向: 外設(shè)→存儲(chǔ)器 寬度: 8位字節(jié) 大小: 66字節(jié) 模式: 正常非循環(huán) 優(yōu)先級(jí): 4級(jí)高于TIM13的5級(jí)6.2 DMA完成通知voidHAL_QSPI_RxCpltCallback(QSPI_HandleTypeDef*hqspi){// DMA已完成66字節(jié)傳輸_adcFunctionParam.qspiDmaComplete1;// 設(shè)置標(biāo)志}DMA傳輸完全由硬件完成CPU在傳輸期間可以處理其他任務(wù)如DAC輸出、DIO刷新。七、階段⑦雙緩沖與數(shù)據(jù)過(guò)濾7.1 雙緩沖寫入// TIM13中斷中處理DMA完成的數(shù)據(jù)for(j0;j_uadc.adc_BufIndexGap;j){for(i0;i8;i){if(通道i使能){// 大端轉(zhuǎn)換int16 adcDataSWAP16(_qspiAdcBuf.data[j][i]);// 更新256點(diǎn)濾波緩沖區(qū)getAdcFilter24[i]-getAdc_Buf256[i][buf256Index];getAdc_Buf256[i][buf256Index]adcData;getAdcFilter24[i]adcData;// 更新雙緩沖區(qū)if(recordAB_flag0)// A緩沖_adcBuf.data[adc_collectIndex][i]adcData;else// B緩沖_adcBufB.data[adc_collectIndex][i]adcData;}}}7.2 緩沖區(qū)滿切換if(adc_collectIndex200){// 緩沖區(qū)滿200點(diǎn)×8通道if(recordAB_flag0){adc_collectFullFlag2;// A滿recordAB_flag1;// 切換到B}else{adc_collectFullFlag3;// B滿recordAB_flag0;// 切換到A}adc_collectIndex0;}八、階段⑧⑨幀打包與CRC8.1 幀組裝// 主線程檢測(cè)到緩沖區(qū)滿if(adc_collectFullFlag2){// A緩沖滿 → 組裝發(fā)送幀_adcBuf.msgHeadSWAP16(0x55aa);// 幀頭_adcBuf.cmdId_cmdId_getAdc_waveData;// 命令I(lǐng)D_adcBuf.frameLenSWAP16(sizeof(_adcBuf));// 幀長(zhǎng)度_adcBuf.adc_ch_Enable_framDatas._adcParam.adc_ch_Enable;_adcBuf.adcSignalType_framDatas._adcParam.adcSignalType;_adcBuf.adcRange_framDatas._adcParam.adcRange;_adcBuf.samplingRateSWAP16(samplingRate);// CRC計(jì)算_adcBuf.crcSWAP16(getCrc16WithTail((u8*)_adcBuf,SWAP16(_adcBuf.frameLen)));// 發(fā)送usb_sendMsg((u8*)_adcBuf,SWAP16(_adcBuf.frameLen));adc_collectFullFlag0;}8.2 CRC計(jì)算u16getCrc16WithTail(unsignedchar*puchMsg,unsignedshortusDataLen){u8 crcL0xFF,crcH0xFF;usDataLen-2;// 減去CRC本身2字節(jié)while(usDataLen--){uIndexcrcH^*puchMsg;crcHcrcL^tableH[uIndex];crcLtableL[uIndex];}return(crcH8|crcL);}8.3 發(fā)送幀結(jié)構(gòu)┌──────┬───────┬──────────┬──────┬────────┬──────┬────────────┬──────┐ │0x55AA│ cmdId │ frameLen │chEn │sigType │ range │sampleRate │waveData│CRC│ │ 2B │ 1B │ 2B │ 1B │ 1B │ 1B │ 2B │3200B │2B│ └──────┴───────┴──────────┴──────┴────────┴──────┴────────────┴──────┘ 總長(zhǎng)度: 212111232002 3212字節(jié)九、階段⑩?USB發(fā)送與C#接收9.1 USB發(fā)送voidusb_sendMsg(u8*data,u16 len){CDC_Transmit_FS(data,len);// USB Bulk傳輸3212字節(jié)分7個(gè)512B包}9.2 USB傳輸時(shí)間3212字節(jié) / 40MB/s ≈ 80μs9.3 C#接收voidUsbReceiveThread(){intlenusbStream.Read(rxBuffer,0,4096);lock(usbRxMsgBuf){for(inti0;ilen;i)usbRxMsgBuf.Add(rxBuffer[i]);}}十、階段??幀解析與波形顯示10.1 幀解析void_deviceRxMsg(byte[]rxData){// 結(jié)構(gòu)體映射msgGetAdcDatasmsg(msgGetAdcDatas)BytesToDataStruct(rxData,typeof(msgGetAdcDatas));// 提取參數(shù)bytechEnablemsg.adc_ch_Enable;bytesignalTypemsg.adcSignalType;byterangemsg.adcRange;ushortsamplingRateSWAP16(msg.samplingRate);// 提取波形數(shù)據(jù)intdataOffset12;// 幀頭參數(shù)長(zhǎng)度intdataLenSWAP16(msg.frameLen)-dataOffset-2;// 減CRCshort[][]waveDatanewshort[8][];intpointsPerChdataLen/2/CountEnabledChannels(chEnable);// 解交錯(cuò)for(inti0;ipointsPerCh;i){for(intch0;ch8;ch){if((chEnable(1ch))!0){intidxdataOffset(i*CountEnabledchIdx)*2;waveData[ch][i](short)((rxData[idx]8)|rxData[idx1]);}}}// 轉(zhuǎn)換為電壓double[][]voltagenewdouble[8][];for(intch0;ch8;ch){for(inti0;ipointsPerCh;i){voltage[ch][i]ADC2Voltage(waveData[ch][i],range,signalType);}}// 顯示DrawWaveform(voltage,samplingRate);}10.2 ADC值轉(zhuǎn)電壓doubleADC2Voltage(shortadcValue,byterange,bytesignalType){doublevref(range0)?5.0:10.0;if(signalType0){// 電壓型returnadcValue*vref/32768.0;}else{// 電流型// 240Ω取樣電阻 → 電壓轉(zhuǎn)回電流return(adcValue*vref/32768.0)/240.0*1000.0;// mA}}// 校準(zhǔn)后轉(zhuǎn)換doubleADC2VoltageCalibrated(shortadcValue,...){// 兩點(diǎn)線性插值doubleresult((adcValue-d1)*(a2-a1)/(d2-d1))a1;returnresult*0.00001;// ×10^7存儲(chǔ)}10.3 ScottPlot波形繪制voidDrawWaveform(double[][]voltage,intsamplingRate){waveform.Plot.Clear();doubletimeStep1.0/samplingRate;double[]xAxisnewdouble[200];for(inti0;i200;i)xAxis[i]i*timeStep;Color[]colors{Colors.Brown,Colors.Blue,Colors.Green,Colors.Red,Colors.Purple,Colors.Orange,Colors.Gray,Colors.Magenta};for(intch0;ch8;ch){if((chEnable(1ch))!0){waveform.Plot.Add.ScatterLine(xAxis,voltage[ch],colors[ch]);}}waveform.Plot.Axes.SetLimitsY(-vref*1.1,vref*1.1);waveform.Refresh();}十一、全鏈路延遲分析11.1 單次采樣到顯示的延遲階段耗時(shí)累計(jì)① 傳感器響應(yīng)~100μs100μs② 信號(hào)調(diào)理~10μs110μs③ AD7606轉(zhuǎn)換2μs112μs④ FPGA FIFO寫入~100ns112.1μs⑤ QSPI傳輸3.22μs115.3μs⑥ DMA搬運(yùn)3.22μs118.5μs⑦ 雙緩沖填滿200點(diǎn)200×采樣周期—⑧ 幀打包~1μs—⑨ CRC計(jì)算~2μs—⑩ USB傳輸~80μs—? C#接收~100μs—? 幀解析~10μs—? ScottPlot繪制~1ms—11.2 關(guān)鍵延遲延遲類型值說(shuō)明單點(diǎn)延遲~200μs從采樣到到達(dá)內(nèi)存幀延遲200×采樣周期3ms從首點(diǎn)到顯示500KSPS幀率200/500K 0.4ms采集3ms傳輸~2.5ms/幀幀率~400幀/s500KSPS下十二、數(shù)據(jù)完整性保障保障措施實(shí)現(xiàn)方式硬件CRCCRC16-Modbus校驗(yàn)整個(gè)幀幀頭搜索0x55AA定位臟數(shù)據(jù)丟棄大端轉(zhuǎn)換SWAP16/SWAP32確??缙脚_(tái)DMA零拷貝硬件搬運(yùn)無(wú)CPU干預(yù)雙緩沖防丟幀A/B交替發(fā)送時(shí)不阻塞采集過(guò)采樣降噪256點(diǎn)滑動(dòng)平均提升精度DIN搭便車FIFO索引嵌入DIN狀態(tài)十三、總結(jié)一個(gè)ADC數(shù)據(jù)點(diǎn)從傳感器到屏幕的完整旅程階段處理者耗時(shí)數(shù)據(jù)格式傳感器物理量100μs4-20mA信號(hào)調(diào)理RCTVS10μs0.96~4.8VAD7606SAR ADC2μs16位補(bǔ)碼FPGA FIFOFPGA硬件100ns66字節(jié)幀QSPI四線STM32 QSPI3.2μsDMA搬運(yùn)雙緩沖固件軟件—200點(diǎn)×8通道CRC16查表法2μs2字節(jié)校驗(yàn)USB CDCBulk傳輸80μs3212字節(jié)幀C#解析Marshal映射10μs結(jié)構(gòu)體ScottPlot圖表庫(kù)1ms屏幕像素從傳感器的物理量到屏幕上的像素點(diǎn)經(jīng)過(guò)13個(gè)階段的轉(zhuǎn)換和傳輸D223的數(shù)據(jù)采集鏈路實(shí)現(xiàn)了從模擬到數(shù)字、從硬件到軟件、從固件到上位機(jī)的完整閉環(huán)。下篇預(yù)告《D223通信協(xié)議命令字典完整版》