cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 CAN bootloader

SZano
Associate III

Hello,

I have a few questions regarding the system memory bootloader on STM32 cortex-M products (especially STM32F446, though other parts as well).

1) Is there no timeout to get out of the bootloader if no communication is detected?

I mean, the system boot is activated by tying the BOOTx pins to the proper voltage, then the bootloader executes, but no one is transmitting anything on any of the interfaces (UART, SPI, etc.).

Will the bootloader keep waiting forever?

Can it be exited by applying different voltages on the BOOTx pins?

Is the only way out that of transmitting a GO instruction via one of the available interfaces?

2) How should I connect the unused interfaces?

For instance, I want to use CAN2 for the firmware update. However, the bootloader will also listen to various USARTs, SPIs, I2Cs, etc.

Do their pins need to be tied to some voltage (e.g. pullups on I2C SDA, pullup on USART RX) to prevent spurious data being received, or will the bootloader initialize all the pins appropriately?

3) What if I have other hardware connected to the pins of unused interfaces?

For instance, if I don't want to use USART1, and I guarantee that nothing will be transmitted to USART1_RX, will USART1_TX still be configured as output while the bootloader is executing?

4) Are there utilities provided by ST to perform a firmware update from a PC?

I know that there's the "Flash loader demonstrator" (https://www.st.com/en/development-tools/flasher-stm32.html#), but as far as I can tell it only supports the USART bootloader protocol.

I would need a utility working with CAN instead (through a USB-to-CAN hardware adapter).

5 REPLIES 5
Ozone
Lead II

To 1.:

AFAIK, no. It would not make sense if there is no application yet.

Or, even with an application in Flash, the system BL was specifically entered by user manipulation. It is his decision to terminate/restart.

To 2. & 3.:

If you can guarantee not undesired communication which would provoke misbehaviour, just leave it as it is.

But yes, the system BL would configure outputs of checked channels (like UART Tx) regardless of your actual schematics.

To 4.:

At least for CAN, not that I'm aware of. AFAIK the STLink Utility supports UARTs in Nucleo boards via VCP.

I think there are no standard (pure) CAN protocols really suitable for BL use, I know only of proprietary one's.

UDS would be a more complex CAN-based and standardized protocol that supports firmware updates.

The system boot loader is sensitive to inputs on multiple interfaces, and these need to be quiet for it to recognize the one you want to use. AN2606 enumerates the pins of interest as I recall. Putting a GPS receiver on the USART interfaces used by the loader, for example, will prevent access by other means.

It is designed as production/de-bricking type loader, and has no specific familiarity with your board design or component choices.

You really should write your own loader, using several of the first flash sectors to store it, and have it implement the functionality you need for user updates, and to validate your app placed deeper into the flash memory.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

STM32 Cube Programmer replaces several of the older tools, and supports CAN in some fashion, but might be limited to specific drivers/dongles

https://www.st.com/en/development-tools/stm32cubeprog.html

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
DCast.2
Associate

0693W000007B47uQAC.jpgThe STM32 Cube programmer, at least version 2.5.0 does not have any option to upgrade by CAN pins

In case you need the CAN bootloader too, here's what I did.

I used ST's standard bootloader.

Developing your own bootloader gives you more flexibility (both in hardware and software), but it's additional work, and it has drawbacks:

1) you need an additional step in production to flash the bootloader itself, unless you flash bootloader and application together; anyway, you need a non-CAN interface for programming, whereas with the default bootloader you don't (except for developing and debugging, of course)

2) the bootloader might get corrupted (unless you fiddle with option bytes, for protection), whereas the default bootloader is always there

I had to be careful not to use peripherals in a way that would conflict with the bootloader.

In particular, since I had to use a serial port that's also used by the bootloader, I used hardware pullups; otherwise, the bootloader would sometimes pick up noise on that port.

This would effectively lock it, because once the bootloader senses some communication on a port, it stops listening to other ports. So, it would receive garbage data on the floating serial pins and stop listening to the CAN pins.

At least, this is what I experienced. Maybe it also depends on the specific ports, with some kind of priority.

Before using my custom board (mounting an STM32F446RETx), I tested the bootloader communication on the Nucleo-64 board (https://www.st.com/en/evaluation-tools/nucleo-f446re.html)

This is the behavior I saw for each relevant pin.

It seems that the bootloader uses pullups for some pins, while others seem to be cyclically initialized (as if polling them, and then putting them back to their reset state; they are marked as '?').

It might also be that all of them are initialized periodically, but I just didn't see them floating.

   PA9 (?): USART1_TX CN10.21 / CN5.1 (D8)

   PA10 (?): USART1_RX CN10.33 / CN9.3 (D2)

   PB10 (?): USART3_TX CN10.25 / CN9.7 (D6)

   PB11 (doesn't exist): USART3_RX

   PC11 (pullup): USART3_RX CN7.2

   PC10 (pullup): USART3_TX CN7.1

   PB5 (pullup): CAN2_RX CN10.29 / CN9.5 (D4)

   PB13 (pullup): CAN2_TX CN10.30

   PB6 (?): I2C1_SCL CN10.17 / CN5.3 (D10)

   PB9 (?): I2C1_SDA CN10.5 / CN5.9 (D14)

   PF1 (doesn't exist): I2C2_SCL

   PF0 (doesn't exist): I2C2_SDA

   PA8 (?): I2C3_SCL

   PC9 (?): I2C3_SDA

   PA7 (no): SPI1_MOSI

   PA6 (pullup): SPI1_MISO

   PA5 (no): SPI1_SCK

   PA4 (no): SPI1_NSS

   PB15 (no): SPI2_MOSI

   PB14 (pullup): SPI2_MISO

   PC7 (no): SPI2_SCK

   PB12 (no): SPI2_NSS

   PE14 (doesn't exist): SPI4_MOSI

   PE13 (doesn't exist): SPI4_MISO

   PE12 (doesn't exist): SPI4_SCK

   PE11 (doesn't exist): SPI4_NSS

   PA11 (no): USB_DM

   PA12 (pullup): USB_DP

   PB4 (pullup): ???

   PC13 (pullup): ???

   PA15 (pullup): ???

   PA13 (pullup): JTAG

I used PB13+PB5 for CAN, and PA9+PA10 for UART (the one that had garbage data problems); this is a debug UART, but I also tried to communicate to the bootloader using it, and it works (for this you can just use the STM32 Cube Programmer).

For the CAN firmware upgrade, I used the 'canprog' utility:

https://pypi.org/project/canprog/

https://github.com/marcinbor85/can-prog

This requires you to use Linux, and a compatible USB-to-CAN adapter. "Compatible" means that it supports the slcan protocol, so that 'canprog' can use standard linux drivers.

One such adapter is "USBtin": https://www.fischl.de/usbtin/

Upgrading this way is quite slow (maybe 100KiB/minute); I don't know what's the bottleneck here: the bus, the bootloader, the adapter, or 'canprog'.

Anyway, it was enough for me.

If you find better alternatives, let me know.

If you need more details about using linux+canprog+usbtin, I can tell you.