This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] LAUNCHXL-F28P65X:SCI 通信问题

Guru**** 2589300 points
Other Parts Discussed in Thread: C2000WARE, SYSCONFIG

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1419963/launchxl-f28p65x-sci-communication-issues

器件型号:LAUNCHXL-F28P65X
主题中讨论的其他器件:C2000WARESysConfig

工具与软件:

大家好!

我目前正在使用串行通信接口(SCI)将65x 板与 GNSS 模块连接。 我遇到了几个我希望在你的帮助下解决的问题。 以下是我的设置和面临的挑战的简要概述:

我需要从模块可靠地接收约70字节的 GNSS 数据。 数据频率和大小可能会有所不同、因此我已经实现了中断和 FIFO 缓冲区以确保数据处理的一致性。 考虑到我的应用对时间的要求严格、数据必须保持准确、因为它会影响多个子系统。

为了管理数据流、我已经为接收启用了 FIFO 中断、并将阈值设置为 FIFO 满级别。 因此、对于70字节的数据、RX FIFO 会生成4个中断来读取64字节。 但是、这会在 FIFO 缓冲区中保留6个字节。 为了检索最后6个字节,我使用 API 检查 RX FIFO 状态SCI_getRxFIFOStatus(SCI0_BASE)

以下是我遇到的具体问题:

  1. FIFO 状态检查的 ISR 问题 :该SCI_getRxFIFOStatus函数似乎在 RX FIFO ISR 中不起作用。 我尝试直接使用访问 FIFO 状态(HWREGH(base_addr + SCI_O_FFRX) & SCI_FFRX_RXFFST_M) >> SCI_FFRX_RXFFST_S;、但也失败了。 直接硬件访问在 ISR 中不起作用是什么原因吗?或者我缺少什么吗?

  2. RX 数据不一致 :我接收的 SCI RX 数据不一致;我通常只接收传输数据的最后32个字节左右。 当我连续发送数据时、似乎会出现这种不一致。 但是、当我只传输一次时、数据是准确的。 我对为什么会发生这种行为感到困惑。

  3. 中断嵌套 :在电路板中或 C2000ware 中是否启用了中断嵌套? 为了启用嵌套中断、我需要执行什么具体操作吗?

我已附上相关代码片段和 SysConfig 作为参考。 非常感谢您提供任何见解或建议!

感谢你的帮助

#include "driverlib.h"
#include "device.h"
#include "board.h"
#include "c2000ware_libraries.h"
#include "stdio.h"
#define BUFFER_SIZE 70
#define CHUNK_SIZE 16
#define base_addr 0x00007210U
//
// Main
//

char txmsg[] = "$GNRMC,123456.00,A,3751.65,N,12225.55,W,0.00,180.00,230920,0.00,E,D";
char rxmsg[BUFFER_SIZE];
char *pos;
volatile uint32_t currentPos = 0;
int check = 0;
volatile uint16_t scitxcount = 0;
volatile uint16_t scirxcount = 0;
volatile uint16_t timerinterruptfreq = 0;
volatile uint32_t scirxlvl;
void buffercntl(char data);
void INT_SCI0_RX_ISR(void);
void INT_SCI0_TX_ISR(void);
void error(void);
void INT_myCPUTIMER0_ISR(void);

//void buffercntl(char data){
//    uint32_t nexthead = (head+16)%BUFFER_SIZE;
//    if (nexthead != tail) {
//        rxmsg[msg] = data;
//        head = nexthead;
//    }
//}


__interrupt void INT_SCI0_RX_ISR(void){
    uint32_t rxintstat = SCI_getInterruptStatus(SCI0_BASE);
    switch(rxintstat){
    case SCI_INT_PE:
        SCI_writeCharNonBlocking(SCI1_BASE, 'P');
        error();
        break;
    case SCI_INT_OE:
        SCI_writeCharNonBlocking(SCI1_BASE, 'O');
        error();
        break;
    case SCI_INT_FE:
        SCI_writeCharNonBlocking(SCI1_BASE, 'F');
        error();
        break;
    case SCI_INT_RXERR:
        SCI_writeCharNonBlocking(SCI1_BASE, 'R');
        error();
        break;
    default:
        //error();
        break;
    }
//
// received data handling
//
//
    uint16_t bytesToRead = CHUNK_SIZE;
    if (currentPos + bytesToRead > BUFFER_SIZE) {
        bytesToRead = BUFFER_SIZE - currentPos;
    }
    SCI_readCharArray(SCI0_BASE, (uint16_t*)&rxmsg[currentPos], bytesToRead);
    currentPos += bytesToRead;

    scirxlvl = (SCI_RxFIFOLevel)(HWREGH(base_addr + SCI_O_FFRX) & SCI_FFRX_RXFFST_M) >> SCI_FFRX_RXFFST_S;
    if((BUFFER_SIZE-currentPos)< CHUNK_SIZE){
        while(scirxlvl){
                rxmsg[currentPos++] = SCI_readCharNonBlocking(SCI0_BASE);
                check++;
            }
    }
    if (currentPos >= BUFFER_SIZE) {
       // SCI_writeCharArray(SCI1_BASE, (uint16_t*)rxmsg, sizeof(rxmsg));
        currentPos = 0; // Reset position
    }

    scirxcount++;
    GPIO_togglePin(myLED1_GPIO);
    //overflow condition check?

    SCI_clearOverflowStatus(SCI0_BASE);
    SCI_clearInterruptStatus(SCI0_BASE, SCI_INT_RXFF);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);

}

__interrupt void INT_SCI0_TX_ISR(void){
    GPIO_togglePin(myLED0_GPIO);
    scitxcount++;
    SCI_clearInterruptStatus(SCI0_BASE, SCI_INT_TXFF);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);

}

__interrupt void INT_myCPUTIMER0_ISR(void){             //cpu timer to simulate data transmission every 1 second
    timerinterruptfreq++;
    SCI_writeCharArray(SCI1_BASE,(uint16_t*)txmsg,sizeof(txmsg));
    Interrupt_clearACKGroup(INT_myCPUTIMER0_INTERRUPT_ACK_GROUP);
}

void error(void)
{
    asm("     ESTOP0"); // Test failed
    for (;;);
}
void main(void)
{

    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Disable pin locks and enable internal pull-ups.
    //
    Device_initGPIO();

    //
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();

    //
    // PinMux and Peripheral Initialization
    //
    Board_init();

    //
    // C2000Ware Library initialization
    //
    C2000Ware_libraries_init();

    //
    // Enable Global Interrupt (INTM) and real time interrupt (DBGM)
    //
    EINT;
    ERTM;
    //SCI_writeCharArray(SCI0_BASE,(uint16_t*)txmsg,sizeof(txmsg));
    while(1)
    {
        scirxlvl = SCI_getRxFIFOStatus(SCI0_BASE);

//        sprintf(pos,"%d",(int)currentPos);
//        SCI_writeCharBlockingNonFIFO(SCI1_BASE,(uint16_t)*pos);
//        sprintf(buff,"%d",)
//        SCI_writeCharNonBlocking(SCI1_BASE, scitxlvl);
//        SCI_writeCharNonBlocking(SCI1_BASE, scirxlvl);
    }
}

//
// End of File
//

如何以最佳方式实施此应用、从而以全双工方式发送和接收数据并仍然保持可靠且一致的数据。

这项工作仍在拟订之中、因此欢迎提出任何建议。

提前感谢您

Ashwin Bhaskar A.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [报价用户 id="624746" url="~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1419963/launchxl-f28p65x-sci-communication-issues "] FIFO 状态检查的 ISR 问题 :该SCI_getRxFIFOStatus函数似乎在 RX FIFO ISR 中不起作用。 我尝试直接使用访问 FIFO 状态(HWREGH(base_addr + SCI_O_FFRX) & SCI_FFRX_RXFFST_M) >> SCI_FFRX_RXFFST_S;、但也失败了。 直接硬件访问在 ISR 中不起作用、或者我缺少什么吗?[/QUOT]

    您能解释一下说失败是什么意思吗? 需要记住的一点是、CPU 的运行速度比 SCI 波特率快得多。 FIFO 可能只是空、因为当您读取 FIFO 状态时没有接收到新的 RX 字符。

    [报价用户 id="624746" url="~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1419963/launchxl-f28p65x-sci-communication-issues "] RX 数据不一致 :我接收的 SCI RX 数据不一致;我通常只接收传输数据的最后32个字节左右。 当我连续发送数据时、似乎会出现这种不一致。 但是、当我只传输一次时、数据是准确的。 我对为什么会出现这种行为感到困惑。

    这听起来您的 FIFO 处理方案存在一些问题。

    [报价用户 id="624746" url="~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1419963/launchxl-f28p65x-sci-communication-issues "] 中断嵌套 :在电路板中或 C2000ware 中是否启用了中断嵌套? 启用嵌套中断是否需要执行任何特定操作?[/QUOT]

    请查看以下文章。

    https://software-dl.ti.com/C2000/docs/c28x_interrupt_nesting/html/index.html

    回到最初的问题、我认为是: 利用 UART FIFO 中断级别生成最少的可能中断、而又不会导致数据留在 FIFO 中的可能性的最佳方法是什么?  

    首先、我个人不会将 RX FIFO 的级别设置为最大  SCI 中断在优先级列表中很低。 当 CPU 无法及时读取数据(例如、当 CPU 处于某个较高优先级的 ISR 时)、将 RX FIFO 设置为最大触发电平会导致 RX FIFO 溢出。 中断嵌套听起来是修复的、但同样、您可能不希望中断某些高优先级 ISR。

    其次、您可以使用值为1的 RX FIFO 触发级别。 这会生成最多的中断、但鉴于 SCI 中断具有较低的优先级、这可能是可以接受的。  

    第三、帧长度是否嵌入在 SCI 数据中? 如果是这样、是否可以架构您的代码、以便您使用中断来接收帧中的 n x 16个字符、然后使用 ISR 外部轮询来读取剩余数量的字符? 您可以在某些后台任务中进行轮询。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Gus

    感谢您的及时响应

    您能解释一下失败的原因吗? 需要记住的一点是、CPU 的运行速度比 SCI 波特率快得多。 FIFO 可能为空、因为读取 FIFO 状态时未接收到新的 RX 字符。[/QUOT]

    我的意思是、我确信数据会留在 FIFO 中、因为我是在 ISR 外部进行检查的。 如果 u 检查代码、您可以在 while (1)循环中看到检查相同内容的注释代码。 这表明 FIFO 中还剩余数据、但当我使用同一 API 在 ISR 内部检查时、有时会抛出垃圾值或0。 即使我尝试直接访问寄存器、也会引发相同的问题。

    [报价 userid="13605" url="~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1419963/launchxl-f28p65x-sci-communication-issues/5441141 #5441141"]其次、您可以使用值为1的 RX FIFO 触发电平。 这会生成最多的中断、但鉴于 SCI 中断具有较低的优先级、这可能是可以接受的。  [报价]

    我对这种方法的担心是,它将坦克我的系统性能,因为我必须产生荒谬的数量的中断. 正如我所说的,我的数据将是动态的大小,可能会出现在200 ms 的周期. 数据大小可高达1024字节。 这是在200ms 内1024个中断。 我的系统是否能够执行其他任务? 我是 TI 板的新手、因此如果我在这方面有任何错误、请原谅我。

    第三、是否在 SCI 数据中嵌入了帧长度? 如果是这样、是否可以架构您的代码、以便您使用中断来接收帧中的 n x 16个字符、然后使用 ISR 外部轮询来读取剩余数量的字符? 您可以在某些后台任务中执行轮询。

    您是说我应该一次获得16个字节的数据、然后进行轮询以获取其余数据吗? 这意味着我需要每16个字节生成一次中断。  

    [报价 userid="13605" url="~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1419963/launchxl-f28p65x-sci-communication-issues/5441141 #5441141"]首先、我个人不应将 RX FIFO 级别设置为最大  SCI 中断在优先级列表中很低。 当 CPU 无法及时读取数据(例如、当 CPU 处于某个较高优先级的 ISR 时)、将 RX FIFO 设置为最大触发电平会导致 RX FIFO 溢出。 中断嵌套听起来很像修复、但您可能不想中断某些高优先级 ISR。[/QUOT]

    但这与你上面所说的相矛盾。 你是说它是一个折衷?

    我的主要关注点是在不影响系统性能的情况下保持数据完整性。  

    正如我说过的、我是 TI 的新员工、因此如果我的任何一件事有误、请纠正我的问题。

    再次感谢您提供的宝贵意见。

    [/quote]
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Ashwin:

    注意:while (scirxlvl){

    检查缓冲器电平(main.c)高速环路可能会导致 CPU 和 SCI 外设之间出现同步问题、此外还会浪费宝贵的 CPU 时间。 如 Gus 提到的、将 FIFO 触发电平设置为低于在单个 PIE 中断中预期的值以供 CPU 处理。 TRM 建议在 RXISR 处理程序中检查 RX 溢出状态。 我们忽略溢出数据、清除溢出并退出 RXISR。 串行数据可能会导致 FIFO 组帧错误、具体取决于电缆长度和 RX/TX 数据路径上的噪声。 即使在器件之间进行测试、也务必使用屏蔽双绞线来减少误差、尤其是在没有长距离接收器和发射驱动器的情况下进行测试。

          /* Check SCIFFRX register FIFO has overflowed */
            //if(SCI_getOverflowStatus(SCIB_BASE))
            if((HWREGH(SCIB_BASE + SCI_O_FFRX) & SCI_FFRX_RXFFOVF) == SCI_FFRX_RXFFOVF)
            {
                /* Clear Rx overflow status */
                //SCI_clearOverflowStatus(SCIB_BASE);
    
                /* clear SCIFFRX RXFFOVF SCIB */
                HWREGH(SCIB_BASE + SCI_O_FFRX) |= SCI_FFRX_RXFFOVRCLR;
    
                /* SCIA Prints event message */
                SCIprintf("\n*ClrOVF\n");
    
                /* Flush the RX buffer */
                for(i=0; i == 31; i++)
                {
                    CcRxBuff[i] = 0;
                }
    
                #if DEBUG
                    SCIprintf("\n>> RxBuffFlushed \n");
    
                #endif
    
                goto Exit;
    
            }
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Ashwin、

    我不知道您的 GNSS 模块的具体细节及其如何生成 UART 帧、因此很难提供建议。 我的建议是*如果*来自 GNSS 模块的 UART 数据包括帧中的字节数、那么您可以围绕该字段设计代码。 例如、 如果 GNSS 模块的最小帧长度为8个字符、和 如果 其中一个字符是帧长度、然后您可以将代码编写为:

    - RX 中断级别= 8

    -在 RX ISR 中,始终从 RX FIFO 读取8个字符。 如果是前8个字符、请确定帧长度、设置一些全局变量来跟踪接收到的字符数与总帧长度之间的关系

    -在 main.c 后台任务中,等待接收的字符数=总帧长度。 如果总帧长度不是8的倍数(UART RX INT 触发电平)、并且最后 N 个字符仍然存在、则轮询 UART RX FIFO 电平、直到接收到最后一个剩余字符。 此处、N =帧长度% 8。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Gus:

    感谢您的建议、

    我想我理解您的建议。 但是理想情况下、我最好在 RX ISR 内处理 N 个字符。 有一个逻辑要求我检查 RXFIL 电平、并使用该逻辑来获取 FIFO 中的数据。 但由于某种原因,即使我正在使用 HWREGH ,我也无法获得寄存器值。 这是我的主要问题之一。  

    正如 Genatco 提到的轮询缓冲区级别或轮询剩余字符可能会浪费系统资源、这也是我在 RX 端进行 FIFO 中断的主要动机。  

    我将尝试实施您的建议、并评估我的系统以查看哪些方法有效。  

    再次感谢您的建议 Gus 和 Genatco。  

    此致

    Ashwin Bhaskar A.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    x49c SCI RX FIFO 16级深度(10位寄存器)第一个字缓冲、(相同的 X65 SCI)??  我们设法在单个 ISR 循环中输入32个字符。 在清除 ACK SCI 组之前、检查 RX FIFO 触发器集6字 RXISR 输入循环函数会调用另一个 FIFO 漏极函数(如下)。  似乎与将 RXISR 返回地址推入堆栈和调用 RX 输入函数处理程序以耗尽 FIFO 有关。

     CPU 在调用 far process 32x 8位缓冲数据后的某个时间弹出调用堆栈。 SCI 外设为总线时钟、RXFIFO 将继续处理串行数据、额外的触发电平中断将被忽略、直到 SCI 组清除 ACK。 您可以输入尽可能多的字符、包括设置保持的字符缓冲器、ePIE 标志状态向 CPU 发出信号以保持处理中断数据。

    #define ARGU_NRX_BUF_SIZE           32
    
    /* Command input buffer */
    char CcRxBuff[ARGU_NRX_BUF_SIZE];
    
    /* Load RX data elements */
    for(i = 0; i <= 31; i++)
    {
        CcRxBuff[i] = (HWREG(SCIB_BASE + SCI_O_RXBUF) & SCI_RXBUF_SAR_M);
    }