The book goes on to say: next, we will take an example of mcu. Let's analyze the source code of Openblt
First of all, in the world of programs, main is king, so let's take a look at the emperor's ideas first
int main(void) { /* initialize the microcontroller */ Init(); /* initialize the bootloader */ BootInit(); /* start the infinite program loop */ while (1) { /* run the bootloader task */ BootTask(); } /* Program should never get here. */ return 0; } /*** end of main ***/
The main function is generally very simple. First of all, we need to know that this is a big loop program. After Init and bootInit enter while, we keep cycling the bootask task.
Init(): initializes the hardware and provides an environment for mcu code to run
static void Init(void) { /* HAL library initialization */ HAL_Init(); /* configure system clock */ SystemClock_Config(); } /*** end of Init ***/
BootInit(); Initialization of openblt
void BootInit(void) { /* initialize the CPU */ CpuInit(); //Non enable interrupt /* initialize the watchdog */ CopInit(); /*Enable open door dog*/ /* initialize the millisecond timer */ TimerInit();/*systick initialization*/ /* initialize the non-volatile memory driver */ NvmInit(); #if (BOOT_FILE_SYS_ENABLE > 0) /* initialize the file system module */ FileInit(); #endif #if (BOOT_COM_ENABLE > 0) /* initialize the communication module */ ComInit();/**If a serial port is used, the serial port is initialized/ #endif #if (ADDON_GATEWAY_MOD_ENABLE > 0) /* initialize the gateway module */ GatewayInit(); #endif /* initialize the backdoor entry */ BackDoorInit();/*Back door initialization*/ } /*** end of BootInit ***/
The code here is also very clear, but some small partners may have some questions here: the code entered by CopInit
void CopInitHook(void) { /* this function is called upon initialization. might as well use it to initialize * the LED driver. It is kind of a visual watchdog anyways. */ LedBlinkInit(100); } /*** end of CopInitHook ***/
Alas, it seems that we are initializing the led lamp. Why is it not a function such as watchdog()?
In addition, for some more strict scenarios, hardware watchdog will be used, similar to
This circuit is a screenshot from the chip manual. You can clearly see that the IO pin of MCU is connected to WDI. In other words, as long as the IO pin level changes (square wave), the chip will not output reset signal. This is the principle of hardware watchdog chip
In the following loop, you can see
CopService();
Eventually called to
void LedBlinkTask(void) { static blt_bool ledOn = BLT_FALSE; static blt_int32u nextBlinkEvent = 0; /* check for blink event */ if (TimerGet() >= nextBlinkEvent) { /* toggle the LED state */ if (ledOn == BLT_FALSE) { ledOn = BLT_TRUE; LL_GPIO_ResetOutputPin(GPIOC, LL_GPIO_PIN_13); } else { ledOn = BLT_FALSE; LL_GPIO_SetOutputPin(GPIOC, LL_GPIO_PIN_13); } /* schedule the next blink event */ nextBlinkEvent = TimerGet() + ledBlinkIntervalMs; } } /*** end of LedBlinkTask ***/
Use systick to carry out a timer to realize the high and low level change of IO pin
Then let's look at the bootask function that compares the core
void BootTask(void) { /* service the watchdog */ CopService(); /* update the millisecond timer */ TimerUpdate(); #if (BOOT_FILE_SYS_ENABLE > 0) /* call worker task for updating firmware from locally attached file storage */ FileTask(); #endif /* BOOT_FILE_SYS_ENABLE > 0 */ #if (BOOT_COM_ENABLE > 0) /* process possibly pending communication data */ ComTask(); #endif #if (ADDON_GATEWAY_MOD_ENABLE > 0) /* run the gateway */ GatewayTask(); #endif /* control the backdoor */ BackDoorCheck(); } /*** end of BootTask ***/
The CopService function has been mentioned above
Let's look at the Comtask() function first
void ComTask(void) { blt_int8u xcpPacketLen; /* make xcpCtoReqPacket static for runtime efficiency */ static blt_int8u xcpCtoReqPacket[BOOT_COM_RX_MAX_DATA]; #if (BOOT_COM_CAN_ENABLE > 0) if (CanReceivePacket(&xcpCtoReqPacket[0], &xcpPacketLen) == BLT_TRUE) { /* make this the active interface */ comActiveInterface = COM_IF_CAN; /* process packet */ XcpPacketReceived(&xcpCtoReqPacket[0], xcpPacketLen); } #endif #if (BOOT_COM_RS232_ENABLE > 0) if (Rs232ReceivePacket(&xcpCtoReqPacket[0], &xcpPacketLen) == BLT_TRUE) { /* make this the active interface */ comActiveInterface = COM_IF_RS232; /* process packet */ XcpPacketReceived(&xcpCtoReqPacket[0], xcpPacketLen); } #endif #if (BOOT_COM_USB_ENABLE > 0) if (UsbReceivePacket(&xcpCtoReqPacket[0], &xcpPacketLen) == BLT_TRUE) { /* make this the active interface */ comActiveInterface = COM_IF_USB; /* process packet */ XcpPacketReceived(&xcpCtoReqPacket[0], xcpPacketLen); } #endif #if (BOOT_COM_NET_ENABLE > 0) if (NetReceivePacket(&xcpCtoReqPacket[0], &xcpPacketLen) == BLT_TRUE) { /* make this the active interface */ comActiveInterface = COM_IF_NET; /* process packet */ XcpPacketReceived(&xcpCtoReqPacket[0], xcpPacketLen); } #endif } /*** end of ComTask ***/
What is mainly involved in this is that if in blt_ If the hardware or those hardware are defined in conf.h, it will keep receiving and writing to flash.
BackDoorCheck();
void BackDoorCheck(void) { #if (BOOT_BACKDOOR_HOOKS_ENABLE == 0) #if (BOOT_COM_ENABLE > 0) /* check if a connection with the host was already established. in this case the * backdoor stays open anyway, so no need to check if it needs to be closed. */ if (ComIsConnected() == BLT_TRUE) { return; } #endif #if (BOOT_FILE_SYS_ENABLE > 0) /* check if the file module is busy, indicating that a firmware update through the * locally attached storage is in progress. in this case the backdoor stays open * anyway, so no need to check if it needs to be closed. */ if (FileIsIdle() == BLT_FALSE) { return; } #endif /* when the backdoor is still open, check if it's time to close it */ if (backdoorOpen == BLT_TRUE) { /* check if the backdoor entry time window elapsed */ if (TimerGet() >= (BOOT_BACKDOOR_ENTRY_TIMEOUT_MS + backdoorExtensionTime + backdoorOpenTime)) { /* close the backdoor */ backdoorOpen = BLT_FALSE; #if (BOOT_FILE_SYS_ENABLE > 0) /* during the timed backdoor no remote update request was detected. now do one * last check to see if a firmware update from locally attached storage is * pending. */ if (FileHandleFirmwareUpdateRequest() == BLT_FALSE) #endif { /* no firmware update requests detected, so attempt to start the user program. * this function does not return if a valid user program is present. */ CpuStartUserProgram(); } } } #endif } /*** end of BackDoorCheck ***/
Where, this line of code
if (TimerGet() >= (BOOT_BACKDOOR_ENTRY_TIMEOUT_MS + backdoorExtensionTime + backdoorOpenTime))
It explains how long the MCU waits to enter the user program after power on reset. These parameters are macro definitions and can be adjusted according to the actual situation
This code means that if you do not receive the instruction to update the firmware of the upper computer, you will start to start the user program, and once the user program is effective, you will directly jump to the user program
if (FileHandleFirmwareUpdateRequest() == BLT_FALSE) #endif { /* no firmware update requests detected, so attempt to start the user program. * this function does not return if a valid user program is present. */ CpuStartUserProgram(); }
The thing that the little partner may be most concerned about here is, how did boot jump from its own boot program to the user program?
Core code in
void CpuStartUserProgram(void)
Just use a function pointer
void (*pProgResetHandler)(void); pProgResetHandler = (void(*)(void))(*((blt_addr *)CPU_USER_PROGRAM_STARTADDR_PTR)); pProgResetHandler();
In addition, you need to do it before jumping
Release the hardware port, re enable the interrupt, and re place the user vector table (SCB - > vtor). After setting, call
pProgResetHandler();
Just jump to our user process.
The general process is like this. Next, analyze the use of the upper computer