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.

[参考译文] TMS320F280039C:SCI FIFO 中断帧错误

Guru**** 2526030 points
Other Parts Discussed in Thread: TMS320F280039C

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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1123907/tms320f280039c-sci-fifo-interrupt-framing-error

器件型号:TMS320F280039C

您好、  

在我的应用中、我有一个微控制 器、它的代码无法更改、从而向 TMS320F280039C 发送连续数据流。 我每次读取1个字节的数据、直到看到起始字符、然后连续读取47个字节的数据。  

如果我在接收到 Rx 中断时按如下所示对所有数据进行阻塞式读取、我可以确保这项工作可靠:  

但是、在57600波特率下、这需要8ms、而我的应用需要一个快速250us 中断来控制电机、因此我无法阻断8ms。 因此、与我在该 MCU 上的 SPI 上执行的操作一样、我切换到了以下过程:  

1) 1)一次读取1个字节、直到我看到停止字符

2) 2)将 FIFO 大小设置为16字节、等待 FIFO 中断接收 FIFO 满

3) 3)将字节存储在数组中

4) 4)获取另一个满16字节的 FIFO

5) 5)将字节存储在数组中

6)获取另一个15字节的 FIFO

7) 7)将字节存储在数组中

8) 8)现在我有了完整的数据包、返回到每次读取1个字节、直到我看到停止字符。  

现在的问题是、随着连续数据流进入、我会得到一个 Rx 组帧错误。 我关注的是、在 TI e2e 上、这似乎是 SCI 驱动程序中的一个错误、如果您使用具有连续数据流的 FIFO、它需要2个停止位? 如果是这种情况、这将是我们使用此 MCU 的主要问题。 我们无法将发送连续数据流的器件更改为发送2个停止位。 轮询不是一个选项、因为我的应用程序有很多必须处理的中断。  

这是我的初始化

void UcapBox_InitRS485(GE_Primary_Container_t *pContainer)
{
    // Register interrupt ISRs
    Interrupt_register(INT_SCIA_TX, &sciATxISR);
    Interrupt_register(INT_SCIA_RX, &sciARxISR);

    // Initialize SCIA and its FIFO.
    SCI_performSoftwareReset(REPJ_REPC_RS485_UART);

    // Configure SCIA
    SCI_setConfig(REPJ_REPC_RS485_UART, DEVICE_LSPCLK_FREQ, REPJ_REPC_BAUDRATE,
                        ( SCI_CONFIG_WLEN_8 |
                          SCI_CONFIG_STOP_ONE |
                          SCI_CONFIG_PAR_NONE ) );

    SCI_resetChannels(REPJ_REPC_RS485_UART);

    SCI_clearInterruptStatus(REPJ_REPC_RS485_UART, SCI_INT_RXFF | SCI_INT_FE | SCI_INT_RXERR);
    SCI_enableInterrupt(REPJ_REPC_RS485_UART, SCI_INT_RXFF); // We don't transmit to REPJ
    SCI_enableInterrupt(REPJ_REPC_RS485_UART, SCI_INT_FE);
    SCI_enableInterrupt(REPJ_REPC_RS485_UART, SCI_INT_RXERR);

    SCI_resetRxFIFO(REPJ_REPC_RS485_UART);
    SCI_resetTxFIFO(REPJ_REPC_RS485_UART);
    SCI_enableFIFO(REPJ_REPC_RS485_UART);
    SCI_enableModule(REPJ_REPC_RS485_UART);

    // Set how many bytes to trigger interrupt on
    SCI_setFIFOInterruptLevel(REPJ_REPC_RS485_UART, SCI_FIFO_TX0, SCI_FIFO_RX1);
    SCI_performSoftwareReset(REPJ_REPC_RS485_UART);

    // Enable interrupts
    Interrupt_enable(INT_SCIA_RX);

    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}

下面介绍了如何根据我是要读取1字节还是47字节来更改 FIFO 大小。  

int32_t UcapBox_StartUartTransfer(GE_Primary_Container_t *pContainer)
{
    pContainer->debugCnt++;

    // Perform software reset of SCI in case of any errors
    SCI_performSoftwareReset(REPJ_REPC_RS485_UART);

    pContainer->debugCnt++;

    if((dataSize < 16) && (dataSize > 0))
    {
        SCI_setFIFOInterruptLevel(REPJ_REPC_RS485_UART, SCI_FIFO_TX0, (SCI_RxFIFOLevel) dataSize);
    }
    else if(dataSize > 0)
    {
        SCI_setFIFOInterruptLevel(REPJ_REPC_RS485_UART, SCI_FIFO_TX0, SCI_FIFO_RX16);
    }

    bytesRemaining = dataSize;

    pContainer->debugCnt++;

    // Reset Rx FIFO
    SCI_clearInterruptStatus(REPJ_REPC_RS485_UART, SCI_INT_RXFF | SCI_INT_FE | SCI_INT_RXERR);
    SCI_clearOverflowStatus(REPJ_REPC_RS485_UART);
    SCI_resetRxFIFO(REPJ_REPC_RS485_UART);

    EINT; // Enable interrupts
    SCI_enableInterrupt(REPJ_REPC_RS485_UART, SCI_INT_RXFF);
    pContainer->debugCnt++;
    return 1;
}

这是我的 Rx 中断-  

void sciARxISRFunc(GE_Primary_Container_t *pContainer)
{
    uint32_t sciInterruptStatus = SCI_getInterruptStatus(REPJ_REPC_RS485_UART);

    pContainer->debugCnt++;

    // Rx error occurred
    if((sciInterruptStatus & SCI_INT_FE) || (sciInterruptStatus & SCI_INT_RXERR))
    {
        errorCnt++;

        SCI_clearInterruptStatus(REPJ_REPC_RS485_UART, SCI_INT_RXFF | SCI_INT_FE | SCI_INT_RXERR);
        SCI_clearOverflowStatus(REPJ_REPC_RS485_UART);
        SCI_resetRxFIFO(REPJ_REPC_RS485_UART);

        // Restart transfer
        UcapBox_SetTransferSize(1); // go back to reading 1 byte at a time
        UcapBox_StartUartTransfer(pContainer);

        pContainer->debugCnt++;
    }
    else if (sciInterruptStatus & SCI_INT_RXFF) // we have a full FIFO
    {
        // Calculate bytes remaining
        if ((bytesRemaining < 16) && (bytesRemaining > 0))
        {
            bytesRemaining = 0;
        }
        else if (bytesRemaining > 0)
        {
            bytesRemaining -= 16;
        }

        uint32_t tempUpperLim = 0;

        if(dataSize == bytesRemaining)
        {
            SCI_RxFIFOLevel RxFifoLevel;
            SCI_TxFIFOLevel TxFifoLevel;

            // Get Fifo level
            SCI_getFIFOInterruptLevel(REPJ_REPC_RS485_UART, &TxFifoLevel, &RxFifoLevel);

            tempUpperLim = (uint32_t) RxFifoLevel;
        }
        else
        {
            tempUpperLim = dataSize - bytesRemaining;
        }

        // Store data read
        int i = bytesRead;
        for(i = bytesRead; i < tempUpperLim; i++)
        {
            pContainer->mpUcapModule->mReceiveBuffer[i] = SCI_readCharNonBlocking(REPJ_REPC_RS485_UART);
            bytesRead++; // Increment bytes read
        }

        // Transfer complete
        if(bytesRemaining == 0)
        {
            // Reset bytesRead
            bytesRead = 0;

            // Call library callback function
            GE_UcapModule_Callback(pContainer, 0, 0);

            // Disable interrupt until we want another one
            SCI_disableInterrupt(REPJ_REPC_RS485_UART, SCI_INT_RXFF);
        }

        else if (bytesRemaining < 16)
        {
            SCI_setFIFOInterruptLevel(REPJ_REPC_RS485_UART, SCI_FIFO_TX0, (SCI_RxFIFOLevel) bytesRemaining);
        }

        else
        {
            SCI_setFIFOInterruptLevel(REPJ_REPC_RS485_UART, SCI_FIFO_TX0, SCI_FIFO_RX16);
        }

    //    uint32_t start = GetProfilerCycles();
    //
    //    // Read data coming in
    //    pContainer->mpCpuUtilization->mDebugTime1 = CalcProfilerTime(start, GetProfilerCycles());
    }

    SCI_clearOverflowStatus(REPJ_REPC_RS485_UART);
    SCI_clearInterruptStatus(REPJ_REPC_RS485_UART, SCI_INT_RXFF | SCI_INT_FE | SCI_INT_RXERR);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}

感谢您的帮助!

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

    尊敬的 Derek:

    我们的 SCI 专家将立即对此进行讨论。

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

    尊敬的 Derek:

    感谢您的提问。 遗憾的是、您所指的 SCI 错误是真实存在的、因为中断之间需要~2位周期才能触发 SCI 中断。

    目前有以下缓解方法:

    让另一个器件在每个16字节的数据包之后发送一个小延迟

    2.在另一个发送设备中使用2个停止位

    3.使用轮询而不是中断

      

    在您使用的器件中、另一种方法是此器件上有带有 DMA 连接的 LIN。 LIN 可在 SCI 模式下用作 SCI、因此理论上可以使用这种方法将 SCI 任务完全卸载到 DMA。

    如果您的系统可以这样做、我建议在 SCI 模式下使用具有 DMA 的 LIN。

    此致、

    Vince

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

    感谢您的回复! 这很不幸。 我们无法更改传输端的任何内容、但我有一个变通办法想法、可能起作用。  

    我们的应用具有1ms 中断、每1ms 数据从发送器获取6个字节。 我可以使用16字节 FIFO、然后每1ms 将 FIFO 中的任何内容存储到我自己的软件 FIFO 中。 让我尝试一下、如果遇到任何问题、我会告诉您!  

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

    您好、Vince、  

    我只想确认使用轮询对我有效! 我所做的是:  

    1) 1)在慢速1ms 中断开始时、我检查 SCI Rx FIFO 中有多少字节

    2) 2)我将这些字节存储在大型软件 FIFO 中

    3) 3)接收到所需的字节数后、我会处理数据

    这很好! 轮询仅占用我的慢速中断220个时钟周期、因此大约2us 即可完成所有这些操作!  

    感谢您的帮助!