servo/controller/fw/embed/bootloader/main.cpp
2025-03-21 14:00:00 +03:00

180 lines
5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <Arduino.h>
#include <STM32_CAN.h>
#include "flash.h"
STM32_CAN Can(CAN2, DEF);
volatile bool fw_update = false;
volatile uint32_t fw_size = 0;
volatile uint32_t fw_crc = 0;
volatile uint32_t jump;
static FLASH_RECORD flash_record = {0};
static uint32_t ptr_flash;
// Прототипы функций
void jump_to_app();
void process_can_message(const CAN_message_t &msg);
void erase_flash_pages();
bool verify_firmware();
void send_ack(uint8_t status);
void setup() {
// Инициализация периферии
Serial.setRx(HARDWARE_SERIAL_RX_PIN);
Serial.setTx(HARDWARE_SERIAL_TX_PIN);
Serial.begin(115200);
Can.begin();
Can.setBaudRate(1000000);
TIM_TypeDef *Instance = TIM2;
HardwareTimer *SendTimer = new HardwareTimer(Instance);
SendTimer->setOverflow(100, HERTZ_FORMAT); // 50 Hz
// SendTimer->attachInterrupt(process_can_message);
SendTimer->resume();
// Разрешить все ID (маска 0x00000000)
Can.setFilter(0, 0, STD);
// Настройка GPIO
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
GPIOC->MODER |= GPIO_MODER_MODE10_0 | GPIO_MODER_MODE11_0;
GPIOC->ODR |= GPIO_ODR_OD11;
// Проверка флага обновления
// erase_sector(6);
// flash_program_word(FLAG_BOOT,0xDEADBEEF,0);
// flash_record.data_id = addr_id;
// flash_record.crc = 0x6933;
// flash_record.value = 0x69;
// flash_record.write_ptr_now = SECTOR_6;
// flash_write(SECTOR_6, &flash_record);
flash_record = load_params();
/* Добавить проверку адреса, т.е во время отправки запроса прошивки по CAN
мы сохраняем как флаг, так и аддрес устройства к которому будет обращатлься во
время прошивки */
if(*(volatile uint32_t*)(FLAG_BOOT) == UPDATE_FLAG) {
fw_update = true;
GPIOC->ODR |= GPIO_ODR_OD10; // Индикация обновления
erase_flash_pages();
} else {
jump_to_app();
}
}
void loop() {
if(fw_update) {
GPIOC->ODR ^= GPIO_ODR_OD10;
// HAL_Delay(100);
CAN_message_t msg;
while(Can.read(msg))
process_can_message(msg);
}
}
void process_can_message(const CAN_message_t &msg) {
switch(msg.id) {
case BOOT_CAN_ID:
if(msg.buf[0] == 0x01) { // Старт передачи
fw_size = *(uint32_t*)&msg.buf[1]; //размер прошивки тип 4 байта
fw_crc = *(uint16_t*)&msg.buf[5]; //crc
ptr_flash = APP_ADDRESS;
send_ack(0x01);
}
break;
case DATA_CAN_ID: // Пакет данных
if(ptr_flash < (APP_ADDRESS + fw_size)) {
write_flash_page((const uint8_t*)msg.buf, msg.len);
ptr_flash += msg.len;
send_ack(0x02);
}
break;
case BOOT_CAN_END: // Завершение передачи
if(verify_firmware()) {
erase_sector(7); // Сброс флага
send_ack(0xAA);
NVIC_SystemReset();
} else {
send_ack(0x55);
}
break;
}
}
void jump_to_app() {
__disable_irq();
jump = *(volatile uint32_t*)(APP_ADDRESS + 4);
void (*app_entry)(void);
app_entry = (void (*)(void))jump;
for (uint32_t i = 0; i < 3; i++) {
NVIC->ICPR[i] = 0xFFFFFFFF;
}
__set_MSP(*(volatile uint32_t*)APP_ADDRESS);
SCB->VTOR = APP_ADDRESS;
app_entry();
}
void erase_flash_pages() {
FLASH_EraseInitTypeDef erase;
erase.TypeErase = FLASH_TYPEERASE_SECTORS;
erase.Sector = FLASH_SECTOR_2;
erase.NbSectors = 4;
erase.VoltageRange = FLASH_VOLTAGE_RANGE_3;
uint32_t error;
flash_unlock();
HAL_FLASHEx_Erase(&erase, &error);
flash_lock();
}
uint16_t CalculateCRC16(const uint8_t* data, uint32_t length) {
uint16_t crc = 0xFFFF; // Начальное значение
while (length--) {
crc ^= *data++; // Обрабатываем LSB первым
for (uint8_t i = 0; i < 8; i++) {
if (crc & 0x0001) { // Проверяем младший бит
crc = (crc >> 1) ^ 0xA001; // Полином 0x8005 (reverse)
} else {
crc >>= 1;
}
}
}
return crc; // Финальный XOR = 0x0000 (не требуется)
}
bool verify_firmware() {
uint32_t calculated_crc = 0;
calculated_crc = CalculateCRC16((uint8_t*)APP_ADDRESS,fw_size);
if(calculated_crc != (uint16_t)fw_crc)
return false;
// Реализация проверки CRC
// ...
// return (calculated_crc == fw_crc);
else
return true;
}
void send_ack(uint8_t status) {
CAN_message_t ack;
ack.id = ACK_CAN_ID;
ack.len = 1;
ack.buf[0] = status;
Can.write(ack);
}