作者:Terry Deng
本文档概述了一种基于 SCI/UART 输入信号,可以自动校准本设备SCI/UART波特率的方法,该方法适用与所有第三代C2000芯片,比如F2807x/37x,F28004x,F28002x等等。

一 原理说明
假设有2块电路板通过SCI进行通信。“Transmitter”向“Receiver”发送未知波特率的数据,“ Receiver”则使用 eCAP 测量未知的波特率,然后修改其自身的波特率和“Transmitter”匹配。
下面款图是一种情况,其中“Transmitter” 的波特率设置为 9889,而“Receiver”的初始波特率设置为 9601 ,相比之下“Receiver”的波特率为 -3% 偏差。 经过算法的自动校准以后,“Receiver”将会把自身波特率校正为与“Transmitter”相同的9889。
8270.a.png
下面框图则是另一种情况,假如“Receiver”和“Transmitter”的初始波特率都是9889,但“Receiver”的内部晶振INTOSC有-3%的偏差。使用上述完全相同的方法原理和步骤,“Receiver”波特率设置将会从9889校准成9601,这样“Receiver”的波特率设置被自动校准抵消内部晶振的偏差。在测量实际信号时,“Receiver”输出到“Transmitter”的信号会是正确的 9889 波特率。
0167.b.png

二 Receiver 的校准代码
1. 初始化
需要配置以下模块来校准波特率:

  • 时钟:使用 INTOSC2 并选择 100MHz 的 LSPCLK
  1. #define DEVICE_SETCLOCK_CFG      (SYSCTL_OSCSRC_OSC2 | SYSCTL_IMULT(20) |  \
  2.                                      SYSCTL_FMULT_NONE | SYSCTL_SYSDIV(2) |   \
  3.                                      SYSCTL_PLL_ENABLE)
  4.     //
  5.     // Set up PLL control and clock dividers
  6.     //
  7.     SysCtl_setClock(DEVICE_SETCLOCK_CFG);
  8.     //
  9.     // Make sure the LSPCLK divider is set to the default (divide by 4)
  10.     //
  11.     SysCtl_setLowSpeedClock(SYSCTL_LSPCLK_PRESCALE_1);

  • SCI 模块:通讯数据使用,发出校准以后的波形
  1.     // Initialize SCIA and its FIFO.
  2.     //
  3.     SCI_performSoftwareReset(SCIA_BASE);
  4.     //
  5.     // Configure SCIA for communications.
  6.     //
  7.     SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, TARGETBAUD, (SCI_CONFIG_WLEN_8 |
  8.                                                         SCI_CONFIG_STOP_ONE |
  9.                                                         SCI_CONFIG_PAR_NONE));
  10.     SCI_resetChannels(SCIA_BASE);
  11.     SCI_resetRxFIFO(SCIA_BASE);
  12.     SCI_resetTxFIFO(SCIA_BASE);
  13.     SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_TXFF | SCI_INT_RXFF);
  14.     SCI_enableFIFO(SCIA_BASE);
  15.     SCI_enableModule(SCIA_BASE);
  16. SCI_performSoftwareReset(SCIA_BASE);

  • Xbar 输入:将 GPIO28/SCI 内部连接到 INPUTXBAR7 与 ECAP1 配合使用
  1. //
  2.     // Configure GPIO 28 as eCAP input
  3.     //
  4.     XBAR_setInputPin(XBAR_INPUT7, 28);

  • ECAP 模块:监控接收到的 SCI 通信脉冲宽度
  1. //
  2.     // Disable ,clear all capture flags and interrupts
  3.     //
  4.     ECAP_disableInterrupt(ECAP1_BASE,
  5.                           (ECAP_ISR_SOURCE_CAPTURE_EVENT_1  |
  6.                            ECAP_ISR_SOURCE_CAPTURE_EVENT_2  |
  7.                            ECAP_ISR_SOURCE_CAPTURE_EVENT_3  |
  8.                            ECAP_ISR_SOURCE_CAPTURE_EVENT_4  |
  9.                            ECAP_ISR_SOURCE_COUNTER_OVERFLOW |
  10.                            ECAP_ISR_SOURCE_COUNTER_PERIOD   |
  11.                            ECAP_ISR_SOURCE_COUNTER_COMPARE));
  12.     ECAP_clearInterrupt(ECAP1_BASE,
  13.                         (ECAP_ISR_SOURCE_CAPTURE_EVENT_1  |
  14.                          ECAP_ISR_SOURCE_CAPTURE_EVENT_2  |
  15.                          ECAP_ISR_SOURCE_CAPTURE_EVENT_3  |
  16.                          ECAP_ISR_SOURCE_CAPTURE_EVENT_4  |
  17.                          ECAP_ISR_SOURCE_COUNTER_OVERFLOW |
  18.                          ECAP_ISR_SOURCE_COUNTER_PERIOD   |
  19.                          ECAP_ISR_SOURCE_COUNTER_COMPARE));
  20.     //
  21.     // Disable CAP1-CAP4 register loads
  22.     //
  23.     ECAP_disableTimeStampCapture(ECAP1_BASE);
  24.     //
  25.     // Configure eCAP
  26.     //    Enable capture mode.
  27.     //    One shot mode, stop capture at event 4.
  28.     //    Set polarity of the events to rising, falling, rising, falling edge.
  29.     //    Set capture in time difference mode.
  30.     //    Select input from XBAR7.
  31.     //    Enable eCAP module.
  32.     //    Enable interrupt.
  33.     //
  34.     ECAP_stopCounter(ECAP1_BASE);
  35.     ECAP_enableCaptureMode(ECAP1_BASE);
  36.     ECAP_setCaptureMode(ECAP1_BASE, ECAP_ONE_SHOT_CAPTURE_MODE, ECAP_EVENT_4);
  37.     ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_1, ECAP_EVNT_FALLING_EDGE);
  38.     ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_2, ECAP_EVNT_RISING_EDGE);
  39.     ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_3, ECAP_EVNT_FALLING_EDGE);
  40.     ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_4, ECAP_EVNT_RISING_EDGE);
  41.     ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_1);
  42.     ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_2);
  43.     ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_3);
  44.     ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_4);
  45.     ECAP_selectECAPInput(ECAP1_BASE, ECAP_INPUT_INPUTXBAR7);
  46.     ECAP_enableLoadCounter(ECAP1_BASE);
  47.     ECAP_setSyncOutMode(ECAP1_BASE, ECAP_SYNC_OUT_DISABLED);
  48.     ECAP_startCounter(ECAP1_BASE);
  49.     ECAP_enableTimeStampCapture(ECAP1_BASE);
  50.     ECAP_reArm(ECAP1_BASE);
  51.     ECAP_enableInterrupt(ECAP1_BASE, ECAP_ISR_SOURCE_CAPTURE_EVENT_4);
2. 中断
捕获传入 SCI 通信的脉冲宽度,每捕获 4 次就中断一次。 将这 4 个捕获添加到阵列中。
  1. __interrupt void ecap1ISR(void)
  2. {
  3.     if(stopCaptures==0)
  4.     {
  5.         //
  6.         // Get the capture counts, interrupt every 4. Can be 1-bit or more wide.
  7.         // add one to account for partial eCAP counts at higher baud rates
  8.         // (e.g. count = 40, but if had higher resolution, this would be 40.5)
  9.         //
  10.         capCountArr[0] = 1+ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_1);
  11.         capCountArr[1] = 1+ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_2);
  12.         capCountArr[2] = 1+ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_3);
  13.         capCountArr[3] = 1+ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_4);
  14.         //
  15.         // Add samples to a buffer. Get average baud and tune INTOSC if buffer filled.
  16.         //
  17.         capCountIter = 0;
  18.         for (capCountIter=0; capCountIter<4; capCountIter++)
  19.         {
  20.             //
  21.             // if we still have samples left to capture, add it to the samples array
  22.             //
  23.             if(samplesArrIter<NUMSAMPLES)
  24.             {
  25.                 samplesArr[samplesArrIter] = capCountArr[capCountIter];
  26.                 samplesArrIter++;
  27.             }
  28.             //
  29.             // else, all samples were received, break to begin tuning
  30.             //
  31.             else
  32.             {
  33.                 stopCaptures=1;
  34.                 break;
  35.             }
  36.         }
  37.     }
  38.     //
  39.     // Clear interrupt flags for more interrupts.
  40.     //
  41.     ECAP_clearInterrupt(ECAP1_BASE,ECAP_ISR_SOURCE_CAPTURE_EVENT_4);
  42.     ECAP_clearGlobalInterrupt(ECAP1_BASE);
  43.     //
  44.     // Start eCAP
  45.     //
  46.     ECAP_reArm(ECAP1_BASE);
  47.     //
  48.     // Acknowledge the group interrupt for more interrupts.
  49.     //
  50.     Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP4);
  51. }
3. 主循环
捕获阵列满后,计算阵列的平均脉冲宽度 (也就是波特率),并更新SCI波特率寄存器,使其尽可能接近计算的平均值。
  1. //
  2.     // Loop forever. Suspend or place breakpoints to observe the buffers.
  3.     //
  4.     for(;;)
  5.     {
  6.         //
  7.         // Array is filled, begin tuning
  8.         //
  9.         if(stopCaptures==1)
  10.         {
  11.             //
  12.             // Get an average baud rate from the array of samples
  13.             //
  14.             uint32_t avgBaud = getAverageBaud(samplesArr,NUMSAMPLES,TARGETBAUD);
  15.             //
  16.             // if the baud function returns the error code '0', then flag an error
  17.             //
  18.             if(avgBaud==0)
  19.             {
  20.                 ESTOP0;
  21.             }
  22.             //
  23.             // Update the device's baud rate to match the measured baud rate
  24.             //
  25.             SCI_setBaud(SCIA_BASE, DEVICE_LSPCLK_FREQ, avgBaud);
  26.             //
  27.             // (OPTIONAL) Continuously send data to SCITX once tuning
  28.             // is complete for external observation (by logic analyzer or scope)
  29.             //
  30.             //unsigned char *msg;
  31.             //while(1)
  32.             //{
  33.             //    msg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\0";
  34.             //    SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 91);
  35.             //}
  36.             //
  37.             // Wait for user to view the results in "Expressions" window
  38.             //
  39.             ESTOP0;
  40.             //
  41.             // If continuing, reset the array iterator and unlock the ISR for new captures
  42.             //
  43.             samplesArrIter=0;
  44.             stopCaptures=0;
  45.         }
  46. }
4. 平均脉冲宽度
对于许多应用的SCI 通信,传输的数据 (例如 0xA5)是变化不固定的,因此SCI的高低电平脉冲宽度就是变化的。所以必须对样本阵列进行如下的预处理,然后才能计算平均脉冲宽度。
a) 丢弃大于 10 位宽的脉冲宽度 (丢弃空闲时间)
b) 将 n 位值除以 n
c) 对修改后的样本数组进行平均化
  1. uint32_t getAverageBaud(volatile float arr[], int size, float targetBaudRate)
  2. {
  3.     //
  4.     // clean up variable width array to single-bit-width array
  5.     //
  6.     uint16_t pass = arrTo1PulseWidth(arr, size, (float)DEVICE_SYSCLK_FREQ/targetBaudRate);
  7.     //
  8.     // pass only if enough good samples provided
  9.     //
  10.     if(pass == 0)
  11.     {
  12.         return 0;
  13.     }
  14.     //
  15.     // convert 2-bit width, 3-bit width, etc. to 1-bit width values by dividing, and average these values.
  16.     // skip unrelated values
  17.     //
  18.     float averageBitWidth = computeAvgWidth(arr, size);
  19.     //
  20.     // get the rounded baud rate from the average number of clocks and the sysclk frequency
  21.     //
  22.     return (uint32_t)(((float)DEVICE_SYSCLK_FREQ/(float)averageBitWidth)+0.5);
  23. }
以下是平均脉宽计算的原理和代码流程图
www.png
8863.dd.png

三 结果
按照以下设置进行测试,结果详见表格,校准以后的误差从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.012%


                               
               



来源:TI