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.