STM32 bootloader接收程序
时间: 2023-09-09 20:12:01 浏览: 125
STM32 bootloader是一种可以在芯片上运行的特殊程序,它可以通过串口或USB等接口接收新的程序文件,然后将其烧录到芯片的Flash中。
以下是一个简单的STM32 bootloader接收程序的示例代码,仅供参考:
```c
#include "stm32f10x.h"
#define APPLICATION_ADDRESS 0x08004000 // 应用程序起始地址
#define BOOTLOADER_TIMEOUT 5000 // 进入bootloader的超时时间,单位ms
#define UART_TIMEOUT 500 // UART接收超时时间,单位ms
#define CMD_JUMP_TO_APP 0x01 // 跳转到应用程序命令
#define CMD_ERASE_APP 0x02 // 擦除应用程序命令
#define CMD_WRITE_APP 0x03 // 写入应用程序命令
uint8_t uart_buf[256];
uint32_t uart_idx = 0;
uint32_t timeout_cnt = 0;
void jump_to_app(void)
{
// 关闭所有中断
__disable_irq();
// 关闭SysTick定时器
SysTick->CTRL = 0;
// 关闭所有外设
RCC->APB1ENR = 0;
RCC->APB2ENR = 0;
// 关闭所有GPIO的输出
GPIOA->ODR = 0;
GPIOB->ODR = 0;
GPIOC->ODR = 0;
GPIOD->ODR = 0;
GPIOE->ODR = 0;
GPIOF->ODR = 0;
GPIOG->ODR = 0;
// 设置栈指针和程序计数器
uint32_t app_start_addr = *(__IO uint32_t*)APPLICATION_ADDRESS;
uint32_t app_stack_ptr = *(__IO uint32_t*)APPLICATION_ADDRESS;
uint32_t app_entry_point = *(__IO uint32_t*)(APPLICATION_ADDRESS+4);
__set_MSP(app_stack_ptr);
__set_PSP(app_stack_ptr);
__ASM volatile ("bx %0"::"r"(app_entry_point));
}
void erase_app(void)
{
FLASH_Unlock();
FLASH_ErasePage(APPLICATION_ADDRESS);
FLASH_Lock();
}
void write_app(uint8_t* data, uint32_t len)
{
uint32_t addr = APPLICATION_ADDRESS;
FLASH_Unlock();
for (uint32_t i = 0; i < len; i += 4) {
uint32_t word = *((uint32_t*)(data + i));
FLASH_ProgramWord(addr, word);
addr += 4;
}
FLASH_Lock();
}
void process_command(uint8_t cmd, uint8_t* data, uint32_t len)
{
switch (cmd) {
case CMD_JUMP_TO_APP:
jump_to_app();
break;
case CMD_ERASE_APP:
erase_app();
break;
case CMD_WRITE_APP:
write_app(data, len);
break;
default:
break;
}
}
int main(void)
{
// 初始化串口
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
// 进入bootloader
while (1) {
if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) {
uart_buf[uart_idx++] = USART_ReceiveData(USART1);
timeout_cnt = 0;
} else {
timeout_cnt++;
if (timeout_cnt >= BOOTLOADER_TIMEOUT) {
jump_to_app();
}
}
if (uart_idx >= 3) {
uint32_t len = uart_buf[2] | (uart_buf[1] << 8) | (uart_buf[0] << 16);
if (uart_idx >= len + 3) {
process_command(uart_buf[3], uart_buf + 4, len);
uart_idx = 0;
}
}
}
}
```
在该示例中,我们通过USART1接收新的程序文件,并根据不同的命令来执行不同的操作。
具体来说,我们定义了三个命令:
- CMD_JUMP_TO_APP:跳转到应用程序命令
- CMD_ERASE_APP:擦除应用程序命令
- CMD_WRITE_APP:写入应用程序命令
当收到这些命令时,我们分别执行了对应的操作:
- 跳转到应用程序:首先关闭所有中断和外设,然后根据应用程序起始地址设置栈指针和程序计数器,最后跳转到应用程序入口点。
- 擦除应用程序:使用STM32的FLASH模块擦除应用程序所在的Flash页面。
- 写入应用程序:使用STM32的FLASH模块将新的程序文件写入到应用程序所在的Flash页面。
需要注意的是,在跳转到应用程序之前必须关闭所有中断和外设,否则可能会导致应用程序无法正常运行。同时,为了避免写入过程中出现错误,我们还需要在写入数据之前调用FLASH_Unlock()函数解锁Flash,写入完成后再调用FLASH_Lock()函数锁定Flash。
阅读全文