структуризирован бутлоадер. работает

надо по протоколу подумать еще, доработать его и описать
This commit is contained in:
2025-09-15 14:41:46 +03:00
parent fbd36705f1
commit 0e834dfe3d
20 changed files with 1018 additions and 778 deletions

View File

@@ -0,0 +1,11 @@
#ifndef __BOOT_CAN_H
#define __BOOT_CAN_H
#include "bootloader.h"
extern CAN_HandleTypeDef hcan_boot;
void MX_BOOT_CAN_Init(void);
void Bootloader_CAN_Receive_Page(Bootloader_t *bl);
#endif //__BOOT_CAN_H

View File

@@ -0,0 +1,14 @@
#ifndef __BOOT_FLASH_H
#define __BOOT_FLASH_H
#include "bootloader.h"
// FOR APP FLASHING
HAL_StatusTypeDef FLASH_Erase_App(void);
HAL_StatusTypeDef FLASH_Write_Page(uint32_t *Address, uint8_t *Data, int Data_size);
// SERVICE
HAL_StatusTypeDef FLASH_Write_Word(uint32_t Address, uint64_t Data);
#endif //__BOOT_FLASH_H

View File

@@ -0,0 +1,14 @@
#ifndef __BOOT_GPIO_H
#define __BOOT_GPIO_H
#include "bootloader.h"
#define LED_BOOT_ON() CLEAR_BIT(LED_BOOT_GPIO_Port->ODR, LED_BOOT_Pin)
#define LED_BOOT_OFF() SET_BIT(LED_BOOT_GPIO_Port->ODR, LED_BOOT_Pin)
#define LED_BOOT_TOOGLE() LED_BOOT_GPIO_Port->ODR ^= LED_BOOT_Pin
void MX_BOOT_GPIO_Init(void);
#endif //__BOOT_GPIO_H

View File

@@ -0,0 +1,26 @@
#ifndef __BOOT_JUMP_H
#define __BOOT_JUMP_H
#include "bootloader.h"
/* Инициализация приложения */
void App_Init(void);
/* Переход в бутлоадер */
void JumpToBootloader(void);
/* Переход к основному приложению */
void JumpToApplocation(void);
/* Сброс ключа BOOT в Flash */
void ResetKey(void);
/* Установка ключа BOOT в Flash */
void SetKey(void);
/* Чтение ключа BOOT из Flash */
uint32_t ReadKey(void);
/* Стирание ключа BOOT в Flash */
void EraseKey(void);
/* Проверка валидности прошивки перед переходом к приложению */
HAL_StatusTypeDef Verify_Firmware(void);
#endif //__BOOT_JUMP_H

View File

@@ -0,0 +1,74 @@
#ifndef __BOOT_SETUP_H
#define __BOOT_SETUP_H
#include "stm32f1xx_hal.h"
// ======================== BOOTLOADER CONFIG ========================
// ---------- MAIN APPLICATION defines ----------
// Адрес и страницы Flash для основного приложения
// MAIN_APP_START_ADR начало кода основного приложения
#define MAIN_APP_START_ADR (uint32_t)0x0800C000UL
#define MAIN_APP_PAGE 21 // страница, с которой начинается приложение
#define MAIN_APP_NUM_OF_PAGE 250-MAIN_APP_PAGE // количество страниц, отведённых под приложение
// ---------- KEY defines ----------
// Адрес и страница Flash для хранения ключа бутлоадера
// Ключ используется для проверки, записано ли приложение корректно
#define BOOTLOADER_KEY_ADR (uint32_t)0x08009800UL // физический адрес ключа
#define BOOTLOADER_KEY_PAGE 20 // страница флеш, на которой хранится ключ
// ---------- RECEIVE defines ----------
// Настройки приёма прошивки
#define FW_RECEIVE_TIMEOUT_MS 500 // таймаут приёма одного байта прошивки (мс)
#define PAGE_SIZE 2048 // размер блока (страницы) прошивки для приёма и записи в Flash
// должен быть таким, чтобы размер страниц Flash был кратен ему
// ---------- LED defines ----------
#define LED_BOOT_Pin GPIO_PIN_5
#define LED_BOOT_GPIO_Port GPIOB
// ======================== RCC (CLOCK) defines ========================
// Макросы для включения тактирования периферии бутлоадера
#define __RCC_LED_BOOT_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() // тактирование UART
#define __RCC_UART_BOOT_CLK_ENABLE() __HAL_RCC_USART3_CLK_ENABLE() // тактирование UART
#define __RCC_UART_PORT_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() // тактирование порта UART
#define __RCC_CAN_BOOT_CLK_ENABLE() __HAL_RCC_CAN1_CLK_ENABLE() // тактирование CAN
#define __RCC_CAN_PORT_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() // тактирование порта CAN
// ======================== UART defines ========================
// Аппаратный UART и скорость передачи
#define UART_BOOT USART3
#define UART_SPEED 256000
#define UART_BOOT_IRQn USART3_IRQn
// Порт и пины UART
#define UART_PORT GPIOB
#define UART_PIN_TX GPIO_PIN_10
#define UART_PIN_RX GPIO_PIN_11
// ======================== CAN defines ========================
// Аппаратный CAN и режим работы
#define CAN_BOOT CAN1
#define CAN_MODE CAN_MODE_NORMAL
// Настройка скорости CAN при 8 MHz
// ------------|-----------|-----------|-----------
// CAN speed | Prescaler | BS1 | BS2
// ------------|-----------|-----------|-----------
// 125 kbps | 4 | 13TQ | 2TQ
// 250 kbps | 2 | 13TQ | 2TQ
// 500 kbps | 1 | 13TQ | 2TQ
#define CAN_SPEED_PRESCALER 4
#define CAN_SPEED_BS1 CAN_BS1_13TQ
#define CAN_SPEED_BS2 CAN_BS2_2TQ
// Порт и пины CAN
#define CAN_PORT GPIOA
#define CAN_PIN_RX GPIO_PIN_11
#define CAN_PIN_TX GPIO_PIN_12
#endif //__BOOT_SETUP_H

View File

@@ -0,0 +1,11 @@
#ifndef __BOOT_UART_H
#define __BOOT_UART_H
#include "bootloader.h"
extern UART_HandleTypeDef huart_boot;
void MX_BOOT_UART_Init(void);
void Bootloader_UART_Receive_Page(Bootloader_t *bl);
#endif //__BOOT_UART_H

View File

@@ -0,0 +1,145 @@
#ifndef __BOOTLOADER_H
#define __BOOTLOADER_H
#include "boot_project_setup.h"
#include "string.h"
/* --- Настройка: подставьте значения для вашей MCU --- */
/* Адрес начала приложения (используется в вашем коде) */
#ifndef MAIN_APP_START_ADR
#error "MAIN_APP_START_ADR must be defined"
#endif
/* Flash boundaries: подставьте реальные границы флеш-памяти вашего MCU */
#ifndef FLASH_START_ADR
#define FLASH_START_ADR MAIN_APP_START_ADR
#endif
#ifndef FLASH_END_ADR
#define FLASH_END_ADR FLASH_BASE + (*((uint16_t*)FLASHSIZE_BASE) * 1024U)
#endif
/* SRAM boundaries: подставьте реальные адреса SRAM вашей MCU */
#ifndef SRAM_START_ADR
#define SRAM_START_ADR 0x20000000UL
#endif
#ifndef SRAM_END_ADR
#define SRAM_END_ADR 0x2003FFFFUL
#endif
/**
* @brief Значение ключа, указывающее что основное приложение записано
*/
#define BL_KEY_APP_WRITTEN 0xAAAA5555
/** @brief Получить сохранённый код ошибки из BKP */
#define GetErrorCode() BKP->DR1
/** @brief Получить счетчик ошибок из BKP */
#define GetErrorCnt() BKP->DR2
/**
* @brief Сохранение кода ошибки и инкремент счетчика
* @param code Код ошибки
* @details
* Включаем тактирование PWR и BKP (APB1) и разрешаем доступ к BKP domain
* Записываем напрямую в регистры RCC/APB1ENR и PWR->CR
* Записываем код ошибки и счётчик ошибок
*/
#define SaveErrorCode(code) do{ \
RCC->APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN); \
PWR->CR |= PWR_CR_DBP; \
GetErrorCode() = code; \
GetErrorCnt() = GetErrorCnt() + 1; \
}while(0u);
/**
* @brief Очистка кода ошибки и счетчика ошибок
*/
#define ClearErrorCode(code) do{ \
RCC->APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN); \
PWR->CR |= PWR_CR_DBP; \
GetErrorCode() = 0; \
GetErrorCnt() = 0; \
}while(0u);
/**
* @brief Команды для управления бутлоадером
*/
typedef enum {
CMD_ERASE = 0x01, ///< Команда на стирание прошивки
CMD_START_RECEIVE, ///< Команда на старт приема прошивки
CMD_WRITE, ///< Команда на запись блока прошивки
CMD_GOTOAPP, ///< Команда на переход в приложение
CMD_RESET, ///< Команда на переход в приложение
CMD_GOTOBOOT, ///< Команда на переход в приложение
}BootloaderCommand_t;
/**
* @brief Состояния конечного автомата бутлоадера
*/
typedef enum {
BL_STATE_INIT = 0, ///< Состояние: инициализация
BL_STATE_JUMP_TO_APP, ///< Состояние: запуск приложения
BL_STATE_IDLE, ///< Состояние: ожидание команд
BL_STATE_ERASE, ///< Состояние: стирание флеша
BL_STATE_RECEIVE_UART, ///< Состояние: прием прошивки по UART
BL_STATE_RECEIVE_CAN, ///< Состояние: прием прошивки по CAN
BL_STATE_WRITE, ///< Состояние: запись данных
BL_STATE_ERROR, ///< Состояние: ошибка
BL_STATE_RESET, ///< Состояние: сброс контролллера
BL_STATE_JUMP_TO_BOOT, ///< Состояние: запуск приложения
} BootloaderState_t;
/**
* @brief Ошибки бутлоадера
*/
typedef union {
uint16_t all; ///< Все ошибки одним числом
struct {
unsigned hardfault_cycle:1; ///< Прерывание HardFault
unsigned memmanage_cycle:1; ///< Прерывание MemManage
unsigned watchdog_reset:1; ///< Watchdog сброс
unsigned unknown_cmd:1; ///< Неизвестная команда
unsigned erase_err:1; ///< Ошибка стирания
unsigned write_err:1; ///< Ошибка записи
unsigned verify_err:1; ///< Ошибка проверки прошивки
unsigned timeout_receive:1; ///< Таймаут приёма
unsigned crc_err:1; ///< Ошибка CRC
} bit;
} BootloaderError_t;
/**
* @brief Дескриптор бутлоадера
*/
typedef struct {
BootloaderState_t state; ///< текущее состояние бутлоадера
BootloaderError_t error;
uint32_t addr; ///< текущий адрес прошивки
uint8_t fw_size; ///< размер прошивки
uint8_t fw_buffer[PAGE_SIZE]; ///< буфер для приема прошивки (UART/CAN)
uint32_t fw_len; ///< длина принятого пакета
uint32_t fw_crc; ///< контрольная сумма прошивки
UART_HandleTypeDef *huart; ///< хендлер UART
CAN_HandleTypeDef *hcan; ///< хендер CAN
CAN_TxHeaderTypeDef TxHeader; ///< Заголовок CAN сообщения для отправки
BootloaderState_t prev_state; ///< предыдущее состояние бутлоадера
} Bootloader_t;
/* Основная задача бутлоадера */
void Bootloader_Task(Bootloader_t *bl);
/* Настройка тактирования */
void Boot_SystemClock_Config(void);
/* Хендлер ошибки */
void Error_Handler(void);
#endif //__BOOTLOADER_H