The A is for asynchronous

In SPI two or more devices communicate and the transmission rate is dictated by the master’s SCLK. Because the SCLK is shared between all devices it’s reliable even at very high speed – the STM32F401RE’s fastest SPI peripheral is good up to 42 MHz.

In UART two devices communicate with agreed-upon speed, character length, parity bit and number of stop bits. To transmit a byte one typically needs to send 10 bits: 1 start bit, 8 data bits and one stop bit. The two devices don’t share a clock – this is the asynchronous part – so if the actual speed of your two UARTs are not the same, you’ll run into trouble at high baud-rates, and that’s exactly what I did.

The remainder of this post is about the exploration of some of the Nucleo board’s various clocks. To spare you from high expectations, the conclusion is that I’ve not reached a higher baud-rate than 230.4 kBps for USART.

It’s evident from the STM32F401’s reference manual, that there may be a discrepancy between the desired and the actual baud-rates. The reason is that the USART’s clock is derived from the APB1/2-clock (PCLK1 for USART2). Unlike the timers though, the USARTs have fractional prescalers, so it’s possible to get quite close to the desired value, say with an error of  <1%.

That’s all fine if you only need to transmit a few bytes, but when you get into the thousands the errors accumulate.

What to do then when you’ve got thousands of bytes (7388) to transfer?

First you make sure the STM32F401RE is clocked by a precise oscillator, which means a piezo-electric crystal. The Nucleo boards I have are revision C-02 and they lack X3. However the MCU on rev. C-02 is actually connected to X1, an 8.000 MHz crystal clocking the STM32F103 on the built-in ST-link, through the STM32F103’s MCO-pin:

Next you need to make sure the STM32F401RE is actually using this crystal and gets the PLL source from the HSE (high speed external oscillator) rather than the relatively imprecise HSI (high speed internal oscillator).

This means fiddling with the file system_stm32f4xx.c in the project src directory, and setting the the correct high speed external oscillator value in the stm32f4xx.h file, that is hidden in the STM32F4xx_SPL/Libraries/CMSIS/Device/ST/STM32F4xx/Include directory.

ST Micro has a clock configuration tool (excel spreadsheet) that does all the dirty work with system_stm32f4xx.c and generates a functional file for you.¹ You still need to make sure HSE is set to 8000000 in stm32f4xx.h

It took a few tries to get the spreadsheet to give me a file with:

 *        Supported STM32F40xx/41xx/427x/437x devices 
  *        System Clock source                    | PLL (HSE) 
  *        SYSCLK(Hz)                             | 84000000 
  *        HCLK(Hz)                               | 84000000 
  *        AHB Prescaler                          | 1 
  *        APB1 Prescaler                         | 2 
  *        APB2 Prescaler                         | 1 
  *        HSE Frequency(Hz)                      | 8000000 
  *        PLL_M                                  | 8 
  *        PLL_N                                  | 336 
  *        PLL_P                                  | 4 
  *        PLL_Q                                  | 7

Next up was to check if the MCU was indeed using the new settings. That means checking two or so RCC-registers. I wrote a small program to do it for me, because I’m a moron at remembering details about this stuff.


The program outputs the STM32F401RE’s MCO, and TIM1 & TIM3 on GPIO’s (check the source code), so you can put verify the speed settings with an oscilloscope. It took me some time to figure out why TIM3 which is connected to the slower APB1-bus had the same frequency as TIM1, when configured with the same period.

Somewhere in the reference manual (section 6.2.1) you find the explanation:

The timer clock frequencies for STM32F401xB/C and STM32F401xD/E are automatically
set by hardware. There are two cases:
1. If the APB prescaler is 1, the timer clock frequencies are set to the same frequency as
  that of the APB domain to which the timers are connected.
2. Otherwise, they are set to twice (×2) the frequency of the APB domain to which the
   timers are connected.

So the general purpose timers (TIM2-TIM5) actually run with 2x 42 MHz. By chance this means that the firmwares I’ve published so far actually output the desired frequencies even though I had erroneously set PLL_M to 16² making the MCU system core clock 42 MHz instead of 84 MHz, and the APB1-clock 21 MHz instead of 42 MHz.

So with all clocks correctly set up, did I get higher baud-rates?

No. I’m still stuck with 230.4 kBps as the highest reliable speed, but at least I know it’s not it’s not by fault of the Nucleo board.

It could be the ST-link that doesn’t support higher baud-rates. Or it’s my linux-terminal skills. I find both equally likely.

Source code for the STM32F401RE speed checker.

NB: Don’t mindlessly replace the new and improved system_stm32f4xx.c from this project into the older firmware src-directories. The timings will be off unless you prescale TIM2-TIM5 properly, or change the periods. I will post an update shortly.

¹ If for some reason you also cannot download the file directly from ST’s page, take a look at this thread: STM32F4xx_Clock_Configuration_VX.Y.Z.xls

² All this time I thought my programs were using the HSI at 16 MHz, when in fact the HSE at 8.000 MHz was used.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.