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

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

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

View File

@@ -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;
}

View File

@@ -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)
{

View File

@@ -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;