Filling firmware in STM32 via USB
- Tutorial

In my project, I use the STM32F103C8 microcontroller and the stm32duino framework . This Arduino clone offers a special bootloader that allows you to upload firmware via USB, without using external components like ST-Link or USB-UART adapter.
Today I needed to work with a naked controller from under CooCox and without stm32duino. But that's the problem. Even a simple blinker poured through this bootloader does not work.
Let's figure it out. Perhaps my calculations seem to someone commonplace. But I am just starting to study the STM32 controllers and, in search of a problem, I killed at least half a day. Suddenly, this article will shorten the development time.
I have nothing against ST-Link and other debuggers. But it won't be in my finished device, but it will definitely be USB. Why not immediately lay the opportunity to update the firmware via USB? Personally, I find this method convenient. Moreover, all the same, I already have a power cord connected to the power supply and USB Serial.
Let's see how the bootloader works. First, using the example of AVR controllers. Why did I remember about him? I switched from Arduino and subconsciously expected the same behavior. But the STM32 turned out to be different. Because I want to talk about the difference between these two microcontrollers.
So. In AVR ATMega microcontrollers, you can reserve a certain amount of memory under the bootloader near the end of the flush. With the help of fuse bits, you can adjust from which address the program will start. If there is no bootloader, the program starts from the address 0x0000. If there is a bootloader, it starts from some other address (for example, in ATMega32 with 0x3C00, if the bootloader size is 2k).

When the bootloader has done its work, it transfers control to the main program from the address 0x0000. Those. the program always starts with the address 0x0000. The compiler and linker work taking into account that the code will be located at the beginning of the address space.
In STM32 microcontrollers, this is not the case. All programs start at address 0x0800000. The bootloader is not so special. This is the same program that starts from the same starting address. In the process of operation, the bootloader can receive firmware (via USB or UART, read from a flash drive, receive from a satellite, get from a whatever, ...) and write it to addresses higher than the bootloader itself. And, of course, at the end of their work, to transfer control to the main program.

So when compiling the firmware, you need to know where the bootloader will write the firmware and adjust the addresses accordingly.
On this with the theory of everything. We proceed to practice. Below is a step-by-step instruction on how to screw the USB bootloader to the STM32F1xx series microcontrollers, and maybe to some others too.
There are, however, some limitations on circuitry. Here I, unfortunately, is not strong. ITP needs a pull-up resistor 1.5k for the PA12 port (also known as USB D +). This allows the bootloader to connect and disconnect from USB at the right times.
Instruction:
- Downloading github.com/rogerclarkmelbourne/STM32duino-bootloader . In the directory STM32F1 \ binaries there is already a package of compiled bootloaders for different boards. The index at the end of the file name indicates where the LED is connected. In the case of my board where the LED is connected to pin C13, I used the file generic_boot20_pc13.bin.
- Flash according to the instructions . Yes, you will need a USB-UART adapter, but you can also use the debugger .
- Now the microcontroller is ready to be downloaded through the USB bootloader. But you still need to correct the firmware itself. And you need to do 2 things:
- Specify the linker starting address. In CooCox, this is done in the project settings, the Link tab, the Memory Areas section, the IROM1 Start Address. The bootloader occupies the first 8 kilobytes, so the starting address of the firmware will be 0x0800000 + 0x2000 = 0x08002000. Size field, probably, should also be reduced by 8k.
- Somewhere at the beginning of the program before the initialization of the periphery to make a call
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x2000);
UPDATE 05/17/2018: In the modern version of the STM32Cube, the function NVIC_SetVectorTable () is not. Instead, you can fix the define VECT_TAB_OFFSET in the system_stm32f1xx.c file (or a similar one for another microcontroller).
- Specify the linker starting address. In CooCox, this is done in the project settings, the Link tab, the Memory Areas section, the IROM1 Start Address. The bootloader occupies the first 8 kilobytes, so the starting address of the firmware will be 0x0800000 + 0x2000 = 0x08002000. Size field, probably, should also be reduced by 8k.
- The firmware firmware can be taken from the stm32duino project . In the tools directory, look for a script called maple_upload. I used only the screw version - maple_upload.bat.
- Run like this:
"maple_upload.bat" COM20 2 1EAF:0003 "Path\To\Firmware.bin"
Instead of COM20, you need to substitute your port where the microcontroller is hooked.
Zalivator thing is very gentle, does not like relative paths. so the path to the firmware must be specified completely.
1EAF: 0003 is the VID and PID
2 is the AltID parameter, which indicates that the firmware should be uploaded to the address 0x08002000 (read here ).
Another bit of nuance. Before uploading the firmware, you need to start the bootloader. The easiest way is to press the reset button. After that, the bootloader will start and the firmware will wait for a few seconds. If at that moment nobody launched maple_upload, the loader will transfer control to the main firmware.
In order not to press resets each time, motherboards based on libmaple / stm32duino use a trick. They listen to usb serial port. If a DTR signal occurs there and a key sequence of bytes is transmitted, then the microcontroller is reloaded into the bootloader. See rxHook () function .
This may cause inconvenience. If the microcontroller zaglyuchil and hung, then he no longer listens to the port. Therefore, he can not hear the key sequence and reboot into the bootloader. Then only reset to help.
That's all. I hope my article will shed light on how the bootloader works in the STM32 and how you can download the firmware via the USB port. Unfortunately, the threshold of entry is still high, but suddenly someone my article will help to overcome it.