Framing errors with UART1 on K64F

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

Framing errors with UART1 on K64F

Jump to solution
1,271 Views
dave408
Senior Contributor II

I'm communicating from a K64F (master) to a K22F (slave) using Modbus RTU over RS485.  On the K64F, I am using UART1 connected to a TI SN65HVD1762 RS485 transceiver.

 

The problem I am having is that I'm seeing framing errors via my logic analyzer.  I am currently trying to send the following 8 byte packet: { 0x02, 0x04, 0x00, 0x0A, 0x00, 0x02, 0x51, 0xFA }.

 

If I use the following code:

 

     if( kStatus_UART_Success != Rs485WriteHelper( FSL_RS485_COMP, RS485_1_TXEN, packet, packet_size, MODBUS_SEND_TIMEOUT)) {       result.data.error_code = E_UART_MODBUSRTU_SEND;       return result;      }   

 

uart_status_t Rs485WriteHelper( uint32_t instance, uint32_t de_pin, const uint8_t *txBuff, uint32_t txSize, uint32_t timeout) {     GPIO_DRV_SetPinOutput( de_pin);     uart_status_t ret = UART_DRV_SendDataBlocking( instance, txBuff, txSize, timeout);     GPIO_DRV_ClearPinOutput( de_pin);     return ret; }

 

where packet_size is 8, I get a framing error in my logic analyzer results right before the 0x51, like this:

47557_47557.pngpastedImage_4.png

The results are the same if I send the first four bytes, followed by the next four bytes.  The results are the same if I send all 8 bytes, but one byte at a time.

 

What's weird is that If I change my code to endlessly loop and send 8 bytes at once, or 1 byte at a time, I don't get any framing errors -- see below:

47556_47556.pngpastedImage_3.png

 

I'm not sure what's going here.  Timing must be okay if the logic analyzer can read an endless stream of bytes.  Can anyone suggest something else for me to look at to understand why it's behaving like this?

Labels (1)
0 Kudos
1 Solution
795 Views
Kan_Li
NXP TechSupport
NXP TechSupport

Hi Dave408,

UART_DRV_SendDataBlocking() ends up the transfer when the last data is put to UART_D register , but it doesn't mean there is no output on the TXD pin when it returns, because the core runs much more faster than the UART peripheral in most of cases. so for your case, which needs an enable control pin for an external transceiver, you have to poll the TC(Transmit Complete Flag) bit before you clear the DE pin. so you may implement Rs485WriteHelper() like below:

  1. uart_status_t Rs485WriteHelper( uint32_t instance, uint32_t de_pin, const uint8_t *txBuff, uint32_t txSize, uint32_t timeout) 
  2. {
  3.     UART_Type * base = g_uartBase[instance];
  4.     GPIO_DRV_SetPinOutput( de_pin);
  5.     uart_status_t ret = UART_DRV_SendDataBlocking( instance, txBuff, txSize, timeout);
  6.     while(!(UART_HAL_GetStatusFlag(base,kUartTxComplete)));
  7.     GPIO_DRV_ClearPinOutput( de_pin);
  8. return ret; 
  9. }

Hope that helps,


Have a great day,
Kan

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

View solution in original post

6 Replies
795 Views
dave408
Senior Contributor II

I do believe this is a bug in the KSDK blocking function UART_DRV_SendDataBlocking.  In my code, I clear the DE pin after that function returns.  However, you will see below that the DE pin is cleared before the transmission of the last byte!

pastedImage_0.png

I have verified in my code that the function is sending an 8 byte packet, so it's not like the driver is expected to send a smaller number of bytes.

EDIT - I have also revised my code to send 4 bytes at a time, and I still see the problem where DE is lowered too early:

pastedImage_0.png

I'm now looking over void UART_DRV_IRQHandler(uint32_t instance) to see if there are any obvious bugs.  At the moment, nothing is jumping out at me.

0 Kudos
796 Views
Kan_Li
NXP TechSupport
NXP TechSupport

Hi Dave408,

UART_DRV_SendDataBlocking() ends up the transfer when the last data is put to UART_D register , but it doesn't mean there is no output on the TXD pin when it returns, because the core runs much more faster than the UART peripheral in most of cases. so for your case, which needs an enable control pin for an external transceiver, you have to poll the TC(Transmit Complete Flag) bit before you clear the DE pin. so you may implement Rs485WriteHelper() like below:

  1. uart_status_t Rs485WriteHelper( uint32_t instance, uint32_t de_pin, const uint8_t *txBuff, uint32_t txSize, uint32_t timeout) 
  2. {
  3.     UART_Type * base = g_uartBase[instance];
  4.     GPIO_DRV_SetPinOutput( de_pin);
  5.     uart_status_t ret = UART_DRV_SendDataBlocking( instance, txBuff, txSize, timeout);
  6.     while(!(UART_HAL_GetStatusFlag(base,kUartTxComplete)));
  7.     GPIO_DRV_ClearPinOutput( de_pin);
  8. return ret; 
  9. }

Hope that helps,


Have a great day,
Kan

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

795 Views
dave408
Senior Contributor II

Thanks, Kan!  I guess I didn't fully understand the UART code when I was reading it.  It was correctly looping over all of the characters and then signaling the semaphore at the right time, but I hadn't realized that the data wasn't actually being sent at that time.  :smileyhappy:

0 Kudos
795 Views
dave408
Senior Contributor II

The idle time before sending 0xFA does look a little weird.  I'm going to take two more logic analyzer screenshots with it zoomed way in.

Framing error when sending just 8 bytes:

framing error.PNG

No framing error when in infinite loop sending 8 bytes at a time:

no framing error if endless loop.PNG

Couldn't get the time scale to match between the two images, but what I see here is that in the failure case, there's not start bit.  The idle time is too long.  Perhaps another thing I can do is to rule out the effects of the DE pin on the RS485 transceiver, which enables transmission.  I could just leave it active high the entire time for the 8 byte transmission, just to see what happens.  I don't expect it to matter since I'm using the blocking UART functions.

0 Kudos
795 Views
dave408
Senior Contributor II

This is odd -- if I comment out the clearing of the DE pin in my Rs485WriteHelper function, then the last byte (0xFA) when sending a single 8 byte packet works fine!

pastedImage_0.png

If I put an OSA_TimeDelay(1) before lowering the DE pin, then it also works:

pastedImage_1.png

However, what's interesting is that it looks like when the DE line is pulled low, there's an associated blip on one of the RS485 lines:

pastedImage_2.png

You might also wonder why it's 5ms after, instead of 1ms after.  I think this is the associated overhead from using SDK functions for GPIO.

The next thing I might do is to toggle the DE pin rapidly to see if I get any sort of noise on the other RS485 line.

0 Kudos
795 Views
dave408
Senior Contributor II

Ok, maybe this has nothing to do with the KSDK or MQX at all.  When I toggle only DE and don't send any data, I get a square wave on one of the RS485 lines:

pastedImage_0.png

0 Kudos