Files
templates/c/protocan-boot/ports/stm32f407/boot_main.c
T
Andrey c6390ae1c9 feat(protocan-boot): Добавь порты MCU и сервисы загрузки
Обеспечь единый процесс обновления для STM32F103/F407/G474 и TMS320F2812/F28335: discovery, служебные ответы, BUSY, тайм-аут сессии и подтверждение приложения. Добавь самостоятельные проекты CCS, аппаратные хранилища и Python-клиент.

Совместимость: структуры конфигурации и порта расширены, поэтому потребители должны пересобраться и обнулить новые поля. Для C28x callbacks используют pcan_boot_byte_t; периодический pcan_boot_poll обслуживает discovery и настроенный тайм-аут.
2026-10-23 14:16:19 +03:00

69 lines
11 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 "boot_profile.h" /* Сохраняет карту Flash climate и зарезервированное SRAM-слово запроса. */
#include "pcan_boot_config.h" /* Идентичность прибора и окно ACK остаются конфигурацией исходного проекта. */
#include "../../include/pcan_boot.h" /* Подключает единственную текущую state machine ProtoCAN из templates. */
#include "stm32f407xx.h" /* Сохраняет лёгкую CMSIS-сборку загрузчика без HAL-драйверов. */
#include <string.h> /* Предоставляет безопасное формирование слов из коротких хвостов CAN. */
#define NATIVE_APP_BASE PCAN_BOOT_APP_ADDRESS /* Приложение climate начинается с физического сектора 2. */
#define NATIVE_APP_SIZE PCAN_BOOT_APP_SIZE /* Ограничивает прошивку секторами 2..5, сохраняя EEPROM-кольцо. */
#define NATIVE_RAM_END 0x20020000UL /* Физическая верхняя граница 128 КиБ SRAM сохраняет совместимость векторов ранее установленных приложений. */
#define NATIVE_PROGRAM_UNIT 4U /* F407 программирует слова x32 при VDD 2,7..3,6 В. */
#define NATIVE_PPRE1_SHIFT 10U /* STM32F4 размещает делитель APB1 в RCC_CFGR[12:10]. */
#define NATIVE_FLASH_ERRORS (FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | FLASH_SR_WRPERR) /* Проверяет последовательность, разрядность, выравнивание и аппаратную защиту Flash по RM0090. */
static pcan_boot_t boot; static volatile uint32_t ticks_ms; /* Хранит единственный автомат CAN и миллисекундные часы загрузчика. */
static bool native_wait(void) /* Ограничивает аппаратное ожидание Flash без бесконечной блокировки. */
{ /* Код продолжит исполняться после аппаратного Flash stall на однобанковом F407. */
uint32_t guard = SystemCoreClock; while ((FLASH->SR & FLASH_SR_BSY) != 0U && guard != 0U) --guard; /* Использует конечный бюджет проверок в единицах итераций текущего CPU. */
return (FLASH->SR & (FLASH_SR_BSY | NATIVE_FLASH_ERRORS)) == 0U; /* Не подтверждает операцию при BUSY или любой выбранной аппаратной ошибке. */
} /* Завершает проверку готовности Flash. */
static bool native_unlock(void) /* Открывает Flash только для текущей операции загрузчика. */
{ /* Геометрия профиля исключает массовое стирание и запись Option Bytes. */
if ((FLASH->SR & FLASH_SR_BSY) != 0U) { return false; } FLASH->SR = NATIVE_FLASH_ERRORS; /* Не посылает ключи занятой Flash и очищает предыдущие ошибки W1C. */
if ((FLASH->CR & FLASH_CR_LOCK) != 0U) { FLASH->KEYR = 0x45670123UL; FLASH->KEYR = 0xCDEF89ABUL; } /* Использует штатную последовательность ключей RM0090. */
return (FLASH->CR & FLASH_CR_LOCK) == 0U; /* Проверяет фактическое снятие блокировки Flash. */
} /* Завершает разблокировку контроллера Flash. */
static void native_lock(void) { FLASH->CR = FLASH_CR_LOCK; } /* Выключает PG/SER и восстанавливает LOCK после успеха и обработанных отказов. */
static void native_sync_cache(void) /* Убирает устаревшие строки Flash cache перед readback соседнего записанного слова. */
{ /* Сохраняет исходное включение instruction/data cache и остальные настройки ACR. */
uint32_t saved = FLASH->ACR; FLASH->ACR = saved & ~(FLASH_ACR_ICEN | FLASH_ACR_DCEN); /* Отключает кэши перед их аппаратным сбросом. */
FLASH->ACR |= FLASH_ACR_ICRST | FLASH_ACR_DCRST; FLASH->ACR &= ~(FLASH_ACR_ICRST | FLASH_ACR_DCRST); FLASH->ACR = saved; /* Сбрасывает обе cache-памяти и возвращает прежние enable/latency/prefetch настройки. */
__DSB(); __ISB(); /* Синхронизирует последующие чтения Flash и исполняемый поток после reset кэшей. */
} /* Завершает синхронизацию Flash cache без HAL. */
static bool native_program(uint32_t address, uint32_t value) /* Программирует и перечитывает одно слово x32. */
{ /* Границы и выравнивание проверяет общий writer до вызова. */
bool ok; FLASH->SR = NATIVE_FLASH_ERRORS; FLASH->CR = FLASH_CR_PG | (2UL << FLASH_CR_PSIZE_Pos); /* Выбирает PSIZE=2, то есть 32-битную запись при VDD 2,7..3,6 В. */
*(volatile uint32_t *)(uintptr_t)address = value; ok = native_wait(); FLASH->CR &= ~FLASH_CR_PG; native_sync_cache(); /* Дожидается завершения записи и сбрасывает устаревшие строки cache перед чтением. */
return ok && *(const volatile uint32_t *)(uintptr_t)address == value; /* Проверяет аппаратные флаги и реально прочитанное значение, включая дополнение FF. */
} /* Завершает одну аппаратную запись F407. */
static bool native_erase(uint32_t size) /* Стирает только используемые секторы 2..5 приложения climate. */
{ /* EEPROM-кольцо 6/7 и загрузочные 0/1 не включаются в таблицу разрешённых секторов. */
static const uint32_t starts[4] = {0x08008000UL, 0x0800C000UL, 0x08010000UL, 0x08020000UL}; /* RM0090: начала секторов 2,3,4,5 объёмом 16,16,64,128 КиБ. */
uint32_t index; bool ok = true; /* Хранит текущий сектор и результат до восстановления LOCK. */
if (size < 8U || size > NATIVE_APP_SIZE || !native_unlock()) return false; /* Отвергает неподдерживаемый размер до первого изменения Flash. */
for (index = 0U; index < 4U && starts[index] < NATIVE_APP_BASE + size; ++index) { /* Не стирает следующий сектор, когда образ заканчивается точно на его границе. */
(void)pcan_boot_report_busy(&boot, PCAN_BOOT_CMD_ERASE, ticks_ms); FLASH->SR = NATIVE_FLASH_ERRORS; /* Продлевает сессию и сообщает прогресс между длительными стираниями. */
FLASH->CR = FLASH_CR_SER | (2UL << FLASH_CR_PSIZE_Pos) | ((index + 2U) << FLASH_CR_SNB_Pos); FLASH->CR |= FLASH_CR_STRT; /* Запускает erase конкретного сектора с разрядностью x32. */
if (!native_wait()) { ok = false; break; } /* Прерывает обновление на первом аппаратном отказе. */
} /* Завершает обход разрешённых секторов. */
native_lock(); native_sync_cache(); return ok; /* Восстанавливает LOCK и обновляет cache как после успеха, так и после обработанного отказа. */
} /* Завершает аппаратное стирание F407. */
static void native_gpio_init(void) /* Сохраняет исходный CAN1 climate на PD0/PD1 AF9. */
{ /* Тактирование APB1 определяется общим кодом из фактического RCC_CFGR. */
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; RCC->APB1ENR |= RCC_APB1ENR_CAN1EN; /* Разрешает аппаратные такты GPIOD и CAN1. */
GPIOD->MODER = (GPIOD->MODER & ~15UL) | 10UL; GPIOD->PUPDR = (GPIOD->PUPDR & ~3UL) | 1UL; /* Назначает PD0/PD1 альтернативной функцией и подтягивает RX к рецессивному уровню. */
GPIOD->OSPEEDR |= 15UL; GPIOD->AFR[0] = (GPIOD->AFR[0] & ~255UL) | 0x99UL; /* Выбирает высокую скорость GPIO и AF9 обоих выводов CAN1 согласно datasheet F407. */
} /* Завершает настройку физического CAN-порта. */
static void native_peripheral_stop(void) { RCC->APB1RSTR |= RCC_APB1RSTR_CAN1RST; RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN1RST; } /* Сбрасывает CAN1 перед handoff без изменения памяти приложения и EEPROM. */
#include "../stm32-common/boot_native.inc" /* Подключает общий ProtoCAN transport, CRC, callbacks и безопасную замену MSP. */
int main(void) /* Самостоятельный загрузчик climate, подключаемый тонкой обёрткой исходного проекта. */
{ /* Сборка PCAN_BOOTLOADER_BUILD сохраняет VTOR startup в начале Flash. */
bool requested = *(volatile uint32_t *)(uintptr_t)PCAN_BOOT_REQUEST_ADDRESS == PCAN_BOOT_REQUEST_MAGIC; /* Читает запрос из отдельного слова SRAM, не используемого стеком или ZI. */
*(volatile uint32_t *)(uintptr_t)PCAN_BOOT_REQUEST_ADDRESS = 0U; /* Потребляет запрос ровно один раз до запуска интерфейсов. */
SystemCoreClockUpdate(); if (SysTick_Config(SystemCoreClock / 1000U) != 0U || !native_init()) for (;;) {} /* Использует фактический HCLK и создаёт millisecond tick до CAN-тайм-аутов. */
while (!native_can_init()) { if (!requested && native_vectors_valid(NATIVE_APP_SIZE)) native_jump(NATIVE_APP_BASE); native_peripheral_stop(); } /* При недоступной шине сохраняет обычный запуск установленного приложения, а по запросу остаётся восстанавливаемым. */
if (!requested && native_vectors_valid(NATIVE_APP_SIZE)) { /* Сохраняет исходное десятисекундное окно входа в обновление после обычного reset. */
uint32_t started = ticks_ms; while ((uint32_t)(ticks_ms - started) < 10000U) { native_can_poll(); if (boot.state != PCAN_BOOT_STATE_IDLE) { requested = true; break; } } /* Обслуживает discovery и команды без ложного входа по одному IDENTIFY. */
if (!requested) native_jump(NATIVE_APP_BASE); /* Запускает приложение после окна, используя безопасный naked handoff. */
} /* Завершает политику обычного запуска. */
for (;;) native_can_poll(); /* Остаётся в общем ProtoCAN-автомате до подтверждённого COMMIT/REBOOT. */
} /* Завершает самостоятельный CMSIS-загрузчик F407. */