作者:Terry Deng
本文檔概述了一種基于 SCI/UART 輸入信號,可以自動校準本設備SCI/UART波特率的方法,該方法適用與所有第三代C2000芯片,比如F2807x/37x,F(xiàn)28004x,F(xiàn)28002x等等。
一 原理說明
假設有2塊電路板通過SCI進行通信?!癟ransmitter”向“Receiver”發(fā)送未知波特率的數(shù)據(jù),“ Receiver”則使用 eCAP 測量未知的波特率,然后修改其自身的波特率和“Transmitter”匹配。
下面款圖是一種情況,其中“Transmitter” 的波特率設置為 9889,而“Receiver”的初始波特率設置為 9601 ,相比之下“Receiver”的波特率為 -3% 偏差。 經(jīng)過算法的自動校準以后,“Receiver”將會把自身波特率校正為與“Transmitter”相同的9889。
下面框圖則是另一種情況,假如“Receiver”和“Transmitter”的初始波特率都是9889,但“Receiver”的內部晶振INTOSC有-3%的偏差。使用上述完全相同的方法原理和步驟,“Receiver”波特率設置將會從9889校準成9601,這樣“Receiver”的波特率設置被自動校準抵消內部晶振的偏差。在測量實際信號時,“Receiver”輸出到“Transmitter”的信號會是正確的 9889 波特率。
二 Receiver 的校準代碼
1. 初始化
需要配置以下模塊來校準波特率:
- 時鐘:使用 INTOSC2 并選擇 100MHz 的 LSPCLK
#define DEVICE_SETCLOCK_CFG (SYSCTL_OSCSRC_OSC2 | SYSCTL_IMULT(20) | \ SYSCTL_FMULT_NONE | SYSCTL_SYSDIV(2) | \ SYSCTL_PLL_ENABLE) // // Set up PLL control and clock dividers // SysCtl_setClock(DEVICE_SETCLOCK_CFG); // // Make sure the LSPCLK divider is set to the default (divide by 4) // SysCtl_setLowSpeedClock(SYSCTL_LSPCLK_PRESCALE_1);
- SCI 模塊:通訊數(shù)據(jù)使用,發(fā)出校準以后的波形
// Initialize SCIA and its FIFO. // SCI_performSoftwareReset(SCIA_BASE); // // Configure SCIA for communications. // SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, TARGETBAUD, (SCI_CONFIG_WLEN_8 | SCI_CONFIG_STOP_ONE | SCI_CONFIG_PAR_NONE)); SCI_resetChannels(SCIA_BASE); SCI_resetRxFIFO(SCIA_BASE); SCI_resetTxFIFO(SCIA_BASE); SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_TXFF | SCI_INT_RXFF); SCI_enableFIFO(SCIA_BASE); SCI_enableModule(SCIA_BASE); SCI_performSoftwareReset(SCIA_BASE);
- Xbar 輸入:將 GPIO28/SCI 內部連接到 INPUTXBAR7 與 ECAP1 配合使用
// // Configure GPIO 28 as eCAP input // XBAR_setInputPin(XBAR_INPUT7, 28);
- ECAP 模塊:監(jiān)控接收到的 SCI 通信脈沖寬度
// // Disable ,clear all capture flags and interrupts // ECAP_disableInterrupt(ECAP1_BASE, (ECAP_ISR_SOURCE_CAPTURE_EVENT_1 | ECAP_ISR_SOURCE_CAPTURE_EVENT_2 | ECAP_ISR_SOURCE_CAPTURE_EVENT_3 | ECAP_ISR_SOURCE_CAPTURE_EVENT_4 | ECAP_ISR_SOURCE_COUNTER_OVERFLOW | ECAP_ISR_SOURCE_COUNTER_PERIOD | ECAP_ISR_SOURCE_COUNTER_COMPARE)); ECAP_clearInterrupt(ECAP1_BASE, (ECAP_ISR_SOURCE_CAPTURE_EVENT_1 | ECAP_ISR_SOURCE_CAPTURE_EVENT_2 | ECAP_ISR_SOURCE_CAPTURE_EVENT_3 | ECAP_ISR_SOURCE_CAPTURE_EVENT_4 | ECAP_ISR_SOURCE_COUNTER_OVERFLOW | ECAP_ISR_SOURCE_COUNTER_PERIOD | ECAP_ISR_SOURCE_COUNTER_COMPARE)); // // Disable CAP1-CAP4 register loads // ECAP_disableTimeStampCapture(ECAP1_BASE); // // Configure eCAP // Enable capture mode. // One shot mode, stop capture at event 4. // Set polarity of the events to rising, falling, rising, falling edge. // Set capture in time difference mode. // Select input from XBAR7. // Enable eCAP module. // Enable interrupt. // ECAP_stopCounter(ECAP1_BASE); ECAP_enableCaptureMode(ECAP1_BASE); ECAP_setCaptureMode(ECAP1_BASE, ECAP_ONE_SHOT_CAPTURE_MODE, ECAP_EVENT_4); ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_1, ECAP_EVNT_FALLING_EDGE); ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_2, ECAP_EVNT_RISING_EDGE); ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_3, ECAP_EVNT_FALLING_EDGE); ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_4, ECAP_EVNT_RISING_EDGE); ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_1); ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_2); ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_3); ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_4); ECAP_selectECAPInput(ECAP1_BASE, ECAP_INPUT_INPUTXBAR7); ECAP_enableLoadCounter(ECAP1_BASE); ECAP_setSyncOutMode(ECAP1_BASE, ECAP_SYNC_OUT_DISABLED); ECAP_startCounter(ECAP1_BASE); ECAP_enableTimeStampCapture(ECAP1_BASE); ECAP_reArm(ECAP1_BASE); ECAP_enableInterrupt(ECAP1_BASE, ECAP_ISR_SOURCE_CAPTURE_EVENT_4);
2. 中斷
捕獲傳入 SCI 通信的脈沖寬度,每捕獲 4 次就中斷一次。 將這 4 個捕獲添加到陣列中。
__interrupt void ecap1ISR(void) { if(stopCaptures==0) { // // Get the capture counts, interrupt every 4. Can be 1-bit or more wide. // add one to account for partial eCAP counts at higher baud rates // (e.g. count = 40, but if had higher resolution, this would be 40.5) // capCountArr[0] = 1+ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_1); capCountArr[1] = 1+ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_2); capCountArr[2] = 1+ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_3); capCountArr[3] = 1+ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_4); // // Add samples to a buffer. Get average baud and tune INTOSC if buffer filled. // capCountIter = 0; for (capCountIter=0; capCountIter<4; capCountIter++) { // // if we still have samples left to capture, add it to the samples array // if(samplesArrIter
捕獲陣列滿后,計算陣列的平均脈沖寬度 (也就是波特率),并更新SCI波特率寄存器,使其盡可能接近計算的平均值。
// // Loop forever. Suspend or place breakpoints to observe the buffers. // for(;;) { // // Array is filled, begin tuning // if(stopCaptures==1) { // // Get an average baud rate from the array of samples // uint32_t avgBaud = getAverageBaud(samplesArr,NUMSAMPLES,TARGETBAUD); // // if the baud function returns the error code '0', then flag an error // if(avgBaud==0) { ESTOP0; } // // Update the device's baud rate to match the measured baud rate // SCI_setBaud(SCIA_BASE, DEVICE_LSPCLK_FREQ, avgBaud); // // (OPTIONAL) Continuously send data to SCITX once tuning // is complete for external observation (by logic analyzer or scope) // //unsigned char *msg; //while(1) //{ // msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\0"; // SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 91); //} // // Wait for user to view the results in "Expressions" window // ESTOP0; // // If continuing, reset the array iterator and unlock the ISR for new captures // samplesArrIter=0; stopCaptures=0; } }
4. 平均脈沖寬度
對于許多應用的SCI 通信,傳輸?shù)臄?shù)據(jù) (例如 0xA5)是變化不固定的,因此SCI的高低電平脈沖寬度就是變化的。所以必須對樣本陣列進行如下的預處理,然后才能計算平均脈沖寬度。
a) 丟棄大于 10 位寬的脈沖寬度 (丟棄空閑時間)
b) 將 n 位值除以 n
c) 對修改后的樣本數(shù)組進行平均化
uint32_t getAverageBaud(volatile float arr[], int size, float targetBaudRate) { // // clean up variable width array to single-bit-width array // uint16_t pass = arrTo1PulseWidth(arr, size, (float)DEVICE_SYSCLK_FREQ/targetBaudRate); // // pass only if enough good samples provided // if(pass == 0) { return 0; } // // convert 2-bit width, 3-bit width, etc. to 1-bit width values by dividing, and average these values. // skip unrelated values // float averageBitWidth = computeAvgWidth(arr, size); // // get the rounded baud rate from the average number of clocks and the sysclk frequency // return (uint32_t)(((float)DEVICE_SYSCLK_FREQ/(float)averageBitWidth)+0.5); }
以下是平均脈寬計算的原理和代碼流程圖
)>
三 結果
按照以下設置進行測試,結果詳見表格,校準以后的誤差從3% 改善為0.1%左右甚至更小。
- “Transmitter”設置為正確的波特率 (我們嘗試匹配的波特率)
- “Receiver”設置為錯誤波特率 (-3% 或 +3%)
- “Receiver”運行校準程序以匹配“Transmitter”
100K 波特率 | 9601波特率 | ||||
-3% | +3% | -3% | +3% | ||
Transmitter (我們正在嘗試匹配的內容) | 理想波特率 (僅供參考) | 103306 | 96899 | 9889 | 9314. |
實際波特率 (必須與此匹配) | 104174. | 96906 | 9890 | 9315. | |
Receiver (初始錯誤波特率) | 波特率 (校準前) | 100154. | 100157. | 9622. | 9622. |
出錯百分比 (校準前) | -3.859% | 3.355% | -2.706% | 3.296% | |
Receiver (校準后波特率) | 波特率 (校準后) | 104336. | 97047. | 9888 | 9314. |
出錯百分比 (校準后) | 0.156% | 0.146% | -0.016% |
-
嵌入式處理
+關注
關注
0文章
341瀏覽量
10016 -
uart
+關注
關注
22文章
1237瀏覽量
101429 -
SCI
+關注
關注
1文章
56瀏覽量
20128
發(fā)布評論請先 登錄
相關推薦
評論