STM32 serial port IAP

Publisher:温柔微笑Latest update time:2016-10-10 Source: eefocusKeywords:STM32 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
The STM32 serial port IAP allows the STM32 application to be upgraded online through the serial port. To achieve serial port upgrade, simply put, it is to write a bootloader for the STM32, just like the BIOS of a computer, in which the serial port data is received, and then the data is solidified into the flash address space specified inside the STM32, and then run this code to execute.
Anyone who has been exposed to Linux uboot should have noticed that in addition to the implementation of functions, the interface design of the bootloader is also very important. Through the serial port, a simple interface is implemented in the serial port software of the computer, listing the various functions of the bootloader and supporting user selection. Implementing such an interpersonal interaction interface is also an indispensable part of an excellent bootloader.
This article will talk about how to design a bootloader program with functions and interface! It is still based on my own standard project.
1. Modification of the project
1) Serial port upgrade of course requires USART and FLASH. My original project has already added the serial port library files stm32f10x_usart.c and stm32f10x_flash.c, so there is no need to add these two files.
2) Copy the SoftTimer.c and SoftTimer.h files written in the article "STM32 Multi-channel Soft Timer" and save them in the src and inc folders under the BSP file of the project file respectively, and add the SoftTimer.c file to the BSP project group.
3) Since the timer is used, add the library file stm32f10x_tim.c to the STM32F10x_StdPeriod_Driver project group.
4) Open the stm32f10x_conf.h file and remove the previously blocked "#include stm32f10x_tim.h" statement.
5) Create two new files, IAP.c and IAP.h, and save them to the src and inc files under the BSP folder respectively. And add the IAP.c file to the BSP project group.
The project architecture is shown in the figure below:
STM32 Serial Port IAP - ziye334 - ziye334's Blog
2. Writing IAP.c and IAP.h files
Considering the development board resources, I use serial port 1 as the upgrade channel, so the relevant codes of serial port 1, which was originally used as the debugging interface in the standard project, need to be completely deleted from the two files BSP.c and BSP.h.
According to the previous habit, the first function to be written in IAP.c should be: IAP_Init(). In this function, configure the serial port related code, such as configuring the serial port pin, serial port clock, serial port properties, serial port interrupt, etc. The specific code is as follows:

/****************************************************************
Function: IAP_Init
Description: IAP initialization function, initialize serial port 1
Input: none
return: none
**********************************************************/
void IAP_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB2PeriphClockCmd(COM1_RCC, ENABLE);//Enable USART1 clock
RCC_APB2PeriphClockCmd(COM1_GPIO_RCC, ENABLE);//Enable serial port 2 pin clock

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//Configure USART1 Tx The pin type is push-pull
GPIO_InitStructure.GPIO_Pin = COM1_TX_PIN;
GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz;
GPIO_Init(COM1_GPIO_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //Configure USART1's Rx as input floating
GPIO_InitStructure.GPIO_Pin = COM1_RX_PIN;
GPIO_Init(COM1_GPIO_PORT, &GPIO_InitStructure);

USART_InitStructure.USART_BaudRate = 115200; //Set the baud rate to 115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//Set data bits to 8 bitsUSART_InitStructure.USART_StopBits
= USART_StopBits_1;//Set stop bit to 1 bitUSART_InitStructure.USART_Parity
= USART_Parity_No;//No parity checkUSART_InitStructure.USART_HardwareFlowControl
= USART_HardwareFlowControl_None;//No hardware flow controlUSART_InitStructure.USART_Mode
= USART_Mode_Rx | USART_Mode_Tx;//Send and receiveUSART_ITConfig

(COM1, USART_IT_RXNE, ENABLE);//Receive interrupt enableUSART_Init
(COM1,&USART_InitStructure);//Configure serial port 2 related registersUSART_Cmd
(COM1,ENABLE); //Enable serial port 2

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //Channel is set to serial port 2 interrupt
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //Interrupt occupies priority 0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //Enable interrupt
NVIC_Init(&NVIC_InitStructure);
}

After the serial port is initialized, of course, the sending and receiving functions must be written. Since the interrupt reception is configured above, in the IAP.c file, you only need to write the serial port sending function:

/****************************************************************
Function: IAP_SerialSendByte
Description: Serial port sends byte
Input: c-byte to be sent
Return: none
**************************************************************/
static void IAP_SerialSendByte(u8 c)
{
USART_SendData(COM1, c);
while (USART_GetFlagStatus(COM1, USART_FLAG_TXE) == RESET) {}
}
/*****************************************************************
Function: IAP_SerialSendStr
Description: Serial port sends string
Input: none
Return: none
*************************************************************/
void IAP_SerialSendStr(u8 *s)
{
while(*s != '\0')
{
IAP_SerialSendByte(*s);
s++;
}
}

As for the implementation of receiving data on the serial port, a circular buffer is needed. The essence of the so-called circular buffer is to define a finite array UsartBuffer[MAXBUFFER], and then use two variables: UsartWptr and UsartRptr to mark the read and write positions of the current circular buffer respectively. When a data is received, the write position variable UsartWptr will shift backward by one position; when a data is read, UsartRptr will also shift backward by one position; when UsartWptr is equal to UsartRptr, it means that there is no new data in the buffer, otherwise there is unread data. The circular buffer can greatly save processor resources, and its specific principle is not to be explained in detail. Let's take a look at its implementation:

#define MAXBUFFER 512 //buffer size
u8 UsartBuffer[MAXBUFFER]; //data buffer
u16 UsartWptr = 0;
u16 UsartRptr = 0;

/****************************************************************
Function: IAP_BufferWrite
Description: Write buffer
Input: none
return: none
**********************************************************/
void IAP_BufferWrite(void)
{
if(UsartWptr == (UsartRptr - 1))//The buffer is full
{
return;//Return
}

UsartBuffer[UsartWptr] = USART_ReceiveData(COM1);//Access serial port data
UsartWptr++;//Buffer write position value increments
UsartWptr = UsartWptr%MAXBUFFER;//Ensure that the write position value does not overflow
}

/*****************************************************************
Function: IAP_BufferRead
Description: Read buffer
Input: none
return: none
*****************************************************************/
static u8 IAP_BufferRead(u8 *data)
{
if(UsartRptr == UsartWptr)//No data to read
{
return 0;
}
*data = UsartBuffer[UsartRptr];//Read buffer data
UsartRptr++;//Read position value increments
UsartRptr = UsartRptr % MAXBUFFER;//Ensure that the read position value does not overflow
return 1;
}

Next, I will talk about the bootloader interface, and then the specific implementation method according to the function options in the interface. The bootloader interface needs to be designed to be concise and clear. The following is the interface I designed:

/****************************************************** ************
Function: IAP_ShowMenu
Description: Display menu interface
Input: none
return: none
************************ *************************************/
void IAP_ShowMenu(void)
{
IAP_SerialSendStr("\r\ n+================(C) COPYRIGHT 2014 Ziye334 ================+");
IAP_SerialSendStr("\r\n | In-Application Programing Application (Version 1.0) |");
IAP_SerialSendStr("\r\n+----command----+-----------------function- ------------------+");
IAP_SerialSendStr("\r\n| 1: FWUPDATA | Update the firmware to flash |");
IAP_SerialSendStr("\r\n| 2: FWERASE | Erase the current firmware |");
IAP_SerialSendStr("\r\n| 3: BOOT | Excute the current firmware |");
IAP_SerialSendStr("\r\n| 4: REBOOT | Reboot |");
IAP_SerialSendStr(" \r\n| ?: HELP | Display this help |");
IAP_SerialSendStr("\r\n+============================ ================================+");
IAP_SerialSendStr("\r\n\r\n");
IAP_SerialSendStr("STM32-IAP>>");
}

The interface above is beautifully designed. It uses various symbols to implement a table-like interface. The first line of the interface emphasizes the copyright and design time. The second line explains the overall function and version of the bootloader. The following lines list the specific functions and instructions that the bootloader can achieve. Finally, there is a design of "STM32-IAP>>" to prompt input selection.
First, implement the first function listed in the interface: FWUPDATA, which means firmware upgrade. To implement firmware upgrade, it is naturally the process of solidifying data into the chip flash. The program burning code of the flash space is as follows:

extern u8 rcvTimeout; //Receive timeout flag

/****************************************************************
Function: IAP_UpdataProgram
Description: Update program
Input: none
Return: none
**********************************************************/
static void IAP_UpdataProgram(void)
{
u8 blockNum = 0; //Block, 4 pages per block, for STM32F10X_HD, 1 page is 2Kbytes
u8 n = 0;
u8 data = 0;
u8 datalow = 0;
u8 datahigh = 0;
u32 UserMemoryMask = 0;

rcvTimeout = 0; //Clear receive timeout flag
blockNum = (IAP_ADDR - FLASH_BASE_ADDR) >> 12; //Calculate flash block
UserMemoryMask = ((u32)(~((1 << blockNum) - 1))); //Calculate the mask
//Check whether the area where the block is located is write protected
if((FLASH_GetWriteProtectionOptionByte() & UserMemoryMask) != UserMemoryMask)
{
FLASH_EraseOptionBytes (); //Turn off write protection
}
while(1)
{
switch(n)
{
case 0:
if(IAP_BufferRead(&data)) //Receive ground byte data
{
datalow = data;
n = 1;
}
else
{
break;
}
case 1:
if(IAP_BufferRead(&data)) //Receive high byte data
{
datahigh = data;
n = 0;
IAP_FlashProgramdata(((u16)(datalow)) | ((u16)(datahigh << 8)));
}
if(rcvTimeout) //Receive timeout, error or end of receive
{
datahigh = 0xff;
n = 0;
IAP_FlashProgramdata(((u16)(datalow)) | ((u16)(datahigh << 8)));
}
default:
break;
}
if(rcvTimeout)//Receive timeout
{
break;
}
}
}

To burn the program into the flash space, first check if this space is write-protected. If it is, turn off the write protection. Then in while(1), read 2 bytes each time to form a half-word, and then call the IAP_FlashProgramdata() function to burn the half-word into the flash. Someone may ask, why not burn it into the flash when the 4 bytes, i.e. a word, are complete? This is possible, but the code implementation is relatively complicated. The following is the IAP_FlashProgramdata() function code:

/****************************************************************
Function: IAP_FlashProgramdata
Description: Burn data
Input: data-data to be burned
Return: none
*************************************************************/
static void IAP_FlashProgramdata(u16 data)
{
static u32 flashwptr = IAP_ADDR;

FLASH_Unlock();//flash lock
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);//clear flash related flags
FLASH_ProgramHalfWord(flashwptr, data); //burn half word data
if(flashwptr == IAP_ADDR)//start burning
{
IAP_SerialSendStr("\r\nUpdating firmware to 0x8005000 ");
}
IAP_SerialSendStr("."); //Show the burning process
flashwptr = flashwptr + 2; //Move the burning address
FLASH_Lock(); //Flash unlock
}

Each time you burn a word or half a word in the flash, you need to unlock the flash. If it is not unlocked, the burning will not be successful. After burning, lock the flash. This is done for safety reasons. In the code, IAP_ADDR is the target flash address for upgrading. It is defined in IAP.h. Here I define the address as 0x8005000. At the beginning of burning, the serial port interface will display the message "Updating firmware to 0x8005000". Then print '.' after each burning is completed, so that you can see the burning progress on the serial port.
Next, we will implement the second function in the interface: FWERASE erase flash space code. The erase here refers to the flash space after the IAP_ADDR address. It should be noted that flash erase is not like burning, which can be operated by one word or half word. For erase, its minimum unit is page, and it can only implement page erase. The size of each page is slightly different depending on the type of processor, and the difference will be given in IAP.h. The flash erase code is as follows:

/****************************************************************
Function: IAP_FlashEease
Description: Erase Flash
Input: none
return: none
**********************************************************/
static void IAP_FlashEease(void)
{
u16 eraseCounter = 0;
u16 nbrOfPage = 0;

nbrOfPage = (FLASH_BASE_ADDR + FLASH_SIZE - IAP_ADDR)/PAGE_SIZE;//Calculate the number of pages

FLASH_Unlock(); //Release flash erase and write lock
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);//Clear flash related flags
for(eraseCounter = 0; eraseCounter < nbrOfPage; eraseCounter++)//Start erasing
{
IAP_SerialSendStr(".");//Display progress
FLASH_ErasePage(IAP_ADDR + (eraseCounter * PAGE_SIZE));//Erase
}
FLASH_Lock();//Flash erase and write lock
}

Next, we will implement the third function in the interface: BOOT startup. BOOT startup means that the program runs the code in the specified space. The implementation of this function requires some skills. Let's take a look at its related code first:

typedef void (*pFunction)(void);
pFunction Jump_To_Application;
u32 JumpAddress; //jump address

/****************************************************************
Function: IAP_JumpToApplication
Description: Jump to the upgrade program
Input: none
return: none
**********************************************************/
void IAP_JumpToApplication(void)
{
if(((*(__IO u32 *)IAP_ADDR) & 0x2FFE0000) == 0x20000000)//There is an upgrade code, the IAP_ADDR address processing should point to the main stack area, that is, 0x20000000
{
JumpAddress = *(__IO u32 *)(IAP_ADDR + 4);//Get the reset address
Jump_To_Application = (pFunction)JumpAddress;//The function pointer points to the reset address
__set_MSP(*(__IO u32*)IAP_ADDR);//Set the main stack pointer MSP to point to the upgrade mechanism IAP_ADDR
Jump_To_Application(); // Jump to the upgrade code
}
}

As can be seen in the code, at the very beginning, a function pointer with no parameters and no return value is customized, and then a function pointer Jump_To_Application pointing to this structure is defined, and a variable JumpAddress is also defined. JumpAddress obtains the reset address of the upgrade code (JumpAddress = *(__IO u32 *)(IAP_ADDR + 4);) Then the function pointer Jump_To_Application points to this code, and then sets the main stack address (__set_MSP(*(__IO u32*)IAP_ADDR);) The __set_MSP function is defined in core_cm3.c. The function pointer points to the reset address of the upgrade space and the main stack address points to the main stack address of the upgrade space. After these two conditions are met, the upgrade program can be executed (Jump_To_Application();). What cannot be ignored here is the condition in if. The condition may be difficult to understand, so here is a brief explanation: determine whether the main stack address pointed to by the upgrade code at the IAP_ADDR address is 0x20000000 (the starting address of the RAM space). If it is, it means there is an upgrade code. If not, it means there is no upgrade code at the upgrade location.
Next, we will implement the fourth function in the interface: REBOOT. The meaning of REBOOT here may be different from what you understand, so I will refer to the function of redisplaying the interface as the REBOOT function. There is no specific function to implement it here, and the implementation of this function will be discussed later.
Finally, implement the last function of the interface: HELP function. The code is as follows:

/****************************************************** ************
Function: ShwHelpInfo
Description: Display help information
Input: none
return: none
************************ *************************************/
static void ShwHelpInfo(void)
{
IAP_SerialSendStr("\r \nEnter '1' to update you apllication code!");
IAP_SerialSendStr("\r\nRnter '2' to erase the current application code!");
IAP_SerialSendStr("\r\nEnter '3' to go to excute the current application code!");
IAP_SerialSendStr("\r\nEnter '4' to restart the system!");
IAP_SerialSendStr("\r\nEnter '?' to show the help infomation!\r\n");
}

The functions related to the functions of such an interface have been written. Now we need to write a function for the user to select a function. In this function, the corresponding function is called according to the user's choice. In other words, this function implements the interaction with the user. Before calling this function, we need to write a function IAP_GetKey() to obtain the value of the user's input. The code is as follows:

/****************************************************************
Function: IAP_GetKey
Description: Get the input value
Input: none
return: Return the key value
******************************************************************/
static u8 IAP_GetKey(void)
{
u8 data;
while(!IAP_BufferRead(&data)){}//Get the key value from the buffer
return data;
}

When this function is called, if no serial port data is received, the function will be blocked.
Next, let's talk about how to implement this interactive code. The code is as follows:

/****************************************************************
Function: IAP_WiatForChoose
Description: Function selection
Input: none
return: none
*************************************************************/
void IAP_WiatForChoose(void)
{
u8 c = 0;

while (1)
{
c = IAP_GetKey();//Get key value
IAP_SerialSendByte(c);//Serial port returns key value
switch(c)
{
case '1': //FWUPDATA firmware upgrade
if((IAP_GetKey() == '\r'))//Detect enter key
{
IAP_SerialSendStr("\r\nErasing...");
IAP_FlashEease();//Erase Flash
IAP_SerialSendStr("\r\nErase done!\r\n");
IAP_SerialSendStr("Please send firmware file!\r\n");
IAP_UpdataProgram();//Burn the upgrade code
IAP_SerialSendStr("\r\nFirmware update done!\r\n");
IAP_SerialSendStr("Booting...\r\n");
Delay_ms(500);
NVIC_SystemReset();//Restart
}
break;
case '2'://FWERASE firmware erase
if((IAP_GetKey() == '\r'))//Detect the enter key
{
IAP_SerialSendStr("\r\nErasing...");
IAP_FlashEease();//Erase Flash
IAP_SerialSendStr("\r\nErase done!\r\n");
return;//Exit the loop
}
break;
case '3'://BOOT execute the upgrade program
if((IAP_GetKey() == '\r'))
{
IAP_SerialSendStr("\r\nBotting...\r\n");
if(((*(__IO u32 *)IAP_ADDR) & 0x2FFE0000) != 0x20000000)
{
IAP_SerialSendStr("No user program! Please download a firmware!\r\n");
}
Delay_ms(500);
NVIC_SystemReset();
return;//Exit the loop
}
break;
case '4'://REBOOT system restart
if((IAP_GetKey() == '\r'))//Detect the enter key
{
IAP_SerialSendStr("\r\nRebooting...\r\n");
return;//Exit the loop
}
break;
case '?'://HELP help
if((IAP_GetKey() == '\r'))
{
ShwHelpInfo();//Display help information
return;//Exit the loop
}
break;
default:
IAP_SerialSendStr("\r\nInvalid Number! The number should be either 1, 2, 3, 4or5\r\n");
return;//Exit the loop
}
}
}

This is an infinite loop function. After displaying the interface, it will wait for the user to select input (c = IAP_GetKey();), then echo the user input value on the interface (IAP_SerialSendByte(c);), and then execute the corresponding function code according to the input value (switch(c)..case statement). If the input option is not a specified function, a message will be prompted. The user's input needs to press the Enter key on the keyboard to be effective, so in the case statement, it is necessary to wait for the user to enter and exit the Enter key (if((IAP_GetKey() == '\r'))). When the user presses the Enter key, the corresponding code will be executed. When the user selects '1', the firmware upgrade starts. To burn the program, the flash space must be erased before burning. Therefore, this function only needs to call the two functions IAP_FlashEease() and IAP_UpdataProgram() and add some progress prompts, and finally restart the software. When the user selects '2', that is, to erase the flash space, it is necessary to call the IAP_FlashEease() function to erase the flash space, and then return to jump out of the loop and exit the function. When the user selects '3', BOOT, first determine whether the upgrade code is valid (if(((*(__IO u32 *)IAP_ADDR) & 0x2FFE0000) != 0x20000000)), if invalid, display the prompt information, and then restart the software; when the user selects '4' REBOOT, it displays relevant information and then exits the function; when the user selects '?' HELP, ShwHelpInfo() is called to display help information.
In this way, the IAP.c file code is complete. Here are the codes in various places of IAP.h:

#ifndef __IAP_H__
#define __IAP_H__
#include "stm32f10x.h"

#define FLASH_BASE_ADDR 0x8000000 //Flash base address
#define IAP_ADDR 0x8005000 //Upgrade code address

#if defined (STM32F10X_MD) || defined (STM32F10X_MD_VL)
#define PAGE_ SIZE (0x400) / / 1 Kbyte
#define FLASH_SIZE (0x20000) // 128 KBytes
#elif defined STM32F10X_CL
#define PAGE_SIZE (0x800) // 2 Kbytes
#define FLASH_SIZE (0x40000) // 256 KBytes
#elif defined STM32F10X_HD || defined (STM32F10X_HD_VL)
#define PAGE_SIZE (0x800) // 2 Kbytes
#define FLASH_SIZE (0x80000) // 512 KBytes
#elif defined STM32F10X_XL
#define PAGE_SIZE (0x800) // 2 Kbytes
#define FLASH_SIZE (0x100000) // 1 M Byte
#else
# error "Please select first the STM32 device to be used (in stm32f10x.h)"
#endif

void IAP_Init(void);
void IAP_SerialSendStr(u8 *s);
void IAP_ShowMenu(void);
void IAP_WiatForChoose(void);
void IAP_BufferWrite(void );
void IAP_JumpToApplication(void);

#endif

In this .h file, you can see that our upgrade address IAP_ADDR is 0x8005000. The page size and flash space corresponding to different models of STM32 are also defined below. I use the STM32F103ZET6 processor, which belongs to the STM32F10X_HD series processor, so it has 0x80000, that is, 512K of flash space, and its page size is 2K.

3. Modification of stm32f10x_it.c file
Since I used the soft timer I wrote before, I need to write its interrupt service function:

/****************************************************************
Function: TIM2_IRQHandler
Description: Timer 2 interrupt service routine
Input: none
return: none
*************************************************************/
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
SoftTimer_TimerExecute();
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}

You also need to write the interrupt service routine of the serial port:

/****************************************************************
Function: USART1_IRQHandler
Description: Serial port 1 interrupt service routine
Input: none
return: none
**********************************************************/
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//Detect receive interrupt flag
{
SoftTimer_TimerStart(0, 100, RcvTimeoutSet, (void*)0, TIMER_ONESHOT);//Start soft timer 1
IAP_BufferWrite();//Store received data
USART_ClearITPendingBit(USART1, USART_IT_RXNE); //Clear flag
}
}

In the interrupt function of the serial port, a soft timer is started with a timing of 100ms, which is used to determine whether the interval between two adjacent bytes has timed out. IAP_BufferWrite() is called to save the received data in a ring buffer.                                    
Now that a soft timer has been started, you need to write its timeout callback function. In this function, set the timeout flag to 1. The code is as follows:

u8 rcvTimeout = 0; //Receive timeout flag

/****************************************************************
Function: RcvTimeoutSet
Description: Serial port receiving data timeout
Input: parameter-parameter
return: none
*************************************************************/
void RcvTimeoutSet(void *parameter)
{
rcvTimeout = 1; //Set the receive timeout flag
}

4. Writing the main function
The process of serial port upgrade is generally: whether to upgrade the program or execute the upgraded code depends on whether a button is pressed, so you need to initialize a button and a detection function first. My development board PA8d corresponds to a button, and its code is as follows:

/****************************************************** ************
Function: KeyInit
Description: Initialization key
Input: none
return: none
************************* ************************************/
void KeyInit (void)
{
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/************************** *************************************
Function: GetKey
Description: Get the key status
Input: none
return: none
* *************************************************** **********/
u8 GetKey (void)
{
return (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8));
}

Then you can also write the main function, the code is as follows:

/****************************************************************
Function: main
Description: main entryInput
: none
return: none
**********************************************************/
int main(void)
{
BSP_Init();//Board initializationKeyInit
();//Initialize the keyif
(!GetKey())//Press the key to enter the upgrade interface
{
set: IAP_Init();//Initialize the serial
portSoftTimer_Init();//Initialize the soft timershw
: IAP_ShowMenu();//Show function
menuIAP_WiatForChoose(); //Wait for the selection interfacegoto
shw;//Redisplay the interface
}
else
{
IAP_JumpToApplication();//Jump to the upgrade code executiongoto
set;//This sentence will be executed only if there is no upgrade program or the upgrade program is wrong, and then jump to the upgrade interface
}
}

After the system is powered on, if no button is detected, it will jump to the upgrade code for execution. If there is an upgrade code, the program will not execute the goto set; statement after IAP_JumpToApplication(). However, if there is no upgrade code, goto will be used to jump to the serial port upgrade code to let the user download the upgrade code.
When the system is powered on, it detects that a button is pressed and points to the serial port upgrade code. When the code executes to the IAP_WiatForChoose() function, it will ask the user whether to jump out of this function. If it jumps out of this function, it will execute the goto statement to jump to the shw code, that is, redisplay the interface.
Someone may ask: how do you use the goto statement? Isn't it better not to use the goto statement? In fact, the reason why the use of goto is restricted is to avoid confusion in the code. However, if you use the goto statement in a function, and the destination of goto is also in this function, this method can reduce the amount of code and increase understanding. As in the above code, both the goto and the destination of goto are in the main function, and anyone with a discerning eye can understand the program flow at a glance.
 
 
5. Testing
When the system is powered on, because there is no upgrade program, it will automatically enter the serial port upgrade program, and the following interface will be displayed first:
STM32 Serial Port IAP - ziye334 - ziye334's Blog
So let's download the upgrade program, enter 1, press Enter, it will first erase the flash space and then prompt you to enter the upgrade file:
STM32 Serial Port IAP - ziye334 - ziye334's Blog
  In Transfer->Send Binary, select the .bn file to be upgraded, and then the serial port will start to burn the received data and print the progress. After the program is burned, it will automatically run the upgraded code, as follows:
STM32 Serial Port IAP - ziye334 - ziye334's Blog
  Re-power on the development board and press the button, the menu will be displayed again, then enter 2 and press Enter to start erasing the flash. After the erasing is completed, the interface will be redisplayed as follows:
STM32 Serial Port IAP - ziye334 - ziye334's Blog
  Next, the user enters 3 and presses Enter, and the upgraded code will be executed, as follows:
STM32 Serial Port IAP - ziye334 - ziye334's Blog
  Re-power the system and press the button at the same time to enter the menu interface again. Enter 4 and press Enter to redisplay the menu interface as follows:
STM32 Serial Port IAP - ziye334 - ziye334's Blog
Enter ? again and press Enter, the help information will be displayed, and then the menu interface will be redisplayed as follows:
STM32 Serial Port IAP - ziye334 - ziye334's Blog

Keywords:STM32 Reference address:STM32 serial port IAP

Previous article:Production of STM32 upgrade files
Next article:STM32 Multi-channel Soft Timer

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号