Обеспечь единый процесс обновления для STM32F103/F407/G474 и TMS320F2812/F28335: discovery, служебные ответы, BUSY, тайм-аут сессии и подтверждение приложения. Добавь самостоятельные проекты CCS, аппаратные хранилища и Python-клиент. Совместимость: структуры конфигурации и порта расширены, поэтому потребители должны пересобраться и обнулить новые поля. Для C28x callbacks используют pcan_boot_byte_t; периодический pcan_boot_poll обслуживает discovery и настроенный тайм-аут.
69 lines
11 KiB
C
69 lines
11 KiB
C
#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. */
|