i.MX28 Windows CE BSP Serial Port Bug Missing Received Data

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

i.MX28 Windows CE BSP Serial Port Bug Missing Received Data

Jump to solution
7,013 Views
markwilliams
Senior Contributor I

Hi,


We are using the i.MX28 with the current BSP and have noticed that the UART serial interface is losing data. On closer inspection of the driver I think I have found a bug in the code and could do with some support to resolve this.

The serial receive interrupt handler function is defined as ULONG SL_RxIntrHandler(PVOID pContext,PUCHAR pTargetBuffer,ULONG *pByteNumber) at the following path:

C:\WINCE600\PLATFORM\COMMON\src\soc\COMMON_FSL_V2_PDK1_9\SERIALAPP\COM_PDD\serialhw.c

The parameters are defined as:

//      pContext

//          [in] Pointer to device head.

//      pTargetBuffer

//          [in] Pointer to the target buffer in which to put the data.

//      pByteNumber

//          [in] Pointer to, on entry, the maximum number of bytes to read. On exit, the number of

//                bytes read.

This follows the Microsoft function prototype for HWRxIntrHandler.

I have found that the pByteNumber value is not the number of bytes to read but a decrementing value each time a block of data is received. On the first receive the value is 2047, and then for each block of received data this value decrements by the size of the last received block each time the RX interrupt handler runs.

Eventually the pByteNumber passed gets lower than the size of the next block of data received. In this case the remaining data is thrown away and the value reset to 2047. I have some debug output to show this:

Below I am sending chunks of 409 bytes into the serial port. The 'len' value in the SL_RxIntrHandler+ debug output is actually the *pByteNumber value - clearly not the number of bytes received and also decrementing on each receive.

The ByteRead value is what the RX interrupt got out of the receive - not always 409 bytes.

4491457 PID:400002 TID:1a50006 Rx Event

4491457 PID:400002 TID:1a50006 SL_RxIntrHandler+ : len 2047. EvtChar 0x1a

4491457 PID:400002 TID:1a50006 After HWGetBytes, Fifo(R=0,W=0,BA=0,L=2048) ByteRead=409

4491907 PID:400002 TID:1a50006 Rx Event

4491907 PID:400002 TID:1a50006 SL_RxIntrHandler+ : len 1639. EvtChar 0x1a

4491907 PID:400002 TID:1a50006 After HWGetBytes, Fifo(R=409,W=409,BA=0,L=2048) ByteRead=409

4494129 PID:400002 TID:1a50006 Rx Event

4494129 PID:400002 TID:1a50006 SL_RxIntrHandler+ : len 1230. EvtChar 0x1a

4494129 PID:400002 TID:1a50006 After HWGetBytes, Fifo(R=818,W=818,BA=0,L=2048) ByteRead=409

4494753 PID:400002 TID:1a50006 Rx Event

4494753 PID:400002 TID:1a50006 SL_RxIntrHandler+ : len 821. EvtChar 0x1a

4494753 PID:400002 TID:1a50006 After HWGetBytes, Fifo(R=1227,W=1227,BA=0,L=2048) ByteRead=409

4497799 PID:400002 TID:1a50006 Rx Event

4497799 PID:400002 TID:1a50006 SL_RxIntrHandler+ : len 412. EvtChar 0x1a

4497799 PID:400002 TID:1a50006 After HWGetBytes, Fifo(R=1636,W=1636,BA=0,L=2048) ByteRead=409

4498068 PID:400002 TID:1a50006 Rx Event                                                                      **********  409 chars are sent in here but after the function it only reads 3 and throws the rest away *************

4498068 PID:400002 TID:1a50006 SL_RxIntrHandler+ : len 3. EvtChar 0x1a

4498068 PID:400002 TID:1a50006 After HWGetBytes, Fifo(R=2045,W=2045,BA=0,L=2048) ByteRead=3

4500466 PID:400002 TID:1a50006 Rx Event                                      

4500466 PID:400002 TID:1a50006 SL_RxIntrHandler+ : len 2047. EvtChar 0x1a                  **********  len 'counter' value back to 2047 *************

4500466 PID:400002 TID:1a50006 After HWGetBytes, Fifo(R=0,W=0,BA=0,L=2048) ByteRead=409

4500906 PID:400002 TID:1a50006 Rx Event

4500906 PID:400002 TID:1a50006 SL_RxIntrHandler+ : len 1639. EvtChar 0x1a

4500906 PID:400002 TID:1a50006 After HWGetBytes, Fifo(R=409,W=409,BA=0,L=2048) ByteRead=409

The calling function SerialEventHandler() is in the freescale file mdd.c at the following path and calls the above using a function pointer as pFuncTbl->HWRxIntrHandler:

C:\WINCE600\PLATFORM\COMMON\src\soc\COMMON_FSL_V2_PDK1_9\SERIALAPP\COM_MDD2\mdd.c

As part of this function it calculates a 'RoomLeft' variable and passes a pointer to this in to the HWRxIntrHandler as the 'pByteNumber' parameter. Clearly this is not the correct thing to be passing.

if ( RxRIndex == 0 ) {

                // have to leave one byte free.

                RoomLeft = RxLength(pSerialHead) - RxWIndex - 1;

            } else {

                RoomLeft = RxLength(pSerialHead) - RxWIndex;

            }

            if ( RxRIndex > RxWIndex ) {

                RoomLeft = RxRIndex - RxWIndex - 1;

            }

            if ( RoomLeft ) {

                pSerialHead->DroppedBytesPDD +=

                    pFuncTbl->HWRxIntrHandler(pHWHead,

                                              RxBuffWrite(pSerialHead),

                                              &RoomLeft);

            } else {

                BYTE TempBuf[16];

                RoomLeft = 16;

                pFuncTbl->HWRxIntrHandler(pHWHead,

                                          TempBuf,

                                          &RoomLeft);

I would have thought that the RX handler would be passed the number of bytes to extract from the DMA memory and return how many it managed to read on that interrupt. Therefore I do not understand why it is a decrementing number.

Anyway it is clear that the Freescale i.MX28 Windows CE 6.0 BSP throws serial data away due to the above issue.

Can anyone help me with this?

Labels (2)
0 Kudos
Reply
1 Solution
4,681 Views
Bio_TICFSL
NXP TechSupport
NXP TechSupport

This issue can be closed

View solution in original post

0 Kudos
Reply
26 Replies
4,682 Views
Bio_TICFSL
NXP TechSupport
NXP TechSupport

This issue can be closed

0 Kudos
Reply
4,250 Views
ScottStone
Contributor I

We too have had this problem. We use an IMX.23  (i.MX233) and needed to download 400kb of data to our cellular device for field updates .  After 4 long and horrible  days of looking at or C++ readfile serial routines and seeing characters lost, we finally found this blog post.

 

We have not tried to resolve this in our BSP, as but have seen this result below  for results proving it is the issue above.

 

  • > if we send blocks of data with mults of 512,1024 or 2048 and wait 100ms in the processing of the block before getting another, we can download 50 MB without a lost byte
  • > if we use any other blocks like 1000 or 2000 bytes, we loose data every 50-100 blocks . This is normally ~ 50-100 bytes at a time.. they just disappear.!

This is 100% verified.  So thanks for the hint above... It saved the day!

We will ask NXP (Freescale) if they have a patch for our WinCE 6.0 BSP. If anyone has this already...please feel very free to post it here!!!  Thanks :)

 

Keyword Phrase:     IMX 23 Freescale looses data and drops packets in receive regardless of how the Comm Port Serial UART is configured and used. Lost data in IMX Jan 2017

 

0 Kudos
Reply
4,250 Views
sinclaireaston
Contributor I

Any update on this thread? I have a very similar issue with the i.MX 6 SABRE with Adeneo BSP WINEC2013.

What are my options?

0 Kudos
Reply
4,250 Views
markwilliams
Senior Contributor I

Hi Sinclair,

I posted my source in one of the replies above. It is worth comparing the serialhw.c file in your WEC2013 BSP. I assume that Adeneo have cloned this into other Windows CE BSPs. The DMA implementation is likely to be different.

Admittedly the thread above is a bit mixed up as I posted as I was tracing through the issue and trying to understand the code.

To identify the fault we had a serial terminal running on our i.MX28 platform and were sending packets of known data in chunks that would not divide into the buffer size (causing an overflow). We then noted that the packet that caused the buffer overflow had missing data.

Mark

0 Kudos
Reply
4,250 Views
sinclaireaston
Contributor I

Hi Mark,

Thank you. It was the same problem. I turned off the DMA and it worked OK. It didn't help that the UARTApp sample also has a bug, sigh.

Sinclair

0 Kudos
Reply
4,278 Views
markwilliams
Senior Contributor I

I have been looking further into the SDMA implementation used by the serial port driver. It appears to work as follows (correct me if I am wrong):

  • The SDMA is set up in serialhw.c in the SL_Open() function initially, then in the SL_RxIntrHandler() function after completion of each DMA command chain.

  • The function SetupRXDescDESC() initialises a chain of commands in memory that is later passed to DDKApbxStartDma() function to load into the DMA registers. There are SERIAL_MAX_DESC_COUNT_RX (2) commands in the chain and a different RAM buffer used for the received data for each DMA command.

  • When serial data is received it triggers an SDMA command complete interrupt either through filling the buffer or a timeout condition (i.e. some data received but not enough to complete the SDMA command, after timeout the command is terminated so the data can be processed)

  • On the first SDMA interrupt the data is collected and the pSerHead->currRxDmaBufId set to 1 to flag to the PDD the second buffer is being used for the next interrupt

  • On the second SDMA interrupt the command chain is complete (just two commands). After extracting the data the pSerHead->currRxDmaBufId is set to 0 and the whole DMA chain reinitialised. Presumably this means that while extracting data from the second command DMA buffer the DMA chain has no more commands to process and therefore any data received filling the UART hardware buffer will be lost until the DMA chain is reinitialised.

I have read the section on SDMA in the reference manual. Is it possible to set the second DMA command in the chain to point back to the first? I.e. after completing receiving data into the second buffer the command chain switches automatically back to receiving into the first buffer?

It looks like I would just need to change SetupRXDescDESC() to make the second command point back to the first so the two commands continually run in a loop without having to re-init the chain on completion.

Can anyone provide and help or advice?

Regards, Mark

0 Kudos
Reply
4,250 Views
YixingKong
Senior Contributor IV

Mark

Had your issue got resolved? If yes, we are going to close the discussion in 3 days. If you still need help, please feel free to reply with an update to this discussion.

Thanks,

Yixing

0 Kudos
Reply
4,278 Views
markwilliams
Senior Contributor I

Further to the above it looks like the usage of the semaphore counter may need to change. The DMA commands are set up to decrement the semaphore counter for the channel on completion. The DDKApbxStartDma() call sets the DMA counter to the number of commands in the chain.

If I was to implement a continuous loop of commands I presume I would need to clear the 'decrement semaphore' flag bit in the SetupRXDescDESC() function to prevent the DMA going idle on completion of the second DMA DESC so they loop forever. Is this ok to do?

Mark

0 Kudos
Reply
4,250 Views
YixingKong
Senior Contributor IV

Mark

When replying, please click reply in the box you want to send email to. The above two email were sent to yourself. Others would not see them.

Thanks,

Yixing

0 Kudos
Reply
4,278 Views
markwilliams
Senior Contributor I

Hi all,

I finally got round to looking at the code for the serial port driver and I believe I have fixed the issue. From my testing I am now receiving all data (whether it wraps-around or not). There are still some parts of the driver I am not too sure about in terms of the decisions made by the original designer to implement the DMA in the way it currently is.

Just to summarise the original issue - the Freescale-supplied Windows CE Application UART driver (C:\WINCE600\PLATFORM\COMMON\src\soc\COMMON_FSL_V2_PDK1_9\SERIALAPP\) does not handle wrapping of the MDD serial receive buffer. If more data is received than there is room at the top of the buffer for, then the additional wrapped data is thrown away. In a packet-based comms protocol this could mean partial packets are lost. With message retries this would potentially be hidden and still work.

The receive is handled by the APBX DMA controller. The DMA command chain for the serial receive consists of two transfers that attempt to transfer the buffer size before generating an interrupt. If a small packet is received a time-out will generate the interrupt. The first DMA command in the chain copies data to buffer 0, the second one to buffer 1.

After the second DMA command the chain is re-initialised (DMA commands reloaded). I am not sure why two DMA buffers are used - if there is enough time to re-initialise the DMA in the interrupt handler then a single buffer could be used.

The problem with the original code was caused by the implementation of the PDD part of the driver. The MDD will call into the PDD while the interrupt is to be processed. To handle buffer wrap-around we need to:

  • MDD - check the interrupt source by calling into the PDD function SL_GetIntrType - do not clear the status flags at this point
  • MDD - Calculate the space to the end of the buffer (ignoring wrap around)
  • PDD - Linearly copy as many bytes from DMA as we can get into the top of the buffer
  • PDD - Clear the interrupt flag if we copied them all and toggle / re-init the DMA
  • PDD - Leave the interrupt if the received bytes exceeds the top of buffer space and need to wrap-around - at this point we need to store how many bytes left to read and where in the DMA buffer to get them from
  • MDD - Move on the write pointer
  • MDD - see the interrupt is still set (for wrap) and recalculate space to read pointer
  • PDD - realise we are back in to collect more data from the previous attempt and copy the rest - then clear the interrupt flag
  • MDD - Move on the write pointer and signal to the read function that there is serial data available

I have implemented this as changes to the PDD. You can see my changes in the two functions: SL_GetIntrType() and SL_RxIntrHandler(). Use a diff tool with the original file for a true comparison. The MDD is the same as supplied.

The file to edit is:

C:\WINCE600\PLATFORM\COMMON\src\soc\COMMON_FSL_V2_PDK1_9\SERIALAPP\COM_PDD\serialhw.c

I will try and attach the code. I would appreciate it if anyone experiencing this issue could 'peer review' for me and let me know if there are any issues. I need to check how this handles errors in the serial data or overrun conditions.

Mark

0 Kudos
Reply
4,277 Views
YixingKong
Senior Contributor IV

Mark

How is the progress of your issue after Adeneo's response? If it is resolved, we are going to close the discussion in 3 days. If you still need help, please feel free to reply with an update to this discussion.

Thanks,

Yixing


0 Kudos
Reply
4,277 Views
markwilliams
Senior Contributor I

Please do not close this issue yet as it is not resolved! I thought I had a fix but Adeneo have since commented.

Please note that this appears to also be in your Compact 7 BSP in the common folder so probably affects your Windows CE serial receive for the i.MX28, i.MX51 and i.MX53 platforms.

C:\WINCE700\platform\common\src\soc\COMMON_FSL_V3\SERIALAPP\COM_MDD2

How do I get Freescale to help resolve this issue? Serial transfer is pretty fundamental in an embedded application so really needs to be working in a reference BSP.

Kind regards,

Mark

0 Kudos
Reply
4,277 Views
codejingle
Contributor I

If you are having trouble with DMA, have you tried the driver with DMA support forced as disabled (set useDMA to FALSE in the function that normally sets it based off of a registry or register setting)?

0 Kudos
Reply
4,277 Views
markwilliams
Senior Contributor I

Unfortunately it won't make any difference. The MDD controls the circular buffer. Even if using direct serial port hardware a received length causing a MDD buffer circular wrap will throw away part of the packet that wraps.

0 Kudos
Reply
4,278 Views
markwilliams
Senior Contributor I

Yixing,

Another forum member sent me some code to use but I am not 100% confident in the fix as I do not understand how the two DMA buffers are intended to be used. It does appear to work in testing.

Did Adeneo write the BSP for these parts? Is it possible to obtain support for the BSPs from them? We plan to put this in a production product and we need reliability in the serial port comms.

0 Kudos
Reply
4,278 Views
JDFAE
NXP Employee
NXP Employee

Please attach the code to this post so others can check it out.

0 Kudos
Reply
4,278 Views
YixingKong
Senior Contributor IV

William

Adeneo did not write BSP, instead works as supporter. You may contact Adeneo directly and ask details.

As to DMA buffers, I may find an engineer from Freescale to help you in the question. But that engieer may answer you general DMA question, not Wince questions. Please put your DMA question here.


Thanks,

Yixing

0 Kudos
Reply
4,278 Views
YixingKong
Senior Contributor IV

karinavalencia, could you see if you are able to find someone to help this one?

Thanks,

Yixing

0 Kudos
Reply
4,278 Views
YixingKong
Senior Contributor IV

Deactivated user, could you see if you could decide this DI can be closed?

Thanks,

Yixing

0 Kudos
Reply
4,278 Views
markwilliams
Senior Contributor I

Testing this a little further it seems the buffer pointer calculations made in mdd.c for the application serial port are incorrect. I need to try and understand a little more about the driver but running through with the debugger it seems that the receive buffer read pointer does not always keep up with the write pointer.

In the instance that the two are equal and not zero the calculation for buffer space remaining is:

RoomLeft = RxLength(pSerialHead) - RxWIndex;


Which is odd. If both pointers are the same and at say byte 2040 then it thinks that there is only 2048-2040 = 8 bytes available to use? Technically the whole buffer is available to use?


I will keep looking through the code but I assume this same driver code is cloned for other Freescale i.MX BSPs? Does anyone else see this issue?


Regards, Mark

0 Kudos
Reply