uart для платы вэп + структурирован чуть проект и описан бутлоадер

Но надо еще его дорабатывать

+ заготовка для протокола приема (не работает скорее всего, просто из чатгпт вставил)
This commit is contained in:
Razvalyaev 2025-09-19 13:32:45 +03:00
parent 0e834dfe3d
commit c61c438b8c
12 changed files with 372 additions and 290 deletions

View File

@ -5,7 +5,16 @@
extern CAN_HandleTypeDef hcan_boot; extern CAN_HandleTypeDef hcan_boot;
extern CAN_TxHeaderTypeDef TxHeaderBoot;
extern CAN_RxHeaderTypeDef RxHeaderBoot;
extern uint32_t TxMailBoxBoot;
extern uint8_t TXDataBoot[8];
/* Инициализация CAN */
void MX_BOOT_CAN_Init(void); void MX_BOOT_CAN_Init(void);
/* Приём команды по CAN по протоколу */
BootloaderCommand_t Bootloader_CAN_Receive(Bootloader_t *bl);
/* Приём CAN: страница + CRC */
void Bootloader_CAN_Receive_Page(Bootloader_t *bl); void Bootloader_CAN_Receive_Page(Bootloader_t *bl);
#endif //__BOOT_CAN_H #endif //__BOOT_CAN_H

View File

@ -32,20 +32,19 @@
// Макросы для включения тактирования периферии бутлоадера // Макросы для включения тактирования периферии бутлоадера
#define __RCC_LED_BOOT_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() // тактирование UART #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_BOOT_CLK_ENABLE() __HAL_RCC_UART4_CLK_ENABLE() // тактирование UART
#define __RCC_UART_PORT_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() // тактирование порта UART #define __RCC_UART_PORT_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() // тактирование порта UART
#define __RCC_CAN_BOOT_CLK_ENABLE() __HAL_RCC_CAN1_CLK_ENABLE() // тактирование CAN #define __RCC_CAN_BOOT_CLK_ENABLE() __HAL_RCC_CAN1_CLK_ENABLE() // тактирование CAN
#define __RCC_CAN_PORT_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() // тактирование порта CAN #define __RCC_CAN_PORT_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() // тактирование порта CAN
// ======================== UART defines ======================== // ======================== UART defines ========================
// Аппаратный UART и скорость передачи // Аппаратный UART и скорость передачи
#define UART_BOOT USART3 #define UART_BOOT UART4
#define UART_SPEED 256000 #define UART_SPEED 115200
#define UART_BOOT_IRQn USART3_IRQn
// Порт и пины UART // Порт и пины UART
#define UART_PORT GPIOB #define UART_PORT GPIOC
#define UART_PIN_TX GPIO_PIN_10 #define UART_PIN_TX GPIO_PIN_10
#define UART_PIN_RX GPIO_PIN_11 #define UART_PIN_RX GPIO_PIN_11

View File

@ -5,7 +5,11 @@
extern UART_HandleTypeDef huart_boot; extern UART_HandleTypeDef huart_boot;
/* Инициализация UART */
void MX_BOOT_UART_Init(void); void MX_BOOT_UART_Init(void);
/* Приём команды по UART по протоколу */
BootloaderCommand_t Bootloader_UART_Receive(Bootloader_t *bl);
/* Приём UART: страница + CRC */
void Bootloader_UART_Receive_Page(Bootloader_t *bl); void Bootloader_UART_Receive_Page(Bootloader_t *bl);
#endif //__BOOT_UART_H #endif //__BOOT_UART_H

View File

@ -71,12 +71,14 @@
* @brief Команды для управления бутлоадером * @brief Команды для управления бутлоадером
*/ */
typedef enum { typedef enum {
NO_CMD = 0x00, ///< Нет комманды
CMD_ERASE = 0x01, ///< Команда на стирание прошивки CMD_ERASE = 0x01, ///< Команда на стирание прошивки
CMD_START_RECEIVE, ///< Команда на старт приема прошивки CMD_START_RECEIVE, ///< Команда на старт приема прошивки
CMD_WRITE, ///< Команда на запись блока прошивки CMD_WRITE, ///< Команда на запись блока прошивки
CMD_GOTOAPP, ///< Команда на переход в приложение CMD_GOTOAPP, ///< Команда на переход в приложение
CMD_RESET, ///< Команда на переход в приложение CMD_RESET, ///< Команда на переход в приложение
CMD_GOTOBOOT, ///< Команда на переход в приложение CMD_GOTOBOOT, ///< Команда на переход в приложение
CMD_PING = 0xAA, ///< Команда на пинг
}BootloaderCommand_t; }BootloaderCommand_t;
/** /**
@ -108,6 +110,7 @@ typedef union {
unsigned erase_err:1; ///< Ошибка стирания unsigned erase_err:1; ///< Ошибка стирания
unsigned write_err:1; ///< Ошибка записи unsigned write_err:1; ///< Ошибка записи
unsigned verify_err:1; ///< Ошибка проверки прошивки unsigned verify_err:1; ///< Ошибка проверки прошивки
unsigned overflow:1; ///< Слишком много данных
unsigned timeout_receive:1; ///< Таймаут приёма unsigned timeout_receive:1; ///< Таймаут приёма
unsigned crc_err:1; ///< Ошибка CRC unsigned crc_err:1; ///< Ошибка CRC
} bit; } bit;
@ -119,7 +122,7 @@ typedef union {
*/ */
typedef struct { typedef struct {
BootloaderState_t state; ///< текущее состояние бутлоадера BootloaderState_t state; ///< текущее состояние бутлоадера
BootloaderError_t error; BootloaderError_t error; ///< ошибки бутлоадера
uint32_t addr; ///< текущий адрес прошивки uint32_t addr; ///< текущий адрес прошивки
@ -141,5 +144,7 @@ void Bootloader_Task(Bootloader_t *bl);
void Boot_SystemClock_Config(void); void Boot_SystemClock_Config(void);
/* Хендлер ошибки */ /* Хендлер ошибки */
void Error_Handler(void); void Error_Handler(void);
/* CRC */
uint32_t CRC32_Compute(const uint8_t* data, uint32_t length);
#endif //__BOOTLOADER_H #endif //__BOOTLOADER_H

View File

@ -3,6 +3,12 @@
CAN_HandleTypeDef hcan_boot; CAN_HandleTypeDef hcan_boot;
CAN_TxHeaderTypeDef TxHeaderBoot;
CAN_RxHeaderTypeDef RxHeaderBoot;
uint32_t TxMailBoxBoot = 0;
uint8_t TXDataBoot[8] = {0};
/** /**
* @brief Инициализация CAN для бутлоадера * @brief Инициализация CAN для бутлоадера
*/ */
@ -68,8 +74,28 @@ void MX_BOOT_CAN_Init(void)
} }
} }
/**
* @brief Приём команды по CAN по протоколу:
* @param bl: указатель на структуру бутлоадера
* @retval BootloaderCommand_t принятая команда или NO_CMD
*/
BootloaderCommand_t Bootloader_CAN_Receive(Bootloader_t *bl)
{
BootloaderCommand_t cmd = NO_CMD;
uint8_t canData[8];
if (HAL_CAN_GetRxFifoFillLevel(bl->hcan, CAN_RX_FIFO0) > 0)
{
if (HAL_CAN_GetRxMessage(bl->hcan, CAN_RX_FIFO0, &RxHeaderBoot, canData) == HAL_OK)
{
cmd = canData[0]; // предполагаем, что команда в первом байте
}
}
return cmd;
}
/** /**
* @brief Приём CAN: страница + CRC * @brief Приём CAN: страница + CRC
* @param bl: указатель на структуру бутлоадера
*/ */
void Bootloader_CAN_Receive_Page(Bootloader_t *bl) void Bootloader_CAN_Receive_Page(Bootloader_t *bl)
{ {

View File

@ -15,12 +15,16 @@ void MX_BOOT_UART_Init(void)
__RCC_UART_PORT_CLK_ENABLE(); __RCC_UART_PORT_CLK_ENABLE();
/* Настройка GPIO TX/RX */ /* Настройка GPIO TX/RX */
GPIO_InitStruct.Pin = UART_PIN_TX | UART_PIN_RX; GPIO_InitStruct.Pin = UART_PIN_TX;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(UART_PORT, &GPIO_InitStruct); HAL_GPIO_Init(UART_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = UART_PIN_RX;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(UART_PORT, &GPIO_InitStruct);
/* Настройка UART */ /* Настройка UART */
huart_boot.Instance = UART_BOOT; huart_boot.Instance = UART_BOOT;
huart_boot.Init.BaudRate = UART_SPEED; huart_boot.Init.BaudRate = UART_SPEED;
@ -37,9 +41,96 @@ void MX_BOOT_UART_Init(void)
} }
} }
/**
* @brief Приём команды по UART по протоколу:
* [SOH][CMD][LEN_H][LEN_L][DATA ...][CRC32_H..CRC32_L]
* Idle не блокируется до SOH
* После SOH блокирующий приём всего пакета
* @param bl: указатель на структуру бутлоадера
* @retval BootloaderCommand_t принятая команда или NO_CMD
*/
BootloaderCommand_t Bootloader_UART_Receive(Bootloader_t *bl)
{
BootloaderCommand_t cmd;
uint8_t byte = 0;
HAL_StatusTypeDef res;
// -----------------------------
// 1. Ждём SOH в неблокирующем режиме
res = HAL_UART_Receive(bl->huart, &byte, 1, 1); // 1 ms таймаут
if(res != HAL_OK)
return NO_CMD; // пакета нет
if(byte != 0xAA)
return NO_CMD; // игнорируем мусор
// -----------------------------
// 2. Блокирующий приём CMD + LEN_H + LEN_L
uint8_t header[3];
res = HAL_UART_Receive(bl->huart, header, 3, FW_RECEIVE_TIMEOUT_MS);
if(res != HAL_OK)
{
bl->error.bit.timeout_receive = 1;
bl->state = BL_STATE_ERROR;
return NO_CMD;
}
cmd = (BootloaderCommand_t)header[0];
bl->fw_len = ((uint16_t)header[1] << 8) | header[2];
if(bl->fw_len > PAGE_SIZE)
{
bl->error.bit.overflow = 1;
bl->state = BL_STATE_ERROR;
return NO_CMD;
}
// -----------------------------
// 3. Блокирующий приём DATA
for(uint16_t i = 0; i < bl->fw_len; i++)
{
res = HAL_UART_Receive(bl->huart, &bl->fw_buffer[i], 1, FW_RECEIVE_TIMEOUT_MS);
if(res != HAL_OK)
{
bl->error.bit.timeout_receive = 1;
bl->state = BL_STATE_ERROR;
return NO_CMD;
}
}
// -----------------------------
// 4. Приём CRC32
uint8_t crc_buf[4];
res = HAL_UART_Receive(bl->huart, crc_buf, 4, FW_RECEIVE_TIMEOUT_MS);
if(res != HAL_OK)
{
bl->error.bit.timeout_receive = 1;
bl->state = BL_STATE_ERROR;
return NO_CMD;
}
bl->fw_crc = (crc_buf[0]<<24) | (crc_buf[1]<<16) | (crc_buf[2]<<8) | crc_buf[3];
// -----------------------------
// 5. Проверка CRC по всему пакету (CMD + LEN + DATA)
uint32_t crc_calc = CRC32_Compute(header, 3); // CMD + LEN
crc_calc = CRC32_Compute(bl->fw_buffer, bl->fw_len) ^ crc_calc; // DATA
if(crc_calc != bl->fw_crc)
{
bl->error.bit.crc_err = 1;
bl->state = BL_STATE_ERROR;
return NO_CMD;
}
// -----------------------------
// 6. Всё верно — возвращаем команду
return cmd;
}
/** /**
* @brief Приём UART: страница + CRC * @brief Приём UART: страница + CRC
* @param bl: указатель на структуру бутлоадера
*/ */
void Bootloader_UART_Receive_Page(Bootloader_t *bl) void Bootloader_UART_Receive_Page(Bootloader_t *bl)
{ {

View File

@ -40,17 +40,12 @@
// Глобальные переменные для HAL-периферии // Глобальные переменные для HAL-периферии
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
HAL_StatusTypeDef res_hal; HAL_StatusTypeDef res_hal;
CAN_TxHeaderTypeDef TxHeaderBoot;
CAN_RxHeaderTypeDef RxHeaderBoot;
uint32_t TxMailBoxBoot = 0;
uint8_t TXDataBoot[8] = {0};
uint32_t led_err_lasttick = 0; uint32_t led_err_lasttick = 0;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Локальные (static) функции // Локальные (static) функции
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
static uint8_t Receive_FW_Command(Bootloader_t *bl); static uint8_t Receive_FW_Command(Bootloader_t *bl);
static uint32_t CRC32_Compute(const uint8_t* data, uint32_t length);
/** /**
* @brief Проверка после сброса MCU. * @brief Проверка после сброса MCU.
@ -72,7 +67,8 @@ void Bootloader_StartCheck(Bootloader_t *bl)
// Чтение сохранённого кода ошибки и количества сбоев // Чтение сохранённого кода ошибки и количества сбоев
ErrCodeBoot = GetErrorCode(); ErrCodeBoot = GetErrorCode();
ErrCntBoot = GetErrorCnt(); ErrCntBoot = GetErrorCnt();
// Если ошибок было больше 5, фиксируем тип ошибки // Если ошибок было больше 5, фиксируем тип ошибки и уходим в бутлоадер
// Данные ошибки фиксируются только в прерываниях бутлоадера. Hardfault в прерывании приложения не считается
if(ErrCntBoot > 5) if(ErrCntBoot > 5)
{ {
ClearErrorCode(); ClearErrorCode();
@ -385,6 +381,8 @@ static uint8_t SetBootState(Bootloader_t *bl, BootloaderCommand_t cmd, uint8_t u
return 0x00; return 0x00;
case CMD_GOTOBOOT: // команда: прыжок в бутлоадер case CMD_GOTOBOOT: // команда: прыжок в бутлоадер
bl->state = BL_STATE_JUMP_TO_BOOT; bl->state = BL_STATE_JUMP_TO_BOOT;
case CMD_PING: // команда: пинг, отправка текущего состояния бутлоадера
bl->prev_state = 0; // обнуляем предыдущее состоояние, чтобы снова отправить комманду с текущим состоянием
return 0x00; return 0x00;
default: default:
@ -406,8 +404,8 @@ static uint8_t Receive_FW_Command(Bootloader_t *bl)
// --------------------------- // ---------------------------
// Чтение команды по UART // Чтение команды по UART
// --------------------------- // ---------------------------
res = HAL_UART_Receive(bl->huart, &cmd, 1, 10); // таймаут 10 ms cmd = Bootloader_UART_Receive(bl); // таймаут 10 ms
if (res == HAL_OK) if (cmd != NO_CMD)
{ {
ret_val = SetBootState(bl, cmd, 1); ret_val = SetBootState(bl, cmd, 1);
} }
@ -415,15 +413,11 @@ static uint8_t Receive_FW_Command(Bootloader_t *bl)
// --------------------------- // ---------------------------
// Чтение команды по CAN // Чтение команды по CAN
// --------------------------- // ---------------------------
uint8_t canData[8]; cmd = Bootloader_CAN_Receive(bl);
if (HAL_CAN_GetRxFifoFillLevel(bl->hcan, CAN_RX_FIFO0) > 0) if (cmd != NO_CMD)
{ {
if (HAL_CAN_GetRxMessage(bl->hcan, CAN_RX_FIFO0, &RxHeaderBoot, canData) == HAL_OK)
{
cmd = canData[0]; // предполагаем, что команда в первом байте
ret_val = SetBootState(bl, cmd, 0); ret_val = SetBootState(bl, cmd, 0);
} }
}
#ifdef TEST_CAN #ifdef TEST_CAN
TxHeaderBoot.StdId = 0x200; // ID OF MESSAGE TxHeaderBoot.StdId = 0x200; // ID OF MESSAGE
@ -451,7 +445,7 @@ static uint8_t Receive_FW_Command(Bootloader_t *bl)
* @param length: длина массива в байтах * @param length: длина массива в байтах
* @retval CRC32 вычисленное значение * @retval CRC32 вычисленное значение
*/ */
static uint32_t CRC32_Compute(const uint8_t* data, uint32_t length) uint32_t CRC32_Compute(const uint8_t* data, uint32_t length)
{ {
const uint32_t polynomial = 0x04C11DB7; const uint32_t polynomial = 0x04C11DB7;
uint32_t crc = 0xFFFFFFFF; uint32_t crc = 0xFFFFFFFF;

View File

@ -0,0 +1,16 @@
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x0800C000 0x00040000 { ; load region size_region
ER_IROM1 0x0800C000 0x00040000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM1 0x20000000 0x0000C000 { ; RW data
.ANY (+RW +ZI)
}
}

View File

@ -28,7 +28,7 @@
<TargetOption> <TargetOption>
<CLKADS>8000000</CLKADS> <CLKADS>8000000</CLKADS>
<OPTTT> <OPTTT>
<gFlags>1</gFlags> <gFlags>0</gFlags>
<BeepAtEnd>1</BeepAtEnd> <BeepAtEnd>1</BeepAtEnd>
<RunSim>0</RunSim> <RunSim>0</RunSim>
<RunTarget>1</RunTarget> <RunTarget>1</RunTarget>
@ -103,7 +103,7 @@
<bEvRecOn>1</bEvRecOn> <bEvRecOn>1</bEvRecOn>
<bSchkAxf>0</bSchkAxf> <bSchkAxf>0</bSchkAxf>
<bTchkAxf>0</bTchkAxf> <bTchkAxf>0</bTchkAxf>
<nTsel>4</nTsel> <nTsel>0</nTsel>
<sDll></sDll> <sDll></sDll>
<sDllPa></sDllPa> <sDllPa></sDllPa>
<sDlgDll></sDlgDll> <sDlgDll></sDlgDll>
@ -114,34 +114,9 @@
<tDlgDll></tDlgDll> <tDlgDll></tDlgDll>
<tDlgPa></tDlgPa> <tDlgPa></tDlgPa>
<tIfile></tIfile> <tIfile></tIfile>
<pMon>Segger\JL2CM3.dll</pMon> <pMon>BIN\UL2CM3.DLL</pMon>
</DebugOpt> </DebugOpt>
<TargetDriverDllRegistry> <TargetDriverDllRegistry>
<SetRegEntry>
<Number>0</Number>
<Key>ARMRTXEVENTFLAGS</Key>
<Name>-L70 -Z18 -C0 -M0 -T1</Name>
</SetRegEntry>
<SetRegEntry>
<Number>0</Number>
<Key>DLGTARM</Key>
<Name>(1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)</Name>
</SetRegEntry>
<SetRegEntry>
<Number>0</Number>
<Key>ARMDBGFLAGS</Key>
<Name></Name>
</SetRegEntry>
<SetRegEntry>
<Number>0</Number>
<Key>DLGUARM</Key>
<Name></Name>
</SetRegEntry>
<SetRegEntry>
<Number>0</Number>
<Key>JL2CM3</Key>
<Name>-U11111118 -O14 -S2 -ZTIFSpeedSel5000 -A0 -C0 -JU1 -JI127.0.0.1 -JP0 -RST0 -N00("ARM CoreSight JTAG-DP") -D00(3BA00477) -L00(4) -N01("Unknown JTAG device") -D01(06414041) -L01(5) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -TB1 -TFE0 -FO7 -FD20000000 -FC1000 -FN1 -FF0STM32F10x_512.FLM -FS08000000 -FL080000 -FP0($$Device:STM32F103RC$Flash\STM32F10x_512.FLM)</Name>
</SetRegEntry>
<SetRegEntry> <SetRegEntry>
<Number>0</Number> <Number>0</Number>
<Key>UL2CM3</Key> <Key>UL2CM3</Key>
@ -149,81 +124,18 @@
</SetRegEntry> </SetRegEntry>
</TargetDriverDllRegistry> </TargetDriverDllRegistry>
<Breakpoint/> <Breakpoint/>
<WatchWindow1>
<Ww>
<count>0</count>
<WinNumber>1</WinNumber>
<ItemText>input</ItemText>
</Ww>
<Ww>
<count>1</count>
<WinNumber>1</WinNumber>
<ItemText>Inputs</ItemText>
</Ww>
<Ww>
<count>2</count>
<WinNumber>1</WinNumber>
<ItemText>duty_cycle,0x0A</ItemText>
</Ww>
<Ww>
<count>3</count>
<WinNumber>1</WinNumber>
<ItemText>frequency,0x0A</ItemText>
</Ww>
<Ww>
<count>4</count>
<WinNumber>1</WinNumber>
<ItemText>uwTick,0x0A</ItemText>
</Ww>
<Ww>
<count>5</count>
<WinNumber>1</WinNumber>
<ItemText>modbus</ItemText>
</Ww>
<Ww>
<count>6</count>
<WinNumber>1</WinNumber>
<ItemText>msgData[0]</ItemText>
</Ww>
<Ww>
<count>7</count>
<WinNumber>1</WinNumber>
<ItemText>CMD_GOTOBOOT</ItemText>
</Ww>
<Ww>
<count>8</count>
<WinNumber>1</WinNumber>
<ItemText>hcan</ItemText>
</Ww>
</WatchWindow1>
<MemoryWindow1>
<Mm>
<WinNumber>1</WinNumber>
<SubType>0</SubType>
<ItemText>0x0800c000</ItemText>
<AccSizeX>0</AccSizeX>
</Mm>
</MemoryWindow1>
<MemoryWindow2>
<Mm>
<WinNumber>2</WinNumber>
<SubType>0</SubType>
<ItemText>0x08009800</ItemText>
<AccSizeX>0</AccSizeX>
</Mm>
</MemoryWindow2>
<Tracepoint> <Tracepoint>
<THDelay>0</THDelay> <THDelay>0</THDelay>
</Tracepoint> </Tracepoint>
<DebugFlag> <DebugFlag>
<trace>0</trace> <trace>0</trace>
<periodic>1</periodic> <periodic>0</periodic>
<aLwin>1</aLwin> <aLwin>0</aLwin>
<aCover>0</aCover> <aCover>0</aCover>
<aSer1>0</aSer1> <aSer1>0</aSer1>
<aSer2>0</aSer2> <aSer2>0</aSer2>
<aPa>0</aPa> <aPa>0</aPa>
<viewmode>1</viewmode> <viewmode>0</viewmode>
<vrSel>0</vrSel> <vrSel>0</vrSel>
<aSym>0</aSym> <aSym>0</aSym>
<aTbox>0</aTbox> <aTbox>0</aTbox>
@ -254,27 +166,9 @@
<pszMrulep></pszMrulep> <pszMrulep></pszMrulep>
<pSingCmdsp></pSingCmdsp> <pSingCmdsp></pSingCmdsp>
<pMultCmdsp></pMultCmdsp> <pMultCmdsp></pMultCmdsp>
<SystemViewers>
<Entry>
<Name>System Viewer\BKP</Name>
<WinId>35902</WinId>
</Entry>
<Entry>
<Name>System Viewer\CAN</Name>
<WinId>35904</WinId>
</Entry>
<Entry>
<Name>System Viewer\GPIOB</Name>
<WinId>35905</WinId>
</Entry>
<Entry>
<Name>System Viewer\IWDG</Name>
<WinId>35903</WinId>
</Entry>
</SystemViewers>
<DebugDescription> <DebugDescription>
<Enable>1</Enable> <Enable>1</Enable>
<EnableFlashSeq>0</EnableFlashSeq> <EnableFlashSeq>1</EnableFlashSeq>
<EnableLog>0</EnableLog> <EnableLog>0</EnableLog>
<Protocol>2</Protocol> <Protocol>2</Protocol>
<DbgClock>10000000</DbgClock> <DbgClock>10000000</DbgClock>
@ -386,7 +280,7 @@
<SetRegEntry> <SetRegEntry>
<Number>0</Number> <Number>0</Number>
<Key>DLGTARM</Key> <Key>DLGTARM</Key>
<Name>(1010=-1605,104,-1155,661,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)</Name> <Name>(1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)</Name>
</SetRegEntry> </SetRegEntry>
<SetRegEntry> <SetRegEntry>
<Number>0</Number> <Number>0</Number>
@ -413,70 +307,25 @@
<Bp> <Bp>
<Number>0</Number> <Number>0</Number>
<Type>0</Type> <Type>0</Type>
<LineNumber>1300</LineNumber> <LineNumber>368</LineNumber>
<EnabledFlag>1</EnabledFlag> <EnabledFlag>1</EnabledFlag>
<Address>134222082</Address> <Address>134230816</Address>
<ByteObject>0</ByteObject> <ByteObject>0</ByteObject>
<HtxType>0</HtxType> <HtxType>0</HtxType>
<ManyObjects>0</ManyObjects> <ManyObjects>0</ManyObjects>
<SizeOfObject>0</SizeOfObject> <SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess> <BreakByAccess>0</BreakByAccess>
<BreakIfRCount>1</BreakIfRCount> <BreakIfRCount>1</BreakIfRCount>
<Filename>../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_can.c</Filename> <Filename>..\Core\Bootloader\Src\bootloader.c</Filename>
<ExecCommand></ExecCommand> <ExecCommand></ExecCommand>
<Expression>\\bootloader\../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_can.c\1300</Expression> <Expression>\\bootloader\../Core/Bootloader/Src/bootloader.c\368</Expression>
</Bp> </Bp>
</Breakpoint> </Breakpoint>
<WatchWindow1> <WatchWindow1>
<Ww> <Ww>
<count>0</count> <count>0</count>
<WinNumber>1</WinNumber> <WinNumber>1</WinNumber>
<ItemText>boot,0x10</ItemText> <ItemText>boot</ItemText>
</Ww>
<Ww>
<count>1</count>
<WinNumber>1</WinNumber>
<ItemText>Inputs</ItemText>
</Ww>
<Ww>
<count>2</count>
<WinNumber>1</WinNumber>
<ItemText>duty_cycle,0x0A</ItemText>
</Ww>
<Ww>
<count>3</count>
<WinNumber>1</WinNumber>
<ItemText>frequency,0x0A</ItemText>
</Ww>
<Ww>
<count>4</count>
<WinNumber>1</WinNumber>
<ItemText>uwTick,0x0A</ItemText>
</Ww>
<Ww>
<count>5</count>
<WinNumber>1</WinNumber>
<ItemText>GoToApp</ItemText>
</Ww>
<Ww>
<count>6</count>
<WinNumber>1</WinNumber>
<ItemText>app_jump_adr</ItemText>
</Ww>
<Ww>
<count>7</count>
<WinNumber>1</WinNumber>
<ItemText>TXDataBoot</ItemText>
</Ww>
<Ww>
<count>8</count>
<WinNumber>1</WinNumber>
<ItemText>\\bootloader\../Core/Bootloader/boot_main.c\boot.error.bit.unknown_cmd</ItemText>
</Ww>
<Ww>
<count>9</count>
<WinNumber>1</WinNumber>
<ItemText>\\bootloader\../Core/Bootloader/boot_main.c\boot.error.bit.write_err</ItemText>
</Ww> </Ww>
</WatchWindow1> </WatchWindow1>
<MemoryWindow1> <MemoryWindow1>
@ -537,15 +386,9 @@
<pszMrulep></pszMrulep> <pszMrulep></pszMrulep>
<pSingCmdsp></pSingCmdsp> <pSingCmdsp></pSingCmdsp>
<pMultCmdsp></pMultCmdsp> <pMultCmdsp></pMultCmdsp>
<SystemViewers>
<Entry>
<Name>System Viewer\GPIOB</Name>
<WinId>35905</WinId>
</Entry>
</SystemViewers>
<DebugDescription> <DebugDescription>
<Enable>1</Enable> <Enable>1</Enable>
<EnableFlashSeq>0</EnableFlashSeq> <EnableFlashSeq>1</EnableFlashSeq>
<EnableLog>0</EnableLog> <EnableLog>0</EnableLog>
<Protocol>2</Protocol> <Protocol>2</Protocol>
<DbgClock>10000000</DbgClock> <DbgClock>10000000</DbgClock>
@ -555,7 +398,7 @@
<Group> <Group>
<GroupName>Application/MDK-ARM</GroupName> <GroupName>Application/MDK-ARM</GroupName>
<tvExp>1</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel> <cbSel>0</cbSel>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
@ -575,7 +418,7 @@
<Group> <Group>
<GroupName>Application/User/Core</GroupName> <GroupName>Application/User/Core</GroupName>
<tvExp>1</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel> <cbSel>0</cbSel>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
@ -982,8 +825,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>..\Core\Bootloader\Src\bootloader.c</PathWithFileName> <PathWithFileName>..\Core\Bootloader\Src\boot_main.c</PathWithFileName>
<FilenameWithoutPath>bootloader.c</FilenameWithoutPath> <FilenameWithoutPath>boot_main.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@ -994,8 +837,8 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>..\Core\Bootloader\Src\boot_main.c</PathWithFileName> <PathWithFileName>..\Core\Bootloader\Src\bootloader.c</PathWithFileName>
<FilenameWithoutPath>boot_main.c</FilenameWithoutPath> <FilenameWithoutPath>bootloader.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
@ -1006,6 +849,18 @@
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2> <bDave2>0</bDave2>
<PathWithFileName>..\Core\Bootloader\Src\boot_uart.c</PathWithFileName>
<FilenameWithoutPath>boot_uart.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>36</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Core\Bootloader\Src\boot_can.c</PathWithFileName> <PathWithFileName>..\Core\Bootloader\Src\boot_can.c</PathWithFileName>
<FilenameWithoutPath>boot_can.c</FilenameWithoutPath> <FilenameWithoutPath>boot_can.c</FilenameWithoutPath>
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
@ -1013,7 +868,7 @@
</File> </File>
<File> <File>
<GroupNumber>5</GroupNumber> <GroupNumber>5</GroupNumber>
<FileNumber>36</FileNumber> <FileNumber>37</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -1025,7 +880,7 @@
</File> </File>
<File> <File>
<GroupNumber>5</GroupNumber> <GroupNumber>5</GroupNumber>
<FileNumber>37</FileNumber> <FileNumber>38</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -1037,7 +892,7 @@
</File> </File>
<File> <File>
<GroupNumber>5</GroupNumber> <GroupNumber>5</GroupNumber>
<FileNumber>38</FileNumber> <FileNumber>39</FileNumber>
<FileType>1</FileType> <FileType>1</FileType>
<tvExp>0</tvExp> <tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg> <tvExpOptDlg>0</tvExpOptDlg>
@ -1047,18 +902,6 @@
<RteFlg>0</RteFlg> <RteFlg>0</RteFlg>
<bShared>0</bShared> <bShared>0</bShared>
</File> </File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>39</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\Core\Bootloader\Src\boot_uart.c</PathWithFileName>
<FilenameWithoutPath>boot_uart.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
</Group> </Group>
<Group> <Group>

View File

@ -667,11 +667,6 @@
<FileType>5</FileType> <FileType>5</FileType>
<FilePath>..\Core\Bootloader\Inc\boot_project_setup.h</FilePath> <FilePath>..\Core\Bootloader\Inc\boot_project_setup.h</FilePath>
</File> </File>
<File>
<FileName>bootloader.c</FileName>
<FileType>1</FileType>
<FilePath>..\Core\Bootloader\Src\bootloader.c</FilePath>
</File>
<File> <File>
<FileName>boot_main.c</FileName> <FileName>boot_main.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
@ -728,6 +723,16 @@
</FileArmAds> </FileArmAds>
</FileOption> </FileOption>
</File> </File>
<File>
<FileName>bootloader.c</FileName>
<FileType>1</FileType>
<FilePath>..\Core\Bootloader\Src\bootloader.c</FilePath>
</File>
<File>
<FileName>boot_uart.c</FileName>
<FileType>1</FileType>
<FilePath>..\Core\Bootloader\Src\boot_uart.c</FilePath>
</File>
<File> <File>
<FileName>boot_can.c</FileName> <FileName>boot_can.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
@ -799,11 +804,6 @@
</FileArmAds> </FileArmAds>
</FileOption> </FileOption>
</File> </File>
<File>
<FileName>boot_uart.c</FileName>
<FileType>1</FileType>
<FilePath>..\Core\Bootloader\Src\boot_uart.c</FilePath>
</File>
</Files> </Files>
</Group> </Group>
<Group> <Group>
@ -854,13 +854,13 @@
<NotGenerated>0</NotGenerated> <NotGenerated>0</NotGenerated>
<InvalidFlash>1</InvalidFlash> <InvalidFlash>1</InvalidFlash>
</TargetStatus> </TargetStatus>
<OutputDirectory>.\</OutputDirectory> <OutputDirectory>.\bootloader\</OutputDirectory>
<OutputName>bootloader</OutputName> <OutputName>bootloader</OutputName>
<CreateExecutable>1</CreateExecutable> <CreateExecutable>1</CreateExecutable>
<CreateLib>0</CreateLib> <CreateLib>0</CreateLib>
<CreateHexFile>1</CreateHexFile> <CreateHexFile>1</CreateHexFile>
<DebugInformation>1</DebugInformation> <DebugInformation>1</DebugInformation>
<BrowseInformation>1</BrowseInformation> <BrowseInformation>0</BrowseInformation>
<ListingPath></ListingPath> <ListingPath></ListingPath>
<HexFormatSelection>1</HexFormatSelection> <HexFormatSelection>1</HexFormatSelection>
<Merge32K>0</Merge32K> <Merge32K>0</Merge32K>
@ -1490,15 +1490,20 @@
<FileType>5</FileType> <FileType>5</FileType>
<FilePath>..\Core\Bootloader\Inc\boot_project_setup.h</FilePath> <FilePath>..\Core\Bootloader\Inc\boot_project_setup.h</FilePath>
</File> </File>
<File>
<FileName>boot_main.c</FileName>
<FileType>1</FileType>
<FilePath>..\Core\Bootloader\Src\boot_main.c</FilePath>
</File>
<File> <File>
<FileName>bootloader.c</FileName> <FileName>bootloader.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>..\Core\Bootloader\Src\bootloader.c</FilePath> <FilePath>..\Core\Bootloader\Src\bootloader.c</FilePath>
</File> </File>
<File> <File>
<FileName>boot_main.c</FileName> <FileName>boot_uart.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>..\Core\Bootloader\Src\boot_main.c</FilePath> <FilePath>..\Core\Bootloader\Src\boot_uart.c</FilePath>
</File> </File>
<File> <File>
<FileName>boot_can.c</FileName> <FileName>boot_can.c</FileName>
@ -1520,11 +1525,6 @@
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>..\Core\Bootloader\Src\boot_jump.c</FilePath> <FilePath>..\Core\Bootloader\Src\boot_jump.c</FilePath>
</File> </File>
<File>
<FileName>boot_uart.c</FileName>
<FileType>1</FileType>
<FilePath>..\Core\Bootloader\Src\boot_uart.c</FilePath>
</File>
</Files> </Files>
</Group> </Group>
<Group> <Group>

95
README.md Normal file
View File

@ -0,0 +1,95 @@
# STM32 Bootloader (Beta)
## Описание
Этот бутлоадер для STM32 реализован как **машина состояний (state machine)**.
Его задача — управлять обновлением прошивки по UART или CAN, а также обеспечивать безопасный переход между приложением и бутлоадером.
---
## Общение с бутлоадером
В [гите](https://git.arktika.cyou/Razvalyaev/boot_terminal) есть терминалка на C# для общения с бутом через SlCan (uart там не сделан).
А вообще реализованы следующие команды
- `0x01` — стирание прошивки во Flash — (`CMD_ERASE`)
- `0x02` — запуск процедуры приёма страницы — (`CMD_START_RECEIVE`)
- `0x03` — запись блока прошивки — (`CMD_WRITE`)
- `0x04` — переход в приложение — (`CMD_GOTOAPP`)
- `0x05`сброс микроконтроллера — (`CMD_RESET`)
- `0x06` — принудительный переход в бутлоадер — (`CMD_GOTOBOOT`)
- `0xAA` — проверка связи (ping) — (`CMD_PING`)
Бутлоадер уже содержит каркас для работы как с **CAN** (и некоторые наработки для **UART**, но не проверенные).
Для расширения функционала и поддержки новых протоколов нужно доопределить следующие функции.
- Приём команды:
```c
BootloaderCommand_t Bootloader_UART_Receive(Bootloader_t *bl); //boot_uart.c
BootloaderCommand_t Bootloader_CAN_Receive(Bootloader_t *bl); //boot_can.c
```
- Читает 1 байт команды и возвращает её (`CMD_ERASE`, `CMD_WRITE`, и т.п.) или, если нет команды, `NO_CMD`.
- Приём страницы прошивки:
```c
void Bootloader_UART_Receive_Page(Bootloader_t *bl); //boot_uart.c
void Bootloader_CAN_Receive_Page(Bootloader_t *bl); //boot_can.c
```
- Принимает блок данных длиной `PAGE_SIZE` байт.
- Принимает CRC32 (4 байта).
- Заполняет поля `bl->fw_buffer`, `bl->fw_len`, `bl->fw_crc`.
---
## Как работает бутлоадер
1. После сброса бутлоадер проверяет сохранённые ошибки и "ключ" прошивки.
- Если приложение корректное — выполняется переход в него.
- Если приложение повреждено или нет ключа — остаётся в бутлоадере.
2. В состоянии `IDLE` бутлоадер слушает команды.
3. Прошивка отправляется страницами, каждая страница проверяется по CRC32.
4. По завершению записи устанавливается "ключ приложения", и возможен переход в основное приложение.
5. При ошибках — возврат в состояние `ERROR`, уведомление хоста и мигание LED. Для сброса ошибок надо перезапустить МК.
---
## Основные особенности бута
- Реализован как конечный автомат со следующими состояниями:
- `INIT` — проверка ключа, и далее переход в приложение или инициализация бута
- `IDLE` — ожидание команды
- `RECEIVE_UART` / `RECEIVE_CAN` — приём страницы прошивки
- `WRITE` — запись принятой страницы во Flash
- `ERASE` — стирание приложения
- `JUMP_TO_APP` — переход к основному приложению
- `JUMP_TO_BOOT` — возврат в бутлоадер
- `RESET` — программный сброс
- `ERROR` — обработка ошибок
- Проверка целостности прошивки с помощью **CRC32**
- Учёт ошибок (hardfault, memmanage, watchdog и т.п.)
- Индикация состояния через LED:
- мигает раз в 500 мс при ошибке
- включается при приеме комады и выключается, когда команда выполнена
---
## Интеграция в проект
Здесь бутлоадер и основное приложение реализованы как отдельные таргеты:
- **Таргет приложения**
Исключает `main()` бутлоадера и компилирует только само приложение.
Адрес загрузки приложения: `0x0800C000`.
- **Таргет бутлоадера**
Исключает код приложения и компилирует только бутлоадер.
Адрес загрузки бутлоадера: `0x08000000`.
Чтобы в основном приложении можно было управлять бутлоадером:
1. Подключить `boot_jump.h` и `boot_jump.c` для взаимодействия с бутлоадером:
```c
#include "boot_jump.h"
```
2. В начале `main()` вызвать `App_Init()`, чтобы установить VTOR на
начало приложения:
```c
App_Init();
```
3. Для перехода в бутлоадер (например, при ошибке или обновлении):
```c
JumpToBootloader();
```