Hey,
In my application, I have one microcontroller whose code cannot be changed sending a continuous stream of data to the TMS320F280039C. I am reading this data 1 byte at a time until I see the start character and then read 47 bytes of data consecutively.
I have this working reliably if I do a blocking read of all data as below when I get an Rx interrupt:
However, at a 57600 baud rate this takes 8ms and my application needs a fast 250us interrupt to control a motor so I cannot block for 8ms. Therefore, like I do on my SPI on this MCU, I switched to the below process:
1) Read 1 byte at a time until I see the stop char
2) Set FIFO size to 16 bytes, wait for FIFO interrupt for Rx FIFO full
3) Store bytes in array
4) Get another FIFO full of 16 bytes
5) Store bytes in array
6) Get another FIFO of 15 bytes
7) Store bytes in array
8) Now I have complete packet, go back to reading 1 byte a time until I see the stop char.
The issue now is that with the continuous data stream coming in I get an Rx framing error. What concerns me is that looking on TI e2e this seems to be a bug in the SCI driver where it needs 2 stop bits if you're using a FIFO with a continuous stream of data? If this is the case this will be a major issue with us using this MCU. We cannot change the device sending a continuous stream of data to send 2 stop bits. Polling is not an option because my application has many interrupts that must be serviced.
This is my initialization
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); }
Here is how I am changing FIFO size based on whether I want to read 1 or 47 bytes.
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; }
Here is my Rx interrupt -
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); }
Thanks for the help!