UART_DRV_EdmaGetReceiveStatus reports that it has received a certain amount of data before it actually has

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

UART_DRV_EdmaGetReceiveStatus reports that it has received a certain amount of data before it actually has

671 Views
siddharthmenon
Contributor I

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

Labels (1)
0 Kudos
2 Replies

336 Views
Kan_Li
NXP TechSupport
NXP TechSupport

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

0 Kudos

336 Views
siddharthmenon
Contributor I

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.

0 Kudos