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?
已解决! 转到解答。
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.
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
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
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):
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
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
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
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:
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
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
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
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)?
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.
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.
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
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