uart для платы вэп + структурирован чуть проект и описан бутлоадер
Но надо еще его дорабатывать + заготовка для протокола приема (не работает скорее всего, просто из чатгпт вставил)
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user