Обеспечь единый процесс обновления для STM32F103/F407/G474 и TMS320F2812/F28335: discovery, служебные ответы, BUSY, тайм-аут сессии и подтверждение приложения. Добавь самостоятельные проекты CCS, аппаратные хранилища и Python-клиент. Совместимость: структуры конфигурации и порта расширены, поэтому потребители должны пересобраться и обнулить новые поля. Для C28x callbacks используют pcan_boot_byte_t; периодический pcan_boot_poll обслуживает discovery и настроенный тайм-аут.
208 lines
19 KiB
Markdown
208 lines
19 KiB
Markdown
# F28335 + M95M02: CAN, отдельный загрузчик и A/B
|
||
|
||
Реализация состоит из Flash-загрузчика `projects/ccs/f28335`, переносимого
|
||
`f28335_boot_store.c`, аппаратного `f28335_boot_hw.c` и адаптера
|
||
`f28335_can_boot.c`. Приложение подключает общий `f28335_can_application.c`
|
||
прямой ссылкой linked resource из templates в CCS Debug/Release.
|
||
В сборке `EEPROM_M95M02=0` CAN Boot отключён. Для установленной M95M02 — значение 1.
|
||
|
||
## Адрес и формат
|
||
|
||
Адрес определяется физическим номером **PERIPH 0–31** по новой Excel-таблице:
|
||
Type = 1 + PERIPH / 16 (целая часть), Device ID = PERIPH mod 16.
|
||
**УМП1 — 1/5, УМП2 — 1/6, задатчик — 1/8**. Product **0x2833**, HW **1**
|
||
описывают существующую аппаратную совместимость F28335 и не являются CAN-адресом.
|
||
Имена паспорта для назначенных плат — `UMP1`, `UMP2`, `Zadatchik`.
|
||
Приложение передаёт Mode в `F28335CanBoot_Init(Mode)`. Загрузчик независимо
|
||
читает те же активные низким уровнем GPIO21/20/22/51 с весами 1/2/4/8 и базой 1.
|
||
Поэтому существующие перемычки ПМ35 задают номера 1–16; номера 0 и 17–31
|
||
поддерживаются адресным контрактом, но требуют другого источника физического номера.
|
||
Общий адрес 3/7 больше не принимается. Чужие адреса отбрасываются аппаратным
|
||
mailbox, ISR и ядром до записи EEPROM, включая данные A/B и управляющие команды.
|
||
В приложении FW берётся из `firmware_version.h`, формат `major<<24 | minor<<16 | patch`;
|
||
для версии 1.1.2 это `0x01010002`. Загрузчик сообщает версию подтверждённого образа
|
||
из журнала, при отсутствии такого образа — 0. Версия кандидата передаётся в BEGIN_COMPAT.
|
||
CAN **250000 бит/с**, Extended ID, окно **16 блоков по 8 октетов**.
|
||
Для задатчика и session=1: ENTER_BOOT `0x11890102`, STATUS `0x198C0102`.
|
||
|
||
## Общий запуск Flash и резервной EEPROM
|
||
|
||
Сектор A и аппаратный boot `0x33FFF6` принадлежат постоянному загрузчику.
|
||
Flash-приложение использует `[0x300000,0x338000)`: первые 16 слов — описание
|
||
FAB1, остальные — собственные LOAD-секции. `f28335_flash_app.c` проверяет
|
||
magic/version, entry, границы, инверсию entry, маркеры и CRC32 IEEE всего
|
||
диапазона после заголовка, включая промежутки, заполненные `0xFFFF`.
|
||
Python-контракт `python/protocan/f28335_flash.py` заполняет зарезервированные
|
||
32 октета COFF по смещению, подтверждённому TI OFD, после линковки.
|
||
|
||
Загрузчик даёт трёхсекундное окно CAN, затем запускает исправную внутреннюю
|
||
Flash в приоритете. Отсутствующая/повреждённая Flash ведёт к прежнему выбору
|
||
EEPROM A/B с trial/CONFIRM/rollback. ENTER_BOOT удерживает CAN recovery.
|
||
Handoff running=`0xFE` обозначает проверенную внутреннюю Flash; 0/1 — EEPROM
|
||
A/B, `0xFF` — отсутствие запущенного приложения. Flash-приложение обслуживает
|
||
PING и ENTER_BOOT, но не подменяет подтверждение EEPROM-кандидата.
|
||
Обновление EEPROM по CAN не меняет приоритет исправной Flash после reset.
|
||
|
||
RS Flash должен стирать только B–H, публиковать FAB1 после проверки остальных
|
||
данных и запрещать любые адреса сектора A. В SETGUI соответствующие JTAG
|
||
маски задаются явными TI `FlashSectorA..H`: A для установки boot, B–H для
|
||
приложения. Полное стирание чипа внешним программатором не ограничивается linker.
|
||
Старая самостоятельная Flash-сборка с codestart `0x33FFF6` несовместима с этим
|
||
размещением и не должна передаваться как обновление приложения.
|
||
|
||
Образ — SCI8 BIN (`AA 08`), чётная длина от 24 до **130560 байт** включительно.
|
||
Числа в протоколе little endian. Адреса внутри SCI8: сначала старшее 16-битное
|
||
слово, затем младшее; каждое слово little endian. В C28x `char` 16-битный,
|
||
поэтому `pcan_boot_byte_t` хранит октет в младших 8 битах.
|
||
|
||
## Разметка EEPROM, байтовые адреса
|
||
|
||
| Область | Начало | Конец включительно | Размер |
|
||
|---|---:|---:|---:|
|
||
| Журнал 0 | 0x00000 | 0x000FF | 256 |
|
||
| Журнал 1 | 0x00100 | 0x001FF | 256 |
|
||
| Slot A | 0x00200 | 0x1FFFF | 130560 |
|
||
| Slot B | 0x20000 | 0x3FDFF | 130560 |
|
||
| Резерв | 0x3FE00 | 0x3FEFB | 252 |
|
||
| Параметры | 0x3FEFC | 0x3FFFD | 258 |
|
||
| Последнее слово | 0x3FFFE | 0x3FFFF | 2 |
|
||
|
||
В каждой странице журнала первые 64 октета содержат magic `FAB2`, версию 1,
|
||
sequence, active/pending/attempted, два manifest, CRC32 первых 56 октетов и
|
||
commit marker в октетах 60..63. Сначала обнуляется marker запасной страницы,
|
||
затем записывается тело с проверкой чтением, последним — marker. Предыдущая
|
||
страница остаётся действующей до полной публикации новой. Выбор sequence
|
||
учитывает переполнение u32. После ошибки публикации журнал перечитывается;
|
||
ошибка чтения блокирует последующие записи.
|
||
|
||
## Сценарий обновления и отката
|
||
|
||
1. Приложение принимает ENTER_BOOT, останавливает управление нагрузкой, выставляет 4 мА и выдерживает
|
||
секундный STOP, затем сохраняет session в NOINIT RAM 0x50..0x57. Watchdog выполняет reset.
|
||
ACK ENTER_BOOT отправляет уже Flash-загрузчик; приложение ничего не стирает.
|
||
2. BEGIN_IMAGE/BEGIN_COMPAT проверяют размер, Product, HW и сессию. Неактивный
|
||
слот выбирается автоматически; при первом образе это A. ERASE инвалидирует
|
||
только его manifest. Полного стирания EEPROM не требуется.
|
||
3. Последовательные DATA_A/B записываются с немедленным readback. VERIFY
|
||
проверяет потоковый CRC32, CRC32 EEPROM и полную таблицу SCI8.
|
||
Разрешена загрузка только в CPU word RAM `[0x8000,0xE000)`: максимум 64 секции,
|
||
без пересечений, усечений и хвостовых данных; entry должен попасть в секцию.
|
||
Запись в Flash, периферию, стек, RAM загрузчика и handoff запрещена.
|
||
4. COMMIT повторно проверяет образ и публикует pending в журнале. Подтверждённый
|
||
слот сохраняется. Повтор COMMIT безопасен. REBOOT выполняется после физического
|
||
CAN ACK ответа. Потеря ACK/тайм-аут передачи отменяет запрос reset.
|
||
5. Перед первым запуском кандидата загрузчик сохраняет attempted=1, затем
|
||
проверяет и копирует SCI8 в RAM. Следующий reset без CONFIRM сбрасывает pending
|
||
и запускает прежний active. Если прежнего образа нет — остаётся CAN recovery.
|
||
6. Новое приложение включает watchdog в начале запуска. До подтверждения
|
||
прерывания не кормят watchdog вместо основного цикла. После READY, 100 проходов
|
||
main и 5 секунд выполняется автоматический CONFIRM. Неудача сохранения
|
||
подтверждения через 10 секунд прекращает кормление watchdog, вызывая откат.
|
||
Адресная команда CONFIRM с ненулевой session также разрешена после READY.
|
||
CONFIRM в загрузчике и до первого запуска кандидата отклоняется.
|
||
|
||
PING, IDENTIFY и паспорт доступны без ENTER_BOOT. QUERY_PROGRESS/ABORT привязаны
|
||
к сессии. Сессия в RAM истекает через 30 секунд без подходящих команд/данных.
|
||
После reset передачу начинают заново; параметры и подтверждённый образ остаются.
|
||
ABORT после COMMIT не отменяет опубликованный pending. Для его пробного запуска
|
||
можно открыть новую сессию и отправить REBOOT. Pending запрещено перезаписывать.
|
||
Повторы ENTER_BOOT, метаданных, ERASE до первого блока, VERIFY и COMMIT учитывают
|
||
потерю ответа. Broadcast никогда не разрешает запись.
|
||
|
||
## Сервисные команды
|
||
|
||
Запрос: MsgType=9, Body=`session<<8 | command`. IDENTIFY/PING/паспорт не требуют сессии.
|
||
Ответ паспорта: MsgType=D, Body=`page<<8 | command`, DLC=8.
|
||
|
||
| Код | Имя | DLC запроса | Ответ |
|
||
|---:|---|---:|---|
|
||
| 01 | IDENTIFY | 0 | Product:u16, HW:u8, protocol:u8, FW:u32; Body=1 |
|
||
| 0C | PING | 0 | protocol, state, active, target, session, slot_count, last_status, 0 |
|
||
| 0D | CAPABILITIES | 0 | flags:u32, slot_capacity:u32 |
|
||
| 0E | DEVICE_NAME | 1 (page) | 8 ASCII-октетов имени; последний фрагмент с NUL |
|
||
| 0F | MEMORY_INFO | 1 (page) | Страницы ниже |
|
||
|
||
MEMORY_INFO 0: EEPROM bytes:u32, page bytes:u16, mode:u8 (0 app/1 boot), running:u8.
|
||
Страница 1: адреса A:u32, B:u32. Страница 2: active, pending, attempted, storage_healthy,
|
||
session_timeout_ms:u32. Страница 3: parameters_offset:u32, parameters_bytes:u32.
|
||
Слот FF означает отсутствие образа/запущенного приложения.
|
||
CAPABILITIES bits 0..11: ping, discovery, identify, name, memory, A/B, confirm,
|
||
rollback, separate loader, session timeout, readback, SCI8 validation.
|
||
Приложение, запущенное старым SPI ROM без handoff загрузчика, сообщает только
|
||
базовые сервисы (0x1F) и отклоняет ENTER_BOOT.
|
||
|
||
Обнаружение: MsgType=D, Body=0, DLC=0, Route=0. Адресный запрос или общий
|
||
DeviceType=7/DeviceID=15. Ответ IDENTIFY приходит с адреса прибора через
|
||
`2*(1+16*DeviceType+DeviceID)` мс. При нескольких одинаковых адресах конфликт
|
||
остаётся: каждому физическому устройству нужен уникальный адрес.
|
||
Python API: `protocan.can_boot.CanBootServices` — запросы и разбор паспорта;
|
||
`CanBootTransfer` — загрузка. Кнопка «Пинг» доступна в режиме ProtoCAN Boot
|
||
окна прошивки SETGUI. Для ENTER/VERIFY/COMMIT клиент ждёт до 15 секунд.
|
||
|
||
## Аппаратная интеграция
|
||
|
||
MBOX3 — адресные входящие Boot; MBOX4 — ответы; MBOX6 — точный broadcast discovery.
|
||
MBOX0..2 сохраняют legacy/UMP, MBOX5 загрузчик не использует. ISR помещает сообщения
|
||
в очередь на 31 кадр. Чужие адреса, RTR и неподходящие типы отбрасываются до очереди.
|
||
При переполнении/потере mailbox сессия отменяется; повторная запись начинается заново.
|
||
SPI-драйвер загрузчика имеет ограничение ожидания байта и WIP, 24-битный адрес,
|
||
разбиение по страницам 256 байт и восстановление конфигурации SPI приложения.
|
||
Он работает только при остановленном Timer2. Обычный Seeprom_write приложения
|
||
ограничен областью параметров; старый RS EXTEND 0x44 запрещён для A/B.
|
||
|
||
Загрузчик исполняется из внутренней Flash A 0x338000..0x33FF7F, entry 0x33FFF6.
|
||
Его RAM — 0xE000..0xFFFF; стек — 0x400..0x7FF. Приложение M95M02 использует
|
||
0x8000..0xD7FF для кода, 0xD800..0xDFFF для констант/инициализации,
|
||
0xE000..0xFFFF для .ebss после перехода в C runtime. Linker резервирует
|
||
NOINIT handoff в обоих проектах. CAN не содержит операций записи внутренней Flash.
|
||
|
||
## Первичная установка
|
||
|
||
1. Собрать приложение с EEPROM_M95M02=1 и обновлённым F28335.cmd; получить SCI8 BIN.
|
||
Старые BIN/OUT автоматически не заменены. Приложение должно содержать интеграцию
|
||
READY/CONFIRM, иначе на следующем reset оно останется неподтверждённым кандидатом.
|
||
2. Собрать отдельный загрузчик TI C2000 COFF compiler:
|
||
`python c/protocan-boot/projects/build.py --device f28335 --compiler <путь-к-ti-cgt-c2000>`.
|
||
Результат — `projects/ccs/f28335/Debug/F28335_CAN_AB.out` и MAP.
|
||
3. Установить обновлённый OUT через JTAG и выбрать аппаратный Flash boot
|
||
согласно схеме платы. При переходе с общего адреса 3/7 обновить и приложение,
|
||
и загрузчик: старый загрузчик не перейдёт на новый адрес после reset сам.
|
||
В SETCAN выбрать «Прошивка → CAN / ProtoCAN Boot → Устройство PERIPH»
|
||
и нужное назначение. Не загружать поверх загрузчика старый application OUT с
|
||
секцией codestart во Flash.
|
||
4. После reset пустая EEPROM или старая разметка автоматически ведут в CAN recovery.
|
||
Передать новое приложение через ProtoCAN Boot, дождаться пробного запуска и
|
||
проверить MEMORY_INFO page 2: pending=FF, active=A. Затем проверить обновление в B.
|
||
|
||
Старая SPI-ROM разметка с AA08 по адресу 0 несовместима с новым журналом.
|
||
Первое обновление заменяет её; параметры по прежнему адресу сохраняются.
|
||
Загрузчик не выполняет скрытую миграцию и не меняет boot pins программно.
|
||
|
||
## Проверки и границы проверенного
|
||
|
||
`python c/protocan-boot/tests/run_tests.py` (переменная CC — clang/gcc) проверяет
|
||
ядро, приложение/загрузчик, wide-octet режим, журнал, обрыв публикации на каждом
|
||
из 69 возможных положений, пробный запуск, CONFIRM, откат, SCI8 и границы памяти.
|
||
Python-тесты проверяют клиентские запросы, паспорт, фильтрацию ответов и лимит A/B.
|
||
Проверка синтаксиса использует настоящие DSP2833x headers. Импорт и сборка TI/CCS,
|
||
раскладка MAP и реальные COFF LOAD-адреса проверены; физические CAN/SPI/reset
|
||
на плате требуют стендовой проверки. Отдельные проекты и команды сборки описаны
|
||
в [инструкции CCS](../../projects/README.md).
|
||
|
||
CRC32 защищает от повреждения, криптографической подписи и anti-rollback по
|
||
версии в этом порту нет. Удалённый CONFIRM подтверждает готовность приложения,
|
||
но не заменяет проверку датчиков/силовой части на стенде.
|
||
|
||
Аппаратный формат SPI boot описан в [TI Boot ROM Reference Guide](https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/171/2742.Boot-ROM.pdf).
|
||
В A/B-схеме ROM выбирает Flash, а разбор EEPROM выполняет этот загрузчик.
|
||
|
||
Проект предоставляет `f28335_can_application_config.h` в include paths.
|
||
Он задаёт `F28335_CAN_BOOT_APPLICATION_ENABLED` (0/1) и при включённом модуле
|
||
`F28335_CAN_BOOT_FIRMWARE_VERSION` из версии приложения. В 167 это ручной
|
||
`firmware_version.h`; профиль включён только при M95M02 без `FLASH_BOOT`.
|
||
Локальный `Source/Internal/can_boot.c` содержит только `F28335Boot_Quiesce`
|
||
со штатной остановкой нагрузки. Общие `.c` повторно включать в него не нужно:
|
||
они компилируются единственным linked resource общей библиотеки.
|
||
Постоянный Flash-загрузчик по-прежнему собирается отдельным проектом
|
||
`projects/ccs/f28335` и не линкуется в RAM-приложение.
|