Changing UART Baud Rate in FreeRTOS? Flushing FIFOs

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

Changing UART Baud Rate in FreeRTOS? Flushing FIFOs

Jump to solution
1,911 Views
myke_predko
Senior Contributor III

Hiya,

I'm using the FreeRTOS UART driver (SDK 2.3.1 with a MK22FN1M0Axxx12) for my application and there are cases where I need to change the baud rate of the UART.  There is a workflow where there is the need to change the initial baud rate, change the (Bluetooth) module that it is communicating with to the higher baud rate and then changing back.  

I have tried using the basic UART driver change baud rate:

UART_SetBaudRate(BT_UART
               , BT_UART_INITIAL_BAUDRATE
               , BT_UART_CLK_FREQ);

When I test with "UART_SetBaudRate", I can see the data come out at the new baud rate.  

But when data comes in, it's not received in software.  

  • I've tried doing an "UART_RTOS_DEINIT()" but this failes with a semihost_hardfault.  
  • I've tried doing a second "UART_RTOS_INIT()" but when data comes in, it's not received.  In the application, this would ahve to be done twice 

If I don't try changing the baud rate, UART operations work without any problems with multiple transmits/receives.  

What is the right way to change the baud rate of the UART in FreeRTOS?

2020.03.28 - I'm doing testing on my product and I'm introducing different error conditions - one being to halt processor execution to force an error on the device connected to the FreeRTOS Kinetis device.  When I resume execution followed by communications, I get repeated Hardware Buffer Overruns until I remove power from the Kinetis.  If I take a look at the Refrence Manual, this looks like the UART FIFOs aren't being flushed on reset.  

Is there a way using the FreeRTOS APIs to flush the UART's FIFOs or will I have to manually access the UARTx_CFIFO Flush bits?  

1 Solution
1,544 Views
myke_predko
Senior Contributor III

Hi Kerry,

Thank you for the information regarding the break operation - I'll be interested in hearing what Daniel has to say about it regards to the FreeRTOS UART Driver.  

There is good news!  Yesterday I built a simple two transistor Open-Collector buffer with the ability to force the output line to be always high from an IO pin.  Sorry that the picture below is from my camera and is a bit fuzzy (and still has the oscillocope scope probes on it).  

2020.04.03 - UART Buffer Circuit - close up.jpg

Creating the circuit turned out to be a bit more work than I expected - I guess it's because I used bipoar NPN transistors, and there is more capacitance in the lines that I would have expected.  The current limiting resistors for the transistor bases turned out to be 4k7 and the pull up on the RX line going to the MK22 needed to be 2k0 in order to get reasonably good quality edges on the signals.  This was a surprise because the datasheet indicates that the input capacitance on the DI/DO pins is 7pF but looking at the oscilloscope traces to measure the rise time constant, the nets were calculated to have an input capacitance of 23pF.   

The other issue I had was the Hardware Buffer Overrun and Daniel's suggestion that I clear the buffer when this error happened worked a treat - it's a simple one line fix:

if (kStatus_UART_RxHardwareOverrun == UART_RTOS_Receive(&handle
                                                      , &recvChar
                                                      , sizeof(recvChar)
                                                      , &n)) {
  UART0->SFIFO |= UART_SFIFO_RXOF(1);  //  Clear Hardware Overrun
#if (2 != SDK_DEBUGCONSOLE)
  PRINTF("\rBTRX_task Hardware Overrun");
#endif
#ifdef stopFromSuspendingOnHardwareOverrun
  vTaskSuspend(NULL);
#endif
}

So, after more than a week of work, I have the FreeRTOS UART drivers working the way I want them.  

Thanks to you and Daniel for your help.  

View solution in original post

7 Replies
1,544 Views
danielchen
NXP TechSupport
NXP TechSupport

Hi Myke:

It is not normal to change the baud rate while the uart is running.

FreeRTOS  uart river is a wrapper based on uart driver.  UART_SetBaudRate is the right way to change baud rate.

If this does not work, you can check the status register, if there is some error flag, please clear it and try it again.

Yes, currently no FreeRTOS API to flush UART FIFO, you need to do it manually.

Regards

Daniel

0 Kudos
1,544 Views
myke_predko
Senior Contributor III

Hey Daniel,

Okay, I've gone through the registers (see my post regarding that distraction) and I can't see why the FreeRTOS UART Receive is shutting down.  

I've reviewed the following UART registers:

C1, C2, C3, C4, C5

S1, S2

D

MA1, MA2

ED

MODEM

IR

PFIFO, CFIFO, SFIFO, TWFIFO, TCFIFO

and other than the RXEDGIF bit in S2 being different (when the first read works this bit is set, if it doesn't the bit is reset - what's interesting is that this bit becomes set on subsequent reads which is strange).  

I don't want to get into too much of the BT Module I'm communicating with but I think I need to explain what's happening.   The issue is that straight from the box the module runs at 19,200bps and I want to run it normally at 921,600bps.  I can set the datarate of the module that is set in EEPROM (so later boots are at full speed) but for the first boot it is at 19,200bps.  

On boot, I do a test communication at 921,600bps as this is the datarate the module will be running at every time except the first time - if I get a good reply packet then I just continue with the rest of the application.  

If I don't get a good reply, I cycle power on the unit and change the Kinetis baud rate to 19,200bps and then go through a process where I set the baud rate to 921,600bps.  Since RTOS_UART_Receive is no longer working, this process can't go forwards.  

I must point out that I am porting code from MQX, so I know this process and BT Module works.  

Can you suggest where I should be looking for the error that stops FreeRTOS receives?  

Thank you.  

0 Kudos
1,544 Views
myke_predko
Senior Contributor III

Hey Kerry and Daniel,

I figured out the problem - The TX line from the BT Module is being dropped for what I guess is too long during the process in which the baud rate of the module is being changed.  


I saw it on my oscilloscope when I triggered on the RX line into the Kinetis from the BT Module - there was a 50ms long low after the ACK reply saying the module had changed it's baud rate.  Not listed on the (admittedly poor) datasheet.  This is obviously not an issue with the Bare Metal implementation.  

Ideas on how to work with this on the FreeRTOS implementation?  There's actually three parts to this question, the first is when I have to change the baud rate, how do I avoid this issue with the FreeRTOS driver.  The second part is when I go into low-power mode on the product.  I'm turning off power to the module when the product goes to sleep and this will drop the RX line coming in to the Kinetis - I do have a 100k pull up on the line but this is overpowered by the BT Module in both cases.  The BT Module does have a "Sleep Mode" but this reduces it's current draw to 0.9mA which isn't all that great.  

I think the best solution to the first two problems is to run the TX lline from the BT Module through an OR gate which I can control as "high" when the TX line goes low.  Could I ask if the line going low is interpreted as a "break" and could be handled in software (which would be the best solution)?  

The third part of the question is what happens when the Kinetis goes into Very Low Power Mode under FreeRTOS?  Can I expect any problems or should I try it and see?  

Thanx.  

1,544 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hello Myke Predko,

   Thanks for your detail analysis.

   Now, I answer your bare-metal question,  do you mean, when you BT go to sleep, then the RX pin will be pull low, and after your BT wakeup and the Kinetis baudrate is changed, it can't receive the UART from your BT module?

  About the break, the kinetis has:

Optional 13-bit break character generation / 11-bit break character detection

 So, I think your break time can't be very long.

  I have a question, when your BT module pull the TX(kinetis RX) as low, then the kinetis can't receive the UART data, what's the data in your register LPUARTx_STAT?

  About the freertos question, Daniel Chen  please help to reply it.

 

Kerry

 

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

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos
1,545 Views
myke_predko
Senior Contributor III

Hi Kerry,

Thank you for the information regarding the break operation - I'll be interested in hearing what Daniel has to say about it regards to the FreeRTOS UART Driver.  

There is good news!  Yesterday I built a simple two transistor Open-Collector buffer with the ability to force the output line to be always high from an IO pin.  Sorry that the picture below is from my camera and is a bit fuzzy (and still has the oscillocope scope probes on it).  

2020.04.03 - UART Buffer Circuit - close up.jpg

Creating the circuit turned out to be a bit more work than I expected - I guess it's because I used bipoar NPN transistors, and there is more capacitance in the lines that I would have expected.  The current limiting resistors for the transistor bases turned out to be 4k7 and the pull up on the RX line going to the MK22 needed to be 2k0 in order to get reasonably good quality edges on the signals.  This was a surprise because the datasheet indicates that the input capacitance on the DI/DO pins is 7pF but looking at the oscilloscope traces to measure the rise time constant, the nets were calculated to have an input capacitance of 23pF.   

The other issue I had was the Hardware Buffer Overrun and Daniel's suggestion that I clear the buffer when this error happened worked a treat - it's a simple one line fix:

if (kStatus_UART_RxHardwareOverrun == UART_RTOS_Receive(&handle
                                                      , &recvChar
                                                      , sizeof(recvChar)
                                                      , &n)) {
  UART0->SFIFO |= UART_SFIFO_RXOF(1);  //  Clear Hardware Overrun
#if (2 != SDK_DEBUGCONSOLE)
  PRINTF("\rBTRX_task Hardware Overrun");
#endif
#ifdef stopFromSuspendingOnHardwareOverrun
  vTaskSuspend(NULL);
#endif
}

So, after more than a week of work, I have the FreeRTOS UART drivers working the way I want them.  

Thanks to you and Daniel for your help.  

1,544 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hello Myke Predko,

  I am the kinetis bare-metal engineer.

  If you want to change the UART, you can modify the baudrate register directly.

  But, please also calculate the error rate, you need to make sure the error rate is smaller than +/- 1.5%.

  Could you please use the SDK UART code test it directly after you change the baudrate? Can you receive the correct data? What about the sending? Any issues?

   I suggest you to test the UART bare-metal at first, after it is working, then you can add it to your MQX again.

   If you need any help from my side, just kindly let me know.

   Wish it helps you!

Kerry

 

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

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos
1,544 Views
myke_predko
Senior Contributor III

Hi Daniel,

I'm trying to figure out how to restart the Receiver after the data coming in at the erroneous data rate comes in.  I can see a number of changed bits in the UART registers and I think I can figure out what's happening.  Once I do that, I'll look at hte FIFO overflow issue.  

Could I suggest that you change your assumption that it is not "normal" to change the baud rate in an application?  If this were I2C, SPI or CAN I would agree but with a UART (or USB or network connections) there's always the chance that the device being communicated with doesn't have the assumed default or there is the situation like I have, the Bluetooth module I'm using starts up at 19,200bps but I want to use it at 921,600bps. 

I'll let you know how I proceed.  

0 Kudos