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 发送连续数据流。 我每次读取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 即可完成所有这些操作!
感谢您的帮助!