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