STM32F103ZET6 HAL库 bootloader 详细代码
时间: 2024-05-13 18:18:57 浏览: 206
STM32F103ZET6的Bootloader代码
这里给出一个简单的基于HAL库的STM32F103ZET6 bootloader代码示例:
```c
#include "main.h"
#define BOOTLOADER_VERSION "1.0"
#define BOOTLOADER_ADDR 0x08000000 // Bootloader程序存储地址
#define APPLICATION_ADDR 0x08004000 // 应用程序存储地址
#define FLASH_PAGE_SIZE 2048 // flash每页大小
#define APP_MAGIC_CODE 0x5A5A // 应用程序标志码
// 函数声明
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_CRC_Init(void);
static void JumpToApp(void);
void FlashErase(uint32_t addr);
void FlashWrite(uint32_t addr, uint8_t *data, uint32_t size);
uint16_t CRC16(uint8_t *data, uint32_t size);
// 全局变量
CRC_HandleTypeDef hcrc;
UART_HandleTypeDef huart1;
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_CRC_Init();
uint8_t buffer[256];
uint32_t size, addr, crc;
uint16_t magic_code;
// 检查是否需要进入bootloader模式
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET)
{
// 进入bootloader模式
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
// 发送欢迎信息
HAL_UART_Transmit(&huart1, (uint8_t *)"--------------------------------------\r\n", 44, HAL_MAX_DELAY);
HAL_UART_Transmit(&huart1, (uint8_t *)"STM32F103ZET6 Bootloader\r\n", 29, HAL_MAX_DELAY);
HAL_UART_Transmit(&huart1, (uint8_t *)"Version: ", 9, HAL_MAX_DELAY);
HAL_UART_Transmit(&huart1, (uint8_t *)BOOTLOADER_VERSION, strlen(BOOTLOADER_VERSION), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart1, (uint8_t *)"\r\n", 2, HAL_MAX_DELAY);
// 等待数据传输
while (1)
{
// 接收地址
HAL_UART_Receive(&huart1, (uint8_t *)&addr, 4, HAL_MAX_DELAY);
// 接收大小
HAL_UART_Receive(&huart1, (uint8_t *)&size, 4, HAL_MAX_DELAY);
// 接收校验码
HAL_UART_Receive(&huart1, (uint8_t *)&crc, 4, HAL_MAX_DELAY);
// 接收数据
HAL_UART_Receive(&huart1, buffer, size, HAL_MAX_DELAY);
// 计算数据校验码
if (CRC16(buffer, size) != crc)
{
// 发送错误信息
HAL_UART_Transmit(&huart1, (uint8_t *)"CRC error!\r\n", 12, HAL_MAX_DELAY);
}
else
{
// 写入flash
FlashErase(addr);
FlashWrite(addr, buffer, size);
// 发送成功信息
HAL_UART_Transmit(&huart1, (uint8_t *)"Write success!\r\n", 16, HAL_MAX_DELAY);
}
// 接收标志码
HAL_UART_Receive(&huart1, (uint8_t *)&magic_code, 2, HAL_MAX_DELAY);
// 检查标志码是否正确
if (magic_code == APP_MAGIC_CODE)
{
// 跳转到应用程序
JumpToApp();
}
}
}
else
{
// 检查应用程序标志码
magic_code = *((uint16_t *)APPLICATION_ADDR);
if (magic_code == APP_MAGIC_CODE)
{
// 跳转到应用程序
JumpToApp();
}
}
while (1)
{
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
/*Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
static void MX_CRC_Init(void)
{
hcrc.Instance = CRC;
hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE;
hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE;
hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE;
hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE;
hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
if (HAL_CRC_Init(&hcrc) != HAL_OK)
{
Error_Handler();
}
}
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
}
void JumpToApp(void)
{
// 关闭中断
__disable_irq();
// 跳转到应用程序
uint32_t jump_address = *((volatile uint32_t *)(APPLICATION_ADDR + 4));
void (*application)(void) = (void (*)(void))jump_address;
application();
}
void FlashErase(uint32_t addr)
{
// 解锁flash
HAL_FLASH_Unlock();
// 擦除flash
FLASH_EraseInitTypeDef erase = {
.TypeErase = FLASH_TYPEERASE_PAGES,
.Banks = FLASH_BANK_1,
.PageAddress = addr,
.NbPages = 1};
uint32_t error;
HAL_FLASHEx_Erase(&erase, &error);
// 上锁flash
HAL_FLASH_Lock();
}
void FlashWrite(uint32_t addr, uint8_t *data, uint32_t size)
{
uint32_t i;
// 解锁flash
HAL_FLASH_Unlock();
// 写入flash
for (i = 0; i < size; i += 2)
{
uint16_t value = (uint16_t)data[i] | ((uint16_t)data[i + 1] << 8);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, addr + i, value);
}
// 上锁flash
HAL_FLASH_Lock();
}
uint16_t CRC16(uint8_t *data, uint32_t size)
{
uint32_t crc = 0xFFFFFFFF;
for (uint32_t i = 0; i < size; i++)
{
crc ^= (uint32_t)(data[i]) << 24;
for (uint32_t j = 0; j < 8; j++)
{
if (crc & 0x80000000)
{
crc = (crc << 1) ^ 0x04C11DB7;
}
else
{
crc <<= 1;
}
}
}
return (uint16_t)(crc >> 16) & 0xFFFF;
}
```
这个bootloader程序的功能比较简单,可以接收通过串口发送的数据,写入到flash中。同时,当接收到应用程序标志码时,会跳转到应用程序的入口地址。注意,这里的bootloader程序大小应该小于应用程序的大小。
阅读全文