0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

根据SCI输入信号自动校准波特率

电子设计 来源:电子设计 作者:电子设计 2022-01-12 13:56 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

作者: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。

下面框图则是另一种情况,假如“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 模块:通讯数据使用,发出校准以后的波形

    // 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 模块:监控接收到的 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 通信,传输的数据 (例如 0xA5)是变化不固定的,因此SCI的高低电平脉冲宽度就是变化的。所以必须对样本阵列进行如下的预处理,然后才能计算平均脉冲宽度。

a) 丢弃大于 10 位宽的脉冲宽度 (丢弃空闲时间)

b) 将 n 位值除以 n

c) 对修改后的样本数组进行平均化

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);
}

以下是平均脉宽计算的原理和代码流程图

)>

poYBAGGKRRaAJv7wAABId9BaVcc607.png

pYYBAGGKRRiAVuqrAAA6HkSAzxQ298.png

三 结果

按照以下设置进行测试,结果详见表格,校准以后的误差从3% 改善为0.1%左右甚至更小。

  1. “Transmitter”设置为正确的波特率 (我们尝试匹配的波特率)
  2. “Receiver”设置为错误波特率 (-3% +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

    浏览量

    10450
  • uart
    +关注

    关注

    22

    文章

    1304

    浏览量

    106117
  • SCI
    SCI
    +关注

    关注

    1

    文章

    59

    浏览量

    20802
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    请问支持小数波特率接收数据的意义在哪儿?

    我看芯源支持小数波特率,话说,支持小数波特率接收数据的意义在哪儿?是通讯更有精度吗?
    发表于 12-02 07:17

    UART波特率计算及UART收发回显实验

    决定串口波特率的寄存器有BRR(Bite Rate Rigister),SEMR(Serial Extended Mode Rigister)和MDDR(Modulation Duty
    的头像 发表于 10-17 09:51 2391次阅读
    UART<b class='flag-5'>波特率</b>计算及UART收发回显实验

    串口波特率设置1200用不了是怎么回事?

    mcu:stm32f407zg 调试时,设置波特率为1200,而串口输出为乱码,电脑设置波特率19200来接收mcu的数据,却能接收正确; (我以前没有用RTT时,用stm32f103rct6
    发表于 09-23 07:19

    115200的波特率,为啥实际速度只有11KB/s?

    波特率≠真实速度! 这几个概念确实容易混淆,但它们描述的是通信过程中不同层面的速率指标。让我们一起来理清楚它们的区别和联系↓ 主要区别解析 比特 (Bit Rate): 指每秒传输的二进制比特数量
    的头像 发表于 09-10 11:18 399次阅读

    请问如何使用低功耗 UART (LP UART) 波特率补偿?

    如何使用低功耗 UART (LP UART) 波特率补偿?
    发表于 08-21 07:05

    波特率是什么

    时间内(通常为每秒)传输的 符号(Symbol)数量 ,即信号变化的次数。这里的“符号”是数据传输的最小单元,可以是电压的高低、频率的变化或相位的偏移等。例如: 若波特率为9600,表示每秒传输9600个符号。 在简单的二进制通信中,一个符号
    的头像 发表于 07-22 11:11 5780次阅读

    【中科昊芯Core_DSC280025C开发板试用体验】+SCI测试与代码解读

    是可以达到的最大波特率 •能够使用直接内存访问(DMA)传输和接收数据 •5 个错误标志和 7 个状态标志提供有关 SCI 事件的详细信息 •两个外部引脚:LINRX 和 LINTX •多缓冲的接收
    发表于 07-17 10:42

    可编程电源的通信波特率应如何设置?

    可编程电源的通信波特率设置需综合考虑设备兼容性、通信稳定性、实时性需求及抗干扰能力,推荐根据设备支持的最高波特率、通信距离、环境干扰等因素,优先选择标准波特率(如9600、19200、
    发表于 07-07 15:01

    基于瑞萨64位MPU RZ/G2L的uboot串口多波特率支持介绍

    本文主要介绍基于瑞萨64位MPU RZ/G2L,讨论uboot下非常规波特率115200的支持方法,用于解决客户对uboot下特殊波特率的需求,供客户参考。
    的头像 发表于 07-04 15:54 2762次阅读
    基于瑞萨64位MPU RZ/G2L的uboot串口多<b class='flag-5'>波特率</b>支持介绍

    MAX13051 ±80V故障保护CAN收发器,具有自动波特率模式技术手册

    MAX13051为具有自动波特率模式、±80V故障保护的CAN收发器,可理想用于需要过压保护的设备网络和其他工业网络应用。MAX13051可以为CAN协议控制器和CAN总线的物理线路提供连接。
    的头像 发表于 05-27 11:07 1070次阅读
    MAX13051 ±80V故障保护CAN收发器,具有<b class='flag-5'>自动波特率</b>模式技术手册

    STM32U575串口接收+GPDMA波特率不匹配怎么解决?

    我用CubeMX配置的串口+GPDMA接收,115200波特率正常能用, 然后如果波特率设置错误为9600,再改回来115200,接收就不能用了,调试好像时DMA出错了,然后启用HAL_UARTEx_ReceiveToIdle_DMA函数依然错误,有大神知道怎么解决吗
    发表于 03-07 07:59

    CAN总线十万个为什么 | CAN自定义波特率有什么用?

    导读CAN总线通信中,波特率一致并不总能保证通信顺畅。本文将揭秘自定义波特率的原理和应用,探讨如何通过优化采样点和提高容忍度解决通信问题,助力工程师提升通信稳定性。通常情况下,CAN总线通信只需确保
    的头像 发表于 02-07 11:36 1100次阅读
    CAN总线十万个为什么 | CAN自定义<b class='flag-5'>波特率</b>有什么用?

    AN-891: ADuC703x系列LIN波特率计算

    电子发烧友网站提供《AN-891: ADuC703x系列LIN波特率计算.pdf》资料免费下载
    发表于 01-14 15:53 0次下载
    AN-891: ADuC703x系列LIN<b class='flag-5'>波特率</b>计算

    请问MSC1210串口UART1如何设置波特率

    如题,MSC1210的手册上面有提到,UART0的波特率可以进行选择,可选择为T1的溢出作为波特率的设置,但是UART1的波特率如何设置?是和UART0的波特率一样吗?还是需要其他
    发表于 01-02 08:27

    RS232通信的波特率设置说明

    RS232通信中,波特率的选择需要根据设备的通信能力和通信距离来确定。 二、波特率的设置范围 RS232通信的波特率可以设置多种不同的速率,常见的
    的头像 发表于 12-10 16:26 6412次阅读