From c61c438b8c2d93b9c45f1e22a422cf9dbc2435af Mon Sep 17 00:00:00 2001 From: Razvalyaev Date: Fri, 19 Sep 2025 13:32:45 +0300 Subject: [PATCH] =?UTF-8?q?uart=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BB=D0=B0?= =?UTF-8?q?=D1=82=D1=8B=20=D0=B2=D1=8D=D0=BF=20+=20=D1=81=D1=82=D1=80?= =?UTF-8?q?=D1=83=D0=BA=D1=82=D1=83=D1=80=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=20=D1=87=D1=83=D1=82=D1=8C=20=D0=BF=D1=80=D0=BE=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=20=D0=B8=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=20?= =?UTF-8?q?=D0=B1=D1=83=D1=82=D0=BB=D0=BE=D0=B0=D0=B4=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Но надо еще его дорабатывать + заготовка для протокола приема (не работает скорее всего, просто из чатгпт вставил) --- Core/Bootloader/Inc/boot_can.h | 9 + Core/Bootloader/Inc/boot_project_setup.h | 11 +- Core/Bootloader/Inc/boot_uart.h | 4 + Core/Bootloader/Inc/bootloader.h | 7 +- Core/Bootloader/Src/boot_can.c | 134 +++++++------ Core/Bootloader/Src/boot_uart.c | 95 +++++++++- Core/Bootloader/Src/bootloader.c | 26 +-- MDK-ARM/{ => bootloader}/bootloader.sct | 0 MDK-ARM/bootloader/uksvep_2_2_v1.sct | 16 ++ MDK-ARM/uksvep_2_2_v1.uvoptx | 227 ++++------------------- MDK-ARM/uksvep_2_2_v1.uvprojx | 38 ++-- README.md | 95 ++++++++++ 12 files changed, 372 insertions(+), 290 deletions(-) rename MDK-ARM/{ => bootloader}/bootloader.sct (100%) create mode 100644 MDK-ARM/bootloader/uksvep_2_2_v1.sct create mode 100644 README.md diff --git a/Core/Bootloader/Inc/boot_can.h b/Core/Bootloader/Inc/boot_can.h index 511a873..b648dae 100644 --- a/Core/Bootloader/Inc/boot_can.h +++ b/Core/Bootloader/Inc/boot_can.h @@ -5,7 +5,16 @@ 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); +/* Приём команды по CAN по протоколу */ +BootloaderCommand_t Bootloader_CAN_Receive(Bootloader_t *bl); +/* Приём CAN: страница + CRC */ void Bootloader_CAN_Receive_Page(Bootloader_t *bl); #endif //__BOOT_CAN_H \ No newline at end of file diff --git a/Core/Bootloader/Inc/boot_project_setup.h b/Core/Bootloader/Inc/boot_project_setup.h index 2a60280..fa32d5d 100644 --- a/Core/Bootloader/Inc/boot_project_setup.h +++ b/Core/Bootloader/Inc/boot_project_setup.h @@ -32,20 +32,19 @@ // Макросы для включения тактирования периферии бутлоадера #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_UART_BOOT_CLK_ENABLE() __HAL_RCC_UART4_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_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 +#define UART_BOOT UART4 +#define UART_SPEED 115200 // Порт и пины UART -#define UART_PORT GPIOB +#define UART_PORT GPIOC #define UART_PIN_TX GPIO_PIN_10 #define UART_PIN_RX GPIO_PIN_11 diff --git a/Core/Bootloader/Inc/boot_uart.h b/Core/Bootloader/Inc/boot_uart.h index ef79f41..b5eb3e0 100644 --- a/Core/Bootloader/Inc/boot_uart.h +++ b/Core/Bootloader/Inc/boot_uart.h @@ -5,7 +5,11 @@ extern UART_HandleTypeDef huart_boot; +/* Инициализация UART */ 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); #endif //__BOOT_UART_H \ No newline at end of file diff --git a/Core/Bootloader/Inc/bootloader.h b/Core/Bootloader/Inc/bootloader.h index a73d04b..2e22637 100644 --- a/Core/Bootloader/Inc/bootloader.h +++ b/Core/Bootloader/Inc/bootloader.h @@ -71,12 +71,14 @@ * @brief Команды для управления бутлоадером */ typedef enum { + NO_CMD = 0x00, ///< Нет комманды CMD_ERASE = 0x01, ///< Команда на стирание прошивки CMD_START_RECEIVE, ///< Команда на старт приема прошивки CMD_WRITE, ///< Команда на запись блока прошивки CMD_GOTOAPP, ///< Команда на переход в приложение CMD_RESET, ///< Команда на переход в приложение CMD_GOTOBOOT, ///< Команда на переход в приложение + CMD_PING = 0xAA, ///< Команда на пинг }BootloaderCommand_t; /** @@ -108,6 +110,7 @@ typedef union { unsigned erase_err:1; ///< Ошибка стирания unsigned write_err:1; ///< Ошибка записи unsigned verify_err:1; ///< Ошибка проверки прошивки + unsigned overflow:1; ///< Слишком много данных unsigned timeout_receive:1; ///< Таймаут приёма unsigned crc_err:1; ///< Ошибка CRC } bit; @@ -119,7 +122,7 @@ typedef union { */ typedef struct { BootloaderState_t state; ///< текущее состояние бутлоадера - BootloaderError_t error; + BootloaderError_t error; ///< ошибки бутлоадера uint32_t addr; ///< текущий адрес прошивки @@ -141,5 +144,7 @@ void Bootloader_Task(Bootloader_t *bl); void Boot_SystemClock_Config(void); /* Хендлер ошибки */ void Error_Handler(void); +/* CRC */ +uint32_t CRC32_Compute(const uint8_t* data, uint32_t length); #endif //__BOOTLOADER_H \ No newline at end of file diff --git a/Core/Bootloader/Src/boot_can.c b/Core/Bootloader/Src/boot_can.c index c033edb..67a9de3 100644 --- a/Core/Bootloader/Src/boot_can.c +++ b/Core/Bootloader/Src/boot_can.c @@ -3,6 +3,12 @@ CAN_HandleTypeDef hcan_boot; +CAN_TxHeaderTypeDef TxHeaderBoot; +CAN_RxHeaderTypeDef RxHeaderBoot; +uint32_t TxMailBoxBoot = 0; +uint8_t TXDataBoot[8] = {0}; + + /** * @brief Инициализация CAN для бутлоадера */ @@ -68,69 +74,89 @@ 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 + * @param bl: указатель на структуру бутлоадера */ void Bootloader_CAN_Receive_Page(Bootloader_t *bl) { - uint16_t bytes_received = 0; - CAN_RxHeaderTypeDef canHeader; - uint8_t canData[8]; - uint32_t start_tick = HAL_GetTick(); + uint16_t bytes_received = 0; + CAN_RxHeaderTypeDef canHeader; + uint8_t canData[8]; + uint32_t start_tick = HAL_GetTick(); - // Приём страницы прошивки - while(bytes_received < PAGE_SIZE) - { - if(HAL_CAN_GetRxFifoFillLevel(bl->hcan, CAN_RX_FIFO0) > 0) - { - if(HAL_CAN_GetRxMessage(bl->hcan, CAN_RX_FIFO0, &canHeader, canData) == HAL_OK) - { - uint8_t len = canHeader.DLC; - if(bytes_received + len > PAGE_SIZE) - len = PAGE_SIZE - bytes_received; + // Приём страницы прошивки + while(bytes_received < PAGE_SIZE) + { + if(HAL_CAN_GetRxFifoFillLevel(bl->hcan, CAN_RX_FIFO0) > 0) + { + if(HAL_CAN_GetRxMessage(bl->hcan, CAN_RX_FIFO0, &canHeader, canData) == HAL_OK) + { + uint8_t len = canHeader.DLC; + if(bytes_received + len > PAGE_SIZE) + len = PAGE_SIZE - bytes_received; - memcpy(&bl->fw_buffer[bytes_received], canData, len); - bytes_received += len; - start_tick = HAL_GetTick(); // сброс таймаута - LED_BOOT_TOOGLE(); - } - } + memcpy(&bl->fw_buffer[bytes_received], canData, len); + bytes_received += len; + start_tick = HAL_GetTick(); // сброс таймаута + LED_BOOT_TOOGLE(); + } + } - // проверка таймаута - if(HAL_GetTick() - start_tick >= FW_RECEIVE_TIMEOUT_MS) - { - bl->error.bit.timeout_receive = 1; - bl->state = BL_STATE_ERROR; - return; - } - } - // Приём CRC (4 байта) - start_tick = HAL_GetTick(); // сброс таймаута - while(1) - { - if(HAL_CAN_GetRxFifoFillLevel(bl->hcan, CAN_RX_FIFO0) > 0) - { - if(HAL_CAN_GetRxMessage(bl->hcan, CAN_RX_FIFO0, &canHeader, canData) == HAL_OK) - { - // CRC в первых 4 байтах пакета - bl->fw_crc = (canData[0] << 24) | - (canData[1] << 16) | - (canData[2] << 8) | - canData[3]; - break; - } - } + // проверка таймаута + if(HAL_GetTick() - start_tick >= FW_RECEIVE_TIMEOUT_MS) + { + bl->error.bit.timeout_receive = 1; + bl->state = BL_STATE_ERROR; + return; + } + } + // Приём CRC (4 байта) + start_tick = HAL_GetTick(); // сброс таймаута + while(1) + { + if(HAL_CAN_GetRxFifoFillLevel(bl->hcan, CAN_RX_FIFO0) > 0) + { + if(HAL_CAN_GetRxMessage(bl->hcan, CAN_RX_FIFO0, &canHeader, canData) == HAL_OK) + { + // CRC в первых 4 байтах пакета + bl->fw_crc = (canData[0] << 24) | + (canData[1] << 16) | + (canData[2] << 8) | + canData[3]; + break; + } + } - // Таймаут - if(HAL_GetTick() - start_tick >= FW_RECEIVE_TIMEOUT_MS) - { - bl->error.bit.timeout_receive = 1; - bl->state = BL_STATE_ERROR; - return; - } - } + // Таймаут + if(HAL_GetTick() - start_tick >= FW_RECEIVE_TIMEOUT_MS) + { + bl->error.bit.timeout_receive = 1; + bl->state = BL_STATE_ERROR; + return; + } + } - bl->fw_len = PAGE_SIZE; - bl->state = BL_STATE_IDLE; + bl->fw_len = PAGE_SIZE; + bl->state = BL_STATE_IDLE; } diff --git a/Core/Bootloader/Src/boot_uart.c b/Core/Bootloader/Src/boot_uart.c index f4ef541..cd15643 100644 --- a/Core/Bootloader/Src/boot_uart.c +++ b/Core/Bootloader/Src/boot_uart.c @@ -15,12 +15,16 @@ void MX_BOOT_UART_Init(void) __RCC_UART_PORT_CLK_ENABLE(); /* Настройка 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.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; 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 */ huart_boot.Instance = UART_BOOT; 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 + * @param bl: указатель на структуру бутлоадера */ void Bootloader_UART_Receive_Page(Bootloader_t *bl) { diff --git a/Core/Bootloader/Src/bootloader.c b/Core/Bootloader/Src/bootloader.c index 53120bb..8a1e224 100644 --- a/Core/Bootloader/Src/bootloader.c +++ b/Core/Bootloader/Src/bootloader.c @@ -40,17 +40,12 @@ // Глобальные переменные для 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; // ----------------------------------------------------------------------------- // Локальные (static) функции // ----------------------------------------------------------------------------- static uint8_t Receive_FW_Command(Bootloader_t *bl); -static uint32_t CRC32_Compute(const uint8_t* data, uint32_t length); /** * @brief Проверка после сброса MCU. @@ -72,7 +67,8 @@ void Bootloader_StartCheck(Bootloader_t *bl) // Чтение сохранённого кода ошибки и количества сбоев ErrCodeBoot = GetErrorCode(); ErrCntBoot = GetErrorCnt(); - // Если ошибок было больше 5, фиксируем тип ошибки + // Если ошибок было больше 5, фиксируем тип ошибки и уходим в бутлоадер + // Данные ошибки фиксируются только в прерываниях бутлоадера. Hardfault в прерывании приложения не считается if(ErrCntBoot > 5) { ClearErrorCode(); @@ -385,6 +381,8 @@ static uint8_t SetBootState(Bootloader_t *bl, BootloaderCommand_t cmd, uint8_t u return 0x00; case CMD_GOTOBOOT: // команда: прыжок в бутлоадер bl->state = BL_STATE_JUMP_TO_BOOT; + case CMD_PING: // команда: пинг, отправка текущего состояния бутлоадера + bl->prev_state = 0; // обнуляем предыдущее состоояние, чтобы снова отправить комманду с текущим состоянием return 0x00; default: @@ -406,8 +404,8 @@ static uint8_t Receive_FW_Command(Bootloader_t *bl) // --------------------------- // Чтение команды по UART // --------------------------- - res = HAL_UART_Receive(bl->huart, &cmd, 1, 10); // таймаут 10 ms - if (res == HAL_OK) + cmd = Bootloader_UART_Receive(bl); // таймаут 10 ms + if (cmd != NO_CMD) { ret_val = SetBootState(bl, cmd, 1); } @@ -415,14 +413,10 @@ static uint8_t Receive_FW_Command(Bootloader_t *bl) // --------------------------- // Чтение команды по CAN // --------------------------- - uint8_t canData[8]; - if (HAL_CAN_GetRxFifoFillLevel(bl->hcan, CAN_RX_FIFO0) > 0) + cmd = Bootloader_CAN_Receive(bl); + 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 @@ -451,7 +445,7 @@ static uint8_t Receive_FW_Command(Bootloader_t *bl) * @param length: длина массива в байтах * @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; uint32_t crc = 0xFFFFFFFF; diff --git a/MDK-ARM/bootloader.sct b/MDK-ARM/bootloader/bootloader.sct similarity index 100% rename from MDK-ARM/bootloader.sct rename to MDK-ARM/bootloader/bootloader.sct diff --git a/MDK-ARM/bootloader/uksvep_2_2_v1.sct b/MDK-ARM/bootloader/uksvep_2_2_v1.sct new file mode 100644 index 0000000..9397989 --- /dev/null +++ b/MDK-ARM/bootloader/uksvep_2_2_v1.sct @@ -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) + } +} + diff --git a/MDK-ARM/uksvep_2_2_v1.uvoptx b/MDK-ARM/uksvep_2_2_v1.uvoptx index 02f32d1..bfe1fad 100644 --- a/MDK-ARM/uksvep_2_2_v1.uvoptx +++ b/MDK-ARM/uksvep_2_2_v1.uvoptx @@ -28,7 +28,7 @@ 8000000 - 1 + 0 1 0 1 @@ -103,7 +103,7 @@ 1 0 0 - 4 + 0 @@ -114,34 +114,9 @@ - Segger\JL2CM3.dll + BIN\UL2CM3.DLL - - 0 - ARMRTXEVENTFLAGS - -L70 -Z18 -C0 -M0 -T1 - - - 0 - DLGTARM - (1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0) - - - 0 - ARMDBGFLAGS - - - - 0 - DLGUARM - - - - 0 - JL2CM3 - -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) - 0 UL2CM3 @@ -149,81 +124,18 @@ - - - 0 - 1 - input - - - 1 - 1 - Inputs - - - 2 - 1 - duty_cycle,0x0A - - - 3 - 1 - frequency,0x0A - - - 4 - 1 - uwTick,0x0A - - - 5 - 1 - modbus - - - 6 - 1 - msgData[0] - - - 7 - 1 - CMD_GOTOBOOT - - - 8 - 1 - hcan - - - - - 1 - 0 - 0x0800c000 - 0 - - - - - 2 - 0 - 0x08009800 - 0 - - 0 0 - 1 - 1 + 0 + 0 0 0 0 0 - 1 + 0 0 0 0 @@ -254,27 +166,9 @@ - - - System Viewer\BKP - 35902 - - - System Viewer\CAN - 35904 - - - System Viewer\GPIOB - 35905 - - - System Viewer\IWDG - 35903 - - 1 - 0 + 1 0 2 10000000 @@ -386,7 +280,7 @@ 0 DLGTARM - (1010=-1605,104,-1155,661,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0) + (1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0) 0 @@ -413,70 +307,25 @@ 0 0 - 1300 + 368 1 -
134222082
+
134230816
0 0 0 0 0 1 - ../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_can.c + ..\Core\Bootloader\Src\bootloader.c - \\bootloader\../Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_can.c\1300 + \\bootloader\../Core/Bootloader/Src/bootloader.c\368
0 1 - boot,0x10 - - - 1 - 1 - Inputs - - - 2 - 1 - duty_cycle,0x0A - - - 3 - 1 - frequency,0x0A - - - 4 - 1 - uwTick,0x0A - - - 5 - 1 - GoToApp - - - 6 - 1 - app_jump_adr - - - 7 - 1 - TXDataBoot - - - 8 - 1 - \\bootloader\../Core/Bootloader/boot_main.c\boot.error.bit.unknown_cmd - - - 9 - 1 - \\bootloader\../Core/Bootloader/boot_main.c\boot.error.bit.write_err + boot @@ -537,15 +386,9 @@ - - - System Viewer\GPIOB - 35905 - - 1 - 0 + 1 0 2 10000000 @@ -555,7 +398,7 @@ Application/MDK-ARM - 1 + 0 0 0 0 @@ -575,7 +418,7 @@ Application/User/Core - 1 + 0 0 0 0 @@ -982,8 +825,8 @@ 0 0 0 - ..\Core\Bootloader\Src\bootloader.c - bootloader.c + ..\Core\Bootloader\Src\boot_main.c + boot_main.c 0 0 @@ -994,8 +837,8 @@ 0 0 0 - ..\Core\Bootloader\Src\boot_main.c - boot_main.c + ..\Core\Bootloader\Src\bootloader.c + bootloader.c 0 0 @@ -1006,6 +849,18 @@ 0 0 0 + ..\Core\Bootloader\Src\boot_uart.c + boot_uart.c + 0 + 0 + + + 5 + 36 + 1 + 0 + 0 + 0 ..\Core\Bootloader\Src\boot_can.c boot_can.c 0 @@ -1013,7 +868,7 @@ 5 - 36 + 37 1 0 0 @@ -1025,7 +880,7 @@ 5 - 37 + 38 1 0 0 @@ -1037,7 +892,7 @@ 5 - 38 + 39 1 0 0 @@ -1047,18 +902,6 @@ 0 0 - - 5 - 39 - 1 - 0 - 0 - 0 - ..\Core\Bootloader\Src\boot_uart.c - boot_uart.c - 0 - 0 - diff --git a/MDK-ARM/uksvep_2_2_v1.uvprojx b/MDK-ARM/uksvep_2_2_v1.uvprojx index 72631d0..43c4925 100644 --- a/MDK-ARM/uksvep_2_2_v1.uvprojx +++ b/MDK-ARM/uksvep_2_2_v1.uvprojx @@ -667,11 +667,6 @@ 5 ..\Core\Bootloader\Inc\boot_project_setup.h - - bootloader.c - 1 - ..\Core\Bootloader\Src\bootloader.c - boot_main.c 1 @@ -728,6 +723,16 @@ + + bootloader.c + 1 + ..\Core\Bootloader\Src\bootloader.c + + + boot_uart.c + 1 + ..\Core\Bootloader\Src\boot_uart.c + boot_can.c 1 @@ -799,11 +804,6 @@ - - boot_uart.c - 1 - ..\Core\Bootloader\Src\boot_uart.c - @@ -854,13 +854,13 @@ 0 1 - .\ + .\bootloader\ bootloader 1 0 1 1 - 1 + 0 1 0 @@ -1490,15 +1490,20 @@ 5 ..\Core\Bootloader\Inc\boot_project_setup.h + + boot_main.c + 1 + ..\Core\Bootloader\Src\boot_main.c + bootloader.c 1 ..\Core\Bootloader\Src\bootloader.c - boot_main.c + boot_uart.c 1 - ..\Core\Bootloader\Src\boot_main.c + ..\Core\Bootloader\Src\boot_uart.c boot_can.c @@ -1520,11 +1525,6 @@ 1 ..\Core\Bootloader\Src\boot_jump.c - - boot_uart.c - 1 - ..\Core\Bootloader\Src\boot_uart.c - diff --git a/README.md b/README.md new file mode 100644 index 0000000..5432f0e --- /dev/null +++ b/README.md @@ -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(); +```