I am implementing an OTA update system for the STM32G4, and want to use the dual flash banks to make it safe. That is, write the new firmware in the inactive flash bank while the main program is still running from the active bank, and reboot only after checking the integrity of the newly installed firmware.
To do this, I'm setting the BFB2 bit from the option bytes to 1, which, according to AN2606 (section 45.2) and this presentation (page 8), tells the MCU to first attempt booting from flash bank 2 if the stack address located at offset 0x0 of the flash bank 2 is a valid SRAM address. Otherwise the MCU boots from flash bank 1. This fits my use case, as I can write the new firmware to the flash bank 2, except for the stack address which is written only after an integrity check to commit the change.
However, it seems the flash banks addresses aren't swapped when booting from the flash bank 2. According to the programming manual (section 10.2.1), swapping the flash banks addresses is done by setting the FB_MODE bit, which is cleared on reset and does not seem to be set when booting from flash bank 2. Not having the flash banks addresses swapped automatically is problematic because it means the firmware cannot be linked assuming a flash address of 0x08000000.
The workaround I can think of is to integrate a bootloader that checks which bank is in use, set the FB_MODE bit accordingly, then jump to the actual firmware entry point. This bootloader would be flashed in both banks, and not updated during an OTA update.
Is there really no way to swap flash banks addresses automatically when booting from flash bank 2? Or is there another solution which wouldn't involve a bootloader?
Edit: after reading this thread on the ST forums, I am not sure anymore my understanding is correct. If this user is right, then setting BFB2 swaps the banks and their addresses, and setting FB_MODE on top of that would "cancel" the swap.
I finally got this to work after a lot of trial and error. Some of my assumptions were wrong. Here's what the update process looks like:
Check the FB_MODE bit to know which bank the firmware is currently running from.
Perform a mass erase on the other bank (MER2 bit if FB_MODE is 0, MER1 otherwise).
Write the new firmware version at 0x08040000. The inactive bank is always mapped at that address, regardless of FB_MODE.
Set the BFB2 bit in the option bytes if FB_MODE is 0, or clear it otherwise. Do not blindly toggle BFB2, because it does not necessarily reflect which bank is active.
Reload option bytes with the LAUNCH bit, which also resets the MCU.
If the stack top address written at 0x08040000 is valid, the ST bootloader should boot to the new firmware. See step 1.
Some notes:
The firmware is always linked with a virtual address of 0x08000000, regardless of which bank it will be flashed to.
In dual bank mode, the main flash is NOT aliased to 0x0, so the firmware can't be linked to that address.
This does not update the flash option bytes, only the firmware code. I solved this by updating the flash option bytes if necessary when the new firmware boots for the first time.
Related
i'm using STM32 as my microprocessor along with I2C EEPROM for storage and ESP8266 for Wifi
How can i download an update binary for the bootloader to flash using ESP8266 although the firmware file will be larger than STM32 Ram so i can't load the file from the ESP8266 in one chunk ?
I suppose that you want to update the stm32 firmware.
In this case allow to upload a new binary for the stm32 to the web, store it in the esp8266 file system (it must be bigger than stm32 flash size).
After that, enable flash memory writing, set an small protocol for update stm32 from serial comm from esp8266 the file to stm32 flash.
Remember that all functions that are used to update the stm32 flash must be in RAM.
I'm doing a project for stm32f4 and esp8266 and I will do exactly this.
OPTION 2:
If your program binary size is under 50% of stm32 flash size, then use the above half of the stm32 flash memory to store the new program, after reset, check if there is something there, and if it is then update (this is what i'm doing actually in stm32, very secure method to update since only stm32 cpu is used for update and it is very fast).
I suppose that you have two firmwares on the STM32 flash. First one is boot loader and the second one is your application. Your boot loader gets new firmware over serial interface of the ESP8266; so you can use flow control pins to halt communication until you write the data into flash memory.
I use that combination, stm32 and esp32/esp8266, for now i have not used firmware upgrade from esp (my stm32 supports it but I have not needed it for now).
The easier way is to set a serial protocol between both cpus. I'm using half of the stm32 memory for code and half for updating. What I do actually is using the communication protocolo is copy the file to the upper half of the flash memory. After when i reset the code i check if there is a firmware ready to be updated, then I copy from top half of flash to bottom half.
With this system, you can check if all is ok and the update process with take few ms. After you have this system tested (using for example a PC) you can try to do it from your esp, but it is just as easy as repeat the process.
My tip about the esp8266 is to download the file to a spiffs. If you are not using spiffs, use it, create a drive a little bigger than your memory.. for example if your stm32 firmware binary is around 60kb, and your target cpu is 256, use around 160kb for it.
There is another way, it is download the html file in chunks and then send them to the top half of the cpu, it is not very complex. I would requests chunks with the same size of the block size of your comunnication process (in my case i'm using 256b or 512b, i dont remember at this moment).
Anyways if you have enough spiffs size download the file, update the stm32 cpu, delete the file and send a reboot.
Dont forget to add a crc for data transmision between stm32 and esp8266
Btw you dont need to download it to ram , since update is used rarely and you have limitations like number of times that you can update a flash memory, so, it is not a problem to save it to flash in the esp8266 neither the stm32
Best regards
My question is, if I manage to develop some kind of bootloader and flash it (is it called that when you put a bootloader on an MCU?), and it works horribly, can it brick the MCU entirely, making it completely unusable, permanently?
The reason I'm asking is that I've been tasked to develop a bootloader for the STM32F407. Problem is, I don't know anything about bootloaders or anything of the sort, which means that I have a lot to learn.
I appreciate any answers, thank you!
In short no you cannot brick a microcontroller with a bootloader.
In the end bootloader is just a firmware and can be erased away using the programmer via SWD
Erase the flash and your controller is as good as new
In general, absolutely, I have a collection of bricked microcontrollers, every so often I get lazy and there goes another.
It is very specific to your microcontroller and family. For example, pin count is very important, as much bang for your buck as you can get, if your microcontroller relies on certain pins for in circuit (or even in a programming fixture) and those pins can be repurposed by software. For example jtag pins that can also be gpio pins. And your code for some reason uses them as gpio pins, AND the design of the chip is such that they cannot use the jtag interface when the chip is in reset, then you can get bricked.
Another very easy one is the pll or clocks in general. If/as you develop code to initialize the clock system (assuming you choose to do that, even if you use chip vendor supplied code) and you have a bug that switches the chip over to a clock that you have not properly initialized or isnt there, it might brick.
Now some chip designs, many, help you out in various ways. The AVR family in general there is a programming mode that happens while the chip is in reset or is related to reset such that whatever code is in flash cannot affect its functionality, you can have a bad board design, sure, but your code cannot prevent it from working. Another method is a "strap" a pin (or pins) that is dedicated to a boot function, set one way normal boot, tie it the other and it goes into an alternate bootloader. This is what you have on the stm32 boot0 and sometimes boot1 depending. that is your get out of jail free card for that chip family, if you brick your chip (pll/clock or mess up the SWD pins by using them as gpio), you "simply" change boot0 and it boots into an internal bootloader (which AFAIK you cant mess up) which is known to work. From that bootloader you can use SWD (chips not bricked now) or the bootloader itself (always serial, sometimes usb or other is supported). NXP similar deal. Atmel ARMs used to have (do have) SAM-BA now they really only support SWD, you can get some samba code and try to lock it into the flash, but way too easy to unlock and or trash that flash, so that is a fail on their part.
As part of your system design if you dont have one of these built into save you from bricking features (like boot0 on an STM32), then I recommend you add one. Very early code initializes a dedicated gpio pin as a strap into your software, if that gpio pin is pulled one way do a normal boot, if pulled the other then spin in an infinite loop or jump to some other guaranteed to not be buggy code. Not a complete guarantee that you wont build the project wrong and trash this code, but it at least allows you to develop your bootloader/project and not brick a tray full of parts/boards as you work through the peripherals that can brick it.
Note letting smoke out of the part is another way to brick it as well, and that can/does happen from time to time as well.
Lots of examples on how to boot an STM32, plus various code from ST that you can use as a starting point as well. (all of which is of various quality, you get what you pay for). Their docs are good, better than some of the competition, not difficult at all to boot and configure their peripherals, sometimes easier than trying to use a canned library. YMMV, you should try various solutions. But if you are new to this, bricking is highly likely, fortunately you have a chip that you cant brick so long as your board design breaks out the boot0 pin. For a prototype board for an STM32 I prefer to have a boot0 button and a reset button, just reset resets the chip and runs, hold boot0 and press reset and it goes into the bootloader. both have to be wired in properly with the right pull up or down as needed for this task. or a jumper works tie boot0 directly high or low then pop reset, costs you more time, but works.
Yes You can brick the Micro controller to never recovered state. I did this and i did it in STM32F427.
Bootloader is all about carefully selecting Clocks, Peripharals and Interrupts priority. if you do this, there are less chances to brick the controller. Also test everything before release your code as some companies wants to save proprietary information to be saved so they blow up the JTAG lines, the only way to program is via Bootloader and if it is not perfect, voila, you just bricked the controller.
I have these related questions:
Does anybody know how an OS gets to know all hardware connected on the motherboard? (I guess this is called "Hardware Enumeration").
How does it determine what kind of hardware is residing at an specific IO address (i.e.: serial or parallel or whatever controller)?
How to code a system module which will do this job? (Assuming no OS loaded yet, just BIOS).
I know BIOS is just a validation and an user friendly interface to configure hardware at boot time with no real use after that for most modern OS's (win, Linux, etc). Besides I know that for the BIOS it should not be difficult to find all hardware because it is specifically tuned by the board manufacturer (who knows everything about it!). But for an OS or an application above BIOS that is a complete different story. Right?
Pre-PCI this was much more difficult, you needed a trick for each product, and even with that it was difficult to figure everything out. With usb and pci you can scan the busses to find a vendor and product id, from that you go into a product specific discovery (like the old days this can be difficult). Sometimes the details for that board are protected by NDA or worse you just dont get to know unless you work there on the right team.
The general approach is either based on detection (usb, pcie, etc vendor/product ids) you load a driver or write a driver for that family of product based on the documentation for that family of product. Since you mentioned BIOS, win, linux that implies X86 or a PC, and that pretty much covers the autodetectable. Beyond that you rely on the user who knows what hardware was installed in the system and a driver that came with it. or in some way you ask them what is installed (the specific printer at the end of a cable or out on the network if not auto detectable is an easy to understand example).
In short you take decades of experience in trying to succeed at this and apply it, and still fail from time to time since you are not in 100% control of all the hardware in the system, there are hundreds of vendors out there each doing their own thing.
BIOS enumerates the pci(e) for an x86 pc, for other platforms the OS might do it. The enumeration includes allocating address space for the device based on pci compliant rules. but within that address space you have to know how to program that specific board from vendor documentation if available.
Sorry my English is not very good.
Responding questions 1 and 2:
During the boot process, only the hardware modules strictly necessary to find and start the OS are loaded.
These hardware modules are: motherboard, hard drive, RAM, graphics card, keyboard, mouse, screen (that is detected by the graphics card), network card, CD / DVD, and a few extra peripherals such as USB units.
Each hardware module you connect to a computer has a controller that is like a small BIOS with all the information of the stored device: manufacturer, device type, protocols, etc
The detection process is very simple: the BIOS has hardcoded all the information about the motherboard, with all communication ports. At startup, the BIOS sends a signal to all system ports asking the questions "Who are you? What are you? How do you function?" and all attached devices answers by sending their information. In this way the computer knows how much RAM you have, if there is present a keyboard or a mouse, which storage devices are available, screen resolution, etc ...
Obviously, this process only works with the basic modules needed to boot the system, and does not work with complex peripherals that require specific drivers: printers, scanners, webcams ... all these complex peripherals are loaded by software once the OS has been charged.
Responding question 3:
If you wants to load a specific module during the boot, you must:
- Create a controller for this module.
- If the peripheral is too complex to load everything from the controller, you must to write all the proccess to control that module directly in the BIOS module, or reprogram the IPL to manage that specific module.
I hope I've helped
Actually, when you turn on your system, the BIOS starts the IPL (Initial program load) from ROM. For check the all connected devices are working good and also check the mandatory devices such as keyboard, CMOS, Hard disk and so on. If it is not success, it gives an error flag to the BIOS. The BIOS shows us the error through video devices.
If it is success, the control of boot is transferred to BIOS for further process.
The above all process are called POST (Power On Self Test).
Now the BIOS have the control. It checks all secondary memory devices for boot loader of the OS. If it hit, the bootloader's memory address is transferred to RAM.
The Ram started to execute the bootloader. Here only the os starts to run.
If the bootloader not hit, the bios shows us the boot failure error.
I hope your doubt clarified...
All I know is It helps in initializing processor hardware and operating system.
First I need to know what is a firmware and how it works.
Probably showing a list of firmware and what they do can be a good idea for explanation.
Typically, microprocessors performa start up process that usually takes the form of "begin execution of the code that is found starting at a specific address" or "look for a multibyte code at a pinpointed location and jump to the indicated locale to begin execution"
Since the introduction of IC ROM, with its many variants, including, but not limited to mask programmed ROMs, and programmable ROMs, and EPROMs. Since this time, firmware boot programs were shipped and isntalled on computers. Then the introduction of an external ROM was an italian telephone switching elaborator, called "Gruppi Speciali".
When a computer's turned off, it's software remains stored on nonvolatile data devices such as HDDs CDs DVDs SD cards, USBs, floppies, etc. WHen the computer's powere don, it doen't have an operating system or its lloader in RAM, it first of all executes a relatively small program stored in ROM, along with a small amount of needed data to access the nonvolatile device or devices from which the operating system programs the data and can be uploaded into RAM, this small program being known as a bootstrap loader.
I am working on USB HIDs on linux platform. Keyboards, mouse etc., are examples of Human Interface Devices. Whenever a HID is inserted to a system, at first device enumeration occurs. Then an entry in the form of hidraw appears in the /dev directory.
In linux, "usbhid and hid" are the modules which are called when an HID device is inserted. When I disabled these modules (using rmmod and system restart), the devices were not enumerated and no hidraw entry appeared on /dev(as expected).
Now my question is there any way to know if any USB HID device is connected to a system with the above two modules being disabled i.e does any interrupt or signal generate upon hardware insertion.
I am planning to execute some code when such signal or interrupt occurs(in C). Any kind of help is appreciated.
Thanks,
Insertion of the device is detected through the voltage level changes occuring on the D+ and the D- lines. I do not think that insertion of USB device generates any interrupt. The voltage level changes are read by the hub(root or any hub further down on the line) and according reported to the core.
The USB core driver would be notified about the same. So may be you can write a user-space driver which targets a specific device (using Vendor and Product ID) and through this you can carry out your functionality.
If you are doing this in user mode, you get get a notification using udev (which use netlink internally).
You can match a device using the vendorId and productId field in the rulefile.
SUBSYSTEMS=="usb", ATTRS{idVendor}=="abcd", ATTRS{idProduct}=="1234"