Hi,
I'm using the Kinetis SDK 1.2 with the FRDMK64f board.
My application uses the CMSIS RTX OS has only one thread. I am trying to start receiving data from UART0 at 115200 baud, using UART_DRV_EdmaReceiveData, and I store the data into a thread safe FIFO. In a polling loop I am making calls to UART_DRV_EdmaGetReceiveStatus, and I advance the tail of the FIFO by how many ever bytes UART_DRV_EdmaGetReceiveStatus tells me it received (I am disabling interrupts when i call UART_DRV_EdmaReceiveData and when I advance the tail of the FIFO).
The problem is that, sporadically, the data actually received looks incorrect. Specifically, although UART_DRV_EdmaReceiveData tells me it has received a certain number of bytes (this is generally of the order of 600 or so), when I copy the "new" data in my FIFO, it looks like the data did not actually get written (old values are being copied). However, if i put a breakpoint in my code (i'm using J-Link for debugging), it looks like the data in the FIFO is correct... so presumably by the time the breakpoint got hit the EDMA completed writing all the data.
Like i mentioned, this happens sporadically, and it is more frequent when a lot of data is being sent to UART0.
The code I have is pretty complicated, and i'm not sure how I can give you reproduction steps. Has anyone encountered anything similar, or is there a bug with the SDK that may be causing this behavior.
Thanks,
Sid
Hi Sid,
As you mentioned "I am disabling interrupts when i call UART_DRV_EdmaReceiveData and when I advance the tail of the FIFO", I think that might be the cause, you know, in the example of "uart_edma_non_blocking", interrupr is enabled before calling UART_DRV_EdmaReceiveData(), please kindly refer to "C:\Freescale\KSDK_1.2.0\examples\frdmk64f\driver_examples\uart\uart_edma_non_blocking" for more details.
Hope that helps,
Have a great day!
Kan
Hi Kan,
Thanks for your suggestion. Unfortunately that does not solve my problem. Let me give you more information.
this is how i initialize the UART EDMA (this is not the actual code, but an equivalent):
void CommService::initializeDMA()
{
/* NOTE: the following properties are stored as private properties of the CommService class
edma_user_config_t edmaConfig_;
uart_edma_user_config_t uartEdmaConfig_;
uart_edma_state_t uartEdmaState_;
edma_callback_t driverTxCallback_;
edma_callback_t driverRxCallback_;
*/
// initialize the EDMA
edmaConfig_.chnArbitration = kEDMAChnArbitrationRoundrobin;
edmaConfig_.notHaltOnError = false;
EDMA_DRV_Init(&edmaState_, &edmaConfig_);
// configure the edma uart driver
uartEdmaConfig_.baudRate = BAUD_RATE;
uartEdmaConfig_.bitCountPerChar = kUart8BitsPerChar;
uartEdmaConfig_.parityMode = kUartParityDisabled;
uartEdmaConfig_.stopBitCount = kUartOneStopBit;
UART_DRV_EdmaInit(UART_INSTANCE, &uartEdmaState_, &uartEdmaConfig_);
// replace dma completions installed by init with our own
driverTxCallback_ = uartEdmaState_.edmaUartTx.callback;
uartEdmaState_.edmaUartTx.callback = sendComplete;
driverRxCallback_ = uartEdmaState_.edmaUartRx.callback;
uartEdmaState_.edmaUartRx.callback = receiveComplete;
dmaInitialized_ = true;
dmaChannelError_ = false;
}
In receiveComplete()... the custom callback that gets invoked after the UART receive has finished(or in case of a channel error), i do this:
extern "C" void receiveComplete(void *param, edma_chn_status_t status)
{
using coder::tgtsvc::CommService;
auto &cs = CommService::instance();
if (status == kEDMAChnError) {
cs.setChannelErrorFlag(); //sets an error flag that terminates the program
}
// call the driver's callback
cs.driverRxCallback_(param, status);
// add recently received bytes to fifo
cs.rxFIFO_.contents_add(cs.recvCount_); //advance the tail of rxFIFO
cs.recvCount_ = 0;
// start a new dma receive
auto ra = cs.rxFIFO_.space_carray(); //ra is an object of data structure that stores contiguous data from a managed pool
cs.recvCount_ = ra.size_; //ra.size is a large number, we don't know how much the sender actually wants to send at this point
// I am currently working around this bug, by setting cs.recvCount_ = 1;
///\todo overflow error if cs.recvCount_ == 0
UART_DRV_EdmaReceiveData(CommService::UART_INSTANCE, ra.addr_, cs.recvCount_);
}
Now in the program's main thread, i call this method:
void CommService::updateReceiveStatus()
{
// I am currently working around this bug by not doing anything in this method, as receiveComplete() advances the tail of rxFIFO
uint32_t n = 0;
UART_DRV_EdmaGetReceiveStatus(UART_INSTANCE, &n);
uint32_t bytesReceived = recvCount_ - n;
if (bytesReceived>0)
{
GlobalGuard guard; //disables interrupts when in scope, note that i'm not doing this before UART_DRV_EdmaGetReceiveStatus is called
recvCount_ = n;
rxFIFO_.contents_add(bytesReceived);
uint8_t cmdId = rxFIFO_.front(); //gets the first 9 bytes in the rxFIFO
// if bytesReceived is a number >100 or so, and , if I pause for an arbitrary amount of time
// for example using CMSIS RTX's osDelay(100) to delay for 100ms
uint8_t cmdId2 = rxFIFO_.front(); //gets the first 9 bytes in the rxFIFO again
assert(cmdId ==cmdId); //this assertion fails!!
}
}
I hope this makes things more clear.