In the following, when referring to code and the example projects, SBL = flash_based_uart_sbl_with_lfu and LFU Application = lfu_uart_cpu1_application.
The detailed steps associated with LFU are outlined below:
- Boot to the SBL and execute the application: On a device reset, execution starts in the SBL. The communication peripheral is initialized and execution branches to the application's codestart routine. In code, this occurs in the
SBL's main() function (flash_based_uart_sbl.c).
- Initiate LFU: The user invokes LFU on the target MCU through a host initiated LFU command.
- Receive LFU command in the application: The application receives the LFU command in its communication peripheral ISR. In code, this occurs in the LFU Application's SBL_uartNotifyISR() (uart_led_blinky_cpu1.c), which sets a flag
to tell the application to jump back into the SBL to process the command.
- Process the LFU command: The application branches back into the SBL to parse and process the LFU command. In code, this occurs in the SBL's commandJumpTable() function (flash_based_uart_sbl.c), which reads the command and
executes the appropriate operations.
- Download the new firmware and program to flash: The LFU flow in the SBL receives the application image from the host and programs it into the inactive flash bank. Background task functions in the old firmware have stopped
executing, but control ISRs continue to be available to keep the application functionality unaffected. In code, this happens in the SBL's cpu1LFUFlow() function (sbl_command_flow.c).
- Return to application and report success: If the firmware image was programmed successfully, the SBL branches back to the application and reports a successful LFU command
- Copy the LFU switchover function into RAM: The application copies the new firmware's LFU switchover function from inactive flash, which is not executable, into RAM, then branches to it. As the old firmware performs the copy of
the new firmware's switchover function, it must be located at a fixed address. In code, the LFU Application's performLFUSwitchover() function (lfu_switchover.c) is responsible for this.
- Initialize the new PIPE vector table: The shadow PIPE vector table is populated with the new firmware's ISRs. In code, this is done in the LFU Application's lfuSwapBanks() function (lfu_switchover.c).
- Wait for the optimal LFU switchover point: A simple state machine with software flags is used to determine the end of a control ISR and the beginning of idle time. This is the optimal time to perform the switchover as it
maximizes the use of idle time between control loop interrupts. In code, the lfuSwapBanks function (lfu_switchover.c) accomplishes this by reading the lfu_switchover_proceed flag, which is set at the end of the INT_myCPUTIMER0_ISR()
routine (uart_led_blinky_cpu1.c).
- Execute the LFU switchover:
- Interrupts are disabled
- The interrupt tables are swapped
- The active and inactive flash banks are swapped
- The stack pointer is reinitialized
- Interrupts are re-enabled
- Execution branches to the new firmware's main() routine
In code, this is the section of the LFU Application's lfuSwapBanks() function (lfu_switchover.c) marked as the time-critical phase.
- Device initialization is skipped in the new firmware, and the background control loop starts executing immediately