|
Core
|
Core bootloader. More...
Go to the source code of this file.
Functions | |
| void | core_boot_init () |
| Initialize the FDCAN filters, check the boot state, and enter the bootloader if necessary. If the state is not valid, an error message will be transmitted. | |
| void | core_boot_reset_and_enter () |
| Reset the chip and enter the bootloader. | |
Core bootloader.
This core library component implements a bootloader that allows boards to be programmed over CAN.
The STM32G473 has 512k of FLASH, which is split into two banks of 256k each. The chip can be configured to boot either from the first or the second bank by configuring the non-volatile BFB2 bit in the option byte registers. When the BFB2 bit is set in the FLASH option byte register, the boots from the second bank, otherwise, it boots from the first bank. However, there is also an option to temporarily swap the banks and run the code in the second bank even when booting from the first bank. This allows the code in the non-booting bank to be verified before finalizing the swap. If the verification fails, then the chip will fall back to the working code in the booting bank.
Programming a board takes place according to the following process:
The bootloader keeps track of its state across resets and between banks using the boot_state variable, which is stored at the highest RAM address (above the stack). This variable is not initialized when the chip is reset, so its value is always preserved unless the chip is power cycled. The highest 24 bits of boot_state are known as the boot key and must always be set to 0xABCDEF. If the boot key is incorrect, an error is raised. This might occur if the boot_state variable is not correctly configured.
The bootloader communicates with the programmer board using FDCAN with extended IDs. The extra bits in the ID are used to communicate they type of message and the address to be programmed (if required), so all 64 bytes in the body of the message can be used for data.
Each board has a unique board ID and master ID, so the master will respond to several IDs, one for each device that can be programmed. The 29-bit extended board IDs have the following format:
| 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
ID[10:0] | CTRL | RD/WR | |||||||||||||
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
PAD | ADDR[14:0] | ||||||||||||||
ID[10:0]: slave ID, used for arbitrationRD/WR: 1 to read from the slave, 0 to write to the slavePAD: Set if the last doubleword in the frame is a padding doublewordADDR[14:0]: Doubleword addressTo decrease the number of bits required to transmit the address, the address is left-shifted by 3 bits. This means that the address will be aligned on an 8-byte boundary. This is required for writing, since all writes to the FLASH memory must be doubleword-aligned.
Messages sent with CTRL set to 0 can have the following contents:
| Data | Operation |
|---|---|
55 55 55 55 55 55 55 55 | Enter bootloader |
00 | Reset chip |
01 | Soft swap (jump to non-booting bank) |
02 | Verify |
03 | Hard swap (only possible after verification with 02) |
04 | Switch to external programming mode (only possible in booting bank) |
05 | Leave external programming mode (only possible in booting bank) |
Note that all commands except "enter bootloader" require the chip to have been booted.
Messages sent with CTRL set to 1 can either be read or write requests. For a read request, the first data byte is the length and the second byte indicates the bank. Note that while the address must be 8-byte aligned, the length of the read can have any value. If the bank byte is non-zero, then the target board will read from the bank that is not currently running.
For a write request, all of the data bytes contain data to be written. The number of data bytes must be a multiple of 8. Since FDCAN only supports certain packet lengths, if the packet contains fewer doublewords than would fit in the packet, the PAD byte is set. For example, to transmit 56 bytes of data (7 doublewords), one would need a packet length of 64 (DLC set to 15) and set the PAD bit to indicate that the last doubleword should be ignored.
The master IDs have the following format:
| 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
ID[10:0] | 1 | DATA/STAT | |||||||||||||
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
PAD | ADDR[14:0] | ||||||||||||||
ID[10:0]: master ID, used for arbitrationDATA/STAT: 1 if the frame contains data (echo or read), 0 if the frame contains a status messagePAD: Set if the last doubleword in the frame is a padding doublewordADDR[15:0]: Doubleword addressStatus messages transmitted from a board to the programmer are 64 bits long and have the following format:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
STATUS[7:0] | MEMRMP | BFB2 | |||||||||||||
| 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
EOP | OPERR | PROGERR | WRPERR | PGAERR | SIZERR | PGSERR | MISSERR | FASTERR | RDERR | OPTVERR | |||||
| 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
VERIFY | VERIFY_SOFT_SWITCH | SOFT_SWITCHED | VERIFIED | ENTER | NB_ERROR | ERROR | BOOT_STATE_KEY[7:0] | ||||||||
| 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
BOOT_STATE_KEY[23:8] | |||||||||||||||
STATUS[7:0]: Status code | 0 | Status | No error |
| 1 | Error | Address out of range |
| 2 | Error | Error while erasing |
| 3 | Error | Error while programming |
| 4 | Error | Boot state error |
| 5 | Error | Write from non-booting bank |
| 6 | Status | Board is already booted (sent when bootloader received opcode 0x55) |
| 7 | Status | BSM did not run |
| 8 | Status | Soft swap successful (sent when core_boot_init() runs in the non-booting bank) |
| 9 | Status | Sent when core_boot_init() runs in the booting bank |
BFB2: BFB2 bit from the option byte register. Indicates which bank the chip will boot fromMEMRMP: MEMRMP bit from the memory remap register. Indicates which bank is currently runningFLASH_SRERROR: Indicates a state error occurred in the booting bankNB_ERROR: Indicates a state error occurred in the non-booting bankENTER: Indicates that the program should enter the bootloader after the next resetVERIFIED: Indicates that the program in the non-booting bank has been verified. If this bit is set, the banks can be swappedSOFT_SWITCHED: Indicates that the soft switching succeededVERIFY_SOFT_SWITCH: Indicates that the signal to soft switch has been processed by the boot state machine in the booting bankVERIFY: Indicates that the chip should soft switch after the next resetThe bootloader consists of four main components: the startup script, the boot state machine, the core_boot_init() function, and an entry point.
For the bootloader to work, the default startup script must be replaced by the startup script startup_stm32g473xx.s. The startup script defines the interrupt handlers for the program, including the reset handler. By default, the reset handler initializes the stack and jumps to the application code. The modified startup script required for the bootloader also runs the boot state machine before performing any additional initialization.
The boot state machine runs before any other code and updates the boot state or soft swaps as necessary. The BSM first checks the nature of the reset. If the reset was caused externally (by pulling the nRST pin low), then the state is reset to NORMAL and the BSM continues to the application code.
The behavior of the BSM depends on whether it is running in the booting or non-booting banks. In the booting bank, the BSM will change the state to VERIFY_SOFT_SWAP and soft-swap if the state is VERIFY and continue to application code otherwise.
In the non-booting bank, the BSM will change the state to SOFT_SWITCHED if the state is VERIFY_SOFT_SWAP. Otherwise, the BSM will set the NB_ERROR bit and reset. This causes the chip to return to the booting bank.
The core_boot_init() function is called by application code after the clocks, GPIO, and FDCAN modules needed for the bootloader have been initialized. This function initializes the RX filter for the board's bootloader ID. The function also checks the boot state and enters the bootloader if necessary. See the state diagram above for details.
The software enters the bootloader by calling core_boot_reset_and_enter(). The FDCAN RX interrupt hander in can.c will automatically call this function if it receives a packet addressed to its bootloader FDCAN ID containing the command to enter the bootloader
| void core_boot_init | ( | ) |
Initialize the FDCAN filters, check the boot state, and enter the bootloader if necessary. If the state is not valid, an error message will be transmitted.