Расширить DEIF, загрузку CAN и общую обработку сигналов

Добавить общее ядро DEIF, эмуляцию приборов и переносимые панели Python/Qt.
Расширить загрузчики F2812 и F28335, обновление Flash и профиль STM Invertor.
Добавить альтернативный МНК Eigen, модели неисправностей и диагностику сигналов.
Обновить справочники устройств, проекты CCS и регрессионные проверки.
This commit is contained in:
2026-10-24 15:40:51 +03:00
parent a5e46d4627
commit 41e24629ce
170 changed files with 43762 additions and 281 deletions
+35 -8
View File
@@ -13,6 +13,7 @@ import json
import os import os
from pathlib import Path from pathlib import Path
import subprocess import subprocess
import tempfile # Резервирует номер сборки через временный файл на том же диске, как общий итератор ветки 166.
def git_state(repository: Path) -> dict: def git_state(repository: Path) -> dict:
@@ -36,20 +37,46 @@ def git_state(repository: Path) -> dict:
def write_atomic(path: Path, text: str): def write_atomic(path: Path, text: str):
path.parent.mkdir(parents=True, exist_ok=True) path.parent.mkdir(parents=True, exist_ok=True)
temporary = path.with_name(path.name + ".tmp") temporary = path.with_name(path.name + ".tmp")
temporary.write_text(text, encoding="utf-8", newline="\n") with open(temporary, "w", encoding="utf-8", newline="\n") as stream: # Сохраняет UTF-8 и LF также на Python 3.8, где Path.write_text ещё не принимает newline.
stream.write(text) # Полностью записывает заголовок или паспорт перед атомарной заменой целевого файла.
temporary.replace(path) temporary.replace(path)
def prepare(repository: Path, templates: Path, config: Path, output: Path) -> dict: def next_version(version): # Повторяет общий итератор 166 и переносит переполнение младшего разряда в старший.
settings = json.loads(config.read_text(encoding="utf-8")) result = list(version) # Не изменяет исходный номер до проверки полного переполнения.
version = settings["version"] for index, limit in ((2, 999), (1, 255), (0, 255)): # Контракт firmware-info v1 допускает patch 0..999 и major/minor 0..255.
if (len(version) != 3 or any(type(v) is not int for v in version) if result[index] < limit: # Выбирает младший разряд, который ещё допускает увеличение.
or not all(0 <= v <= limit for v, limit in zip(version, (255, 255, 999)))): result[index] += 1 # Занимает следующий номер попытки сборки ровно один раз.
raise ValueError("version must be [major 0..255, minor 0..255, patch 0..999]") return result # Возвращает новый номер с сохранёнными старшими и обнулёнными переполненными младшими разрядами.
result[index] = 0 # Переносит единицу к следующему разряду при достижении предела текущего.
raise ValueError("Firmware version exhausted at 255.255.999") # Не допускает повторного использования версии после полного переполнения контракта.
def prepare(repository: Path, templates: Path, config: Path, output: Path) -> dict: # Формирует один паспорт текущей попытки после сохранения номера автоматической сборки.
settings = json.loads(config.read_text(encoding="utf-8-sig")) # Принимает исходный JSON в UTF-8, включая старые файлы Windows с BOM.
version = settings["version"] # Начальный номер берётся из единственного сохраняемого источника проекта.
if not isinstance(version, list) or len(version) != 3 or any(type(value) is not int or not 0 <= value <= limit for value, limit in zip(version, (255, 255, 999))): # Проверяет три целых разряда и пределы протокола до изменения JSON.
raise ValueError("version must be [major 0..255, minor 0..255, patch 0..999]") # Останавливает prebuild при неверном формате счётчика.
if type(settings.get("increment_version", False)) is not bool: # Старые проекты сохраняют ручной режим; автоматический требует настоящего логического true.
raise ValueError("increment_version must be true or false") # Не принимает строки и числа вместо явной настройки счётчика.
for field in ("product", "target"): for field in ("product", "target"):
if not isinstance(settings.get(field), str) or not settings[field].strip(): if not isinstance(settings.get(field), str) or not settings[field].strip():
raise ValueError(f"missing {field}") raise ValueError(f"missing {field}")
source, dependency = git_state(repository), git_state(templates) if settings.get("increment_version", False): # Увеличение выполняется только при подготовке основного проекта, а не при упаковке RAM, CAN и Flash.
version = settings["version"] = next_version(version) # Один вычисленный номер используется исходным JSON, генерируемым заголовком и паспортом.
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", newline="\n", dir=config.parent, prefix=".firmware-version-", delete=False) as stream: # Временный файл рядом с JSON позволяет атомарную замену счётчика на том же диске.
temporary = Path(stream.name) # Запоминает только собственный файл для очистки при отказе сохранения.
try: # Ошибка записи должна сохранить исходный JSON и удалить незавершённый временный файл.
stream.write(json.dumps(settings, ensure_ascii=False, indent=2) + "\n") # Сохраняет новый номер и все дополнительные настройки проекта в UTF-8.
except BaseException: # Освобождает собственный файл также при прерывании процесса записи.
stream.close() # Windows разрешает удалить временный файл после закрытия его дескриптора.
temporary.unlink() # Удаляет только незавершённый файл этой попытки резервирования номера.
raise # Возвращает исходную ошибку вместо продолжения сборки с несохранённой версией.
try: # Номер должен быть надёжно занят до генерации выходов и начала компиляции.
temporary.replace(config) # Атомарно фиксирует счётчик, чтобы следующая попытка не повторила номер при последующей ошибке сборки.
finally: # При неудачной замене исходный JSON остаётся прежним, а собственный временный файл очищается.
temporary.unlink(missing_ok=True) # После успешного переименования файла уже нет; Python 3.8 поддерживает missing_ok.
source, dependency = git_state(repository), git_state(templates) # Отмечает изменённый счётчик в происхождении текущего выпуска после резервирования номера.
# A clean application built with a modified templates checkout is dirty too. # A clean application built with a modified templates checkout is dirty too.
known = source["commit"] is not None and dependency["commit"] is not None known = source["commit"] is not None and dependency["commit"] is not None
dirty = bool(source["dirty"] or dependency["dirty"]) dirty = bool(source["dirty"] or dependency["dirty"])
+8
View File
@@ -0,0 +1,8 @@
# Результаты отдельных конфигураций CCS воспроизводятся установленным TI compiler.
/projects/ccs/*/Debug/
/projects/ccs/*/Release/
# Служебные локальные настройки IDE и launch не входят в переносимый проект.
/projects/ccs/*/.settings/
/projects/ccs/*/.launches/
# Python cache не является исходником общего модуля или проекта.
**/__pycache__/
+13 -4
View File
@@ -1,6 +1,6 @@
# РЎР±РѕСЂРєР° библиотеки protocan_boot. Состав РёСЃС…РѕРґРЅРёРєРѕРІ Рё публичные include-пути задают # Общая C99-библиотека ProtoCAN Boot и аппаратно независимые host-тесты.
# подключение Рє проекту потребителя. Файл также собирает Рё регистрирует хостовые проверки; # Каждый контроллер сохраняет собственное состояние и отдельный аппаратный порт.
# запускать РёС… следует через CTest РёР· каталога СЃР±РѕСЂРєРё. # Дополнительные проекты CCS находятся в projects/ccs и не требуют CMake для TI-сборки.
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
project(protocan_boot C) project(protocan_boot C)
@@ -17,7 +17,7 @@ else()
target_compile_options(protocan_boot PRIVATE -Wall -Wextra -Wpedantic) target_compile_options(protocan_boot PRIVATE -Wall -Wextra -Wpedantic)
endif() endif()
option(PCAN_BOOT_BUILD_TESTS "Собирать тесты ProtoCAN boot" ON) option(PCAN_BOOT_BUILD_TESTS "Собирать тесты ProtoCAN Boot" ON) # Не включает host-модели в код MCU.
if(PCAN_BOOT_BUILD_TESTS) if(PCAN_BOOT_BUILD_TESTS)
enable_testing() enable_testing()
add_executable(test_pcan_boot tests/test_pcan_boot.c) add_executable(test_pcan_boot tests/test_pcan_boot.c)
@@ -45,3 +45,12 @@ if(PCAN_BOOT_BUILD_TESTS)
add_test(NAME f28335_store_${width} COMMAND test_f28335_store_${width}) add_test(NAME f28335_store_${width} COMMAND test_f28335_store_${width})
endforeach() endforeach()
endif() endif()
if(PCAN_BOOT_BUILD_TESTS) # Подключает настоящий аппаратно независимый драйвер NOR F2812 и регрессию длительного BUSY.
add_executable(test_f2812_nor tests/test_f2812_nor.c src/pcan_boot.c ports/tms320f2812/nor_flash.c ports/tms320f2812/boot_store.c) # Компилирует production-код вместе с x16 моделью чипа.
target_compile_definitions(test_f2812_nor PRIVATE PCAN_BOOT_WIDE_BYTES BOOT2812_HOST) # Октеты C28x широкие; подменяется только физическая шина памяти.
add_test(NAME f2812_nor COMMAND test_f2812_nor) # Регистрирует проверки CRC, SCI8, границ, manifest и отказов NOR.
add_executable(test_pcan_busy tests/test_pcan_busy.c src/pcan_boot.c) # Использует тот же codec, который обслуживает длинные аппаратные операции.
target_compile_definitions(test_pcan_busy PRIVATE PCAN_BOOT_WIDE_BYTES) # Проверяет wire-статус при 16-битном представлении октета C28x.
add_test(NAME pcan_busy COMMAND test_pcan_busy) # Регистрирует проверку продления session при живом прогрессе erase.
endif() # Включение библиотек без тестов не добавляет host-модель в прошивку.
+7 -1
View File
@@ -180,8 +180,14 @@ ctest --test-dir build --output-on-failure
## F28335 / большая EEPROM ## F28335 / большая EEPROM
[Порт M95M02](ports/tms320f28335/README.md) подключён в `tms_periph/periph_167`. [Порт M95M02](ports/tms320f28335/README.md) подключён в `28335_periph`, ветка 167.
Использует отдельный Flash-загрузчик и два слота EEPROM по 130560 байт. Использует отдельный Flash-загрузчик и два слота EEPROM по 130560 байт.
Реализованы readback/CRC, проверка SCI8, журнал метаданных, пробный запуск, Реализованы readback/CRC, проверка SCI8, журнал метаданных, пробный запуск,
CONFIRM/откат, PING/discovery и сервисный паспорт. Первичная установка Flash- CONFIRM/откат, PING/discovery и сервисный паспорт. Первичная установка Flash-
загрузчика и выбор Flash boot описаны в README порта. загрузчика и выбор Flash boot описаны в README порта.
## Самостоятельные проекты CCS
Готовые проекты **F28335_CAN_AB** (M95M02) и **F2812_CAN_NOR** (AM29LV800BT),
включая необходимые файлы поддержки TI, находятся в `projects/ccs`.
[Импорт, сборка, карты памяти и установка](projects/README.md).
+6 -1
View File
@@ -52,7 +52,8 @@ typedef enum {
PCAN_BOOT_CMD_PING = 0x0CU, PCAN_BOOT_CMD_PING = 0x0CU,
PCAN_BOOT_CMD_CAPABILITIES = 0x0DU, PCAN_BOOT_CMD_CAPABILITIES = 0x0DU,
PCAN_BOOT_CMD_DEVICE_NAME = 0x0EU, PCAN_BOOT_CMD_DEVICE_NAME = 0x0EU,
PCAN_BOOT_CMD_MEMORY_INFO = 0x0FU PCAN_BOOT_CMD_MEMORY_INFO = 0x0FU, /* Сохраняет существующий номер постраничного паспорта памяти. */
PCAN_BOOT_CMD_SELECT_MEMORY = 0x10U /* Выбирает 0=штатное хранилище, 1=внутренняя Flash до передачи метаданных. */
} pcan_boot_command_t; } pcan_boot_command_t;
typedef enum { typedef enum {
@@ -127,6 +128,7 @@ typedef struct {
/** Optional precise result, replacing legacy boolean verify_image. */ /** Optional precise result, replacing legacy boolean verify_image. */
pcan_boot_status_t (*verify_status)(void *user, pcan_boot_byte_t slot, pcan_boot_status_t (*verify_status)(void *user, pcan_boot_byte_t slot,
const pcan_boot_manifest_t *manifest); const pcan_boot_manifest_t *manifest);
pcan_boot_status_t (*select_memory)(void *user, pcan_boot_byte_t memory, pcan_boot_config_t *config); /* Необязательный порт явно переключает назначение образа до ERASE; старые порты возвращают INVALID_COMMAND. */
} pcan_boot_port_t; } pcan_boot_port_t;
typedef struct { typedef struct {
@@ -164,6 +166,9 @@ bool pcan_boot_process(pcan_boot_t *boot, uint32_t can_id,
/** Call regularly with a wrapping monotonic millisecond clock. */ /** Call regularly with a wrapping monotonic millisecond clock. */
void pcan_boot_poll(pcan_boot_t *boot, uint32_t now_ms); void pcan_boot_poll(pcan_boot_t *boot, uint32_t now_ms);
uint32_t pcan_boot_crc32_update(uint32_t crc, const pcan_boot_byte_t *data, size_t length); /* Общий потоковый CRC32 для readback аппаратных хранилищ; начальное состояние равно нулю. */
bool pcan_boot_report_busy(pcan_boot_t *boot, pcan_boot_byte_t command, uint32_t now_ms); /* Долгие аппаратные операции сообщают BUSY тем же codec и той же session, что обычный ответ. */
/** Переносимые операции с 29-битным ProtoCAN ID. */ /** Переносимые операции с 29-битным ProtoCAN ID. */
uint32_t pcan_boot_make_id(pcan_boot_byte_t priority, pcan_boot_byte_t route, uint32_t pcan_boot_make_id(pcan_boot_byte_t priority, pcan_boot_byte_t route,
pcan_boot_byte_t device_type, pcan_boot_byte_t device_id, pcan_boot_byte_t device_type, pcan_boot_byte_t device_id,
@@ -0,0 +1,15 @@
# F2812 / AM29LV800BT
Самостоятельный проект, карта NOR, параметры CAN, установка и ограничения
описаны в [общей инструкции CCS](../../projects/README.md).
- `boot2812.h` — физические CPU word-адреса и отдельная совместимость F2812;
- `nor_flash.c` — x16 AMD driver с ID, ограниченными program/sector erase,
DQ7/DQ5 polling, readback и BUSY;
- `boot_store.c` — упаковка октетов, проверка всей SCI8-таблицы, CRC32,
публикация manifest последними magic-словами, проверенная загрузка RAM;
- `projects/ccs/f2812/board.c` — подтверждённые линии CPLD и XINTF ПМ67;
- `projects/ccs/f2812/main.c` — независимые eCAN/IRQ/очередь/main F2812.
Протокол и CRC повторно используются из `src/pcan_boot.c`. EEPROM отсутствует;
код F28335 и его A/B-журнал не подключаются к этому проекту.
@@ -0,0 +1,24 @@
#ifndef BOOT2812_H /* Исключает повторное объявление профиля NOR-загрузчика F2812. */
#define BOOT2812_H /* Отделяет основной контроллер ПМ67 от периферийного F28335. */
#include "../../include/pcan_boot.h" /* Использует существующий ProtoCAN codec и представление октетов C28x. */
#define BOOT2812_NOR_BASE 0x100000UL /* CPU word-адрес AM29LV800BT взят из START_ADR_FLASH действующего flash_tools.h платы. */
#define BOOT2812_IMAGE_WORD 0x160000UL /* Новый CAN-образ занимает три полных верхних обычных сектора, выше старого образа и данных FPGA. */
#define BOOT2812_IMAGE_BYTES 0x30000UL /* Три сектора по 0x8000 слов дают 196608 октетов полезного SCI8. */
#define BOOT2812_META_WORD 0x17E000UL /* Последний top-boot сектор начинается после областей 16K/4K/4K слов и содержит 8192 слова. */
#define BOOT2812_PRODUCT 0x2812U /* Отдельный Product Type запрещает запись образа F28335 в основной контроллер F2812. */
#define BOOT2812_DEVICE_TYPE 3U /* Тип загрузчика остаётся в том же адресном классе ProtoCAN, что F28335. */
#define BOOT2812_DEVICE_ID 6U /* Отдельный ID 6 исключает совпадение с существующим F28335 на адресе 3/7. */
#define BOOT2812_RECOVERY_MS 3000UL /* После reset загрузчик три секунды принимает ENTER_BOOT до автоматического запуска сохранённого образа. */
unsigned long Boot2812_Now(void); /* Возвращает монотонные миллисекунды Timer1 для CAN и ограниченных ожиданий NOR. */
void Boot2812_Busy(void); /* Во время долгого стирания сообщает BUSY через общий codec и обслуживает аппаратный TX ACK. */
void Boot2812_BoardInit(void); /* Настраивает действующие линии CPLD и XINTF платы ПМ67. */
bool Boot2812_NorIdentify(void); /* До первого erase требует AMD manufacturer 0001 и top-boot device 22DA. */
unsigned int Boot2812_NorRead(unsigned long word); /* Читает одно 16-битное слово по CPU-адресу внешней NOR. */
bool Boot2812_NorProgram(unsigned long word, unsigned int value); /* Программирует только зарезервированные CAN-области и проверяет прочитанный результат. */
bool Boot2812_NorErase(unsigned long word); /* Принимает только начала трёх секторов образа и одного сектора метаданных. */
bool Boot2812_Erase(void *user, pcan_boot_byte_t slot); /* Удаляет публикацию до стирания единственного CAN-слота. */
bool Boot2812_Write(void *user, pcan_boot_byte_t slot, uint32_t offset, const pcan_boot_byte_t *data, pcan_boot_byte_t length); /* Сохраняет октеты ProtoCAN в x16 NOR младшим байтом вперёд. */
pcan_boot_status_t Boot2812_Verify(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *image); /* Проверяет CRC прочитанной NOR и все CPU-адреса SCI8 до COMMIT. */
bool Boot2812_Commit(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *image); /* Публикует manifest только после повторной проверки всей внешней Flash. */
bool Boot2812_Load(uint32_t *entry); /* Читает действующий manifest, проверяет образ и переносит только разрешённую RAM. */
#endif /* Завершает интерфейс самостоятельного NOR-порта F2812. */
@@ -0,0 +1,105 @@
#include "boot2812.h" /* Использует отдельные адреса и совместимость внешней NOR F2812. */
static unsigned int octet(uint32_t offset) /* Читает октет файла SCI8 из x16 NOR, где младший октет хранится первым. */
{ /* Поток CAN остаётся независимым от sizeof(char) на C28x. */
unsigned int word = Boot2812_NorRead(BOOT2812_IMAGE_WORD + offset / 2UL); /* Преобразует смещение в октетах в CPU word-адрес слота. */
return (offset & 1UL) ? word >> 8 : word & 255U; /* Передаёт младшие восемь бит октета без знакового расширения. */
} /* Все дальнейшие поля таблицы собираются из того же порядка октетов. */
static unsigned int u16(uint32_t offset) /* Восстанавливает слово TI boot table в little endian. */
{ /* Вызывается только после проверки достаточной длины соответствующего поля. */
return octet(offset) | (octet(offset + 1UL) << 8); /* Два октета соответствуют одному слову C28x. */
} /* Завершает чтение длины секции или данных программы. */
static uint32_t address_at(uint32_t offset) /* Адрес TI SCI8 содержит старшее 16-битное слово перед младшим. */
{ /* Этот порядок отличается от обычного u32 little endian метаданных ProtoCAN. */
return ((uint32_t)u16(offset) << 16) | u16(offset + 2UL); /* Внутри каждого слова по-прежнему сохраняется little endian. */
} /* Возвращает CPU-адрес, измеряемый в словах. */
static bool allowed(uint32_t first, uint32_t end) /* Разрешает только реальную RAM приложения и исключает RAM работающего загрузчика. */
{ /* Новое приложение не должно загружать инициализированные секции в L1 или RAM InitFlash до перехода в runtime. */
return end > first && ((first >= 0x8000UL && end <= 0x8F00UL) || (first >= 0x3F8000UL && end <= 0x3FA000UL) || (first >= 0x80000UL && end <= 0x100000UL)); /* L0 до ramfuncs, полный H0 и внешняя SRAM зоны 2; периферия, NOR, стек и внутренние Flash запрещены. */
} /* Проверки входа и всех секций выполняются до первой записи приложения в RAM. */
static bool table(uint32_t size, bool copy, uint32_t *entry) /* Проверяет целиком SCI8 и при повторном проходе переносит данные в RAM. */
{ /* Устойчивость загрузчика не зависит от адресов, заявленных принимаемым файлом. */
uint32_t starts[64], ends[64], offset = 22UL, address, end; /* Лимит 64 секции ограничивает стек и число сравнений перекрытий. */
unsigned int sections = 0U, count, i; bool entry_loaded = false; /* Требует, чтобы точка входа реально находилась среди загружаемых слов. */
if (size < 24UL || (size & 1UL) || u16(0UL) != 0x08AAU) return false; /* Ключ SCI8 AA08, чётный размер и терминатор обязательны. */
*entry = address_at(18UL); /* После ключа и восьми резервных слов находится CPU word-адрес C runtime. */
while (offset + 2UL <= size) { /* Поле count читается только при наличии обоих октетов. */
count = u16(offset); offset += 2UL; /* Размер секции выражен в 16-битных словах, а не октетах файла. */
if (!count) return offset == size && entry_loaded; /* Запрещает хвост, незавершённую таблицу и entry вне payload. */
if (sections == 64U || size - offset < 4UL) return false; /* Не допускает переполнения ограниченных массивов или усечённого адреса. */
address = address_at(offset); offset += 4UL; end = address + count; /* Восстанавливает исключающую верхнюю границу CPU-диапазона секции. */
if (!allowed(address, end) || (uint32_t)count * 2UL > size - offset) return false; /* Проверяет адреса и полный payload до обращения к RAM назначения. */
for (i = 0; i < sections; ++i) if (address < ends[i] && starts[i] < end) return false; /* Даже правильно переданная CRC не разрешает две секции поверх одного слова. */
starts[sections] = address; ends[sections++] = end; /* Сохраняет уже проверенный диапазон для следующих секций. */
if (*entry >= address && *entry < end) entry_loaded = true; /* Подтверждает наличие исполняемого слова по адресу входа. */
if (copy) { /* Этот проход выполняется только после полной read-only проверки всего образа. */
for (i = 0; i < count; ++i) { /* Переносит ровно заявленные и предварительно проверенные слова секции. */
#if defined(BOOT2812_HOST) /* Аппаратная модель проверяет тот же диапазон без записи по адресам процесса ПК. */
extern void NorModel_LoadWord(uint32_t target, unsigned int value); /* Модель сохраняет каждое слово переноса для независимой проверки. */
NorModel_LoadWord(address + i, u16(offset + (uint32_t)i * 2UL)); /* Подменяет только шину RAM назначения. */
#else /* На F2812 CPU-адреса уже выражены в 16-битных словах. */
*(volatile unsigned int *)(address + i) = u16(offset + (uint32_t)i * 2UL); /* Записывает секцию только в разрешённую RAM приложения. */
#endif /* Завершает аппаратную запись либо её host-модель. */
} /* Завершает перенос текущей секции. */
} /* После проверочного прохода RAM остаётся нетронутой. */
offset += (uint32_t)count * 2UL; /* Пропускает полезные октеты до следующего count. */
} /* Исчерпание файла без терминатора означает неполный образ. */
return false; /* Не запускает незавершённую таблицу. */
} /* Образ с ошибкой не публикуется как запускаемый. */
bool Boot2812_Erase(void *user, pcan_boot_byte_t slot) /* Реализует single-slot подготовку внешней NOR. */
{ /* Существующие legacy-образы и FPGA ниже 160000 не входят в новый CAN-раздел. */
unsigned long sector; (void)user; /* Перебирает только три полных обычных сектора нового образа. */
if (slot || !Boot2812_NorIdentify() || !Boot2812_NorErase(BOOT2812_META_WORD)) return false; /* Сначала удаляет marker старого CAN-образа; при обрыве стирания сохраняется recovery. */
for (sector = BOOT2812_IMAGE_WORD; sector < BOOT2812_IMAGE_WORD + BOOT2812_IMAGE_BYTES / 2UL; sector += 0x8000UL) if (!Boot2812_NorErase(sector)) return false; /* Геометрия x16 допускает erase только по границам обычных секторов 32K слов. */
return true; /* Ядро ProtoCAN разрешает DATA только после полного успешного стирания слота. */
} /* EEPROM-операции и несуществующий второй слот отсутствуют. */
bool Boot2812_Write(void *user, pcan_boot_byte_t slot, uint32_t offset, const pcan_boot_byte_t *data, pcan_boot_byte_t length) /* Упаковывает поступившие октеты в x16 слова NOR. */
{ /* В одном вызове записывается не более одного classic CAN кадра. */
unsigned int i, word; (void)user; /* Счётчик относится к октетам кадра, адрес NOR отдельно делится на два. */
if (slot || !length || length > 8U || (offset & 1UL) || offset > BOOT2812_IMAGE_BYTES || length > BOOT2812_IMAGE_BYTES - offset) return false; /* Не допускает выхода из слота либо продолжения слова с неверного октета. */
for (i = 0; i < length; i += 2U) { /* Последовательные 8-октетные блоки начинаются на границе x16 слова. */
word = (data[i] & 255U) | ((i + 1U < length ? data[i + 1U] & 255U : 255U) << 8); /* Неполное последнее слово сохраняет FF в незанятом старшем октете. */
if (!Boot2812_NorProgram(BOOT2812_IMAGE_WORD + (offset + i) / 2UL, word)) return false; /* Аппаратный драйвер проверяет и допустимый адрес, и результат записи каждого слова. */
} /* Завершает сохранение текущего CAN-блока. */
return true; /* ACK означает проверенную запись, а не только получение кадра. */
} /* CRC ядра продвигается только после успешного возврата этого callback. */
pcan_boot_status_t Boot2812_Verify(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *image) /* Перепроверяет CRC непосредственно из сохранённой NOR. */
{ /* Потоковая CRC при приёме не заменяет аппаратный readback полного файла. */
uint32_t offset, crc = 0UL, entry; pcan_boot_byte_t bytes[32]; unsigned int count, i; (void)user; /* Небольшой буфер не требует размещать весь образ во внутренней RAM F2812. */
if (slot || image->image_size < 24UL || image->image_size > BOOT2812_IMAGE_BYTES || (image->image_size & 1UL)) return PCAN_BOOT_STATUS_INVALID_SIZE; /* SCI8 должен целиком помещаться в выделенных трёх секторах и содержать целые слова. */
if (image->product_type != BOOT2812_PRODUCT || image->hardware_revision_min > 1U || image->hardware_revision_max < 1U) return PCAN_BOOT_STATUS_WRONG_DEVICE; /* Образ F28335 или несовместимого изделия не становится загрузочным. */
for (offset = 0; offset < image->image_size; offset += count) { /* Проверяет каждый фактически сохранённый октет ровно один раз. */
count = image->image_size - offset < 32UL ? (unsigned int)(image->image_size - offset) : 32U; /* Последний буфер ограничен реальной длиной без FF-дополнения CAN. */
for (i = 0; i < count; ++i) bytes[i] = octet(offset + i); /* Читает данные из NOR, а не из приёмной очереди CAN. */
crc = pcan_boot_crc32_update(crc, bytes, count); /* Использует общий CRC32 ProtoCAN без дублирования полинома в аппаратном порту. */
Boot2812_Busy(); /* Большой файл сохраняет ответы клиента при длинной проверке на реальном CPU. */
} /* Завершает вычисление CRC readback. */
if (crc != image->image_crc32) return PCAN_BOOT_STATUS_CRC_ERROR; /* Различает повреждение памяти и ошибку структуры SCI8. */
return table(image->image_size, false, &entry) ? PCAN_BOOT_STATUS_OK : PCAN_BOOT_STATUS_INVALID_STATE; /* Все адреса, перекрытия, терминатор и entry проверяются до COMMIT. */
} /* До успеха verifier никакие слова приложения не переносятся в RAM. */
bool Boot2812_Commit(void *user, pcan_boot_byte_t slot, const pcan_boot_manifest_t *image) /* Публикует загрузочный manifest последней операцией после readback. */
{ /* Формат из 12 слов фиксирован и не зависит от sizeof C-структуры. */
unsigned int words[12], i; /* Два magic-слова, версия формата, размер, CRC, версия FW и контроль manifest. */
pcan_boot_byte_t bytes[20]; uint32_t crc; /* CRC первых десяти слов защищает размер и контрольную сумму самого образа. */
if (Boot2812_Verify(user, slot, image) != PCAN_BOOT_STATUS_OK) return false; /* Не публикует файл, испорченный после предыдущего VERIFY. */
words[0] = 0x2812U; words[1] = 0xCA7EU; words[2] = 1U; words[3] = 0U; /* Magic 2812/CA7E и версия 1 отличают новый CAN manifest от прежних данных платы. */
words[4] = (unsigned int)(image->image_size & 0xFFFFUL); words[5] = (unsigned int)(image->image_size >> 16); /* Длина выражена октетами и хранится младшим словом первой. */
words[6] = (unsigned int)(image->image_crc32 & 0xFFFFUL); words[7] = (unsigned int)(image->image_crc32 >> 16); /* Сохраняет точную CRC всего полученного файла. */
words[8] = (unsigned int)(image->firmware_version & 0xFFFFUL); words[9] = (unsigned int)(image->firmware_version >> 16); /* Версия кандидата не подменяется версией постоянного загрузчика. */
for (i = 0; i < 10U; ++i) { bytes[2U * i] = words[i] & 255U; bytes[2U * i + 1U] = words[i] >> 8; } /* Wire-представление manifest использует октеты независимо от ширины C28x char. */
crc = pcan_boot_crc32_update(0UL, bytes, 20U); words[10] = (unsigned int)(crc & 0xFFFFUL); words[11] = (unsigned int)(crc >> 16); /* CRC manifest не позволяет принять частично записанные поля размера и CRC образа. */
for (i = 2U; i < 12U; ++i) if (!Boot2812_NorProgram(BOOT2812_META_WORD + i, words[i])) return false; /* Сначала записывает все поля, пока оба magic-слова ещё равны FF. */
if (!Boot2812_NorProgram(BOOT2812_META_WORD + 1UL, words[1])) return false; /* Второе magic-слово фиксируется после полного тела manifest. */
return Boot2812_NorProgram(BOOT2812_META_WORD, words[0]); /* Первое magic записывается последним: потеря питания раньше оставляет recovery. */
} /* Повтор COMMIT обрабатывает идемпотентный автомат общего ядра. */
bool Boot2812_Load(uint32_t *entry) /* Проверяет опубликованный образ после reset перед переносом в RAM приложения. */
{ /* Пустой или повреждённый manifest оставляет прибор в постоянном CAN recovery. */
unsigned int words[12], i; pcan_boot_byte_t bytes[20]; uint32_t crc; pcan_boot_manifest_t image; /* Сериализованные поля читаются явно, без memcpy по ABI структуры. */
for (i = 0; i < 12U; ++i) words[i] = Boot2812_NorRead(BOOT2812_META_WORD + i); /* Читает только фиксированные 24 октета manifest. */
if (words[0] != 0x2812U || words[1] != 0xCA7EU || words[2] != 1U || words[3]) return false; /* Не интерпретирует старые данные Flash либо неполный commit как запускаемый файл. */
for (i = 0; i < 10U; ++i) { bytes[2U * i] = words[i] & 255U; bytes[2U * i + 1U] = words[i] >> 8; } /* Восстанавливает то же октетное представление, что защищалось при COMMIT. */
crc = pcan_boot_crc32_update(0UL, bytes, 20U); /* Проверяет метаданные до использования объявленной ими длины. */
if (crc != ((uint32_t)words[10] | ((uint32_t)words[11] << 16))) return false; /* Повреждённый размер не может вывести чтение за пределы CAN-слота. */
image.image_size = (uint32_t)words[4] | ((uint32_t)words[5] << 16); image.image_crc32 = (uint32_t)words[6] | ((uint32_t)words[7] << 16); /* Размер и CRC файла восстанавливаются только после успешной CRC manifest. */
image.firmware_version = (uint32_t)words[8] | ((uint32_t)words[9] << 16); image.product_type = BOOT2812_PRODUCT; image.hardware_revision_min = image.hardware_revision_max = 1U; /* Профиль образа был проверен до публикации manifest. */
return Boot2812_Verify(0, 0U, &image) == PCAN_BOOT_STATUS_OK && table(image.image_size, true, entry); /* Сначала полный read-only проход, затем перенос и только после успеха разрешение вызова entry. */
} /* Не загружает старые flat BIN автоматически: новый проект использует проверяемую SCI8-таблицу. */
@@ -0,0 +1,69 @@
#include "boot2812.h" /* Ограничивает аппаратный драйвер разделами обновления конкретного профиля ПМ67. */
#if defined(BOOT2812_HOST) /* Host-модель воспроизводит команды NOR без обращения к физическим CPU-адресам. */
extern unsigned int NorModel_Read(unsigned long word); /* Модель отдаёт данные, ID и аппаратные биты готовности чипа. */
extern void NorModel_Write(unsigned long word, unsigned int value); /* Модель принимает настоящую последовательность unlock/program/erase драйвера. */
#define NOR_READ(word) NorModel_Read(word) /* Подменяет только чтение шины, сохраняя алгоритм драйвера. */
#define NOR_WRITE(word, value) NorModel_Write(word, value) /* Подменяет физическую запись при проверке границ и отказов. */
#else /* Production использует 16-битную параллельную XINTF-шину. */
#define NOR_READ(word) (*(volatile unsigned int *)(word)) /* Один CPU-адрес C28x соответствует одному x16 слову AM29LV800BT. */
#define NOR_WRITE(word, value) (*(volatile unsigned int *)(word) = (value)) /* Volatile сохраняет каждый командный цикл AMD в исходном порядке. */
#endif /* Завершает выбор физической шины либо модели. */
static void reset_read(void) /* Выводит чип из autoselect либо неудачной операции в обычный режим чтения. */
{ /* Reset не стирает слова памяти и допустим по любому адресу чипа. */
NOR_WRITE(BOOT2812_NOR_BASE, 0x00F0U); /* F0 — Read/Reset из таблицы команд AMD Am29LV800B. */
} /* Все ошибки возвращают NOR в состояние, пригодное для следующей recovery-сессии. */
static void unlock(unsigned int command) /* Выполняет общий префикс x16-команд согласно datasheet AMD. */
{ /* Адреса ниже являются смещениями в словах, а не октетными AAA/555 режима x8. */
NOR_WRITE(BOOT2812_NOR_BASE + 0x555UL, 0x00AAU); /* Первый unlock-цикл AA по смещению 555h в режиме x16. */
NOR_WRITE(BOOT2812_NOR_BASE + 0x2AAUL, 0x0055U); /* Второй unlock-цикл 55 по смещению 2AAh. */
NOR_WRITE(BOOT2812_NOR_BASE + 0x555UL, command); /* Третий цикл выбирает autoselect, программирование либо начало стирания. */
} /* Последующий цикл данных или адрес сектора выполняет вызывающая операция. */
unsigned int Boot2812_NorRead(unsigned long word) /* Читает только физический диапазон установленной NOR ёмкостью 1 МиБ. */
{ /* Верхняя исключающая граница равна BASE + 512K слов. */
return word >= BOOT2812_NOR_BASE && word < BOOT2812_NOR_BASE + 0x80000UL ? NOR_READ(word) : 0xFFFFU; /* Вне чипа не создаёт шинного чтения по неизвестному адресу. */
} /* Возвращает полное x16 слово без перестановки октетов. */
bool Boot2812_NorIdentify(void) /* Идентификация обязательна перед разрешением изменяющих операций. */
{ /* Не подменяет top-boot геометрию похожим bottom-boot или NAND-чипом. */
unsigned int maker, device; /* Хранит два слова autoselect, прежде чем вернуть чип к чтению. */
reset_read(); unlock(0x0090U); /* 90h включает чтение manufacturer/device ID после обычного unlock. */
maker = NOR_READ(BOOT2812_NOR_BASE); device = NOR_READ(BOOT2812_NOR_BASE + 1UL); /* AMD: offset 0 содержит 0001, offset 1 — 22DA для Am29LV800BT x16. */
reset_read(); /* Обычные чтения образа после проверки не должны видеть таблицу autoselect. */
return maker == 0x0001U && device == 0x22DAU; /* Отличающийся чип получает отказ до первого sector erase. */
} /* Не выполняет разрушительных пробных записей для определения типа памяти. */
static bool wait_word(unsigned long word, unsigned int expected, unsigned long timeout) /* Ограничивает DQ7/DQ5 polling временем и числом проходов. */
{ /* DQ7 отражает готовность программируемого старшего бита; DQ5 требует завершающего повторного чтения. */
unsigned long started = Boot2812_Now(), budget = 50000000UL; /* Итерационный предел обеспечивает выход даже при остановленном Timer1. */
unsigned int value; /* Снимок status считывается один раз на основной проход. */
do { /* Не вызывает никаких функций из программируемой внешней NOR: код загрузчика находится во внутренней Flash. */
value = NOR_READ(word); /* Читает именно адрес программирования либо начало стираемого сектора. */
if ((value & 0x0080U) == (expected & 0x0080U)) return NOR_READ(word) == expected; /* После совпадения DQ7 подтверждает все 16 бит результата. */
if (value & 0x0020U) { /* DQ5 сообщает превышение внутреннего времени алгоритма AMD. */
if ((NOR_READ(word) & 0x0080U) == (expected & 0x0080U)) return NOR_READ(word) == expected; /* Повтор исключает нормальное завершение операции одновременно с чтением DQ5. */
break; /* После подтверждённой ошибки больше не ждёт неопределённое время. */
} /* Завершает трактовку аппаратного статуса текущего прохода. */
Boot2812_Busy(); /* Долгое стирание продолжает давать клиенту живой ответ и не блокирует CAN ISR. */
} while (--budget && Boot2812_Now() - started < timeout); /* Беззнаковое вычитание сохраняет корректность при переполнении миллисекунд. */
reset_read(); /* Отказ возвращает чип в режим чтения перед следующей recovery-попыткой. */
return false; /* Не сообщает успех по одному окончанию тайм-аута. */
} /* Завершает ограниченное ожидание аппаратной операции. */
bool Boot2812_NorProgram(unsigned long word, unsigned int value) /* Программирует только выделенный CAN-образ либо manifest. */
{ /* Старые данные приложения, FPGA и остальные сектора чипа не входят в разрешённые диапазоны. */
unsigned int before; /* Предварительное чтение исключает попытку перевода NOR-бита из нуля в единицу. */
if (!((word >= BOOT2812_IMAGE_WORD && word < BOOT2812_IMAGE_WORD + BOOT2812_IMAGE_BYTES / 2UL) || (word >= BOOT2812_META_WORD && word < BOOT2812_META_WORD + 0x2000UL))) return false; /* Проверяет word-адрес до любого unlock или командного цикла. */
before = NOR_READ(word); /* Проверяет текущее содержимое перед началом операции. */
if (before == value) return true; /* Повтор одинакового блока не выполняет лишнее программирование. */
if ((before & value) != value) return false; /* Бит 0→1 требует отдельного sector erase и не должен маскироваться чтением старого слова. */
unlock(0x00A0U); NOR_WRITE(word, value); /* A0 запускает word program; следующий цикл содержит адрес и полные 16 бит данных. */
return wait_word(word, value, 100UL); /* Сто миллисекунд дают ограниченный запас для программирования одного слова. */
} /* Каждый успех означает фактическое совпадение прочитанного слова. */
bool Boot2812_NorErase(unsigned long word) /* Не принимает произвольный адрес или команду полного стирания чипа. */
{ /* Обновление ограничено секторами 12/13/14 и последним top-boot сектором 18. */
unsigned long i, count = word == BOOT2812_META_WORD ? 0x2000UL : 0x8000UL; /* AM29LV800BT: обычный сектор 32K слов, последний boot-сектор 8K слов. */
if (!(word == BOOT2812_IMAGE_WORD || word == BOOT2812_IMAGE_WORD + 0x8000UL || word == BOOT2812_IMAGE_WORD + 0x10000UL || word == BOOT2812_META_WORD)) return false; /* Только точные разрешённые начала секторов исключают округление в соседнюю область. */
unlock(0x0080U); /* 80h начинает шеститактовую последовательность Sector Erase AMD. */
NOR_WRITE(BOOT2812_NOR_BASE + 0x555UL, 0x00AAU); NOR_WRITE(BOOT2812_NOR_BASE + 0x2AAUL, 0x0055U); /* Повторяет вторую unlock-пару перед выбором сектора. */
NOR_WRITE(word, 0x0030U); /* 30h по sector address выбирает один сектор; команда Chip Erase 10h отсутствует. */
if (!wait_word(word, 0xFFFFU, 20000UL)) return false; /* Ограничивает ожидание двадцатью секундами с периодическими BUSY-ответами. */
for (i = 0; i < count; ++i) if (NOR_READ(word + i) != 0xFFFFU) return false; /* Проверяет всю стёртую область, а не только её первое слово. */
return true; /* Разрешает запись лишь после полного аппаратного readback сектора. */
} /* При сбое сохранённый manifest уже недействителен, загрузчик остаётся в recovery. */
+88 -12
View File
@@ -1,18 +1,55 @@
# F28335 + M95M02: CAN, отдельный загрузчик и A/B # F28335 + M95M02: CAN, отдельный загрузчик и A/B
Реализация состоит из Flash-загрузчика `periph_167/Bootloader`, переносимого Реализация состоит из Flash-загрузчика `projects/ccs/f28335`, переносимого
`f28335_boot_store.c`, аппаратного `f28335_boot_hw.c` и адаптера `f28335_boot_store.c`, аппаратного `f28335_boot_hw.c` и адаптера
`f28335_can_boot.c`. Приложение подключает их через `Source/Internal/can_boot.c`. `f28335_can_boot.c`. Приложение подключает общий `f28335_can_application.c`
прямой ссылкой linked resource из templates в CCS Debug/Release.
В сборке `EEPROM_M95M02=0` CAN Boot отключён. Для установленной M95M02 — значение 1. В сборке `EEPROM_M95M02=0` CAN Boot отключён. Для установленной M95M02 — значение 1.
## Адрес и формат ## Адрес и формат
Device Type **3**, Device ID **7**, имя **F28335-M95M02**, Product **0x2833**, HW **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`; В приложении FW берётся из `firmware_version.h`, формат `major<<24 | minor<<16 | patch`;
для версии 1.1.2 это `0x01010002`. Загрузчик сообщает версию подтверждённого образа для версии 1.1.2 это `0x01010002`. Загрузчик сообщает версию подтверждённого образа
из журнала, при отсутствии такого образа — 0. Версия кандидата передаётся в BEGIN_COMPAT. из журнала, при отсутствии такого образа — 0. Версия кандидата передаётся в BEGIN_COMPAT.
CAN **250000 бит/с**, Extended ID, окно **16 блоков по 8 октетов**. CAN **250000 бит/с**, Extended ID, окно **16 блоков по 8 октетов**.
ENTER_BOOT для session=1: `0x13790102`, STATUS: `0x1B7C0102`. Для задатчика и 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 байт** включительно. Образ — SCI8 BIN (`AA 08`), чётная длина от 24 до **130560 байт** включительно.
Числа в протоколе little endian. Адреса внутри SCI8: сначала старшее 16-битное Числа в протоколе little endian. Адреса внутри SCI8: сначала старшее 16-битное
@@ -106,7 +143,7 @@ Python API: `protocan.can_boot.CanBootServices` — запросы и разбо
## Аппаратная интеграция ## Аппаратная интеграция
MBOX3 — адресные входящие Boot; MBOX4 — ответы; MBOX6 — точный broadcast discovery. MBOX3 — адресные входящие Boot; MBOX4 — ответы; MBOX6 — точный broadcast discovery.
MBOX0..2 сохраняют legacy/UMP, MBOX5 остаётся heartbeat. ISR помещает сообщения MBOX0..2 сохраняют legacy/UMP, MBOX5 загрузчик не использует. ISR помещает сообщения
в очередь на 31 кадр. Чужие адреса, RTR и неподходящие типы отбрасываются до очереди. в очередь на 31 кадр. Чужие адреса, RTR и неподходящие типы отбрасываются до очереди.
При переполнении/потере mailbox сессия отменяется; повторная запись начинается заново. При переполнении/потере mailbox сессия отменяется; повторная запись начинается заново.
SPI-драйвер загрузчика имеет ограничение ожидания байта и WIP, 24-битный адрес, SPI-драйвер загрузчика имеет ограничение ожидания байта и WIP, 24-битный адрес,
@@ -118,7 +155,31 @@ SPI-драйвер загрузчика имеет ограничение ожи
Его RAM — 0xE000..0xFFFF; стек — 0x400..0x7FF. Приложение M95M02 использует Его RAM — 0xE000..0xFFFF; стек — 0x400..0x7FF. Приложение M95M02 использует
0x8000..0xD7FF для кода, 0xD800..0xDFFF для констант/инициализации, 0x8000..0xD7FF для кода, 0xD800..0xDFFF для констант/инициализации,
0xE000..0xFFFF для .ebss после перехода в C runtime. Linker резервирует 0xE000..0xFFFF для .ebss после перехода в C runtime. Linker резервирует
NOINIT handoff в обоих проектах. CAN не содержит операций записи внутренней Flash. NOINIT handoff в обоих проектах. TI Flash API временно использует RAM
`0x8000..0x97FF` до запуска приложения. В обновлённом постоянном загрузчике
CAN также записывает внутреннюю Flash приложения B–H; сектор A защищён.
## Внутренняя Flash по CAN
После ENTER_BOOT клиент явно отправляет SELECT_MEMORY (`0x10`, DLC=1,
DATA[0]=1) до BEGIN_IMAGE/BEGIN_COMPAT. Новая сессия по умолчанию использует
EEPROM A/B, поэтому старые клиенты сохраняют прежнее поведение. Выбор памяти
после метаданных запрещён; старый boot отвечает INVALID_COMMAND до ERASE.
CAPABILITIES bit 12 обозначает поддержку записи внутренней Flash.
Flash SCI8 с FAB1 передаётся в неактивный EEPROM-слот как staging. VERIFY
проверяет CRC32 EEPROM, таблицу, непересекающиеся адреса только B–H и FAB1/CRC
будущей Flash. COMMIT повторяет проверку staging, вызывает официальный TI API
со стиранием `0x00FE`, пишет и проверяет данные порциями до 128 слов, публикует
FAB1 последним и проверяет CRC физической Flash. ACK COMMIT приходит после
записи; клиент даёт до 180 секунд и затем отправляет отдельный REBOOT.
EEPROM active и параметры сохраняются; прежний неактивный образ заменяется staging.
В SETGUI: «Прошивка → CAN / ProtoCAN Boot → ProtoCAN: память прошивки →
Внутренняя Flash F28335», файл `*_flash_rs.bin` существующего выпуска.
Сначала требуется обновить постоянный `F28335_CAN_AB.out` через JTAG с маской
только сектора A. В Debug/Release подключён установленный TI Flash API v2.10;
его код и таблицы копируются в RAM перед занятостью общего банка Flash A–H.
## Первичная установка ## Первичная установка
@@ -126,10 +187,13 @@ NOINIT handoff в обоих проектах. CAN не содержит опе
Старые BIN/OUT автоматически не заменены. Приложение должно содержать интеграцию Старые BIN/OUT автоматически не заменены. Приложение должно содержать интеграцию
READY/CONFIRM, иначе на следующем reset оно останется неподтверждённым кандидатом. READY/CONFIRM, иначе на следующем reset оно останется неподтверждённым кандидатом.
2. Собрать отдельный загрузчик TI C2000 COFF compiler: 2. Собрать отдельный загрузчик TI C2000 COFF compiler:
`Bootloader/build.ps1 -CompilerRoot <путь-к-ti-cgt-c2000>`. `python c/protocan-boot/projects/build.py --device f28335 --compiler <путь-к-ti-cgt-c2000>`.
Результат — `Bootloader/build/F28335_CAN_AB.out` и MAP. Результат — `projects/ccs/f28335/Debug/F28335_CAN_AB.out` и MAP.
3. Один раз установить этот OUT через JTAG и выбрать аппаратный Flash boot 3. Установить обновлённый OUT через JTAG и выбрать аппаратный Flash boot
согласно схеме платы. Не загружать поверх него старый application OUT с согласно схеме платы. При переходе с общего адреса 3/7 обновить и приложение,
и загрузчик: старый загрузчик не перейдёт на новый адрес после reset сам.
В SETCAN выбрать «Прошивка → CAN / ProtoCAN Boot → Устройство PERIPH»
и нужное назначение. Не загружать поверх загрузчика старый application OUT с
секцией codestart во Flash. секцией codestart во Flash.
4. После reset пустая EEPROM или старая разметка автоматически ведут в CAN recovery. 4. После reset пустая EEPROM или старая разметка автоматически ведут в CAN recovery.
Передать новое приложение через ProtoCAN Boot, дождаться пробного запуска и Передать новое приложение через ProtoCAN Boot, дождаться пробного запуска и
@@ -145,8 +209,10 @@ NOINIT handoff в обоих проектах. CAN не содержит опе
ядро, приложение/загрузчик, wide-octet режим, журнал, обрыв публикации на каждом ядро, приложение/загрузчик, wide-octet режим, журнал, обрыв публикации на каждом
из 69 возможных положений, пробный запуск, CONFIRM, откат, SCI8 и границы памяти. из 69 возможных положений, пробный запуск, CONFIRM, откат, SCI8 и границы памяти.
Python-тесты проверяют клиентские запросы, паспорт, фильтрацию ответов и лимит A/B. Python-тесты проверяют клиентские запросы, паспорт, фильтрацию ответов и лимит A/B.
Проверка синтаксиса использует настоящие DSP2833x headers. Сборка TI/CCS, Проверка синтаксиса использует настоящие DSP2833x headers. Импорт и сборка TI/CCS,
раскладка итогового MAP и физические CAN/SPI/reset на плате ещё не подтверждены. раскладка MAP и реальные COFF LOAD-адреса проверены; физические CAN/SPI/reset
на плате требуют стендовой проверки. Отдельные проекты и команды сборки описаны
в [инструкции CCS](../../projects/README.md).
CRC32 защищает от повреждения, криптографической подписи и anti-rollback по CRC32 защищает от повреждения, криптографической подписи и anti-rollback по
версии в этом порту нет. Удалённый CONFIRM подтверждает готовность приложения, версии в этом порту нет. Удалённый CONFIRM подтверждает готовность приложения,
@@ -154,3 +220,13 @@ CRC32 защищает от повреждения, криптографичес
Аппаратный формат SPI boot описан в [TI Boot ROM Reference Guide](https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/171/2742.Boot-ROM.pdf). Аппаратный формат 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 выполняет этот загрузчик. В 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-приложение.
@@ -1,6 +1,7 @@
#ifndef F28335_BOOT_PLATFORM_H #ifndef F28335_BOOT_PLATFORM_H
#define F28335_BOOT_PLATFORM_H #define F28335_BOOT_PLATFORM_H
#include "f28335_boot_store.h" #include "f28335_boot_store.h"
#include "f28335_flash_app.h" /* Общий handoff различает EEPROM A/B, защищённое Flash-приложение и неизвестный запуск. */
#ifndef F28335_BOOT_LOADER #ifndef F28335_BOOT_LOADER
#define F28335_BOOT_LOADER 0 #define F28335_BOOT_LOADER 0
#endif #endif
@@ -0,0 +1,10 @@
#include "f28335_can_application_config.h" /* Получает от проекта разрешение CAN A/B и версию приложения; этот конфигурационный заголовок должен находиться в include paths CCS. */
#ifndef F28335_CAN_BOOT_APPLICATION_ENABLED /* Отсутствующее аппаратное решение нельзя трактовать как разрешение записи служебных областей EEPROM. */
#error "Define F28335_CAN_BOOT_APPLICATION_ENABLED in f28335_can_application_config.h" /* Останавливает сборку до появления приложения с неполной интеграцией загрузчика. */
#endif /* Завершает проверку обязательного конфигурационного признака проекта. */
#if F28335_CAN_BOOT_APPLICATION_ENABLED /* Самостоятельный Flash-образ и платы без M95M02 исключают весь CAN A/B-код на этапе компиляции. */
#include "../../src/pcan_boot.c" /* Компилирует единственный автомат команд ProtoCAN Boot с его штатными сессиями, CRC32 и проверкой последовательности пакетов. */
#include "f28335_boot_store.c" /* Подключает общий A/B-журнал, readback, проверку SCI8 и выбор подтверждённого слота той же версии templates. */
#include "f28335_boot_hw.c" /* Предоставляет SPI EEPROM, watchdog и согласованный handoff между приложением и постоянным Flash-загрузчиком. */
#include "f28335_can_boot.c" /* В режиме приложения обслуживает вход в boot и READY/CONFIRM, сохраняя служебные mailbox 3/4/6 отдельно от технологического CAN. */
#endif /* Постоянный загрузчик собирается отдельным CCS-проектом templates с F28335_BOOT_LOADER=1, а не этим прикладным модулем. */
@@ -8,6 +8,21 @@
* Сброс сессии не удаляет active/pending из EEPROM. */ * Сброс сессии не удаляет active/pending из EEPROM. */
static pcan_boot_t boot; static pcan_boot_t boot;
static f28335_boot_store_t store; static f28335_boot_store_t store;
static unsigned int healthy; /* Результат открытия EEPROM-журнала известен также функции выбора назначения Flash. */
#if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* Flash API доступен только постоянному загрузчику с явной поддержкой обновления B–H. */
#include "f28335_flash_update.h" /* Подключает проверку Flash SCI8 и аппаратный writer с сохранением сектора A. */
#include "f28335_flash_update.c" /* Общий алгоритм компилируется с тем же pcan_boot и разметкой, что этот порт. */
static f28335_flash_update_t flash_update; /* Индекс и кеш занимают ограниченную внутреннюю RAM без загрузки приложения поверх boot. */
static unsigned int flash_selected, flash_staging; /* Явная цель Flash использует только неактивный EEPROM-слот как временное хранилище. */
static pcan_boot_status_t select_memory(void *u, pcan_boot_byte_t memory, pcan_boot_config_t *cfg) /* Выбирает назначение до BEGIN_IMAGE, сохраняя прежний EEPROM-путь по умолчанию. */
{ /* Изменения конфигурации разрешены только при исправном EEPROM-журнале. */
(void)u; if (!healthy) return PCAN_BOOT_STATUS_FLASH_ERROR; /* Ошибка чтения журнала запрещает выбор staging поверх неизвестного active. */
if (memory > 1U) return PCAN_BOOT_STATUS_INVALID_COMMAND; /* Единственные определённые цели: 0=EEPROM A/B и 1=внутренняя Flash. */
flash_selected = memory; flash_update.valid = false; /* Новая цель отменяет прежнее разрешение программирования. */
cfg->slot_count = memory ? 1U : 2U; cfg->active_slot = memory ? 0U : store.active; /* CAN Flash использует один логический слот A, EEPROM сохраняет выбор неактивного A/B. */
return PCAN_BOOT_STATUS_OK; /* Физический staging будет инвалидирован лишь при последующей команде ERASE. */
} /* Никакие данные Flash или EEPROM при выборе цели не изменяются. */
#endif /* Приложение и старые host-модели не подключают Flash API. */
/* Кольцевая очередь: ISR производит кадры, main потребляет. Из 32 элементов /* Кольцевая очередь: ISR производит кадры, main потребляет. Из 32 элементов
* используется 31, чтобы head==tail однозначно означало пустую очередь. * используется 31, чтобы head==tail однозначно означало пустую очередь.
* Долгие операции SPI запрещены внутри обработчика CAN. */ * Долгие операции SPI запрещены внутри обработчика CAN. */
@@ -16,9 +31,10 @@ static struct { uint32_t id; unsigned int dlc; pcan_boot_byte_t data[8]; } queue
/* reset_requested только планирует reset; Service ждёт завершения TX. /* reset_requested только планирует reset; Service ждёт завершения TX.
* ready сообщает об окончании старта приложения, confirmed — о сохранённом * ready сообщает об окончании старта приложения, confirmed — о сохранённом
* подтверждении слота. healthy отражает результат открытия журнала при Init. */ * подтверждении слота. healthy отражает результат открытия журнала при Init. */
static unsigned int reset_requested,reset_session,ready,healthy,confirmed; static unsigned int reset_requested,reset_session,ready,confirmed; /* Состояние перехода и подтверждения приложения отделено от доступности EEPROM. */
static uint32_t sent_at,ready_at; static uint32_t sent_at,ready_at;
static unsigned int main_passes; static unsigned int main_passes;
static unsigned int addressed; /* Разрешает обслуживание только после проверки номера PERIPH и установки согласованных фильтров CAN. */
static int tx_busy,tx_canceling; static int tx_busy,tx_canceling;
/* Один исходящий mailbox исключает перезапись ещё передаваемого ответа. /* Один исходящий mailbox исключает перезапись ещё передаваемого ответа.
* MDL содержит первые четыре октета, MDH — следующие четыре, младшим вперёд. * MDL содержит первые четыре октета, MDH — следующие четыре, младшим вперёд.
@@ -48,9 +64,19 @@ static bool transmit(void *u, uint32_t id, const pcan_boot_byte_t *d, pcan_boot_
* эти callbacks возвращают отказ, даже если им удастся передать команду записи. * эти callbacks возвращают отказ, даже если им удастся передать команду записи.
* ERASE для EEPROM означает инвалидирование manifest выбранного слота. */ * ERASE для EEPROM означает инвалидирование manifest выбранного слота. */
static bool erase(void *u,pcan_boot_byte_t slot) static bool erase(void *u,pcan_boot_byte_t slot)
{ (void)u; return F28335_BOOT_LOADER && healthy && f28335_boot_prepare(&store,slot); } { /* ERASE подготавливает staging; внутренняя Flash остаётся неизменной до VERIFY и COMMIT. */
#if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* Новая цель не меняет прежний формат EEPROM A/B. */
if (flash_selected) { flash_update.valid = false; flash_staging = store.active == 0U ? 1U : 0U; return healthy && f28335_boot_prepare(&store, flash_staging); } /* Инвалидирует только неактивный слот, сохраняя подтверждённый резерв и параметры. */
#endif /* В остальных сборках остаётся штатная подготовка EEPROM-слота. */
(void)u; return F28335_BOOT_LOADER && healthy && f28335_boot_prepare(&store,slot); /* Обычный CAN-клиент сохраняет прежний путь обновления RAM-приложения. */
} /* Подготовка не вызывает TI Flash_Erase. */
static bool write_block(void *u,pcan_boot_byte_t slot,uint32_t offset,const pcan_boot_byte_t *d,pcan_boot_byte_t n) static bool write_block(void *u,pcan_boot_byte_t slot,uint32_t offset,const pcan_boot_byte_t *d,pcan_boot_byte_t n)
{ (void)u; return F28335_BOOT_LOADER && healthy && f28335_boot_write(&store,slot,offset,d,n); } { /* CAN ISR только ставит данные в очередь; запись staging выполняет main. */
#if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* Запись Flash-файла использует тот же проверенный EEPROM writer. */
if (flash_selected) return healthy && f28335_boot_write(&store, flash_staging, offset, d, n); /* Логический DATA_A направляется в выбранный неактивный физический слот. */
#endif /* Обычные A/B-данные сохраняют исходную адресацию. */
(void)u; return F28335_BOOT_LOADER && healthy && f28335_boot_write(&store,slot,offset,d,n); /* Не допускает записи из прикладной сборки. */
} /* Внутренняя Flash ещё не затронута. */
/* Проверка включает CRC EEPROM и структуру SCI8. Сейчас отказ этого слоя /* Проверка включает CRC EEPROM и структуру SCI8. Сейчас отказ этого слоя
* кодируется CRC_ERROR как общий отказ проверки образа; причины внутри * кодируется CRC_ERROR как общий отказ проверки образа; причины внутри
* парсера SCI8 отдельными статусами протокола не различаются. */ * парсера SCI8 отдельными статусами протокола не различаются. */
@@ -58,10 +84,21 @@ static pcan_boot_status_t verify(void *u,pcan_boot_byte_t slot,const pcan_boot_m
{ {
(void)u; (void)u;
if(!F28335_BOOT_LOADER || !healthy) return PCAN_BOOT_STATUS_INVALID_STATE; if(!F28335_BOOT_LOADER || !healthy) return PCAN_BOOT_STATUS_INVALID_STATE;
#if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* Для внутренней Flash нужен собственный допустимый диапазон SCI8 и обязательный FAB1. */
if (flash_selected) return f28335_flash_update_validate(&flash_update, &store.io, flash_staging ? F28335_AB_SLOT_B : F28335_AB_SLOT_A, m) ? PCAN_BOOT_STATUS_OK : PCAN_BOOT_STATUS_CRC_ERROR; /* Повторно читает EEPROM и проверяет транспортную CRC, таблицу и CRC будущей Flash до erase. */
#endif /* RAM SCI8 проходит прежнюю проверку приложения EEPROM. */
return f28335_boot_verify(&store,slot,m,0)?PCAN_BOOT_STATUS_OK:PCAN_BOOT_STATUS_CRC_ERROR; return f28335_boot_verify(&store,slot,m,0)?PCAN_BOOT_STATUS_OK:PCAN_BOOT_STATUS_CRC_ERROR;
} }
static bool commit(void *u,pcan_boot_byte_t slot,const pcan_boot_manifest_t *m) static bool commit(void *u,pcan_boot_byte_t slot,const pcan_boot_manifest_t *m)
{ (void)u; return F28335_BOOT_LOADER && healthy && f28335_boot_commit(&store,slot,m); } { /* COMMIT выполняет фактическую запись только после подтверждённой проверки образа. */
#if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* Постоянный boot остаётся вне обновляемых секторов B–H. */
if (flash_selected) { /* Синхронный TI API может работать дольше обычного интервала CAN, не создавая pending EEPROM. */
bool result = healthy && F28335Boot_FlashProgram(&flash_update); /* Итог зависит от erase, каждой порции readback и полной CRC физической Flash. */
boot.now_ms = F28335Boot_Now(); boot.last_activity_ms = boot.now_ms; return result; /* Обновляет срок сессии после аппаратной операции, чтобы штатный REBOOT не был отклонён из-за времени записи. */
} /* Ошибка записи оставляет постоянный boot доступным для нового сеанса. */
#endif /* Обычное обновление EEPROM сохраняет trial/CONFIRM. */
(void)u; return F28335_BOOT_LOADER && healthy && f28335_boot_commit(&store,slot,m); /* Публикует только RAM-образ в исходном журнале A/B. */
} /* Итоговый статус и отдельный REBOOT отправляет существующее ядро ProtoCAN. */
/* Подтверждение принадлежит приложению после READY. Загрузчик не может /* Подтверждение принадлежит приложению после READY. Загрузчик не может
* подтвердить кандидата сам: иначе исчезнет смысл проверки пробного запуска. * подтвердить кандидата сам: иначе исчезнет смысл проверки пробного запуска.
* Разрешение кормления watchdog из ISR открываем только после записи журнала. */ * Разрешение кормления watchdog из ISR открываем только после записи журнала. */
@@ -82,9 +119,14 @@ static unsigned int enter(void *u,pcan_boot_byte_t session)
{ {
(void)u; (void)u;
if(!healthy) return 2; if(!healthy) return 2;
if(F28335_BOOT_LOADER) return 0; if(F28335_BOOT_LOADER) { /* Постоянный загрузчик открывает сессию без дополнительного reset. */
#if F28335_CAN_FLASH_UPDATE /* Каждая новая сессия должна начинаться со штатного EEPROM-назначения. */
if (boot.state == PCAN_BOOT_STATE_IDLE) (void)select_memory(0, 0U, &boot.config); /* Повторный ENTER текущей сессии не меняет уже выбранную Flash. */
#endif /* Старые сборки не используют переключение назначения. */
return 0; /* Ядро отправит адресный ACK готовности. */
} /* Прикладной handoff проверяется ниже. */
/* No destructive fallback on boards still starting through the SPI ROM. */ /* No destructive fallback on boards still starting through the SPI ROM. */
if(F28335Boot_RunningSlot()>1 || !confirmed) return 2; if((F28335Boot_RunningSlot()>1 && F28335Boot_RunningSlot()!=F28335_BOOT_FLASH_SLOT) || !confirmed) return 2; /* Только handoff общего загрузчика разрешает переход из EEPROM либо защищённой внутренней Flash; старый SPI-ROM старт остаётся запрещён. */
reset_session=session; reset_requested=1; return 1; reset_session=session; reset_requested=1; return 1;
} }
static void info32(pcan_boot_byte_t *p,uint32_t v) static void info32(pcan_boot_byte_t *p,uint32_t v)
@@ -95,18 +137,21 @@ static void info32(pcan_boot_byte_t *p,uint32_t v)
* 2 — active/pending/attempted/healthy/тайм-аут, 3 — область параметров. */ * 2 — active/pending/attempted/healthy/тайм-аут, 3 — область параметров. */
static bool info(void *u,pcan_boot_byte_t command,pcan_boot_byte_t page,pcan_boot_byte_t *out) static bool info(void *u,pcan_boot_byte_t command,pcan_boot_byte_t page,pcan_boot_byte_t *out)
{ {
static const char name[]=F28335_CAN_BOOT_DEVICE_NAME; const char *name=boot.config.device_type==1U && boot.config.device_id==8U?"Zadatchik":boot.config.device_type==1U && boot.config.device_id==5U?"UMP1":boot.config.device_type==1U && boot.config.device_id==6U?"UMP2":F28335_CAN_BOOT_DEVICE_NAME; /* Паспорт различает три назначенных Excel устройства; резервные номера сохраняют аппаратное имя. */
unsigned int i,index; (void)u; unsigned int i,index,name_size=(unsigned int)strlen(name)+1U; (void)u; /* Длина включает завершающий NUL, чтобы последняя страница имени однозначно завершала чтение. */
if(command==PCAN_BOOT_CMD_CAPABILITIES && page==0) { if(command==PCAN_BOOT_CMD_CAPABILITIES && page==0) {
/* bits: ping, discovery, identity, name, memory, A/B, confirm, rollback, /* bits: ping, discovery, identity, name, memory, A/B, confirm, rollback,
* separate loader, session timeout, readback, SCI8 validation. */ * separate loader, session timeout, readback, SCI8 validation. */
info32(out,(F28335_BOOT_LOADER || F28335Boot_RunningSlot()<2)?0xFFFUL:0x1FUL); info32(out,(F28335_BOOT_LOADER || F28335Boot_RunningSlot()<2 || F28335Boot_RunningSlot()==F28335_BOOT_FLASH_SLOT)?0xFFFUL:0x1FUL); /* Flash-приложение с достоверным handoff поддерживает вход в постоянный CAN Boot так же, как подтверждённый EEPROM-образ. */
info32(out+4,F28335_AB_SLOT_BYTES); return true; #if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* Дополнительный бит сообщает клиенту поддержку явной внутренней Flash. */
out[1] |= 0x10U; /* Бит 12 общего little-endian capability word означает SELECT_MEMORY и запись B–H. */
#endif /* Старые приложения продолжают сообщать прежние возможности. */
info32(out+4,F28335_AB_SLOT_BYTES); return true; /* Максимальная длина одинакова для staging Flash и EEPROM A/B. */
} }
if(command==PCAN_BOOT_CMD_DEVICE_NAME) { if(command==PCAN_BOOT_CMD_DEVICE_NAME) {
if((unsigned int)page*8U>=sizeof(name)) return false; if((unsigned int)page*8U>=name_size) return false; /* Страница после конца выбранного имени не является допустимой частью паспорта. */
for(i=0;i<8;++i) { index=(unsigned int)page*8U+i; for(i=0;i<8;++i) { index=(unsigned int)page*8U+i;
out[i]=index<sizeof(name)?(pcan_boot_byte_t)name[index]:0; } out[i]=index<name_size?(pcan_boot_byte_t)name[index]:0; } /* Дополняет последнюю восьмибайтовую страницу нулями без выхода за строку. */
return true; return true;
} }
if(command!=PCAN_BOOT_CMD_MEMORY_INFO) return false; if(command!=PCAN_BOOT_CMD_MEMORY_INFO) return false;
@@ -124,14 +169,16 @@ void F28335CanBoot_EarlyInit(void) { confirmed=0; ready=0; }
/* Общий Init для приложения и загрузчика: открываем журнал, привязываем /* Общий Init для приложения и загрузчика: открываем журнал, привязываем
* callbacks, задаём идентификацию, ёмкость слота, окно 16 и тайм-аут 30 секунд. * callbacks, задаём идентификацию, ёмкость слота, окно 16 и тайм-аут 30 секунд.
* В загрузчике FW берётся из active manifest; приложение сообщает версию сборки. */ * В загрузчике FW берётся из active manifest; приложение сообщает версию сборки. */
void F28335CanBoot_Init(void) void F28335CanBoot_Init(unsigned int periph_id) /* Один номер платы преобразуется одинаково в приложении и постоянном загрузчике. */
{ {
pcan_boot_config_t cfg; pcan_boot_port_t port; pcan_boot_config_t cfg; pcan_boot_port_t port;
f28335_boot_io_t io; unsigned int running=F28335Boot_RunningSlot(); f28335_boot_io_t io; unsigned int running=F28335Boot_RunningSlot();
addressed=0U; EALLOW; ECanaRegs.CANME.all&=~88UL; EDIS; /* Закрывает только Boot mailbox 3/4/6 до проверки адреса, включая повторный Init с ошибочным номером. */
if(periph_id>=F28335_CAN_BOOT_PERIPH_COUNT) return; /* Номер вне Excel-диапазона 0–31 не подменяется общим адресом и не открывает запись другой платы. */
memset(&cfg,0,sizeof(cfg)); memset(&port,0,sizeof(port)); memset(&cfg,0,sizeof(cfg)); memset(&port,0,sizeof(port));
io.read=F28335Boot_Read; io.write=F28335Boot_Write; io.user=0; io.read=F28335Boot_Read; io.write=F28335Boot_Write; io.user=0;
healthy=f28335_boot_open(&store,&io); healthy=f28335_boot_open(&store,&io);
cfg.device_type=F28335_CAN_BOOT_DEVICE_TYPE; cfg.device_id=F28335_CAN_BOOT_DEVICE_ID; cfg.device_type=1U+periph_id/16U; cfg.device_id=periph_id%16U; /* Excel: PERIPH 0–15 → Type 1, 16–31 → Type 2; младшие четыре бита задают Device ID. */
cfg.product_type=F28335_CAN_BOOT_PRODUCT; cfg.hardware_revision=1; cfg.product_type=F28335_CAN_BOOT_PRODUCT; cfg.hardware_revision=1;
#if F28335_BOOT_LOADER #if F28335_BOOT_LOADER
cfg.firmware_version=store.active<2?store.image[store.active].firmware_version:0; cfg.firmware_version=store.active<2?store.image[store.active].firmware_version:0;
@@ -139,15 +186,20 @@ void F28335CanBoot_Init(void)
cfg.firmware_version=F28335_CAN_BOOT_FIRMWARE_VERSION; cfg.firmware_version=F28335_CAN_BOOT_FIRMWARE_VERSION;
#endif #endif
head=tail=overflow=reset_requested=reset_session=ready=main_passes=0; tx_busy=tx_canceling=0; head=tail=overflow=reset_requested=reset_session=ready=main_passes=0; tx_busy=tx_canceling=0;
confirmed=healthy && running<2 && store.active==running && store.pending==F28335_AB_NONE; confirmed=running==F28335_BOOT_FLASH_SLOT || (healthy && running<2 && store.active==running && store.pending==F28335_AB_NONE); /* Flash уже проверена CRC постоянным boot; пробное подтверждение требуется только EEPROM-кандидату. */
cfg.active_slot=store.active; cfg.active_slot=store.active;
cfg.slot_count=2; cfg.max_image_size=F28335_AB_SLOT_BYTES; cfg.ack_window=16; cfg.slot_count=2; cfg.max_image_size=F28335_AB_SLOT_BYTES; cfg.ack_window=16;
cfg.session_timeout_ms=30000UL; cfg.session_timeout_ms=30000UL;
#if F28335_BOOT_LOADER && F28335_CAN_FLASH_UPDATE /* После reset никакое случайное содержимое RAM не выбирает внутреннюю Flash. */
flash_selected = 0U; flash_staging = F28335_AB_NONE; flash_update.valid = false; /* Возвращает исходную цель и отменяет разрешение записи предыдущей сессии. */
port.select_memory = select_memory; /* Новая команда доступна только сборке с реально подключённым TI API. */
#endif /* Приложение отвечает только через постоянный загрузчик после handoff. */
port.send=transmit; port.erase_slot=erase; port.write_slot=write_block; port.send=transmit; port.erase_slot=erase; port.write_slot=write_block;
port.verify_status=verify; port.set_pending_slot=commit; port.reboot=reboot; port.verify_status=verify; port.set_pending_slot=commit; port.reboot=reboot;
port.confirm_running_slot=confirm; port.enter_boot=enter; port.confirm_running_slot=confirm; port.enter_boot=enter;
port.can_reboot=can_reboot; port.service_info=info; port.can_reboot=can_reboot; port.service_info=info;
if(!pcan_boot_init(&boot,&cfg,&port,0)) return; if(!pcan_boot_init(&boot,&cfg,&port,0)) return;
addressed=1U; /* Дальнейшие ISR, основной цикл и handoff используют только успешно созданную адресную конфигурацию. */
EALLOW; EALLOW;
/* Меняем только MBOX3/4/6: маска 88=8+16+64. MBOX0..2 — старый обмен, /* Меняем только MBOX3/4/6: маска 88=8+16+64. MBOX0..2 — старый обмен,
* MBOX5 — heartbeat. Приём broadcast выделен в отдельный точный mailbox, * MBOX5 — heartbeat. Приём broadcast выделен в отдельный точный mailbox,
@@ -181,8 +233,8 @@ static void receive_box(volatile struct MBOX *box,uint32_t mask)
type=pcan_boot_id_msg_type(id); type=pcan_boot_id_msg_type(id);
if(!(box->MSGID.all&0x80000000UL) || pcan_boot_id_route(id)!=0 || if(!(box->MSGID.all&0x80000000UL) || pcan_boot_id_route(id)!=0 ||
(type!=9 && type!=10 && type!=11 && type!=13) || (type!=9 && type!=10 && type!=11 && type!=13) ||
!((pcan_boot_id_device_type(id)==F28335_CAN_BOOT_DEVICE_TYPE && !((pcan_boot_id_device_type(id)==boot.config.device_type && /* Сравнивает тип именно этой платы, а не прежнюю общую константу 3. */
pcan_boot_id_device_id(id)==F28335_CAN_BOOT_DEVICE_ID) || pcan_boot_id_device_id(id)==boot.config.device_id) || /* Отбрасывает команды соседних PERIPH ещё до очереди и любых операций EEPROM. */
(type==13 && pcan_boot_id_device_type(id)==7 && pcan_boot_id_device_id(id)==15 && (type==13 && pcan_boot_id_device_type(id)==7 && pcan_boot_id_device_id(id)==15 &&
pcan_boot_id_msg_body(id)==0))) { ECanaRegs.CANRMP.all=mask; return; } pcan_boot_id_msg_body(id)==0))) { ECanaRegs.CANRMP.all=mask; return; }
if(next==tail) overflow=1; if(next==tail) overflow=1;
@@ -199,6 +251,7 @@ static void receive_box(volatile struct MBOX *box,uint32_t mask)
void F28335CanBoot_RxISR(void) void F28335CanBoot_RxISR(void)
{ {
if(!addressed) return; /* Неверный или ещё не настроенный номер PERIPH не должен принимать даже оставшиеся флаги RX. */
receive_box(&ECanaMboxes.MBOX3,8UL); receive_box(&ECanaMboxes.MBOX3,8UL);
receive_box(&ECanaMboxes.MBOX6,64UL); receive_box(&ECanaMboxes.MBOX6,64UL);
} }
@@ -214,9 +267,11 @@ unsigned int F28335CanBoot_WatchdogAllowed(void)
/* Неблокирующий диспетчер относительно ожидания CAN: вызывать в каждом проходе main. /* Неблокирующий диспетчер относительно ожидания CAN: вызывать в каждом проходе main.
* Сами callbacks проверки/записи EEPROM синхронные. Порядок здесь важен: * Сами callbacks проверки/записи EEPROM синхронные. Порядок здесь важен:
* проба приложения -> завершение TX -> reset -> poll -> ошибки RX -> один кадр. */ * проба приложения -> завершение TX -> reset -> poll -> ошибки RX -> один кадр. */
unsigned int F28335CanBoot_Active(void) { return addressed && (boot.state!=PCAN_BOOT_STATE_IDLE || reset_requested); } /* Открытый ENTER_BOOT удерживает recovery; диагностический PING не меняет приоритет Flash и EEPROM. */
void F28335CanBoot_Service(void) void F28335CanBoot_Service(void)
{ {
uint32_t now=F28335Boot_Now(); uint32_t now=F28335Boot_Now();
if(!addressed) return; /* Не обслуживает старую RAM-сессию после отказа повторной инициализации адреса. */
if(!F28335_BOOT_LOADER && ready && !confirmed && healthy && F28335Boot_RunningSlot()<2) { if(!F28335_BOOT_LOADER && ready && !confirmed && healthy && F28335Boot_RunningSlot()<2) {
/* A trial must keep executing main, not merely a timer ISR. */ /* A trial must keep executing main, not merely a timer ISR. */
/* После 100 проходов main и 5 секунд пробуем сохранить CONFIRM. /* После 100 проходов main и 5 секунд пробуем сохранить CONFIRM.
@@ -261,15 +316,16 @@ void F28335CanBoot_Service(void)
* или CRC незавершённой передачи: данные сессии через reset не сохраняются. */ * или CRC незавершённой передачи: данные сессии через reset не сохраняются. */
void F28335CanBoot_Resume(unsigned int session) void F28335CanBoot_Resume(unsigned int session)
{ {
if(F28335_BOOT_LOADER && session && session<256) if(addressed && F28335_BOOT_LOADER && session && session<256) /* Восстанавливает только допустимую сессию адресованного загрузчика после reset. */
(void)pcan_boot_process(&boot,pcan_boot_make_id(1,0, (void)pcan_boot_process(&boot,pcan_boot_make_id(1,0, /* ACK относится к тому же физическому PERIPH, который принимал ENTER_BOOT в приложении. */
F28335_CAN_BOOT_DEVICE_TYPE,F28335_CAN_BOOT_DEVICE_ID,9,(session<<8)|2),0,0); boot.config.device_type,boot.config.device_id,9,(session<<8)|2),0,0); /* MsgType 9, команда 2 и исходный SessionID сохраняют протокол handoff. */
} }
#else #else
void F28335CanBoot_EarlyInit(void) {} void F28335CanBoot_EarlyInit(void) {}
void F28335CanBoot_Init(void) {} void F28335CanBoot_Init(unsigned int periph_id) { (void)periph_id; } /* Сборка без M95M02 не занимает CAN-адрес и не открывает сервис записи. */
void F28335CanBoot_RxISR(void) {} void F28335CanBoot_RxISR(void) {}
void F28335CanBoot_Service(void) {} void F28335CanBoot_Service(void) {}
unsigned int F28335CanBoot_Active(void) { return 0U; } /* Профиль без M95M02 не создаёт CAN-сеанс и не удерживает старт общего загрузчика. */
void F28335CanBoot_Ready(void) {} void F28335CanBoot_Ready(void) {}
unsigned int F28335CanBoot_WatchdogAllowed(void) { return 1; } unsigned int F28335CanBoot_WatchdogAllowed(void) { return 1; }
void F28335CanBoot_Resume(unsigned int session) { (void)session; } void F28335CanBoot_Resume(unsigned int session) { (void)session; }
@@ -9,8 +9,7 @@
#endif #endif
/* Адрес ProtoCAN состоит из Device Type (3 бита) и Device ID (4 бита). /* Адрес ProtoCAN состоит из Device Type (3 бита) и Device ID (4 бита).
* ProductType — отдельный код совместимости прошивки; это не CAN ID и не RS-адрес. */ * ProductType — отдельный код совместимости прошивки; это не CAN ID и не RS-адрес. */
#define F28335_CAN_BOOT_DEVICE_TYPE 3U #define F28335_CAN_BOOT_PERIPH_COUNT 32U /* Лист «Интерфейс протокола», строки 45–76: PERIPH 0–31 занимают два типа по 16 экземпляров. */
#define F28335_CAN_BOOT_DEVICE_ID 7U
#define F28335_CAN_BOOT_PRODUCT 0x2833U #define F28335_CAN_BOOT_PRODUCT 0x2833U
#define F28335_CAN_BOOT_DEVICE_NAME "F28335-M95M02" #define F28335_CAN_BOOT_DEVICE_NAME "F28335-M95M02"
/* Порядок интеграции приложения: /* Порядок интеграции приложения:
@@ -18,10 +17,11 @@
* таймера и EEPROM; Ready после старта прикладных подсистем; Service в main. * таймера и EEPROM; Ready после старта прикладных подсистем; Service в main.
* RxISR вызывается из CAN ISR, WatchdogAllowed проверяется перед кормлением * RxISR вызывается из CAN ISR, WatchdogAllowed проверяется перед кормлением
* watchdog таймерным ISR. Resume применяется только отдельным загрузчиком. */ * watchdog таймерным ISR. Resume применяется только отдельным загрузчиком. */
void F28335CanBoot_Init(void); void F28335CanBoot_Init(unsigned int periph_id); /* Принимает физический номер PERIPH: 5 — УМП1, 6 — УМП2, 8 — задатчик; общий адрес для всех плат исключён. */
void F28335CanBoot_EarlyInit(void); void F28335CanBoot_EarlyInit(void);
void F28335CanBoot_RxISR(void); void F28335CanBoot_RxISR(void);
void F28335CanBoot_Service(void); void F28335CanBoot_Service(void);
unsigned int F28335CanBoot_Active(void); /* Удерживает загрузчик в CAN recovery после ENTER_BOOT, не запуская приложение по окончании стартового окна. */
void F28335CanBoot_Ready(void); void F28335CanBoot_Ready(void);
void F28335CanBoot_Resume(unsigned int session); void F28335CanBoot_Resume(unsigned int session);
unsigned int F28335CanBoot_WatchdogAllowed(void); unsigned int F28335CanBoot_WatchdogAllowed(void);
@@ -0,0 +1,26 @@
#include "f28335_flash_app.h" /* Использует ту же границу сектора A и формат описания, что сборщик и RS-программатор. */
bool f28335_flash_app_validate(f28335_flash_read_word_t read_word, void *user, uint32_t *entry) /* Не обращается к EEPROM и подходит для постоянного загрузчика и проверки staging RAM. */
{ /* Никакие адреса из непроверенного заголовка не используются для чтения до проверки границ. */
uint16_t header[F28335_FLASH_APP_HEADER_WORDS], word, octet, bit, i; /* Малый локальный буфер хранит 16 слов описания FAB1. */
uint32_t address, start, end, expected, crc = 0xFFFFFFFFUL, target, inverse; /* CRC32 IEEE начинается со всех единиц и инвертируется после последнего октета. */
if (!read_word || !entry) return false; /* Отсутствующий источник или выходной указатель не должен вызывать обращение к памяти. */
for (i = 0; i < F28335_FLASH_APP_HEADER_WORDS; ++i) header[i] = read_word(user, F28335_FLASH_APP_START + i); /* Читает только фиксированное описание в секторе H. */
if (header[0] != 0x4146U || header[1] != 0x3142U || header[2] != 1U || header[3] != F28335_FLASH_APP_HEADER_WORDS || header[14] != 0x5AA5U || header[15] != 0xA55AU) return false; /* Физические октеты ASCII FAB1, версия 1, размер и два маркера отличают завершённый образ от стёртого либо старого Flash. */
target = (uint32_t)header[4] | ((uint32_t)header[5] << 16); /* Точка входа хранится младшим 16-битным словом вперёд внутри описания. */
start = (uint32_t)header[6] | ((uint32_t)header[7] << 16); /* Нижняя граница защищённого CRC диапазона должна начинаться сразу после описания. */
end = (uint32_t)header[8] | ((uint32_t)header[9] << 16); /* Верхняя граница является исключённым адресом слова, а не длиной в байтах. */
expected = (uint32_t)header[10] | ((uint32_t)header[11] << 16); /* Сохранённая CRC32 рассчитана по физическим октетам всех слов диапазона. */
inverse = (uint32_t)header[12] | ((uint32_t)header[13] << 16); /* Инверсия адреса выявляет частичную публикацию управляющих полей. */
if (start != F28335_FLASH_APP_DATA || end <= start || end > F28335_FLASH_APP_STOP || target < start || target >= end || inverse != ~target) return false; /* Запрещает RAM, сектор загрузчика, пустой код и случайные адреса из повреждённого описания. */
for (address = start; address < end; ++address) { /* Проверяет также стёртые промежутки между LOAD-секциями, чтобы JTAG и RS давали одинаковое содержимое. */
word = read_word(user, address); /* Получает одно 16-битное слово из Flash либо из модели staging SCI8. */
for (i = 0; i < 2U; ++i) { /* Каждый адрес C28x содержит два физических октета: сначала младший, затем старший. */
octet = (word >> (8U * i)) & 255U; /* Маска отделяет октет независимо от 16-битного char TI. */
crc ^= octet; /* Добавляет очередной октет в отражённое состояние CRC32 IEEE. */
for (bit = 0; bit < 8U; ++bit) crc = (crc & 1UL) ? ((crc >> 1) ^ 0xEDB88320UL) : (crc >> 1); /* 0xEDB88320 — отражённый полином IEEE 802.3, совпадающий с zlib.crc32. */
} /* Завершает обработку обоих октетов текущего слова. */
} /* Завершает чтение только внутри области приложения ниже сектора A. */
if ((crc ^ 0xFFFFFFFFUL) != expected) return false; /* Повреждённое или частично записанное приложение остаётся недоступным для запуска. */
*entry = target; /* Публикует точку старта только после подтверждения всех адресов и данных. */
return true; /* Разрешает загрузчику запустить именно проверенную Flash-программу. */
} /* Ошибка никогда не меняет EEPROM, Flash или сохранённый выходной адрес. */
@@ -0,0 +1,11 @@
#ifndef F28335_FLASH_APP_H /* Защищает общий контракт Flash-приложения от повторного объявления. */
#define F28335_FLASH_APP_H /* Один заголовок используется загрузчиком, RS-проверкой и host-тестами. */
#include "../../include/pcan_boot.h" /* Получает переносимые 16- и 32-битные типы и bool для C28x и ПК. */
#define F28335_FLASH_APP_START 0x300000UL /* Первые 16 слов сектора H содержат описание FAB1, а не аппаратный boot. */
#define F28335_FLASH_APP_HEADER_WORDS 16U /* Размер описания равен 32 октетам при 16-битном адресуемом слове C28x. */
#define F28335_FLASH_APP_DATA 0x300010UL /* Код и Flash LOAD-секции следуют после служебного описания. */
#define F28335_FLASH_APP_STOP 0x338000UL /* Начало сектора A является исключённой границей приложения. */
#define F28335_BOOT_FLASH_SLOT 0xFEU /* Отдельный handoff отличает внутреннюю Flash от EEPROM A/B и неизвестного SPI-ROM запуска. */
typedef uint16_t (*f28335_flash_read_word_t)(void *user, uint32_t address); /* Callback читает одно физическое слово без предположения о памяти host-тестов. */
bool f28335_flash_app_validate(f28335_flash_read_word_t read_word, void *user, uint32_t *entry); /* Проверяет описание, границы и CRC32 до передачи управления приложению. */
#endif /* Завершает единый контракт защищённой области Flash-приложения. */
@@ -0,0 +1,86 @@
#include "f28335_flash_update.h" /* Разделяет проверяемый алгоритм и аппаратные вызовы TI Flash API. */
#include <string.h> /* Явно очищает состояние источника перед разбором нового SCI8. */
static unsigned int octet(f28335_flash_update_t *s, uint32_t offset) /* Читает октет через страничный кеш, исключая SPI-транзакцию на каждый байт CRC. */
{ /* Все смещения ограничены фактической длиной принятого файла. */
if (offset >= s->length) { s->fault = true; return 0U; } /* Обрезанное поле не превращается в данные за концом staging. */
if (!s->cache_size || offset < s->cache_at || offset - s->cache_at >= s->cache_size) { /* Загружает новую страницу только при выходе за текущую. */
s->cache_at = offset & ~255UL; /* Выравнивает смещение на страницу из 256 физических октетов. */
s->cache_size = s->length - s->cache_at > 256UL ? 256U : (unsigned int)(s->length - s->cache_at); /* Последнее чтение не включает паддинг CAN за концом образа. */
if (!s->io.read(s->io.user, s->base + s->cache_at, s->cache, s->cache_size)) { s->fault = true; s->cache_size = 0U; return 0U; } /* Любой неполный аппаратный обмен запрещает erase. */
} /* После заполнения кеша извлечение октета не обращается к SPI. */
return s->cache[offset - s->cache_at] & 255U; /* Маска сохраняет восьмибитный wire-формат на C28x. */
} /* Завершает ограниченное чтение октета. */
static uint16_t word(f28335_flash_update_t *s, uint32_t offset) /* SCI8 передаёт младший октет каждого 16-битного слова первым. */
{ /* Объединяет два октета только через проверяемый источник. */
unsigned int low = octet(s, offset); /* Явный порядок вызовов не зависит от порядка вычисления операндов компилятором. */
return (uint16_t)(low | (octet(s, offset + 1UL) << 8)); /* Восстанавливает одно слово CPU из двух октетов SCI8. */
} /* Завершает декодирование слова. */
static uint32_t address_at(f28335_flash_update_t *s, uint32_t offset) /* Адрес таблицы TI содержит старшее слово перед младшим. */
{ /* Порядок слов адреса отличается от порядка октетов внутри слова. */
uint32_t high = word(s, offset); /* Читает старшие 16 бит адреса раньше младших. */
return (high << 16) | word(s, offset + 2UL); /* Получает CPU word-address без перевода в байты. */
} /* Завершает восстановление адреса SCI8. */
static uint16_t image_word(void *user, uint32_t address) /* Предоставляет общему валидатору будущий вид Flash, включая стёртые промежутки. */
{ /* Отсортированный индекс позволяет проверять весь CRC-диапазон последовательно. */
f28335_flash_update_t *s = user; f28335_flash_section_t *p; /* Контекст содержит только предварительно проверенные секции. */
if (s->cursor >= s->count || address < s->section[s->cursor].address) s->cursor = 0U; /* Возврат от заголовка к началу диапазона корректно перематывает индекс. */
while (s->cursor < s->count) { /* Пропускает только секции, целиком лежащие перед запрошенным словом. */
p = &s->section[s->cursor]; /* Обращается к существующему элементу проверенного индекса. */
if (address < p->address) return 0xFFFFU; /* Flash_Erase оставляет незагружаемый промежуток заполненным единицами. */
if (address - p->address < p->words) return word(s, p->offset + 2UL * (address - p->address)); /* Переводит смещение слов секции в октеты SCI8. */
++s->cursor; /* Следующий запрос не должен повторно сканировать уже пройденную секцию. */
} /* После последней секции остаётся только стёртая Flash. */
return 0xFFFFU; /* CRC учитывает также завершающий промежуток диапазона FAB1. */
} /* Сам этот callback никогда не читает аппаратную Flash. */
bool f28335_flash_update_validate(f28335_flash_update_t *s, const f28335_boot_io_t *io, uint32_t base, const pcan_boot_manifest_t *m) /* Проверяет транспорт, таблицу, допустимые адреса и FAB1 перед erase. */
{ /* Любая ошибка оставляет объект непригодным для программирования. */
uint32_t offset = 22UL, crc = 0UL, entry, checked_entry, bytes; unsigned int i, j, headers = 0U, have_entry = 0U; /* Заголовок SCI8 занимает 11 слов, то есть 22 октета. */
f28335_flash_section_t p; bool ended = false; /* Временная секция нужна для вставки в отсортированный индекс. */
if (!s || !io || !io->read || !m) return false; /* Не разыменовывает отсутствующие callbacks и manifest. */
memset(s, 0, sizeof(*s)); s->io = *io; s->base = base; s->length = m->image_size; s->crc = m->image_crc32; /* Отбрасывает кеш и разрешение записи предыдущего образа. */
if (s->length < 24UL || (s->length & 1UL) || s->length > F28335_AB_SLOT_BYTES || word(s, 0UL) != 0x08AAU) return false; /* Принимает только полный чётный SCI8 в пределах staging-слота. */
for (offset = 0UL; offset < s->length; offset += bytes) { /* Независимо проверяет фактически записанную EEPROM, а не только принятые CAN-кадры. */
bytes = s->length - offset > 256UL ? 256UL : s->length - offset; /* Делит чтение на ограниченные страницы без выхода за файл. */
if (!s->io.read(s->io.user, base + offset, s->cache, (unsigned int)bytes)) return false; /* Аппаратная ошибка запрещает последующий erase. */
crc = pcan_boot_crc32_update(crc, s->cache, (size_t)bytes); /* Использует общий CRC32 IEEE, совпадающий с клиентом SETGUI. */
} /* Все октеты staging включены в транспортную CRC32. */
s->cache_size = 0U; if (crc != s->crc) return false; /* Сбрасывает кеш после прямого чтения и отклоняет повреждённую EEPROM. */
entry = address_at(s, 18UL); offset = 22UL; /* Точка входа следует после ключа и восьми резервных слов SCI8. */
if (entry < F28335_FLASH_APP_DATA || entry >= F28335_FLASH_APP_STOP) return false; /* Запуск разрешён только из приложения ниже постоянного сектора A. */
while (offset + 2UL <= s->length) { /* Для каждой секции сначала проверяет наличие поля длины. */
p.words = word(s, offset); offset += 2UL; /* Длина секции выражена адресуемыми словами C28x. */
if (!p.words) { ended = offset == s->length; break; } /* Нулевой терминатор обязан завершать файл без лишнего хвоста. */
if (s->count == F28335_AB_MAX_SECTIONS || offset + 4UL > s->length) return false; /* Не допускает переполнение индекса либо обрезанный адрес секции. */
p.address = address_at(s, offset); offset += 4UL; p.offset = offset; bytes = 2UL * p.words; /* Хранит CPU-адрес и байтовое смещение полезных данных отдельно. */
if (bytes > s->length - offset || p.address < F28335_FLASH_APP_START || p.address >= F28335_FLASH_APP_STOP || p.words > F28335_FLASH_APP_STOP - p.address) return false; /* Исключает RAM, сектор A, CSM, OTP и выход за конец staging. */
if (p.address == F28335_FLASH_APP_START) { if (p.words < F28335_FLASH_APP_HEADER_WORDS) return false; ++headers; } /* Полные 16 слов FAB1 должны публиковаться одной заключительной операцией. */
if (entry >= p.address && entry - p.address < p.words) have_entry = 1U; /* Код entry обязан присутствовать именно в принятой таблице. */
for (i = 0U; i < s->count; ++i) if (p.address < s->section[i].address + s->section[i].words && s->section[i].address < p.address + p.words) return false; /* Повторное программирование пересекающихся диапазонов запрещено. */
for (j = s->count; j && s->section[j - 1U].address > p.address; --j) s->section[j] = s->section[j - 1U]; /* Сортирует индекс по адресу независимо от порядка секций в SCI8. */
s->section[j] = p; ++s->count; offset += bytes; /* Запоминает непересекающуюся секцию и переходит к следующему заголовку. */
} /* Структура файла полностью разобрана без записи Flash. */
if (!ended || headers != 1U || !have_entry || s->fault) return false; /* Требует терминатор, единственный FAB1 и фактический исполняемый entry. */
s->cursor = 0U; if (!f28335_flash_app_validate(image_word, s, &checked_entry) || s->fault || checked_entry != entry) return false; /* Общий валидатор проверяет magic, границы, инверсию entry и CRC будущей Flash. */
s->entry = entry; s->valid = true; return true; /* Разрешает программирование только после всех независимых проверок. */
} /* Ошибка проверки не меняет текущую Flash и журнал активной EEPROM. */
bool f28335_flash_update_program(f28335_flash_update_t *s, const f28335_flash_ops_t *ops) /* Выполняет запись B–H только из полностью проверенного staging. */
{ /* Заголовок FAB1 фиксируется после успешной проверки каждой порции данных. */
uint16_t buffer[128]; unsigned int i, j, n; uint32_t at, left, entry; pcan_boot_manifest_t m; f28335_boot_io_t io; /* Одна порция содержит не более 128 слов, то есть 256 физических октетов. */
if (!s || !s->valid || !ops || !ops->erase || !ops->program || !ops->read) return false; /* Неполный аппаратный контракт не должен начать стирание. */
memset(&m, 0, sizeof(m)); m.image_size = s->length; m.image_crc32 = s->crc; io = s->io; at = s->base; /* Сохраняет исходные параметры перед полной повторной проверкой EEPROM. */
if (!f28335_flash_update_validate(s, &io, at, &m)) return false; /* Изменение staging между VERIFY и COMMIT обнаруживается до первого erase. */
s->valid = false; if (!ops->erase(ops->user)) return false; /* Одно разрешение записи расходуется до изменения Flash; повтор после отказа требует нового VERIFY. */
for (i = 0U; i < s->count; ++i) { /* Программирует обычные данные каждой непересекающейся секции. */
at = s->section[i].address; left = s->section[i].words; /* CPU-курсор и остаток выражены словами. */
if (at == F28335_FLASH_APP_START) { at += F28335_FLASH_APP_HEADER_WORDS; left -= F28335_FLASH_APP_HEADER_WORDS; } /* Пропускает FAB1 до подтверждения всех остальных данных. */
while (left) { /* Большие секции разбивает на порции рабочего буфера. */
n = left > 128UL ? 128U : (unsigned int)left; /* Последняя порция может быть короче 128 слов. */
for (j = 0U; j < n; ++j) buffer[j] = word(s, s->section[i].offset + 2UL * (at + j - s->section[i].address)); /* Распаковывает слова непосредственно из staging EEPROM. */
if (s->fault || !ops->program(ops->user, at, buffer, n)) return false; /* Ошибка чтения, записи или readback оставляет FAB1 неопубликованным. */
at += n; left -= n; /* Продвигает курсоры только после подтверждённой порции. */
} /* Завершает запись данных секции. */
} /* Все обычные слова уже записаны и проверены аппаратным портом. */
for (i = 0U; i < F28335_FLASH_APP_HEADER_WORDS; ++i) buffer[i] = image_word(s, F28335_FLASH_APP_START + i); /* Собирает единственное проверенное описание FAB1 для заключительной записи. */
if (s->fault || !ops->program(ops->user, F28335_FLASH_APP_START, buffer, F28335_FLASH_APP_HEADER_WORDS)) return false; /* Публикует описание только после успешной записи остальных секций. */
return f28335_flash_app_validate(ops->read, ops->user, &entry) && entry == s->entry; /* Итоговый успех требует общей CRC уже физической Flash, а не только поблочного сравнения. */
} /* Решение о CAN-подтверждении и перезапуске остаётся существующему протоколу. */
@@ -0,0 +1,20 @@
#ifndef F28335_FLASH_UPDATE_H /* Один контракт объединяет проверку CAN-образа и аппаратную запись внутренней Flash. */
#define F28335_FLASH_UPDATE_H /* Исключает повторное объявление структур при подключении аппаратного порта. */
#include "f28335_boot_store.h" /* Использует существующий побайтовый доступ к staging-слоту EEPROM и manifest ProtoCAN. */
#include "f28335_flash_app.h" /* Получает границы приложения B–H и проверку завершающего описания FAB1. */
typedef struct { uint32_t address, offset; uint16_t words; } f28335_flash_section_t; /* Адрес CPU считается словами, смещение SCI8 — октетами, длина секции — словами. */
typedef struct { /* Хранит проверенный индекс SCI8, не размещая целый образ во внутренней RAM загрузчика. */
f28335_boot_io_t io; uint32_t base, length, crc, entry; /* Источник EEPROM, начало staging, точная длина, транспортная CRC32 и подтверждённый entry. */
f28335_flash_section_t section[F28335_AB_MAX_SECTIONS]; /* Лимит 64 совпадает с ограничением выпуска SCI8 и ограничивает расход RAM. */
unsigned int count, cursor, cache_size; bool fault, valid; /* Курсор ускоряет последовательную CRC; fault запрещает принятие неполного чтения EEPROM. */
uint32_t cache_at; pcan_boot_byte_t cache[256]; /* Одна страница M95M02 содержит 256 физических октетов, даже при 16-битном char C28x. */
} f28335_flash_update_t; /* Объект принадлежит только main постоянного загрузчика, а не CAN ISR. */
typedef struct { /* Аппаратные операции отделены от формата SCI8 для испытаний обрыва и ошибок TI API. */
bool (*erase)(void *user); /* Стирает только секторы B–H, сохраняя сектор A с постоянным загрузчиком. */
bool (*program)(void *user, uint32_t address, uint16_t *data, unsigned int words); /* Записывает и проверяет одну порцию слов по допустимому CPU-адресу. */
f28335_flash_read_word_t read; void *user; /* Чтение физической Flash подтверждает общий FAB1/CRC после последней записи. */
} f28335_flash_ops_t; /* Никаких неявных операций reset или изменения EEPROM-журнала здесь нет. */
bool f28335_flash_update_validate(f28335_flash_update_t *s, const f28335_boot_io_t *io, uint32_t base, const pcan_boot_manifest_t *m); /* Полностью проверяет staging до первого стирания Flash. */
bool f28335_flash_update_program(f28335_flash_update_t *s, const f28335_flash_ops_t *ops); /* Повторяет проверку, пишет данные и публикует FAB1 последним. */
bool F28335Boot_FlashProgram(f28335_flash_update_t *s); /* Аппаратная реализация подключает официальный TI Flash API только в постоянном загрузчике. */
#endif /* Завершает защиту интерфейса CAN-обновления внутренней Flash. */
+156
View File
@@ -0,0 +1,156 @@
# Отдельные проекты CCS: F28335 и F2812
Весь комплект находится внутри `templates/c/protocan-boot`: проекты CCS,
исходники загрузчиков, аппаратные порты, linker command files, необходимая
поддержка TI, CLI-сборка, тесты и документация. Зависимости от исходников
`28335_periph` и `BALZAM_167` при сборке отсутствуют. Требуется установленный
TI C2000 compiler с поддержкой **COFF ABI**; проверена версия **22.6.0.LTS**.
| Проект CCS | Контроллер | Обновляемая память | Схема |
| --- | --- | --- | --- |
| `ccs/f28335` — `F28335_CAN_AB` | TMS320F28335 | M95M02, 256 КиБ | A/B, trial, CONFIRM, rollback |
| `ccs/f2812` — `F2812_CAN_NOR` | TMS320F2812 / ПМ67 | AM29LV800BT-70EI, 1 МиБ, x16 | Один выделенный NOR-слот, проверяемый manifest, CAN recovery |
F2812 не использует EEPROM. Его карта, GPIO, частота CAN, допустимые адреса
приложения и состояние протокола отделены от F28335.
## Открытие в Code Composer Studio
1. **Project → Import CCS Projects**, каталог поиска — `c/protocan-boot/projects/ccs`.
2. Выбрать `F28335_CAN_AB` и `F2812_CAN_NOR`. Оставить проекты в исходном
расположении: **не включать Copy projects into workspace**, поскольку
переносимые ссылки `PCAN_ROOT` ведут к общей библиотеке выше проектов.
3. Выбрать **Debug** либо **Release**, затем **Build Project**. Оба проекта
содержат собственные `.project`, `.cproject`, `.ccsproject`.
4. OUT/MAP появятся в `ccs/<контроллер>/<Debug|Release>/`.
В `targetConfigs` сохранены существующие конфигурации Sauris SAU510:
F28335 — Iso Plus v.2, F2812 — Iso Plus. Для другого адаптера выбрать свой
Connection в Target Configuration. Компиляция и импорт не подключаются к JTAG
и не программируют плату.
Для отдельных workspace с ограниченными правами CCS допускает переменную
`TI_APPDATA_DIR` с доступным для записи каталогом. Это служебный cache IDE,
он не относится к исходникам загрузчиков.
## Сборка без запуска IDE
Из корня **templates**:
```powershell
python c/protocan-boot/projects/build.py --device f28335
python c/protocan-boot/projects/build.py --device f2812
python c/protocan-boot/projects/build.py --device f28335 --configuration Release
python c/protocan-boot/projects/build.py --device f2812 --configuration Release
```
Можно передать `--compiler <каталог-ti-cgt-c2000>` и `--output <каталог>`.
Скрипт читает состав исходников и настройки из этих же CCS-проектов, полностью
пересобирает их и проверяет реальные COFF LOAD-адреса официальным `ofd2000`.
Проверка отклоняет загружаемый RAM-код без Flash LOAD, пересечения, отсутствующие
boot branch/C entry, запись CSM/OTP и посторонних внутренних секторов.
Рядом с OUT сохраняются MAP, `build.log` и manifest с SHA-256.
Результаты:
- `ccs/f28335/Debug/F28335_CAN_AB.out`;
- `ccs/f2812/Debug/F2812_CAN_NOR.out`.
OUT — постоянный загрузчик для первоначальной установки через JTAG во
**внутреннюю Flash** соответствующего TMS. Образ самого приложения передаётся
по CAN в его внешнюю память. Для автоматического запуска должен быть выбран
внутренний Flash boot; у ПМ67 необходимо также учитывать штатную логику CPLD
выбора источника reset/boot из `big_dsp_module` платы.
## F28335 / M95M02
Проект использует существующий порт и формат журнала без изменения адресов:
**PERIPH 0–31: Type = 1 + PERIPH / 16, Device ID = PERIPH mod 16**.
УМП1 — **1/5**, УМП2 — **1/6**, задатчик — **1/8**.
Product **0x2833**, HW **1**, CAN **250000 бит/с**. Приложение и загрузчик
используют один аппаратный номер платы; прежний общий адрес **3/7** отменён.
Код загрузчика — внутренний сектор A `0x338000..0x33FF7F`, boot — `0x33FFF6`.
Слоты M95M02 имеют по **130560 октетов**, параметры — прежние 258 октетов
по адресу `0x3FEFC`. Приложение загружается в RAM ниже CPU word-адреса `0xE000`.
После установки постоянного загрузчика новое приложение 167 передаётся
существующим клиентом SETGUI **CAN / ProtoCAN Boot**. Оно обязано содержать
hooks READY/CONFIRM и watchdog: пример интеграции реализован в ветке 167.
Без CONFIRM следующий reset возвращает подтверждённый active.
Полная последовательность — [документация порта F28335](../ports/tms320f28335/README.md).
## F2812 / AM29LV800BT
Профиль: **Device Type 3, Device ID 6, Product 0x2812, HW 1,
CAN 250000 бит/с, SYSCLKOUT 150 МГц**. CAN находится на **GPIOF6 TX / GPIOF7 RX**.
F2812 использует программную арифметику `rts2800_ml.lib`; F28335 — FPU32
и `rts2800_fpu32.lib`.
Внутренний сектор A загрузчика: `0x3F6000..0x3F7F7F`, boot — `0x3F7FF6`.
Внешняя NOR подключена по **CPU word-адресу `0x100000`**. Новый CAN-раздел
задан явно в `ports/tms320f2812/boot2812.h`:
| Область | CPU word-адреса включительно | Размер |
| --- | --- | ---: |
| Существующая нижняя область: прежние образы/параметры/FPGA | `0x100000..0x15FFFF` | 768 КиБ |
| Новый SCI8 CAN-образ: обычные сектора 12/13/14 | `0x160000..0x177FFF` | **192 КиБ** |
| Неизменяемые этим загрузчиком top-boot сектора 15/16/17 | `0x178000..0x17DFFF` | 48 КиБ |
| Новый manifest: последний top-boot сектор 18 | `0x17E000..0x17FFFF` | 16 КиБ |
Это **новое явное размещение CAN-образа**, а не автоматическое определение
свободного места в уже заполненном чипе. Перед первоначальной установкой
согласовать эти два выделенных участка с фактической картой NOR конкретной
платы. В известном исходнике FPGA начинается с `0x130000`, а новый CAN-слот
находится выше; драйвер не изменяет ничего ниже `0x160000` и в секторах 15–17.
После reset доступно **3 секунды** для ENTER_BOOT. Открытая сессия удерживает
загрузчик; пустой/повреждённый manifest оставляет CAN recovery постоянно.
Для обновления уже работающего приложения нужно войти в это окно после reset;
приложение F2812 само по себе пока не получает обработчик ENTER_BOOT от добавления
отдельного проекта загрузчика.
Перед записью требуется AMD manufacturer **`0x0001`**, device **`0x22DA`**.
Сначала стирается сектор manifest, затем три сектора образа. Запись проверяет
каждое слово. VERIFY повторно читает NOR, проверяет CRC32, SCI8, entry,
перекрытия и запрещённые назначения. COMMIT повторяет проверку, сохраняет
manifest с собственной CRC, два magic-слова публикуются последними.
Стирание сообщает BUSY каждые 250 мс, продлевая живую сессию.
Это single-slot схема: при обрыве обновления последнего CAN-образа остаётся
recovery, автоматический A/B rollback для F2812 не заявляется. Полное стирание
NOR, запись внутренней Flash по CAN и программирование FPGA отсутствуют.
Образ приложения — **TI SCI8 `AA 08`**, максимум **196608 октетов**. Старый
flat BIN основного контроллера автоматически не мигрируется. Допустимый payload:
- L0 `0x8000..0x8EFF`;
- H0 `0x3F8000..0x3F9FFF`;
- внешняя SRAM zone2 `0x80000..0xFFFFF`.
Стек M1, L1 `0x9000..0x9FFF`, RAM InitFlash `0x8F00..0x8FFF`, периферия,
внутренняя Flash и NOR не допускаются как назначения SCI8. `.ebss` приложения
может занять L1 после перехода в его C runtime; инициализированный payload
работающую RAM загрузчика перезаписывать не должен. Настройка приложения
F2812/его linker — отдельная от импорта загрузчика операция.
Геометрия x16, ID и команды AA/55/A0/80/30/F0 взяты из
[оригинального datasheet AMD Am29LV800B](https://cms.nacsemi.com/content/AuthDatasheets/FASLS02690-1.pdf).
Аппаратные GPIO/CPLD и XINTF-тайминги перенесены из действующих
`big_dsp_module.c` / `flash_tools.c` ПМ67, без зависимости от этих файлов при сборке.
## Проверки
```powershell
$env:CC = 'C:/msys64/ucrt64/bin/gcc.exe'
python c/protocan-boot/tests/run_tests.py
```
Проверяются протокол, CRC, сессии/BUSY, A/B F28335 с trial/rollback/CONFIRM,
NOR F2812 с настоящими AMD command cycles, ID, readback, запрещёнными секторами,
обрывами COMMIT, повреждением CRC/SCI8 и тайм-аутом DQ7.
Вариант с CMake/CTest также поддерживается.
Подтверждены реальные import/build обоих проектов в CCS 12.3, CLI-сборки
Debug/Release TI 22.6 COFF и проверки секций OUT. Физические JTAG/CAN/XINTF,
режим boot и поведение конкретной платы при отключении питания требуют стенда;
физическое программирование этим комплектом автоматически не выполнялось.
+86
View File
@@ -0,0 +1,86 @@
"""Сборка отдельных CCS-проектов ProtoCAN для F28335/M95M02 и F2812/AM29LV800BT.""" # Требует только Python и установленный TI C2000 COFF compiler.
import argparse # Разбирает выбранный контроллер, конфигурацию и пути toolchain.
import base64 # Читает настоящие программируемые данные COFF из официального OFD XML.
import hashlib # Связывает собранный OUT с контрольной суммой в локальном build manifest.
import json # Сохраняет точные команды, происхождение исходников и результаты проверки.
from pathlib import Path # Разрешает все зависимости внутри templates относительно расположения проекта.
import subprocess # Вызывает установленный TI compiler без shell-интерполяции аргументов.
import xml.etree.ElementTree as ET # Использует действующие .project/.cproject как источник состава и опций сборки.
ROOT = Path(__file__).resolve().parents[1] # Корень protocan-boot содержит codec, порты, проекты и vendored TI support.
DEFAULT_COMPILER = Path("C:/ti/ccs1230/ccs/tools/compiler/ti-cgt-c2000_22.6.0.LTS") # Сохраняет проверенную версию установленного C2000 COFF compiler.
def settings(device, configuration, compiler): # Читает те же исходники и пути, которые получает импортированный проект CCS.
project = ROOT / "projects/ccs" / device # Каждое семейство контроллера имеет собственный Eclipse projectDescription.
config = next(item for item in ET.parse(project / ".cproject").findall(".//configuration") if item.get("name") == configuration) # Не подменяет Debug настройками Release или другого устройства.
options = {item.get("superClass", "").rsplit(".", 1)[-1]: item for item in config.findall("folderInfo/toolChain/tool/option")} # Собирает только параметры общего folderInfo без переопределений отдельных файлов.
macros = {"${PROJECT_ROOT}": str(project), "${PROJECT_LOC}": str(project), "${CG_TOOL_ROOT}": str(compiler)} # Разрешает только известные пути, не выполняя shell-подстановки.
def values(name): # Возвращает listOptionValue после подстановки локальных макросов CCS.
result = [] # Порядок include paths и библиотек остаётся тем же, что в проекте.
for item in options[name].findall("listOptionValue"): # Обрабатывает каждое явное значение текущей конфигурации.
value = item.get("value", "") # Отсутствующее значение не превращается в имя неизвестного каталога.
for macro, replacement in macros.items(): value = value.replace(macro, replacement) # Ограничивает подстановки определёнными выше путями.
if "${" in value: raise ValueError("Unresolved CCS macro: " + value) # Останавливает сборку вместо поиска случайной зависимости на машине.
result.append(value) # Добавляет параметр в исходном порядке конфигурации CCS.
return result # Возвращает обычные аргументы без скрытых изменений окружения.
sources = sorted(project.glob("*.c")) + sorted(project.glob("*.asm")) # Локальные production-исходники проекта компилируются вместе с аппаратным портом.
commands = sorted(project.glob("*.cmd")) # Каждый проект имеет собственную разметку памяти соответствующего F28xx.
for link in ET.parse(project / ".project").findall(".//linkedResources/link"): # Добавляет только explicit linkedResources из templates.
uri = link.findtext("locationURI", "") # Все общие исходники привязаны к переменной PCAN_ROOT.
if not uri.startswith("PCAN_ROOT/"): raise ValueError("Unsupported linked resource: " + uri) # Не допускает зависимость от старого firmware checkout или абсолютного чужого пути.
path = ROOT / uri.removeprefix("PCAN_ROOT/") # Разрешает vendor и общие исходники внутри переносимого protocan-boot.
if path.suffix.lower() in (".c", ".asm"): sources.append(path) # Заголовки не компилируются самостоятельными единицами трансляции.
elif path.suffix.lower() == ".cmd": commands.append(path) # Подключает оригинальное TI размещение регистров выбранного контроллера.
flags = ["-v28", "-ml", "-mt", "--abi=coffabi", "-O" + options["OPT_LEVEL"].get("value").rsplit(".", 1)[-1], "--opt_for_speed=" + options["OPT_FOR_SPEED"].get("value").rsplit(".", 1)[-1], "--gen_func_subsections=on"] # Повторяет архитектуру COFF, большие адреса, оптимизацию и сборку отдельных функций проекта CCS.
if device == "f28335": flags.append("--float_support=fpu32") # Только F28335 имеет используемый аппаратный FPU32.
flags += ["--include_path=" + value for value in values("INCLUDE_PATH")] + ["--define=" + value for value in values("DEFINE")] # Передаёт конкретные аппаратные заголовки и profile defines без потери различий между контроллерами.
if configuration == "Debug": flags.append("-g") # Debug OUT сохраняет символы для пошагового JTAG-анализа загрузчика.
return project, config.get("artifactName"), flags, sources, commands, values("LIBRARY"), values("SEARCH_PATH") # Возвращает полный воспроизводимый набор исходников и linker inputs.
def verify(device, image, compiler): # Проверяет реальные секции OUT после линковки, а не только текст соседнего MAP.
xml = ET.fromstring(subprocess.check_output([str(compiler / "bin/ofd2000.exe"), "-x", str(image)])) # Официальный декодер TI читает COFF текущей завершившейся сборки.
coff = xml.find(".//ti_coff") # Загружать через JTAG разрешено именно executable C2000 COFF.
if coff is None or coff.findtext("file_header/exec") != "true" or coff.findtext("file_header/target_id") != "0x9d": raise ValueError("Expected executable C2000 COFF") # Не подписывает чужой объект, ELF либо незалинкованный файл.
first, end, boot = (0x338000, 0x33FF80, 0x33FFF6) if device == "f28335" else (0x3F6000, 0x3F7F80, 0x3F7FF6) # Адреса внутренних секторов A и аппаратных boot-переходов различаются между F28335/F2812.
loaded = set() # Повторная загрузка одного физического слова из двух секций запрещена.
for section in coff.findall("section"): # Рассматривает только реальные данные секций после линковки.
address = int(section.findtext("virtual_addr", "0"), 0); raw = section.findtext("raw_data") # COFF virtual_addr обозначает LOAD, physical_addr — RUN копируемых ramfuncs.
if raw is None or section.findtext("copy") == "true" or section.findtext("name") == ".adc_cal": continue # Исключает только явные COPY/отладочные секции, BSS без raw_data и заводскую ADC-калибровку; загружаемый RAM-код обязан иметь Flash LOAD.
data = base64.b64decode(raw) # Читает точные октеты программируемого содержимого из COFF, а не считает по объявленному размеру.
if len(data) % 2 or not (first <= address < address + len(data) // 2 <= end or address == boot and len(data) == 4): raise ValueError("Loaded section outside bootloader Flash: " + str(section.findtext("name"))) # Защищает OTP, CSM, внешнюю NOR/EEPROM и остальные внутренние секторы.
for word in range(address, address + len(data) // 2): # Контролирует физические 16-битные слова всех программируемых секций.
if word in loaded: raise ValueError("Overlapping load sections") # Даже совпадающие данные не разрешают неоднозначную разметку OUT.
loaded.add(word) # Фиксирует фактически загружаемый диапазон текущего результата.
entry = int(coff.findtext("optional_file_header/entry_point", "0"), 0) # Извлекает реальную точку входа C runtime из заголовка файла.
if entry not in loaded or boot not in loaded or boot + 1 not in loaded: raise ValueError("Missing loaded C entry or codestart") # JTAG OUT обязан одновременно содержать C startup и аппаратный Flash boot переход.
return {"entry_word": entry, "boot_word": boot, "loaded_words": len(loaded)} # Эти проверенные значения входят в build manifest рядом с SHA-256.
def build(device, configuration, compiler, output=None): # Полностью собирает один из двух самостоятельных проектов без установки на плату.
compiler = compiler.resolve(); project, name, flags, sources, commands, libraries, searches = settings(device, configuration, compiler) # Использует абсолютный toolchain и актуальную конфигурацию CCS.
output = (output or project / configuration).resolve(); output.mkdir(parents=True, exist_ok=True) # Генерирует результаты только в каталоге выбранной сборки.
objects = [] # В линковку входят только успешно пересобранные исходники текущего вызова.
with (output / "build.log").open("w", encoding="utf-8") as log: # Журнал содержит полный набор команд и диагностику TI.
def run(command): # Не продолжает сборку после ошибки компилятора или linker.
log.write(json.dumps([str(arg) for arg in command], ensure_ascii=False) + "\n"); log.flush() # Сохраняет команду до запуска процесса без исполнения как shell-кода.
subprocess.run([str(arg) for arg in command], cwd=project, stdout=log, stderr=subprocess.STDOUT, check=True) # Ненулевой статус исключает публикацию ложного успешного результата.
for source in sources: # Все локальные и linked TI-файлы пересобираются для выбранного контроллера.
obj = output / (source.stem + ".obj"); run([compiler / "bin/cl2000.exe", *flags, "-c", "--output_file=" + str(obj), source]); objects.append(obj) # Объекты F2812 soft-float и F28335 FPU32 не смешиваются.
image = output / (name + ".out") # Имя результата совпадает с artifactName импортированного CCS-проекта.
link = [compiler / "bin/cl2000.exe", "-v28", "--abi=coffabi"] + (["--float_support=fpu32"] if device == "f28335" else []) # Linker ABI и FPU точно соответствуют скомпилированным объектам.
run([*link, "-z", "--rom_model", "--entry_point=_c_int00", "--stack_size=0x3f0", "--warn_sections", "--reread_libs", "-m" + str(image.with_suffix(".map")), "-o", image, *["--search_path=" + value for value in searches], *commands, *objects, *["-l" + value for value in libraries]]) # Подключает только собственный linker и оригинальные peripheral sections выбранного MCU.
checked = verify(device, image, compiler) # Физические LOAD-адреса, boot branch и C entry проверяются после каждой CLI-сборки.
manifest = {"device": device, "configuration": configuration, "sha256": hashlib.sha256(image.read_bytes()).hexdigest(), "sources": {str(path.relative_to(ROOT)): hashlib.sha256(path.read_bytes()).hexdigest() for path in sources}, **checked} # Связывает OUT с конкретными исходниками и результатом проверки карты.
image.with_suffix(".out.manifest.json").write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") # Не изменяет версии приложения или данные физической памяти.
return image # Вызывающий явно решает, когда устанавливать OUT через JTAG.
if __name__ == "__main__": # Импорт для проверки проектов не запускает compiler автоматически.
parser = argparse.ArgumentParser(description=__doc__) # Описывает два самостоятельных проекта и отсутствие программирования платы.
parser.add_argument("--device", choices=("f2812", "f28335"), required=True) # Не допускает случайной сборки для другого контроллера.
parser.add_argument("--configuration", choices=("Debug", "Release"), default="Debug") # Повторяет имена управляемых конфигураций CCS.
parser.add_argument("--compiler", type=Path, default=DEFAULT_COMPILER) # Поддерживает другую установленную версию TI с COFF ABI.
parser.add_argument("--output", type=Path) # Разрешает изолированную проверочную сборку без загрязнения импортированного CCS-проекта.
args = parser.parse_args(); print(build(args.device, args.configuration, args.compiler, args.output)) # Сообщает конкретный успешно проверенный OUT, не инициируя JTAG.
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<?ccsproject version="1.0"?>
<projectOptions>
<!-- Описывает ccsVersion: 12.3.0. -->
<ccsVersion value="12.3.0" />
<!-- Описывает deviceVariant: TMS320C28XX.TMS320F2812. -->
<deviceVariant value="TMS320C28XX.TMS320F2812" />
<!-- Описывает deviceFamily: C2000. -->
<deviceFamily value="C2000" />
<!-- Описывает deviceEndianness: little. -->
<deviceEndianness value="little" />
<!-- Описывает codegenToolVersion: 22.6.0.LTS. -->
<codegenToolVersion value="22.6.0.LTS" />
<!-- Описывает isElfFormat: false. -->
<isElfFormat value="false" />
<!-- Описывает rts: rts2800_ml.lib. -->
<rts value="rts2800_ml.lib" />
<!-- Описывает isTargetManual: false. -->
<isTargetManual value="false" />
</projectOptions>
@@ -0,0 +1,306 @@
<?xml version="1.0" encoding="UTF-8"?>
<?fileVersion 4.0.0?>
<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<!-- Описывает storageModule: org.eclipse.cdt.core.settings. -->
<storageModule moduleId="org.eclipse.cdt.core.settings">
<!-- Описывает cconfiguration: cconfiguration. -->
<cconfiguration id="com.ti.ccstudio.buildDefinitions.C2000.Debug.952393063.f2812">
<!-- Описывает storageModule: Debug. -->
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.ti.ccstudio.buildDefinitions.C2000.Debug.952393063.f2812" moduleId="org.eclipse.cdt.core.settings" name="Debug">
<!-- Описывает externalSettings: externalSettings. -->
<externalSettings />
<!-- Описывает extensions: extensions. -->
<extensions>
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.binaryparser.CoffParser.f2812" point="org.eclipse.cdt.core.BinaryParser" />
<!-- Описывает extension: extension. -->
<extension id="org.eclipse.cdt.core.GmakeErrorParser.f2812" point="org.eclipse.cdt.core.ErrorParser" />
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.errorparser.CoffErrorParser.f2812" point="org.eclipse.cdt.core.ErrorParser" />
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.errorparser.AsmErrorParser.f2812" point="org.eclipse.cdt.core.ErrorParser" />
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.errorparser.LinkErrorParser.f2812" point="org.eclipse.cdt.core.ErrorParser" />
</extensions>
</storageModule>
<!-- Описывает storageModule: cdtBuildSystem. -->
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<!-- Описывает configuration: Debug. -->
<configuration artifactExtension="out" artifactName="F2812_CAN_NOR" buildProperties="" cleanCommand="${CG_CLEAN_CMD}" description="" id="com.ti.ccstudio.buildDefinitions.C2000.Debug.952393063.f2812" name="Debug" parent="com.ti.ccstudio.buildDefinitions.C2000.Debug" postbuildStep="" preannouncebuildStep="" prebuildStep="">
<!-- Описывает folderInfo: /. -->
<folderInfo id="com.ti.ccstudio.buildDefinitions.C2000.Debug.952393063.f2812." name="/" resourcePath="">
<!-- Описывает toolChain: TI Build Tools. -->
<toolChain id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.DebugToolchain.1656408937.f2812" name="TI Build Tools" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.DebugToolchain" targetTool="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.linkerDebug.1238234098.f2812">
<!-- Задаёт параметр сборки: option. -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS.1809066827.f2812" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS" valueType="stringList">
<!-- Передаёт значение параметра: DEVICE_CONFIGURATION_ID=TMS320C28XX.TMS320F2812. -->
<listOptionValue builtIn="false" value="DEVICE_CONFIGURATION_ID=TMS320C28XX.TMS320F2812" />
<!-- Передаёт значение параметра: DEVICE_ENDIANNESS=little. -->
<listOptionValue builtIn="false" value="DEVICE_ENDIANNESS=little" />
<!-- Передаёт значение параметра: OUTPUT_FORMAT=COFF. -->
<listOptionValue builtIn="false" value="OUTPUT_FORMAT=COFF" />
<!-- Передаёт значение параметра: LINKER_COMMAND_FILE=F2812_CAN_NOR.cmd. -->
<listOptionValue builtIn="false" value="LINKER_COMMAND_FILE=F2812_CAN_NOR.cmd" />
<!-- Передаёт значение параметра: RUNTIME_SUPPORT_LIBRARY=rts2800_ml.lib. -->
<listOptionValue builtIn="false" value="RUNTIME_SUPPORT_LIBRARY=rts2800_ml.lib" />
<!-- Передаёт значение параметра: CCS_MBS_VERSION=6.1.3. -->
<listOptionValue builtIn="false" value="CCS_MBS_VERSION=6.1.3" />
<!-- Передаёт значение параметра: OUTPUT_TYPE=executable. -->
<listOptionValue builtIn="false" value="OUTPUT_TYPE=executable" />
</option>
<!-- Задаёт параметр сборки: Compiler version. -->
<option id="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION.1182984787.f2812" name="Compiler version" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION" value="22.6.0.LTS" valueType="string" />
<!-- Описывает targetPlatform: Platform. -->
<targetPlatform id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.targetPlatformDebug.2023332194.f2812" name="Platform" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.targetPlatformDebug" />
<!-- Описывает builder: GNU Make. -->
<builder buildPath="${BuildDirectory}" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.builderDebug.1704049401.f2812" keepEnvironmentInBuildfile="false" name="GNU Make" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.builderDebug" />
<!-- Описывает tool: C2000 Compiler. -->
<tool id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.compilerDebug.68471068.f2812" name="C2000 Compiler" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.compilerDebug">
<!-- Задаёт параметр сборки: Option deprecated, set by default (- -large_memory_model, -ml). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.LARGE_MEMORY_MODEL.1683926605.f2812" name="Option deprecated, set by default (--large_memory_model, -ml)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.LARGE_MEMORY_MODEL" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Unified memory (- -unified_memory, -mt). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.UNIFIED_MEMORY.884660743.f2812" name="Unified memory (--unified_memory, -mt)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.UNIFIED_MEMORY" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Processor version (- -silicon_version, -v). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.SILICON_VERSION.750562333.f2812" name="Processor version (--silicon_version, -v)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.SILICON_VERSION" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.SILICON_VERSION.28" valueType="enumerated" />
<!-- Задаёт параметр сборки: Optimization level (- -opt_level, -O). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_LEVEL.1217592973.f2812" name="Optimization level (--opt_level, -O)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_LEVEL" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_LEVEL.3" valueType="enumerated" />
<!-- Задаёт параметр сборки: Place each function in a separate subsection (- -gen_func_subsections, -mo). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.GEN_FUNC_SUBSECTIONS.eeprom.40.f2812" name="Place each function in a separate subsection (--gen_func_subsections, -mo)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.GEN_FUNC_SUBSECTIONS" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.GEN_FUNC_SUBSECTIONS.on" valueType="enumerated" />
<!-- Задаёт параметр сборки: Speed vs. size trade-offs (- -opt_for_speed, -mf). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_FOR_SPEED.1885063317.f2812" name="Speed vs. size trade-offs (--opt_for_speed, -mf)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_FOR_SPEED" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_FOR_SPEED.0" valueType="enumerated" />
<!-- Задаёт параметр сборки: Add dir to #include search path (- -include_path, -I). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.INCLUDE_PATH.24504397.f2812" name="Add dir to #include search path (--include_path, -I)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.INCLUDE_PATH" valueType="includePath">
<!-- Передаёт значение параметра: ${PROJECT_ROOT}. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}" />
<!-- Передаёт значение параметра: ${PROJECT_ROOT}/../../../vendor/ti/f2812/include. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}/../../../vendor/ti/f2812/include" />
<!-- Передаёт значение параметра: ${PROJECT_ROOT}/../../../vendor/ti/f2812/common/include. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}/../../../vendor/ti/f2812/common/include" />
<!-- Передаёт значение параметра: ${CG_TOOL_ROOT}/include. -->
<listOptionValue builtIn="false" value="${CG_TOOL_ROOT}/include" />
</option>
<!-- Задаёт параметр сборки: Pre-define NAME (- -define, -D). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEFINE.409484878.f2812" name="Pre-define NAME (--define, -D)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEFINE" valueType="definedSymbols">
<!-- Передаёт значение параметра: LARGE_MODEL. -->
<listOptionValue builtIn="false" value="LARGE_MODEL" />
<!-- Передаёт значение параметра: _DEBUG. -->
<listOptionValue builtIn="false" value="_DEBUG" />
</option>
<!-- Задаёт параметр сборки: Debugging model. -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEBUGGING_MODEL.1803616155.f2812" name="Debugging model" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEBUGGING_MODEL" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEBUGGING_MODEL.SYMDEBUG__DWARF" valueType="enumerated" />
<!-- Задаёт параметр сборки: Emit diagnostic identifier numbers (- -display_error_number, -pden). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DISPLAY_ERROR_NUMBER.362706119.f2812" name="Emit diagnostic identifier numbers (--display_error_number, -pden)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DISPLAY_ERROR_NUMBER" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Application binary interface [See 'General' page to edit] (- -abi). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.ABI.1036638377.f2812" name="Application binary interface [See 'General' page to edit] (--abi)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.ABI" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.ABI.coffabi" valueType="enumerated" />
<!-- Описывает inputType: C Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__C_SRCS.413246530.f2812" name="C Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__C_SRCS" />
<!-- Описывает inputType: C++ Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__CPP_SRCS.1626831603.f2812" name="C++ Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__CPP_SRCS" />
<!-- Описывает inputType: Assembly Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM_SRCS.291886960.f2812" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM_SRCS" />
<!-- Описывает inputType: Assembly Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM2_SRCS.231319110.f2812" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM2_SRCS" />
</tool>
<!-- Описывает tool: C2000 Linker. -->
<tool id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.linkerDebug.1238234098.f2812" name="C2000 Linker" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.linkerDebug">
<!-- Задаёт параметр сборки: Set C system stack size (- -stack_size, -stack). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.STACK_SIZE.1288161308.f2812" name="Set C system stack size (--stack_size, -stack)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.STACK_SIZE" value="0x3f0" valueType="string" />
<!-- Задаёт параметр сборки: Link information (map) listed into <file> (- -map_file, -m). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.MAP_FILE.1478857036.f2812" name="Link information (map) listed into &lt;file&gt; (--map_file, -m)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.MAP_FILE" value="F2812_CAN_NOR.map" valueType="string" />
<!-- Задаёт параметр сборки: Specify output file name (- -output_file, -o). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.OUTPUT_FILE.1263270138.f2812" name="Specify output file name (--output_file, -o)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.OUTPUT_FILE" value="F2812_CAN_NOR.out" valueType="string" />
<!-- Задаёт параметр сборки: Include library file or command file as input (- -library, -l). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.LIBRARY.1967188356.f2812" name="Include library file or command file as input (--library, -l)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.LIBRARY" valueType="libs">
<!-- Передаёт значение параметра: rts2800_ml.lib. -->
<listOptionValue builtIn="false" value="rts2800_ml.lib" />
</option>
<!-- Задаёт параметр сборки: Add <dir> to library search path (- -search_path, -i). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.SEARCH_PATH.1097407993.f2812" name="Add &lt;dir&gt; to library search path (--search_path, -i)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.SEARCH_PATH" valueType="libPaths">
<!-- Передаёт значение параметра: ${CG_TOOL_ROOT}/lib. -->
<listOptionValue builtIn="false" value="${CG_TOOL_ROOT}/lib" />
<!-- Передаёт значение параметра: ${PROJECT_ROOT}. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}" />
</option>
<!-- Задаёт параметр сборки: Emit diagnostic identifier numbers (- -display_error_number). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.DISPLAY_ERROR_NUMBER.2141790994.f2812" name="Emit diagnostic identifier numbers (--display_error_number)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.DISPLAY_ERROR_NUMBER" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Detailed link information data-base into <file> (- -xml_link_info, -xml_link_info). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.XML_LINK_INFO.1355214148.f2812" name="Detailed link information data-base into &lt;file&gt; (--xml_link_info, -xml_link_info)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.XML_LINK_INFO" value="F2812_CAN_NOR_linkInfo.xml" valueType="string" />
<!-- Задаёт параметр сборки: Specify program entry point for the output module (- -entry_point, -e). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.ENTRY_POINT.862275171.f2812" name="Specify program entry point for the output module (--entry_point, -e)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.ENTRY_POINT" value="_c_int00" valueType="string" />
<!-- Описывает inputType: Linker Command Files. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD_SRCS.1082823352.f2812" name="Linker Command Files" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD_SRCS" />
<!-- Описывает inputType: Linker Command Files. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD2_SRCS.1635863502.f2812" name="Linker Command Files" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD2_SRCS" />
<!-- Описывает inputType: Generated Linker Command Files. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__GEN_CMDS.209596448.f2812" name="Generated Linker Command Files" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__GEN_CMDS" />
</tool>
<!-- Описывает tool: C2000 Hex Utility. -->
<tool id="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex.183039420.f2812" name="C2000 Hex Utility" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex">
<!-- Описывает outputType: Binary File. -->
<outputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex.outputType__BIN.139478444.f2812" name="Binary File" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex.outputType__BIN" />
</tool>
</toolChain>
</folderInfo>
<!-- Ограничивает компилируемые исходники проекта: sourceEntries. -->
<sourceEntries>
<!-- Описывает entry: entry. -->
<entry excluding="Debug|Release" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="" />
</sourceEntries>
</configuration>
</storageModule>
<!-- Описывает storageModule: org.eclipse.cdt.core.externalSettings. -->
<storageModule moduleId="org.eclipse.cdt.core.externalSettings" />
</cconfiguration>
<!-- Описывает cconfiguration: cconfiguration. -->
<cconfiguration id="com.ti.ccstudio.buildDefinitions.C2000.Release.952393063.f2812">
<!-- Описывает storageModule: Release. -->
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.ti.ccstudio.buildDefinitions.C2000.Release.952393063.f2812" moduleId="org.eclipse.cdt.core.settings" name="Release">
<!-- Описывает externalSettings: externalSettings. -->
<externalSettings />
<!-- Описывает extensions: extensions. -->
<extensions>
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.binaryparser.CoffParser.f2812" point="org.eclipse.cdt.core.BinaryParser" />
<!-- Описывает extension: extension. -->
<extension id="org.eclipse.cdt.core.GmakeErrorParser.f2812" point="org.eclipse.cdt.core.ErrorParser" />
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.errorparser.CoffErrorParser.f2812" point="org.eclipse.cdt.core.ErrorParser" />
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.errorparser.AsmErrorParser.f2812" point="org.eclipse.cdt.core.ErrorParser" />
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.errorparser.LinkErrorParser.f2812" point="org.eclipse.cdt.core.ErrorParser" />
</extensions>
</storageModule>
<!-- Описывает storageModule: cdtBuildSystem. -->
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<!-- Описывает configuration: Release. -->
<configuration artifactExtension="out" artifactName="F2812_CAN_NOR" buildProperties="" cleanCommand="${CG_CLEAN_CMD}" description="" id="com.ti.ccstudio.buildDefinitions.C2000.Release.952393063.f2812" name="Release" parent="com.ti.ccstudio.buildDefinitions.C2000.Release" postbuildStep="" preannouncebuildStep="" prebuildStep="">
<!-- Описывает folderInfo: /. -->
<folderInfo id="com.ti.ccstudio.buildDefinitions.C2000.Release.952393063.f2812." name="/" resourcePath="">
<!-- Описывает toolChain: TI Build Tools. -->
<toolChain id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.ReleaseToolchain.1656408937.f2812" name="TI Build Tools" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.ReleaseToolchain" targetTool="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.linkerRelease.1238234098.f2812">
<!-- Задаёт параметр сборки: option. -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS.1809066827.f2812" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS" valueType="stringList">
<!-- Передаёт значение параметра: DEVICE_CONFIGURATION_ID=TMS320C28XX.TMS320F2812. -->
<listOptionValue builtIn="false" value="DEVICE_CONFIGURATION_ID=TMS320C28XX.TMS320F2812" />
<!-- Передаёт значение параметра: DEVICE_ENDIANNESS=little. -->
<listOptionValue builtIn="false" value="DEVICE_ENDIANNESS=little" />
<!-- Передаёт значение параметра: OUTPUT_FORMAT=COFF. -->
<listOptionValue builtIn="false" value="OUTPUT_FORMAT=COFF" />
<!-- Передаёт значение параметра: LINKER_COMMAND_FILE=F2812_CAN_NOR.cmd. -->
<listOptionValue builtIn="false" value="LINKER_COMMAND_FILE=F2812_CAN_NOR.cmd" />
<!-- Передаёт значение параметра: RUNTIME_SUPPORT_LIBRARY=rts2800_ml.lib. -->
<listOptionValue builtIn="false" value="RUNTIME_SUPPORT_LIBRARY=rts2800_ml.lib" />
<!-- Передаёт значение параметра: CCS_MBS_VERSION=6.1.3. -->
<listOptionValue builtIn="false" value="CCS_MBS_VERSION=6.1.3" />
<!-- Передаёт значение параметра: OUTPUT_TYPE=executable. -->
<listOptionValue builtIn="false" value="OUTPUT_TYPE=executable" />
</option>
<!-- Задаёт параметр сборки: Compiler version. -->
<option id="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION.1182984787.f2812" name="Compiler version" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION" value="22.6.0.LTS" valueType="string" />
<!-- Описывает targetPlatform: Platform. -->
<targetPlatform id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.targetPlatformRelease.2023332194.f2812" name="Platform" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.targetPlatformRelease" />
<!-- Описывает builder: GNU Make. -->
<builder buildPath="${BuildDirectory}" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.builderRelease.1704049401.f2812" keepEnvironmentInBuildfile="false" name="GNU Make" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.builderRelease" />
<!-- Описывает tool: C2000 Compiler. -->
<tool id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.compilerRelease.68471068.f2812" name="C2000 Compiler" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.compilerRelease">
<!-- Задаёт параметр сборки: Option deprecated, set by default (- -large_memory_model, -ml). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.LARGE_MEMORY_MODEL.1683926605.f2812" name="Option deprecated, set by default (--large_memory_model, -ml)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.LARGE_MEMORY_MODEL" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Unified memory (- -unified_memory, -mt). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.UNIFIED_MEMORY.884660743.f2812" name="Unified memory (--unified_memory, -mt)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.UNIFIED_MEMORY" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Processor version (- -silicon_version, -v). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.SILICON_VERSION.750562333.f2812" name="Processor version (--silicon_version, -v)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.SILICON_VERSION" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.SILICON_VERSION.28" valueType="enumerated" />
<!-- Задаёт параметр сборки: Optimization level (- -opt_level, -O). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_LEVEL.1217592973.f2812" name="Optimization level (--opt_level, -O)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_LEVEL" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_LEVEL.3" valueType="enumerated" />
<!-- Задаёт параметр сборки: Place each function in a separate subsection (- -gen_func_subsections, -mo). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.GEN_FUNC_SUBSECTIONS.eeprom.40.f2812" name="Place each function in a separate subsection (--gen_func_subsections, -mo)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.GEN_FUNC_SUBSECTIONS" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.GEN_FUNC_SUBSECTIONS.on" valueType="enumerated" />
<!-- Задаёт параметр сборки: Speed vs. size trade-offs (- -opt_for_speed, -mf). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_FOR_SPEED.1885063317.f2812" name="Speed vs. size trade-offs (--opt_for_speed, -mf)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_FOR_SPEED" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_FOR_SPEED.0" valueType="enumerated" />
<!-- Задаёт параметр сборки: Add dir to #include search path (- -include_path, -I). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.INCLUDE_PATH.24504397.f2812" name="Add dir to #include search path (--include_path, -I)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.INCLUDE_PATH" valueType="includePath">
<!-- Передаёт значение параметра: ${PROJECT_ROOT}. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}" />
<!-- Передаёт значение параметра: ${PROJECT_ROOT}/../../../vendor/ti/f2812/include. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}/../../../vendor/ti/f2812/include" />
<!-- Передаёт значение параметра: ${PROJECT_ROOT}/../../../vendor/ti/f2812/common/include. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}/../../../vendor/ti/f2812/common/include" />
<!-- Передаёт значение параметра: ${CG_TOOL_ROOT}/include. -->
<listOptionValue builtIn="false" value="${CG_TOOL_ROOT}/include" />
</option>
<!-- Задаёт параметр сборки: Pre-define NAME (- -define, -D). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEFINE.409484878.f2812" name="Pre-define NAME (--define, -D)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEFINE" valueType="definedSymbols">
<!-- Передаёт значение параметра: LARGE_MODEL. -->
<listOptionValue builtIn="false" value="LARGE_MODEL" />
<!-- Передаёт значение параметра: _DEBUG. -->
</option>
<!-- Задаёт параметр сборки: Releaseging model. -->
<!-- Задаёт параметр сборки: Emit diagnostic identifier numbers (- -display_error_number, -pden). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DISPLAY_ERROR_NUMBER.362706119.f2812" name="Emit diagnostic identifier numbers (--display_error_number, -pden)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DISPLAY_ERROR_NUMBER" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Application binary interface [See 'General' page to edit] (- -abi). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.ABI.1036638377.f2812" name="Application binary interface [See 'General' page to edit] (--abi)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.ABI" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.ABI.coffabi" valueType="enumerated" />
<!-- Описывает inputType: C Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__C_SRCS.413246530.f2812" name="C Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__C_SRCS" />
<!-- Описывает inputType: C++ Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__CPP_SRCS.1626831603.f2812" name="C++ Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__CPP_SRCS" />
<!-- Описывает inputType: Assembly Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM_SRCS.291886960.f2812" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM_SRCS" />
<!-- Описывает inputType: Assembly Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM2_SRCS.231319110.f2812" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM2_SRCS" />
</tool>
<!-- Описывает tool: C2000 Linker. -->
<tool id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.linkerRelease.1238234098.f2812" name="C2000 Linker" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.linkerRelease">
<!-- Задаёт параметр сборки: Set C system stack size (- -stack_size, -stack). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.STACK_SIZE.1288161308.f2812" name="Set C system stack size (--stack_size, -stack)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.STACK_SIZE" value="0x3f0" valueType="string" />
<!-- Задаёт параметр сборки: Link information (map) listed into <file> (- -map_file, -m). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.MAP_FILE.1478857036.f2812" name="Link information (map) listed into &lt;file&gt; (--map_file, -m)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.MAP_FILE" value="F2812_CAN_NOR.map" valueType="string" />
<!-- Задаёт параметр сборки: Specify output file name (- -output_file, -o). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.OUTPUT_FILE.1263270138.f2812" name="Specify output file name (--output_file, -o)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.OUTPUT_FILE" value="F2812_CAN_NOR.out" valueType="string" />
<!-- Задаёт параметр сборки: Include library file or command file as input (- -library, -l). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.LIBRARY.1967188356.f2812" name="Include library file or command file as input (--library, -l)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.LIBRARY" valueType="libs">
<!-- Передаёт значение параметра: rts2800_ml.lib. -->
<listOptionValue builtIn="false" value="rts2800_ml.lib" />
</option>
<!-- Задаёт параметр сборки: Add <dir> to library search path (- -search_path, -i). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.SEARCH_PATH.1097407993.f2812" name="Add &lt;dir&gt; to library search path (--search_path, -i)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.SEARCH_PATH" valueType="libPaths">
<!-- Передаёт значение параметра: ${CG_TOOL_ROOT}/lib. -->
<listOptionValue builtIn="false" value="${CG_TOOL_ROOT}/lib" />
<!-- Передаёт значение параметра: ${PROJECT_ROOT}. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}" />
</option>
<!-- Задаёт параметр сборки: Emit diagnostic identifier numbers (- -display_error_number). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.DISPLAY_ERROR_NUMBER.2141790994.f2812" name="Emit diagnostic identifier numbers (--display_error_number)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.DISPLAY_ERROR_NUMBER" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Detailed link information data-base into <file> (- -xml_link_info, -xml_link_info). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.XML_LINK_INFO.1355214148.f2812" name="Detailed link information data-base into &lt;file&gt; (--xml_link_info, -xml_link_info)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.XML_LINK_INFO" value="F2812_CAN_NOR_linkInfo.xml" valueType="string" />
<!-- Задаёт параметр сборки: Specify program entry point for the output module (- -entry_point, -e). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.ENTRY_POINT.862275171.f2812" name="Specify program entry point for the output module (--entry_point, -e)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.ENTRY_POINT" value="_c_int00" valueType="string" />
<!-- Описывает inputType: Linker Command Files. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD_SRCS.1082823352.f2812" name="Linker Command Files" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD_SRCS" />
<!-- Описывает inputType: Linker Command Files. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD2_SRCS.1635863502.f2812" name="Linker Command Files" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD2_SRCS" />
<!-- Описывает inputType: Generated Linker Command Files. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__GEN_CMDS.209596448.f2812" name="Generated Linker Command Files" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__GEN_CMDS" />
</tool>
<!-- Описывает tool: C2000 Hex Utility. -->
<tool id="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex.183039420.f2812" name="C2000 Hex Utility" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex">
<!-- Описывает outputType: Binary File. -->
<outputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex.outputType__BIN.139478444.f2812" name="Binary File" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex.outputType__BIN" />
</tool>
</toolChain>
</folderInfo>
<!-- Ограничивает компилируемые исходники проекта: sourceEntries. -->
<sourceEntries>
<!-- Описывает entry: entry. -->
<entry excluding="Release|Release" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="" />
</sourceEntries>
</configuration>
</storageModule>
<!-- Описывает storageModule: org.eclipse.cdt.core.externalSettings. -->
<storageModule moduleId="org.eclipse.cdt.core.externalSettings" />
</cconfiguration>
</storageModule>
<!-- Описывает storageModule: cdtBuildSystem. -->
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<!-- Регистрирует тип самостоятельного C2000-проекта: без этой записи CCS не определяет compiler definition при импорте. -->
<project id="F2812_CAN_NOR.com.ti.ccstudio.buildDefinitions.C2000.ProjectType.1" name="C2000" projectType="com.ti.ccstudio.buildDefinitions.C2000.ProjectType" />
</storageModule>
</cproject>
+106
View File
@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<!-- Описывает name: name. -->
<name>F2812_CAN_NOR</name>
<!-- Описывает comment: comment. -->
<comment>Отдельный постоянный загрузчик ProtoCAN для F2812</comment>
<!-- Описывает projects: projects. -->
<projects />
<!-- Описывает buildSpec: buildSpec. -->
<buildSpec>
<!-- Описывает buildCommand: buildCommand. -->
<buildCommand>
<!-- Описывает name: name. -->
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<!-- Описывает arguments: arguments. -->
<arguments />
</buildCommand>
<!-- Описывает buildCommand: buildCommand. -->
<buildCommand>
<!-- Описывает name: name. -->
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<!-- Описывает arguments: arguments. -->
<arguments />
</buildCommand>
</buildSpec>
<!-- Описывает natures: natures. -->
<natures>
<!-- Описывает nature: nature. -->
<nature>com.ti.ccstudio.core.ccsNature</nature>
<!-- Описывает nature: nature. -->
<nature>org.eclipse.cdt.core.cnature</nature>
<!-- Описывает nature: nature. -->
<nature>org.eclipse.cdt.core.ccnature</nature>
<!-- Описывает nature: nature. -->
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<!-- Описывает nature: nature. -->
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
<!-- Описывает linkedResources: linkedResources. -->
<linkedResources>
<!-- Подключает исходник или linker из общей библиотеки: link. -->
<link>
<!-- Описывает name: name. -->
<name>ti/DSP281x_CpuTimers.c</name>
<!-- Описывает type: type. -->
<type>1</type>
<!-- Описывает locationURI: locationURI. -->
<locationURI>PCAN_ROOT/vendor/ti/f2812/source/DSP281x_CpuTimers.c</locationURI>
</link>
<!-- Подключает исходник или linker из общей библиотеки: link. -->
<link>
<!-- Описывает name: name. -->
<name>ti/DSP281x_GlobalVariableDefs.c</name>
<!-- Описывает type: type. -->
<type>1</type>
<!-- Описывает locationURI: locationURI. -->
<locationURI>PCAN_ROOT/vendor/ti/f2812/source/DSP281x_GlobalVariableDefs.c</locationURI>
</link>
<!-- Подключает исходник или linker из общей библиотеки: link. -->
<link>
<!-- Описывает name: name. -->
<name>ti/DSP281x_PieCtrl.c</name>
<!-- Описывает type: type. -->
<type>1</type>
<!-- Описывает locationURI: locationURI. -->
<locationURI>PCAN_ROOT/vendor/ti/f2812/source/DSP281x_PieCtrl.c</locationURI>
</link>
<!-- Подключает исходник или linker из общей библиотеки: link. -->
<link>
<!-- Описывает name: name. -->
<name>ti/DSP281x_SysCtrl.c</name>
<!-- Описывает type: type. -->
<type>1</type>
<!-- Описывает locationURI: locationURI. -->
<locationURI>PCAN_ROOT/vendor/ti/f2812/source/DSP281x_SysCtrl.c</locationURI>
</link>
<!-- Подключает исходник или linker из общей библиотеки: link. -->
<link>
<!-- Описывает name: name. -->
<name>ti/DSP281x_usDelay.asm</name>
<!-- Описывает type: type. -->
<type>1</type>
<!-- Описывает locationURI: locationURI. -->
<locationURI>PCAN_ROOT/vendor/ti/f2812/source/DSP281x_usDelay.asm</locationURI>
</link>
<!-- Подключает исходник или linker из общей библиотеки: link. -->
<link>
<!-- Описывает name: name. -->
<name>DSP281x_Headers_nonBIOS.cmd</name>
<!-- Описывает type: type. -->
<type>1</type>
<!-- Описывает locationURI: locationURI. -->
<locationURI>PCAN_ROOT/vendor/ti/f2812/cmd/DSP281x_Headers_nonBIOS.cmd</locationURI>
</link>
</linkedResources>
<!-- Описывает variableList: variableList. -->
<variableList>
<!-- Описывает variable: variable. -->
<variable>
<!-- Описывает name: name. -->
<name>PCAN_ROOT</name>
<!-- Описывает value: value. -->
<value>$%7BPARENT-3-PROJECT_LOC%7D</value>
</variable>
</variableList>
</projectDescription>
@@ -0,0 +1,28 @@
MEMORY /* Постоянный загрузчик F2812 хранится во внутренней Flash, обновляемые данные — во внешней AM29LV800BT. */
{ /* Адреса указаны в 16-битных словах C28x, независимо от размера файлов CAN. */
PAGE 0: /* Исполняемый код и его копируемая RAM-часть. */
FLASHA : origin = 0x3F6000, length = 0x001F80 /* Сектор A исключает зарезервированные слова CSM в верхних 128 словах. */
BEGIN : origin = 0x3F7FF6, length = 0x000002 /* Аппаратный Flash boot F2812 начинает длинный переход из двух слов. */
RAMFUNCS : origin = 0x008F00, length = 0x000100 /* Последние 256 слов L0 содержат InitFlash и исключены из SCI8 payload приложения. */
RESET : origin = 0x3FFFC0, length = 0x000002 /* ROM reset не программируется при установке загрузчика. */
PAGE 1: /* Рабочая RAM постоянно работающего загрузчика не должна входить в загружаемый файл. */
RAMM0 : origin = 0x000050, length = 0x0003B0 /* Исключает первые 80 слов Boot ROM scratch. */
RAMM1 : origin = 0x000400, length = 0x000400 /* Отдельный стек на 1024 слова совпадает с аппаратным банком M1. */
RAMDATA : origin = 0x009000, length = 0x001000 /* Банк L1 хранит очередь CAN и состояния загрузчика до перехода в приложение. */
} /* Верхний H0 и внешняя SRAM остаются доступны payload приложения. */
SECTIONS /* Ни одна загружаемая секция OUT не записывается во внешнюю NOR автоматически. */
{ /* Все команды программирования NOR исполняются из внутреннего сектора A. */
codestart : > BEGIN, PAGE = 0 /* Направляет аппаратный boot в watchdog-safe C startup. */
.text : > FLASHA, PAGE = 0 /* Размещает общий ProtoCAN, driver NOR и проверку SCI8 в постоянной Flash. */
.fast_run : > FLASHA, PAGE = 0 /* Штатный DSP281x_usDelay вызывается ещё из InitSysCtrl до копирования ramfuncs, поэтому его LOAD/RUN должны сразу находиться во Flash. */
.cinit : > FLASHA, PAGE = 0 /* Таблицы ROM-модели инициализируют состояние до main. */
.pinit : > FLASHA, PAGE = 0 /* Сохраняет стандартный startup для возможных статических конструкторов. */
.econst : > FLASHA, PAGE = 0 /* Константы не расходуют ограниченную RAM L1. */
.switch : > FLASHA, PAGE = 0 /* Таблицы switch остаются доступны во время erase внешнего чипа. */
ramfuncs : LOAD = FLASHA, RUN = RAMFUNCS, LOAD_START(_RamfuncsLoadStart), LOAD_END(_RamfuncsLoadEnd), RUN_START(_RamfuncsRunStart), PAGE = 0 /* InitFlash копируется в внутреннюю RAM до изменения таймингов Flash. */
.stack : > RAMM1, PAGE = 1 /* Стек не пересекает RAM назначения проверяемого образа. */
.ebss : > RAMDATA, PAGE = 1 /* Состояния очереди и текущей сессии исключены из разрешённых SCI8 адресов. */
.esysmem : > RAMDATA, PAGE = 1 /* Поддерживает стандартную секцию runtime, хотя алгоритм не требует heap. */
.fast_vars1 : > RAMDATA, PAGE = 1 /* Подключает штатный HSPCLK выбранного TI SDK без размещения случайной orphan-секции. */
.reset : > RESET, PAGE = 0, TYPE = DSECT /* Не выдаёт ROM reset за программируемую часть OUT. */
} /* Не создаёт секции OTP или паролей CSM. */
@@ -0,0 +1,30 @@
#include "DSP281x_Device.h" /* Использует оригинальные TI определения GPIO и XINTF F2812. */
#include "../../../ports/tms320f2812/boot2812.h" /* Получает отдельный аппаратный профиль внешней NOR ПМ67. */
static void operation(unsigned int a, unsigned int b, unsigned int c, unsigned int d) /* Повторяет управляющую защёлку CPLD из big_dsp_module.c штатной платы. */
{ /* GPIOA13/A14/A15 и GPIOB13 задают код, GPIOB15 формирует строб. */
EALLOW; /* Разрешает запись системных GPIO платы. */
GpioDataRegs.GPADAT.bit.GPIOA13 = a; GpioDataRegs.GPADAT.bit.GPIOA14 = b; /* Первые два бита аппаратной команды соответствуют oper_mode1/2. */
GpioDataRegs.GPADAT.bit.GPIOA15 = c; GpioDataRegs.GPBDAT.bit.GPIOB13 = d; /* Третий и четвёртый биты повторяют штатный write_oper. */
asm(" NOP"); GpioDataRegs.GPBDAT.bit.GPIOB15 = 0; /* Снимает строб после установки всех четырёх битов команды. */
asm(" RPT #2 || NOP"); GpioDataRegs.GPBDAT.bit.GPIOB15 = 1; /* Даёт защёлке время установления и формирует активный фронт. */
asm(" RPT #2 || NOP"); GpioDataRegs.GPBDAT.bit.GPIOB15 = 0; /* Возвращает строб в исходное состояние с выдержкой как в рабочем драйвере. */
asm(" RPT #2 || NOP"); EDIS; /* Завершает длительность импульса до следующей команды CPLD. */
} /* Команда не изменяет выбранные аппаратные boot-перемычки контроллера. */
void Boot2812_BoardInit(void) /* Настраивает подтверждённую схему ПМ67 с AM29LV800BT на XINTF zone6. */
{ /* Значения линий взяты из setup_oper_line/init_flash/xintf_zone6and7_timing действующего проекта BALZAM_167. */
EALLOW; /* GPIO mux/direction и XINTF изменяются в разрешённом защищённом контексте. */
GpioMuxRegs.GPAMUX.bit.C1TRIP_GPIOA13 = 0; GpioMuxRegs.GPAMUX.bit.C2TRIP_GPIOA14 = 0; GpioMuxRegs.GPAMUX.bit.C3TRIP_GPIOA15 = 0; /* Выбирает GPIO для трёх командных линий CPLD вместо функций event manager. */
GpioMuxRegs.GPBMUX.bit.C4TRIP_GPIOB13 = 0; GpioMuxRegs.GPBMUX.bit.C6TRIP_GPIOB15 = 0; /* Освобождает четвёртый бит команды и строб CPLD. */
GpioMuxRegs.GPADIR.bit.GPIOA13 = 1; GpioMuxRegs.GPADIR.bit.GPIOA14 = 1; GpioMuxRegs.GPADIR.bit.GPIOA15 = 1; /* Переводит командные линии A в выходы, как рабочий драйвер платы. */
GpioMuxRegs.GPBDIR.bit.GPIOB13 = 1; GpioMuxRegs.GPBDIR.bit.GPIOB15 = 1; /* Разрешает выдачу четвёртого бита и импульса защёлки. */
XintfRegs.XINTCNF2.bit.XTIMCLK = 1; XintfRegs.XINTCNF2.bit.WRBUFF = 0; /* XTIMCLK=SYSCLKOUT/2; отключённая буферизация сохраняет порядок unlock-циклов AMD. */
XintfRegs.XINTCNF2.bit.CLKOFF = 0; XintfRegs.XINTCNF2.bit.CLKMODE = 0; XintfRegs.XINTCNF2.bit.MPNMC = 0; /* Повторяет штатный режим XCLKOUT и микроконтроллерный boot платы. */
XintfRegs.XTIMING6.bit.XWRLEAD = 3; XintfRegs.XTIMING6.bit.XWRACTIVE = 7; XintfRegs.XTIMING6.bit.XWRTRAIL = 3; /* Времена записи NOR повторяют проверенный flash_tools/init_flash платы в единицах XTIMCLK. */
XintfRegs.XTIMING6.bit.XRDLEAD = 3; XintfRegs.XTIMING6.bit.XRDACTIVE = 3; XintfRegs.XTIMING6.bit.XRDTRAIL = 3; /* Времена чтения соответствуют штатному профилю AM29LV800BT-70EI. */
XintfRegs.XTIMING6.bit.X2TIMING = 0; XintfRegs.XTIMING6.bit.USEREADY = 0; XintfRegs.XTIMING6.bit.READYMODE = 0; XintfRegs.XTIMING6.bit.XSIZE = 3; /* Выбирает 16-битную зону без внешнего READY и без дополнительного удвоения тактов. */
XintfRegs.XTIMING2.bit.XWRLEAD = 3; XintfRegs.XTIMING2.bit.XWRACTIVE = 7; XintfRegs.XTIMING2.bit.XWRTRAIL = 3; /* Консервативный x16 режим внешней SRAM позволяет загружать приложение в zone2. */
XintfRegs.XTIMING2.bit.XRDLEAD = 3; XintfRegs.XTIMING2.bit.XRDACTIVE = 7; XintfRegs.XTIMING2.bit.XRDTRAIL = 3; /* Удлинённое чтение SRAM не зависит от коротких прикладных таймингов. */
XintfRegs.XTIMING2.bit.X2TIMING = 0; XintfRegs.XTIMING2.bit.USEREADY = 0; XintfRegs.XTIMING2.bit.READYMODE = 0; XintfRegs.XTIMING2.bit.XSIZE = 3; /* Не включает неподтверждённую линию READY платы. */
asm(" RPT #7 || NOP"); EDIS; /* Сбрасывает pipeline после изменения XINTF до первого внешнего чтения. */
operation(1U, 1U, 1U, 1U); operation(1U, 0U, 1U, 0U); operation(0U, 0U, 0U, 0U); /* Штатные select_nothing, select_strob_67_for_flash, select_work_with_flash выбирают CPU-доступ к NOR. */
} /* Изменение схемы CPLD требует отдельного профиля платы, а не другого размера EEPROM. */
@@ -0,0 +1 @@
#include "../../../ports/tms320f2812/boot_store.c" /* Подключает проверку SCI8 и публикацию NOR manifest без копирования кода в проект CCS. */
@@ -0,0 +1,12 @@
.ref _c_int00 ; Стандартный COFF startup применяет .cinit и вызывает main после отключения раннего watchdog.
.sect "codestart" ; Boot ROM передаёт управление двухсловному переходу по аппаратному адресу слова 0x33FFF6.
LB flash_boot_start ; Переходит к короткой подготовке C28x во Flash, сохраняя точный размер аппаратного входа два слова.
.text ; Последовательность взята из штатного TI DSP2833x_CodeStartBranch.asm и размещается в секторе основного кода.
flash_boot_start: ; Отключает watchdog до возможной длительной обработки таблиц инициализации C, а не только после входа в main.
SETC OBJMODE ; Выбирает C28x object mode, требуемый стандартным COFF startup процессора F28335.
EALLOW ; Разрешает запись защищённого регистра WDCR перед запуском C runtime.
MOVZ DP, #7029h>>6 ; Адрес слова WDCR=0x7029 из карты F28335; DP выбирает соответствующую страницу по 64 слова.
MOV @7029h, #0068h ; Значение 0x0068 содержит контрольные биты WDCHK=101 и WDDIS=1, как официальный TI startup.
EDIS ; Возвращает защиту системных регистров перед переходом в библиотечную инициализацию.
LB _c_int00 ; Применяет штатную ROM-модель инициализации и затем запускает текущий main 167.
.end ; Завершает модуль, не добавляя произвольных данных рядом с CSM-паролями сектора A.
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
#include "../../../ports/tms320f2812/nor_flash.c" /* Собирает канонический драйвер AM29LV800BT из templates, сохраняя hardware callbacks отдельно от протокола. */
@@ -0,0 +1 @@
#include "../../../src/pcan_boot.c" /* Подключает общий ProtoCAN codec, сессии и CRC32 без второй реализации протокола. */
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<configurations XML_version="1.2" id="configurations_0">
<configuration XML_version="1.2" id="configuration_0">
<instance XML_version="1.2" desc="Sauris SAU510-USB Iso Plus Emulator" href="connections/SAU510USBIsoPlus_Connection.xml" id="Sauris SAU510-USB Iso Plus Emulator" xml="SAU510USBIsoPlus_Connection.xml" xmlpath="connections"/>
<connection XML_version="1.2" id="Sauris SAU510-USB Iso Plus Emulator">
<instance XML_version="1.2" href="drivers/sau510c28x.xml" id="drivers" xml="sau510c28x.xml" xmlpath="drivers"/>
<platform XML_version="1.2" id="platform_0">
<instance XML_version="1.2" desc="TMS320F2812" href="devices/f2812.xml" id="TMS320F2812" xml="f2812.xml" xmlpath="devices"/>
</platform>
</connection>
</configuration>
</configurations>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<?ccsproject version="1.0"?>
<projectOptions>
<!-- Описывает ccsVersion: 12.3.0. -->
<ccsVersion value="12.3.0" />
<!-- Описывает deviceVariant: TMS320C28XX.TMS320F28335. -->
<deviceVariant value="TMS320C28XX.TMS320F28335" />
<!-- Описывает deviceFamily: C2000. -->
<deviceFamily value="C2000" />
<!-- Описывает deviceEndianness: little. -->
<deviceEndianness value="little" />
<!-- Описывает codegenToolVersion: 22.6.0.LTS. -->
<codegenToolVersion value="22.6.0.LTS" />
<!-- Описывает isElfFormat: false. -->
<isElfFormat value="false" />
<!-- Описывает rts: rts2800_fpu32.lib. -->
<rts value="rts2800_fpu32.lib" />
<!-- Описывает isTargetManual: false. -->
<isTargetManual value="false" />
</projectOptions>
@@ -0,0 +1,326 @@
<?xml version="1.0" encoding="UTF-8"?>
<?fileVersion 4.0.0?>
<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<!-- Описывает storageModule: org.eclipse.cdt.core.settings. -->
<storageModule moduleId="org.eclipse.cdt.core.settings">
<!-- Описывает cconfiguration: cconfiguration. -->
<cconfiguration id="com.ti.ccstudio.buildDefinitions.C2000.Debug.952393063.f28335">
<!-- Описывает storageModule: Debug. -->
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.ti.ccstudio.buildDefinitions.C2000.Debug.952393063.f28335" moduleId="org.eclipse.cdt.core.settings" name="Debug">
<!-- Описывает externalSettings: externalSettings. -->
<externalSettings />
<!-- Описывает extensions: extensions. -->
<extensions>
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.binaryparser.CoffParser.f28335" point="org.eclipse.cdt.core.BinaryParser" />
<!-- Описывает extension: extension. -->
<extension id="org.eclipse.cdt.core.GmakeErrorParser.f28335" point="org.eclipse.cdt.core.ErrorParser" />
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.errorparser.CoffErrorParser.f28335" point="org.eclipse.cdt.core.ErrorParser" />
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.errorparser.AsmErrorParser.f28335" point="org.eclipse.cdt.core.ErrorParser" />
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.errorparser.LinkErrorParser.f28335" point="org.eclipse.cdt.core.ErrorParser" />
</extensions>
</storageModule>
<!-- Описывает storageModule: cdtBuildSystem. -->
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<!-- Описывает configuration: Debug. -->
<configuration artifactExtension="out" artifactName="F28335_CAN_AB" buildProperties="" cleanCommand="${CG_CLEAN_CMD}" description="" id="com.ti.ccstudio.buildDefinitions.C2000.Debug.952393063.f28335" name="Debug" parent="com.ti.ccstudio.buildDefinitions.C2000.Debug" postbuildStep="" preannouncebuildStep="" prebuildStep="">
<!-- Описывает folderInfo: /. -->
<folderInfo id="com.ti.ccstudio.buildDefinitions.C2000.Debug.952393063.f28335." name="/" resourcePath="">
<!-- Описывает toolChain: TI Build Tools. -->
<toolChain id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.DebugToolchain.1656408937.f28335" name="TI Build Tools" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.DebugToolchain" targetTool="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.linkerDebug.1238234098.f28335">
<!-- Задаёт параметр сборки: option. -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS.1809066827.f28335" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS" valueType="stringList">
<!-- Передаёт значение параметра: DEVICE_CONFIGURATION_ID=TMS320C28XX.TMS320F28335. -->
<listOptionValue builtIn="false" value="DEVICE_CONFIGURATION_ID=TMS320C28XX.TMS320F28335" />
<!-- Передаёт значение параметра: DEVICE_ENDIANNESS=little. -->
<listOptionValue builtIn="false" value="DEVICE_ENDIANNESS=little" />
<!-- Передаёт значение параметра: OUTPUT_FORMAT=COFF. -->
<listOptionValue builtIn="false" value="OUTPUT_FORMAT=COFF" />
<!-- Передаёт значение параметра: LINKER_COMMAND_FILE=F28335_CAN_AB.cmd. -->
<listOptionValue builtIn="false" value="LINKER_COMMAND_FILE=F28335_CAN_AB.cmd" />
<!-- Передаёт значение параметра: RUNTIME_SUPPORT_LIBRARY=rts2800_fpu32.lib. -->
<listOptionValue builtIn="false" value="RUNTIME_SUPPORT_LIBRARY=rts2800_fpu32.lib" />
<!-- Передаёт значение параметра: CCS_MBS_VERSION=6.1.3. -->
<listOptionValue builtIn="false" value="CCS_MBS_VERSION=6.1.3" />
<!-- Передаёт значение параметра: OUTPUT_TYPE=executable. -->
<listOptionValue builtIn="false" value="OUTPUT_TYPE=executable" />
</option>
<!-- Задаёт параметр сборки: Compiler version. -->
<option id="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION.1182984787.f28335" name="Compiler version" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION" value="22.6.0.LTS" valueType="string" />
<!-- Описывает targetPlatform: Platform. -->
<targetPlatform id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.targetPlatformDebug.2023332194.f28335" name="Platform" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.targetPlatformDebug" />
<!-- Описывает builder: GNU Make. -->
<builder buildPath="${BuildDirectory}" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.builderDebug.1704049401.f28335" keepEnvironmentInBuildfile="false" name="GNU Make" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.builderDebug" />
<!-- Описывает tool: C2000 Compiler. -->
<tool id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.compilerDebug.68471068.f28335" name="C2000 Compiler" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.compilerDebug">
<!-- Задаёт параметр сборки: Option deprecated, set by default (- -large_memory_model, -ml). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.LARGE_MEMORY_MODEL.1683926605.f28335" name="Option deprecated, set by default (--large_memory_model, -ml)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.LARGE_MEMORY_MODEL" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Unified memory (- -unified_memory, -mt). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.UNIFIED_MEMORY.884660743.f28335" name="Unified memory (--unified_memory, -mt)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.UNIFIED_MEMORY" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Processor version (- -silicon_version, -v). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.SILICON_VERSION.750562333.f28335" name="Processor version (--silicon_version, -v)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.SILICON_VERSION" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.SILICON_VERSION.28" valueType="enumerated" />
<!-- Задаёт параметр сборки: Specify floating point support (- -float_support). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.FLOAT_SUPPORT.1723304888.f28335" name="Specify floating point support (--float_support)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.FLOAT_SUPPORT" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.FLOAT_SUPPORT.fpu32" valueType="enumerated" />
<!-- Задаёт параметр сборки: Optimization level (- -opt_level, -O). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_LEVEL.1217592973.f28335" name="Optimization level (--opt_level, -O)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_LEVEL" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_LEVEL.3" valueType="enumerated" />
<!-- Задаёт параметр сборки: Place each function in a separate subsection (- -gen_func_subsections, -mo). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.GEN_FUNC_SUBSECTIONS.eeprom.40.f28335" name="Place each function in a separate subsection (--gen_func_subsections, -mo)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.GEN_FUNC_SUBSECTIONS" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.GEN_FUNC_SUBSECTIONS.on" valueType="enumerated" />
<!-- Задаёт параметр сборки: Speed vs. size trade-offs (- -opt_for_speed, -mf). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_FOR_SPEED.1885063317.f28335" name="Speed vs. size trade-offs (--opt_for_speed, -mf)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_FOR_SPEED" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_FOR_SPEED.0" valueType="enumerated" />
<!-- Задаёт параметр сборки: Add dir to #include search path (- -include_path, -I). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.INCLUDE_PATH.24504397.f28335" name="Add dir to #include search path (--include_path, -I)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.INCLUDE_PATH" valueType="includePath">
<!-- Передаёт значение параметра: ${PROJECT_ROOT}. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}" />
<!-- Передаёт значение параметра: ${PROJECT_ROOT}/../../../vendor/ti/f28335/include. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}/../../../vendor/ti/f28335/include" />
<!-- Передаёт значение параметра: ${PROJECT_ROOT}/../../../vendor/ti/f28335/common/include. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}/../../../vendor/ti/f28335/common/include" />
<!-- Передаёт значение параметра: ${CG_TOOL_ROOT}/include. -->
<listOptionValue builtIn="false" value="${CG_TOOL_ROOT}/include" />
<listOptionValue builtIn="false" value="C:/ti/controlSUITE/libs/utilities/flash_api/2833x/28335/v210/include" /> <!-- Подключает официальный TI Flash API v2.10 F28335 для обновления секторов B–H по CAN. -->
</option>
<!-- Задаёт параметр сборки: Pre-define NAME (- -define, -D). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEFINE.409484878.f28335" name="Pre-define NAME (--define, -D)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEFINE" valueType="definedSymbols">
<!-- Передаёт значение параметра: LARGE_MODEL. -->
<listOptionValue builtIn="false" value="LARGE_MODEL" />
<!-- Передаёт значение параметра: EEPROM_M95M02=1. -->
<listOptionValue builtIn="false" value="EEPROM_M95M02=1" />
<!-- Передаёт значение параметра: F28335_BOOT_LOADER=1. -->
<listOptionValue builtIn="false" value="F28335_BOOT_LOADER=1" />
<listOptionValue builtIn="false" value="F28335_CAN_FLASH_UPDATE=1" /> <!-- Разрешает выбор внутренней Flash только при реально подключённом TI API. -->
<!-- Передаёт значение параметра: _DEBUG. -->
<listOptionValue builtIn="false" value="_DEBUG" />
</option>
<!-- Задаёт параметр сборки: Debugging model. -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEBUGGING_MODEL.1803616155.f28335" name="Debugging model" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEBUGGING_MODEL" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEBUGGING_MODEL.SYMDEBUG__DWARF" valueType="enumerated" />
<!-- Задаёт параметр сборки: Emit diagnostic identifier numbers (- -display_error_number, -pden). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DISPLAY_ERROR_NUMBER.362706119.f28335" name="Emit diagnostic identifier numbers (--display_error_number, -pden)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DISPLAY_ERROR_NUMBER" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Application binary interface [See 'General' page to edit] (- -abi). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.ABI.1036638377.f28335" name="Application binary interface [See 'General' page to edit] (--abi)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.ABI" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.ABI.coffabi" valueType="enumerated" />
<!-- Описывает inputType: C Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__C_SRCS.413246530.f28335" name="C Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__C_SRCS" />
<!-- Описывает inputType: C++ Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__CPP_SRCS.1626831603.f28335" name="C++ Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__CPP_SRCS" />
<!-- Описывает inputType: Assembly Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM_SRCS.291886960.f28335" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM_SRCS" />
<!-- Описывает inputType: Assembly Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM2_SRCS.231319110.f28335" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM2_SRCS" />
</tool>
<!-- Описывает tool: C2000 Linker. -->
<tool id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.linkerDebug.1238234098.f28335" name="C2000 Linker" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.linkerDebug">
<!-- Задаёт параметр сборки: Set C system stack size (- -stack_size, -stack). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.STACK_SIZE.1288161308.f28335" name="Set C system stack size (--stack_size, -stack)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.STACK_SIZE" value="0x3f0" valueType="string" />
<!-- Задаёт параметр сборки: Link information (map) listed into <file> (- -map_file, -m). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.MAP_FILE.1478857036.f28335" name="Link information (map) listed into &lt;file&gt; (--map_file, -m)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.MAP_FILE" value="F28335_CAN_AB.map" valueType="string" />
<!-- Задаёт параметр сборки: Specify output file name (- -output_file, -o). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.OUTPUT_FILE.1263270138.f28335" name="Specify output file name (--output_file, -o)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.OUTPUT_FILE" value="F28335_CAN_AB.out" valueType="string" />
<!-- Задаёт параметр сборки: Include library file or command file as input (- -library, -l). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.LIBRARY.1967188356.f28335" name="Include library file or command file as input (--library, -l)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.LIBRARY" valueType="libs">
<!-- Передаёт значение параметра: rts2800_fpu32.lib. -->
<listOptionValue builtIn="false" value="rts2800_fpu32.lib" />
<listOptionValue builtIn="false" value="Flash28335_API_V210.lib" /> <!-- Официальные erase/program/verify копируются в RAM перед занятостью общего банка Flash. -->
</option>
<!-- Задаёт параметр сборки: Add <dir> to library search path (- -search_path, -i). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.SEARCH_PATH.1097407993.f28335" name="Add &lt;dir&gt; to library search path (--search_path, -i)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.SEARCH_PATH" valueType="libPaths">
<!-- Передаёт значение параметра: ${CG_TOOL_ROOT}/lib. -->
<listOptionValue builtIn="false" value="${CG_TOOL_ROOT}/lib" />
<listOptionValue builtIn="false" value="C:/ti/controlSUITE/libs/utilities/flash_api/2833x/28335/v210/lib" /> <!-- Находит установленную библиотеку TI без добавления её двоичного содержимого в проект. -->
<!-- Передаёт значение параметра: ${PROJECT_ROOT}. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}" />
</option>
<!-- Задаёт параметр сборки: Emit diagnostic identifier numbers (- -display_error_number). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.DISPLAY_ERROR_NUMBER.2141790994.f28335" name="Emit diagnostic identifier numbers (--display_error_number)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.DISPLAY_ERROR_NUMBER" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Detailed link information data-base into <file> (- -xml_link_info, -xml_link_info). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.XML_LINK_INFO.1355214148.f28335" name="Detailed link information data-base into &lt;file&gt; (--xml_link_info, -xml_link_info)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.XML_LINK_INFO" value="F28335_CAN_AB_linkInfo.xml" valueType="string" />
<!-- Задаёт параметр сборки: Specify program entry point for the output module (- -entry_point, -e). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.ENTRY_POINT.862275171.f28335" name="Specify program entry point for the output module (--entry_point, -e)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.ENTRY_POINT" value="_c_int00" valueType="string" />
<!-- Описывает inputType: Linker Command Files. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD_SRCS.1082823352.f28335" name="Linker Command Files" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD_SRCS" />
<!-- Описывает inputType: Linker Command Files. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD2_SRCS.1635863502.f28335" name="Linker Command Files" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD2_SRCS" />
<!-- Описывает inputType: Generated Linker Command Files. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__GEN_CMDS.209596448.f28335" name="Generated Linker Command Files" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__GEN_CMDS" />
</tool>
<!-- Описывает tool: C2000 Hex Utility. -->
<tool id="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex.183039420.f28335" name="C2000 Hex Utility" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex">
<!-- Описывает outputType: Binary File. -->
<outputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex.outputType__BIN.139478444.f28335" name="Binary File" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex.outputType__BIN" />
</tool>
</toolChain>
</folderInfo>
<!-- Ограничивает компилируемые исходники проекта: sourceEntries. -->
<sourceEntries>
<!-- Описывает entry: entry. -->
<entry excluding="Debug|Release" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="" />
</sourceEntries>
</configuration>
</storageModule>
<!-- Описывает storageModule: org.eclipse.cdt.core.externalSettings. -->
<storageModule moduleId="org.eclipse.cdt.core.externalSettings" />
</cconfiguration>
<!-- Описывает cconfiguration: cconfiguration. -->
<cconfiguration id="com.ti.ccstudio.buildDefinitions.C2000.Release.952393063.f28335">
<!-- Описывает storageModule: Release. -->
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.ti.ccstudio.buildDefinitions.C2000.Release.952393063.f28335" moduleId="org.eclipse.cdt.core.settings" name="Release">
<!-- Описывает externalSettings: externalSettings. -->
<externalSettings />
<!-- Описывает extensions: extensions. -->
<extensions>
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.binaryparser.CoffParser.f28335" point="org.eclipse.cdt.core.BinaryParser" />
<!-- Описывает extension: extension. -->
<extension id="org.eclipse.cdt.core.GmakeErrorParser.f28335" point="org.eclipse.cdt.core.ErrorParser" />
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.errorparser.CoffErrorParser.f28335" point="org.eclipse.cdt.core.ErrorParser" />
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.errorparser.AsmErrorParser.f28335" point="org.eclipse.cdt.core.ErrorParser" />
<!-- Описывает extension: extension. -->
<extension id="com.ti.ccstudio.errorparser.LinkErrorParser.f28335" point="org.eclipse.cdt.core.ErrorParser" />
</extensions>
</storageModule>
<!-- Описывает storageModule: cdtBuildSystem. -->
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<!-- Описывает configuration: Release. -->
<configuration artifactExtension="out" artifactName="F28335_CAN_AB" buildProperties="" cleanCommand="${CG_CLEAN_CMD}" description="" id="com.ti.ccstudio.buildDefinitions.C2000.Release.952393063.f28335" name="Release" parent="com.ti.ccstudio.buildDefinitions.C2000.Release" postbuildStep="" preannouncebuildStep="" prebuildStep="">
<!-- Описывает folderInfo: /. -->
<folderInfo id="com.ti.ccstudio.buildDefinitions.C2000.Release.952393063.f28335." name="/" resourcePath="">
<!-- Описывает toolChain: TI Build Tools. -->
<toolChain id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.ReleaseToolchain.1656408937.f28335" name="TI Build Tools" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.ReleaseToolchain" targetTool="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.linkerRelease.1238234098.f28335">
<!-- Задаёт параметр сборки: option. -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS.1809066827.f28335" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS" valueType="stringList">
<!-- Передаёт значение параметра: DEVICE_CONFIGURATION_ID=TMS320C28XX.TMS320F28335. -->
<listOptionValue builtIn="false" value="DEVICE_CONFIGURATION_ID=TMS320C28XX.TMS320F28335" />
<!-- Передаёт значение параметра: DEVICE_ENDIANNESS=little. -->
<listOptionValue builtIn="false" value="DEVICE_ENDIANNESS=little" />
<!-- Передаёт значение параметра: OUTPUT_FORMAT=COFF. -->
<listOptionValue builtIn="false" value="OUTPUT_FORMAT=COFF" />
<!-- Передаёт значение параметра: LINKER_COMMAND_FILE=F28335_CAN_AB.cmd. -->
<listOptionValue builtIn="false" value="LINKER_COMMAND_FILE=F28335_CAN_AB.cmd" />
<!-- Передаёт значение параметра: RUNTIME_SUPPORT_LIBRARY=rts2800_fpu32.lib. -->
<listOptionValue builtIn="false" value="RUNTIME_SUPPORT_LIBRARY=rts2800_fpu32.lib" />
<!-- Передаёт значение параметра: CCS_MBS_VERSION=6.1.3. -->
<listOptionValue builtIn="false" value="CCS_MBS_VERSION=6.1.3" />
<!-- Передаёт значение параметра: OUTPUT_TYPE=executable. -->
<listOptionValue builtIn="false" value="OUTPUT_TYPE=executable" />
</option>
<!-- Задаёт параметр сборки: Compiler version. -->
<option id="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION.1182984787.f28335" name="Compiler version" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION" value="22.6.0.LTS" valueType="string" />
<!-- Описывает targetPlatform: Platform. -->
<targetPlatform id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.targetPlatformRelease.2023332194.f28335" name="Platform" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.targetPlatformRelease" />
<!-- Описывает builder: GNU Make. -->
<builder buildPath="${BuildDirectory}" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.builderRelease.1704049401.f28335" keepEnvironmentInBuildfile="false" name="GNU Make" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.builderRelease" />
<!-- Описывает tool: C2000 Compiler. -->
<tool id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.compilerRelease.68471068.f28335" name="C2000 Compiler" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.compilerRelease">
<!-- Задаёт параметр сборки: Option deprecated, set by default (- -large_memory_model, -ml). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.LARGE_MEMORY_MODEL.1683926605.f28335" name="Option deprecated, set by default (--large_memory_model, -ml)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.LARGE_MEMORY_MODEL" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Unified memory (- -unified_memory, -mt). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.UNIFIED_MEMORY.884660743.f28335" name="Unified memory (--unified_memory, -mt)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.UNIFIED_MEMORY" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Processor version (- -silicon_version, -v). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.SILICON_VERSION.750562333.f28335" name="Processor version (--silicon_version, -v)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.SILICON_VERSION" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.SILICON_VERSION.28" valueType="enumerated" />
<!-- Задаёт параметр сборки: Specify floating point support (- -float_support). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.FLOAT_SUPPORT.1723304888.f28335" name="Specify floating point support (--float_support)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.FLOAT_SUPPORT" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.FLOAT_SUPPORT.fpu32" valueType="enumerated" />
<!-- Задаёт параметр сборки: Optimization level (- -opt_level, -O). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_LEVEL.1217592973.f28335" name="Optimization level (--opt_level, -O)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_LEVEL" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_LEVEL.3" valueType="enumerated" />
<!-- Задаёт параметр сборки: Place each function in a separate subsection (- -gen_func_subsections, -mo). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.GEN_FUNC_SUBSECTIONS.eeprom.40.f28335" name="Place each function in a separate subsection (--gen_func_subsections, -mo)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.GEN_FUNC_SUBSECTIONS" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.GEN_FUNC_SUBSECTIONS.on" valueType="enumerated" />
<!-- Задаёт параметр сборки: Speed vs. size trade-offs (- -opt_for_speed, -mf). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_FOR_SPEED.1885063317.f28335" name="Speed vs. size trade-offs (--opt_for_speed, -mf)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_FOR_SPEED" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.OPT_FOR_SPEED.0" valueType="enumerated" />
<!-- Задаёт параметр сборки: Add dir to #include search path (- -include_path, -I). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.INCLUDE_PATH.24504397.f28335" name="Add dir to #include search path (--include_path, -I)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.INCLUDE_PATH" valueType="includePath">
<!-- Передаёт значение параметра: ${PROJECT_ROOT}. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}" />
<!-- Передаёт значение параметра: ${PROJECT_ROOT}/../../../vendor/ti/f28335/include. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}/../../../vendor/ti/f28335/include" />
<!-- Передаёт значение параметра: ${PROJECT_ROOT}/../../../vendor/ti/f28335/common/include. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}/../../../vendor/ti/f28335/common/include" />
<!-- Передаёт значение параметра: ${CG_TOOL_ROOT}/include. -->
<listOptionValue builtIn="false" value="${CG_TOOL_ROOT}/include" />
<listOptionValue builtIn="false" value="C:/ti/controlSUITE/libs/utilities/flash_api/2833x/28335/v210/include" /> <!-- Подключает официальный TI Flash API v2.10 F28335 для обновления секторов B–H по CAN. -->
</option>
<!-- Задаёт параметр сборки: Pre-define NAME (- -define, -D). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEFINE.409484878.f28335" name="Pre-define NAME (--define, -D)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DEFINE" valueType="definedSymbols">
<!-- Передаёт значение параметра: LARGE_MODEL. -->
<listOptionValue builtIn="false" value="LARGE_MODEL" />
<!-- Передаёт значение параметра: EEPROM_M95M02=1. -->
<listOptionValue builtIn="false" value="EEPROM_M95M02=1" />
<!-- Передаёт значение параметра: F28335_BOOT_LOADER=1. -->
<listOptionValue builtIn="false" value="F28335_BOOT_LOADER=1" />
<listOptionValue builtIn="false" value="F28335_CAN_FLASH_UPDATE=1" /> <!-- Разрешает выбор внутренней Flash только при реально подключённом TI API. -->
<!-- Передаёт значение параметра: _DEBUG. -->
</option>
<!-- Задаёт параметр сборки: Releaseging model. -->
<!-- Задаёт параметр сборки: Emit diagnostic identifier numbers (- -display_error_number, -pden). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DISPLAY_ERROR_NUMBER.362706119.f28335" name="Emit diagnostic identifier numbers (--display_error_number, -pden)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.DISPLAY_ERROR_NUMBER" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Application binary interface [See 'General' page to edit] (- -abi). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.ABI.1036638377.f28335" name="Application binary interface [See 'General' page to edit] (--abi)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.ABI" value="com.ti.ccstudio.buildDefinitions.C2000_22.6.compilerID.ABI.coffabi" valueType="enumerated" />
<!-- Описывает inputType: C Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__C_SRCS.413246530.f28335" name="C Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__C_SRCS" />
<!-- Описывает inputType: C++ Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__CPP_SRCS.1626831603.f28335" name="C++ Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__CPP_SRCS" />
<!-- Описывает inputType: Assembly Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM_SRCS.291886960.f28335" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM_SRCS" />
<!-- Описывает inputType: Assembly Sources. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM2_SRCS.231319110.f28335" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.compiler.inputType__ASM2_SRCS" />
</tool>
<!-- Описывает tool: C2000 Linker. -->
<tool id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.linkerRelease.1238234098.f28335" name="C2000 Linker" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exe.linkerRelease">
<!-- Задаёт параметр сборки: Set C system stack size (- -stack_size, -stack). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.STACK_SIZE.1288161308.f28335" name="Set C system stack size (--stack_size, -stack)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.STACK_SIZE" value="0x3f0" valueType="string" />
<!-- Задаёт параметр сборки: Link information (map) listed into <file> (- -map_file, -m). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.MAP_FILE.1478857036.f28335" name="Link information (map) listed into &lt;file&gt; (--map_file, -m)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.MAP_FILE" value="F28335_CAN_AB.map" valueType="string" />
<!-- Задаёт параметр сборки: Specify output file name (- -output_file, -o). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.OUTPUT_FILE.1263270138.f28335" name="Specify output file name (--output_file, -o)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.OUTPUT_FILE" value="F28335_CAN_AB.out" valueType="string" />
<!-- Задаёт параметр сборки: Include library file or command file as input (- -library, -l). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.LIBRARY.1967188356.f28335" name="Include library file or command file as input (--library, -l)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.LIBRARY" valueType="libs">
<!-- Передаёт значение параметра: rts2800_fpu32.lib. -->
<listOptionValue builtIn="false" value="rts2800_fpu32.lib" />
<listOptionValue builtIn="false" value="Flash28335_API_V210.lib" /> <!-- Официальные erase/program/verify копируются в RAM перед занятостью общего банка Flash. -->
</option>
<!-- Задаёт параметр сборки: Add <dir> to library search path (- -search_path, -i). -->
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.SEARCH_PATH.1097407993.f28335" name="Add &lt;dir&gt; to library search path (--search_path, -i)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.SEARCH_PATH" valueType="libPaths">
<!-- Передаёт значение параметра: ${CG_TOOL_ROOT}/lib. -->
<listOptionValue builtIn="false" value="${CG_TOOL_ROOT}/lib" />
<listOptionValue builtIn="false" value="C:/ti/controlSUITE/libs/utilities/flash_api/2833x/28335/v210/lib" /> <!-- Находит установленную библиотеку TI без добавления её двоичного содержимого в проект. -->
<!-- Передаёт значение параметра: ${PROJECT_ROOT}. -->
<listOptionValue builtIn="false" value="${PROJECT_ROOT}" />
</option>
<!-- Задаёт параметр сборки: Emit diagnostic identifier numbers (- -display_error_number). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.DISPLAY_ERROR_NUMBER.2141790994.f28335" name="Emit diagnostic identifier numbers (--display_error_number)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.DISPLAY_ERROR_NUMBER" value="true" valueType="boolean" />
<!-- Задаёт параметр сборки: Detailed link information data-base into <file> (- -xml_link_info, -xml_link_info). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.XML_LINK_INFO.1355214148.f28335" name="Detailed link information data-base into &lt;file&gt; (--xml_link_info, -xml_link_info)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.XML_LINK_INFO" value="F28335_CAN_AB_linkInfo.xml" valueType="string" />
<!-- Задаёт параметр сборки: Specify program entry point for the output module (- -entry_point, -e). -->
<option id="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.ENTRY_POINT.862275171.f28335" name="Specify program entry point for the output module (--entry_point, -e)" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.linkerID.ENTRY_POINT" value="_c_int00" valueType="string" />
<!-- Описывает inputType: Linker Command Files. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD_SRCS.1082823352.f28335" name="Linker Command Files" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD_SRCS" />
<!-- Описывает inputType: Linker Command Files. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD2_SRCS.1635863502.f28335" name="Linker Command Files" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__CMD2_SRCS" />
<!-- Описывает inputType: Generated Linker Command Files. -->
<inputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__GEN_CMDS.209596448.f28335" name="Generated Linker Command Files" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.exeLinker.inputType__GEN_CMDS" />
</tool>
<!-- Описывает tool: C2000 Hex Utility. -->
<tool id="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex.183039420.f28335" name="C2000 Hex Utility" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex">
<!-- Описывает outputType: Binary File. -->
<outputType id="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex.outputType__BIN.139478444.f28335" name="Binary File" superClass="com.ti.ccstudio.buildDefinitions.C2000_22.6.hex.outputType__BIN" />
</tool>
</toolChain>
</folderInfo>
<!-- Ограничивает компилируемые исходники проекта: sourceEntries. -->
<sourceEntries>
<!-- Описывает entry: entry. -->
<entry excluding="Release|Release" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="" />
</sourceEntries>
</configuration>
</storageModule>
<!-- Описывает storageModule: org.eclipse.cdt.core.externalSettings. -->
<storageModule moduleId="org.eclipse.cdt.core.externalSettings" />
</cconfiguration>
</storageModule>
<!-- Описывает storageModule: cdtBuildSystem. -->
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<!-- Регистрирует тип самостоятельного C2000-проекта: без этой записи CCS не определяет compiler definition при импорте. -->
<project id="F28335_CAN_AB.com.ti.ccstudio.buildDefinitions.C2000.ProjectType.1" name="C2000" projectType="com.ti.ccstudio.buildDefinitions.C2000.ProjectType" />
</storageModule>
</cproject>
@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<!-- Описывает name: name. -->
<name>F28335_CAN_AB</name>
<!-- Описывает comment: comment. -->
<comment>Отдельный постоянный загрузчик ProtoCAN для F28335</comment>
<!-- Описывает projects: projects. -->
<projects />
<!-- Описывает buildSpec: buildSpec. -->
<buildSpec>
<!-- Описывает buildCommand: buildCommand. -->
<buildCommand>
<!-- Описывает name: name. -->
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<!-- Описывает arguments: arguments. -->
<arguments />
</buildCommand>
<!-- Описывает buildCommand: buildCommand. -->
<buildCommand>
<!-- Описывает name: name. -->
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<!-- Описывает arguments: arguments. -->
<arguments />
</buildCommand>
</buildSpec>
<!-- Описывает natures: natures. -->
<natures>
<!-- Описывает nature: nature. -->
<nature>com.ti.ccstudio.core.ccsNature</nature>
<!-- Описывает nature: nature. -->
<nature>org.eclipse.cdt.core.cnature</nature>
<!-- Описывает nature: nature. -->
<nature>org.eclipse.cdt.core.ccnature</nature>
<!-- Описывает nature: nature. -->
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<!-- Описывает nature: nature. -->
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
<!-- Описывает linkedResources: linkedResources. -->
<linkedResources>
<!-- Подключает исходник или linker из общей библиотеки: link. -->
<link>
<!-- Описывает name: name. -->
<name>ti/DSP2833x_ADC_cal.asm</name>
<!-- Описывает type: type. -->
<type>1</type>
<!-- Описывает locationURI: locationURI. -->
<locationURI>PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_ADC_cal.asm</locationURI>
</link>
<!-- Подключает исходник или linker из общей библиотеки: link. -->
<link>
<!-- Описывает name: name. -->
<name>ti/DSP2833x_CpuTimers.c</name>
<!-- Описывает type: type. -->
<type>1</type>
<!-- Описывает locationURI: locationURI. -->
<locationURI>PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_CpuTimers.c</locationURI>
</link>
<!-- Подключает исходник или linker из общей библиотеки: link. -->
<link>
<!-- Описывает name: name. -->
<name>ti/DSP2833x_GlobalVariableDefs.c</name>
<!-- Описывает type: type. -->
<type>1</type>
<!-- Описывает locationURI: locationURI. -->
<locationURI>PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_GlobalVariableDefs.c</locationURI>
</link>
<!-- Подключает исходник или linker из общей библиотеки: link. -->
<link>
<!-- Описывает name: name. -->
<name>ti/DSP2833x_PieCtrl.c</name>
<!-- Описывает type: type. -->
<type>1</type>
<!-- Описывает locationURI: locationURI. -->
<locationURI>PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_PieCtrl.c</locationURI>
</link>
<!-- Подключает исходник или linker из общей библиотеки: link. -->
<link>
<!-- Описывает name: name. -->
<name>ti/DSP2833x_SysCtrl.c</name>
<!-- Описывает type: type. -->
<type>1</type>
<!-- Описывает locationURI: locationURI. -->
<locationURI>PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_SysCtrl.c</locationURI>
</link>
<!-- Подключает исходник или linker из общей библиотеки: link. -->
<link>
<!-- Описывает name: name. -->
<name>ti/DSP2833x_usDelay.asm</name>
<!-- Описывает type: type. -->
<type>1</type>
<!-- Описывает locationURI: locationURI. -->
<locationURI>PCAN_ROOT/vendor/ti/f28335/source/DSP2833x_usDelay.asm</locationURI>
</link>
<!-- Подключает исходник или linker из общей библиотеки: link. -->
<link>
<!-- Описывает name: name. -->
<name>DSP2833x_Headers_nonBIOS.cmd</name>
<!-- Описывает type: type. -->
<type>1</type>
<!-- Описывает locationURI: locationURI. -->
<locationURI>PCAN_ROOT/vendor/ti/f28335/cmd/DSP2833x_Headers_nonBIOS.cmd</locationURI>
</link>
</linkedResources>
<!-- Описывает variableList: variableList. -->
<variableList>
<!-- Описывает variable: variable. -->
<variable>
<!-- Описывает name: name. -->
<name>PCAN_ROOT</name>
<!-- Описывает value: value. -->
<value>$%7BPARENT-3-PROJECT_LOC%7D</value>
</variable>
</variableList>
</projectDescription>
@@ -0,0 +1,32 @@
MEMORY /* Отделяет постоянный загрузчик от адресов RAM payload приложения 167. */
{ /* Все адреса и длины указаны в 16-битных словах CPU C28x. */
PAGE 0: /* Исполняемые секции и их Flash LOAD-адреса. */
FLASHA : origin = 0x338000, length = 0x007F80 /* Сектор A до зарезервированной CSM-области содержит постоянный загрузчик. */
BEGIN : origin = 0x33FFF6, length = 0x000002 /* Два слова аппаратного Flash boot перехода; пароли CSM не выделяются. */
RAMFUNCS : origin = 0x00F800, length = 0x000800 /* Верхние 2048 слов RAM загрузчика нужны InitFlash и не входят в SCI8 payload приложения. */
RAMAPI : origin = 0x008000, length = 0x001800 /* 6144 слова временно принадлежат TI Flash API; приложение использует эту RAM только после выхода загрузчика. */
ADC_CAL : origin = 0x380080, length = 0x000009 /* Заводская калибровка TI используется без записи/стирания. */
RESET : origin = 0x3FFFC0, length = 0x000002 /* Аппаратный reset находится в ROM и не программируется. */
PAGE 1: /* Рабочие данные не пересекают код RAM-приложения ниже E000. */
BOOT_SHARED : origin = 0x000050, length = 0x000008 /* Общие с приложением восемь слов NOINIT handoff после ROM scratch 0..4F. */
RAMM0 : origin = 0x000058, length = 0x0003A8 /* Малый банк доступен служебным неинициализированным данным. */
RAMM1 : origin = 0x000400, length = 0x000400 /* Стек на 1024 слова не меняет расположение при переходе в приложение. */
RAMDATA : origin = 0x00E000, length = 0x001800 /* 6144 слова store/очереди; приложение использует их только после перехода в C startup. */
} /* Завершает физическую карту постоянного загрузчика. */
SECTIONS /* Не выделяет ни одного загружаемого слова в RAM приложения. */
{ /* Инициализированные Flash-секции остаются в секторе A. */
codestart : > BEGIN, PAGE = 0 /* Аппаратный переход передаёт управление watchdog-safe C startup. */
flash_api : { -lFlash28335_API_V210.lib(.text) -lFlash28335_API_V210.lib(.econst) } LOAD = FLASHA, RUN = RAMAPI, LOAD_START(_FlashApiLoadStart), LOAD_END(_FlashApiLoadEnd), RUN_START(_FlashApiRunStart), PAGE = 0 /* Код и таблицы TI API выполняются из RAM, пока общий банк Flash занят изменением B–H. */
.text : > FLASHA, PAGE = 0 /* Весь постоянный алгоритм и библиотеки исполняются из Flash A. */
.cinit : > FLASHA, PAGE = 0 /* Таблицы ROM-модели подготавливают данные загрузчика до main. */
.pinit : > FLASHA, PAGE = 0 /* Сохраняет стандартный порядок C runtime, если компилятор создаст эту секцию. */
.econst : > FLASHA, PAGE = 0 /* Константы протокола и имена сервиса не расходуют рабочую RAM. */
.switch : > FLASHA, PAGE = 0 /* Таблицы переходов находятся в постоянной области загрузчика. */
ramfuncs : LOAD = FLASHA, RUN = RAMFUNCS, LOAD_START(_RamfuncsLoadStart), LOAD_END(_RamfuncsLoadEnd), RUN_START(_RamfuncsRunStart), PAGE = 0 /* InitFlash копируется до изменения настроек самой Flash. */
.boot_shared : > BOOT_SHARED, PAGE = 1, TYPE = NOINIT /* Не обнуляет session/slot, полученные через watchdog reset. */
.stack : > RAMM1, PAGE = 1 /* Стек не пересекает ни handoff, ни загружаемые секции SCI8. */
.ebss : > RAMDATA, PAGE = 1 /* Размещает очередь, журнал и структуры драйвера вне RAM payload. */
.esysmem : > RAMDATA, PAGE = 1 /* Поддерживает стандартную секцию runtime без использования heap в алгоритме. */
.reset : > RESET, PAGE = 0, TYPE = DSECT /* Reset-вектор ROM описывается, но не попадает в программируемый OUT. */
.adc_cal : > ADC_CAL, PAGE = 0, TYPE = NOLOAD /* Сохраняет заводские данные ADC TI при установке загрузчика. */
} /* Не создаёт секций CSM, OTP или паролей. */
@@ -0,0 +1,12 @@
.ref _c_int00 ; Стандартный COFF startup применяет .cinit и вызывает main после отключения раннего watchdog.
.sect "codestart" ; Boot ROM передаёт управление двухсловному переходу по аппаратному адресу слова 0x33FFF6.
LB flash_boot_start ; Переходит к короткой подготовке C28x во Flash, сохраняя точный размер аппаратного входа два слова.
.text ; Последовательность взята из штатного TI DSP2833x_CodeStartBranch.asm и размещается в секторе основного кода.
flash_boot_start: ; Отключает watchdog до возможной длительной обработки таблиц инициализации C, а не только после входа в main.
SETC OBJMODE ; Выбирает C28x object mode, требуемый стандартным COFF startup процессора F28335.
EALLOW ; Разрешает запись защищённого регистра WDCR перед запуском C runtime.
MOVZ DP, #7029h>>6 ; Адрес слова WDCR=0x7029 из карты F28335; DP выбирает соответствующую страницу по 64 слова.
MOV @7029h, #0068h ; Значение 0x0068 содержит контрольные биты WDCHK=101 и WDDIS=1, как официальный TI startup.
EDIS ; Возвращает защиту системных регистров перед переходом в библиотечную инициализацию.
LB _c_int00 ; Применяет штатную ROM-модель инициализации и затем запускает текущий main 167.
.end ; Завершает модуль, не добавляя произвольных данных рядом с CSM-паролями сектора A.
@@ -0,0 +1,33 @@
#include "DSP2833x_Device.h" /* Предоставляет реальные типы C28x, частоту SYSCLKOUT, CSM и маскирование IRQ. */
#include "../../../ports/tms320f28335/f28335_flash_update.h" /* Подключает проверяемый алгоритм staging SCI8 и аппаратный контракт записи. */
#include "Flash2833x_API_Library.h" /* Использует официальный TI Flash API v2.10 для F28335, а не запись Flash обычным указателем. */
#include <string.h> /* Копирует код и таблицы TI API из постоянного сектора A во внутреннюю RAM до операции Flash. */
extern Uint16 FlashApiLoadStart, FlashApiLoadEnd, FlashApiRunStart; /* Символы LOAD/RUN задаёт linker в адресуемых словах CPU. */
static FLASH_ST flash_status; /* Диагностика TI хранится во внутренней RAM во время стирания и программирования. */
static bool erase_flash(void *user) /* Стирает только область приложения, сохраняя постоянный загрузчик. */
{ /* Даже IRQ из сектора A запрещены, поскольку F28335 имеет общий банк Flash для A–H. */
Uint16 saved, status; (void)user; /* Сохраняет прежнее состояние IRQ и точный результат TI API. */
saved = __disable_interrupts(); status = Flash_Erase(0x00FEU, &flash_status); __restore_interrupts(saved); /* Бит 0 — сектор A; маска FE выбирает только B–H согласно TI API v2.10. */
return status == STATUS_SUCCESS; /* Ошибка erase запрещает любую последующую публикацию FAB1. */
} /* После возврата TI API банк Flash снова доступен коду постоянного загрузчика. */
static bool program_flash(void *user, uint32_t address, uint16_t *data, unsigned int words) /* Записывает и проверяет одну ограниченную порцию Flash. */
{ /* Аппаратный слой повторно защищает сектор A независимо от валидатора SCI8. */
Uint16 saved, status; (void)user; /* Результат API и маска IRQ не размещаются в обновляемой Flash. */
if (!words || address < F28335_FLASH_APP_START || address >= F28335_FLASH_APP_STOP || words > F28335_FLASH_APP_STOP - address) return false; /* Не допускает даже частичного выхода за B–H, включая CSM и аппаратный boot. */
saved = __disable_interrupts(); status = Flash_Program((Uint16 *)address, data, words, &flash_status); /* Во время программирования процессор выполняет только скопированный в RAM TI API. */
if (!status) status = Flash_Verify((Uint16 *)address, data, words, &flash_status); /* Проверяет фактические слова до подтверждения этой порции. */
__restore_interrupts(saved); return status == STATUS_SUCCESS; /* Возвращает исходное состояние IRQ даже при отказе записи или readback. */
} /* Общий writer опубликует FAB1 лишь после успешной записи остальных порций. */
static uint16_t read_flash(void *user, uint32_t address) /* Читает физическую Flash для итоговой проверки FAB1/CRC. */
{ /* Этот callback вызывается только после окончания аппаратных операций TI API. */
(void)user; return *(volatile Uint16 *)address; /* Адрес уже ограничен общим валидатором диапазоном приложения B–H. */
} /* Программирование не подменяется чтением staging EEPROM. */
bool F28335Boot_FlashProgram(f28335_flash_update_t *s) /* Единственная точка фактической записи внутренней Flash из CAN COMMIT. */
{ /* Постоянный загрузчик может вернуться к CAN recovery при любой ошибке. */
f28335_flash_ops_t ops; /* Аппаратные операции передаются проверяемому транспортно-независимому writer. */
if (CsmRegs.CSMSCR.bit.SECURE) return false; /* Защищённый CSM запрещает стирание до любого вызова TI API. */
memcpy(&FlashApiRunStart, &FlashApiLoadStart, &FlashApiLoadEnd - &FlashApiLoadStart); /* API и его константы должны быть в RAM даже при сохранении сектора A. */
Flash_CPUScaleFactor = (Uint32)(1048576.0L * (200.0L * (long double)SYSCLKOUT / 1000000000.0L)); /* Формула TI IQ20 использует реальную частоту SYSCLKOUT в герцах. */
Flash_CallbackPtr = 0; ops.erase = erase_flash; ops.program = program_flash; ops.read = read_flash; ops.user = 0; /* Исключает callback во Flash во время занятости общего банка A–H. */
return f28335_flash_update_program(s, &ops); /* Итоговый ACK COMMIT появляется только после CRC физической Flash; REBOOT остаётся отдельной командой клиента. */
} /* Постоянный boot, handoff и EEPROM-параметры не программируются. */
+127
View File
@@ -0,0 +1,127 @@
#include "DSP2833x_Device.h" /* Использует действующую частоту и штатную карту регистров той же платы 167. */
#include "DSP2833x_Examples.h" /* Предоставляет InitSysCtrl, InitPieCtrl, InitFlash и управление Timer1. */
#include "../../../ports/tms320f28335/f28335_can_boot.h" /* Подключает адрес, сервисы и очередь существующего загрузчика. */
#include "../../../ports/tms320f28335/f28335_boot_platform.h" /* Использует общий handoff, SPI и энергонезависимый A/B-журнал. */
#include <string.h> /* Копирует ramfuncs до настройки времен доступа Flash. */
extern Uint16 RamfuncsLoadStart, RamfuncsLoadEnd, RamfuncsRunStart; /* Адреса LOAD/RUN задаёт отдельный linker загрузчика в словах C28x. */
static f28335_boot_store_t image_store; /* Журнал загрузки остаётся в RAM E000..FFFF до перехода в приложение. */
interrupt void boot_tick(void) /* Timer1 продолжает миллисекундные тайм-ауты общего CAN/SPI порта. */
{ /* Этот ISR принадлежит постоянному загрузчику, а не кандидату приложения. */
CpuTimer1.InterruptCount++; /* Один тик равен одной миллисекунде согласно ConfigCpuTimer ниже. */
ServiceDog(); /* Длительные CRC/SPI операции загрузчика не должны сбрасывать аппарат во время обновления. */
} /* Возвращает управление основному циклу загрузчика. */
interrupt void boot_can_rx(void) /* CAN IRQ выполняет только короткий перенос принятых кадров в общую очередь. */
{ /* Запись EEPROM, CRC и публикация pending остаются в главном цикле. */
F28335CanBoot_RxISR(); /* Читает только выделенные mailbox 3 и 6 существующего адаптера. */
PieCtrlRegs.PIEACK.all = 0x0100U; /* Бит 8 подтверждает группу PIE9, в которой находится ECAN0INTA. */
} /* Позволяет принять следующее окно CAN, пока main занят SPI. */
static void boot_can_init(void) /* Настраивает тот же физический CAN-A и 250 кбит/с, что приложение 167. */
{ /* Загрузчик не использует прикладные mailbox 0..2 и не меняет адрес общего порта. */
Uint32 shadow; /* Защищённые eCAN-регистры изменяются только полными 32-битными обращениями. */
EALLOW; /* Разрешает настройку мультиплексора, eCAN и таблицы векторов. */
GpioCtrlRegs.GPAMUX2.bit.GPIO30 = 1; /* GPIO30 служит CANRXA, как в штатном InitCan проекта. */
GpioCtrlRegs.GPAMUX2.bit.GPIO31 = 1; /* GPIO31 служит CANTXA того же трансивера. */
ECanaRegs.CANTIOC.all = 8UL; /* Бит TXFUNC включает функцию CAN у выхода контроллера. */
ECanaRegs.CANRIOC.all = 8UL; /* Бит RXFUNC включает аппаратный вход CAN. */
ECanaRegs.CANME.all = 0UL; /* Изменяет mailbox и фильтры только при выключенных ящиках. */
ECanaRegs.CANMIM.all = 0UL; /* Ни один старый mailbox не должен создавать IRQ во время настройки. */
ECanaRegs.CANMIL.all = 0UL; /* Направляет служебные mailbox на ECAN0INTA группы PIE9. */
ECanaRegs.CANMC.all = 0x00003080UL; /* SCB=1 выбирает eCAN, ABO=1 автоматическое восстановление, CCR=1 режим настройки битового времени; SRES остаётся нулём. */
while (!ECanaRegs.CANES.bit.CCE) {} /* Не пишет CANBTC до аппаратного подтверждения режима настройки. */
shadow = ((Uint32)(CLKMULT * 3L - 1L) << 16) | 0x0000017AUL; /* BRP=CLKMULT*3-1, SJW=1, TSEG1=15, TSEG2=2 как в приложении: 250000 бит/с при текущем SYSCLKOUT. */
ECanaRegs.CANBTC.all = shadow; /* Передаёт параметры одним 32-битным обращением к eCAN. */
ECanaRegs.CANMC.all &= ~0x00001000UL; /* Снимает CCR после настройки тактов CAN. */
while (ECanaRegs.CANES.bit.CCE) {} /* Ждёт возврата контроллера к обычной работе перед включением фильтров. */
ECanaRegs.CANTA.all = 0xFFFFFFFFUL; /* Удаляет старые TX ACK, которые не относятся к новой сессии. */
ECanaRegs.CANRMP.all = 0xFFFFFFFFUL; /* Удаляет старые RX-флаги до включения IRQ. */
ECanaRegs.CANRML.all = 0xFFFFFFFFUL; /* Начинает контроль потери mailbox с чистого состояния. */
ECanaRegs.CANGIF0.all = 0xFFFFFFFFUL; /* Снимает накопленные флаги линии CAN0. */
ECanaRegs.CANGIM.all = 1UL; /* I0EN разрешает mailbox IRQ по линии 0; ошибки не требуют прикладного ISR. */
PieVectTable.ECAN0INTA = &boot_can_rx; /* Использует постоянный обработчик загрузчика вместо кода RAM-приложения. */
PieCtrlRegs.PIEIER9.bit.INTx5 = 1; /* Разрешает ECAN0INTA в группе PIE9. */
EDIS; /* Возвращает защиту аппаратной конфигурации. */
IER |= M_INT9; /* Разрешает группе CAN доставлять IRQ ядру после общего EINT. */
} /* Общий порт затем настроит адресные mailbox 3/4/6. */
static unsigned int boot_periph_id(void) /* Повторяет аппаратное чтение Mode из peripher.c, чтобы после reset адрес загрузчика совпадал с приложением. */
{ /* Четыре активных низким уровнем перемычки существующей ПМ35 задают номера 1–16. */
unsigned int periph_id; /* Номер является ID PERIPH из Excel, а не уменьшенным на единицу индексом старого CAN. */
EALLOW; /* Разрешает настройку только четырёх входов адресных перемычек. */
GpioCtrlRegs.GPAMUX2.bit.GPIO20=0; /* GPIO20 работает входом адреса с весом 2, как в get_Mode приложения. */
GpioCtrlRegs.GPAMUX2.bit.GPIO21=0; /* GPIO21 работает входом адреса с весом 1, а не альтернативной периферией. */
GpioCtrlRegs.GPAMUX2.bit.GPIO22=0; /* GPIO22 работает входом адреса с весом 4. */
GpioCtrlRegs.GPBMUX2.bit.GPIO51=0; /* GPIO51 работает входом адреса с весом 8. */
GpioCtrlRegs.GPADIR.bit.GPIO20=0; /* Запрещает выходной драйвер, чтобы загрузчик не воздействовал на перемычку. */
GpioCtrlRegs.GPADIR.bit.GPIO21=0; /* Оставляет младшую адресную перемычку входом. */
GpioCtrlRegs.GPADIR.bit.GPIO22=0; /* Оставляет третий разряд аппаратного номера входом. */
GpioCtrlRegs.GPBDIR.bit.GPIO51=0; /* Оставляет старшую перемычку входом порта B. */
EDIS; /* Восстанавливает защиту конфигурации GPIO до чтения физического номера. */
periph_id=1U+!GpioDataRegs.GPADAT.bit.GPIO21; /* Штатный Mode начинается с 1; замкнутая GPIO21 добавляет единицу. */
periph_id+=2U*!GpioDataRegs.GPADAT.bit.GPIO20; /* Замкнутая GPIO20 добавляет два к номеру платы. */
periph_id+=4U*!GpioDataRegs.GPADAT.bit.GPIO22; /* Замкнутая GPIO22 добавляет четыре к номеру платы. */
periph_id+=8U*!GpioDataRegs.GPBDAT.bit.GPIO51; /* Замкнутая GPIO51 добавляет восемь; аппаратный диапазон заканчивается на 16. */
return periph_id; /* Общий CAN-порт преобразует номер 16 в Type 2 / Device 0 согласно Excel. */
} /* Приложение и recovery используют один и тот же физический адрес без общего значения 3/7. */
static bool ram_word(void *user, uint32_t address, uint16_t value) /* Аппаратная запись одного слова уже проверенной таблицы SCI8. */
{ /* Повторяет нижнюю защиту RAM даже при ошибке вызывающего слоя. */
(void)user; /* Контекст не нужен для единственной внутренней RAM данного F28335. */
if (address < 0x8000UL || address >= 0xE000UL) return false; /* Не позволяет таблице затронуть периферию, handoff, стек или RAM загрузчика. */
*(volatile Uint16 *)address = value; /* Адрес измеряется в 16-битных словах C28x, значение уже декодировано из SCI8. */
return true; /* Сообщает полную запись слова, а не частичное выполнение секции. */
} /* После загрузки всех слов общий store вернёт проверенную точку входа. */
static uint16_t flash_word(void *user, uint32_t address) /* Читает только фиксированный заголовок и проверенный диапазон приложения ниже сектора A. */
{ /* Загрузчик остаётся во Flash A, поэтому чтение H–B не меняет выполняемый код. */
(void)user; /* Единственная внутренняя Flash не требует отдельного контекста источника. */
return *(volatile Uint16 *)address; /* C28x адресует Flash 16-битными словами; разбиение на октеты выполняет общий валидатор CRC. */
} /* Никакая запись или стирание Flash при выборе источника запуска не выполняется. */
static void start_application(uint32_t entry, unsigned int source) /* Передаёт управление Flash либо EEPROM только после проверки соответствующего образа. */
{ /* Останавливает собственные IRQ до C startup приложения, который заново настроит периферию и рабочую RAM. */
DINT; IER = 0U; IFR = 0U; /* Старые прерывания не должны войти в очередь или стек завершённого загрузчика. */
CpuTimer1Regs.TCR.bit.TSS = 1; /* Прекращает миллисекундные IRQ до запуска прикладного InitSysCtrl. */
ECanaRegs.CANMIM.all = 0UL; /* Не доставляет CAN IRQ во время смены векторов приложения. */
F28335Boot_SetRunning(source); /* Сохраняет достоверный источник: 0/1 для EEPROM A/B либо FE для проверенной Flash. */
((void (*)(void))entry)(); /* Вызывает watchdog-safe startup Flash или проверенную точку C runtime RAM-образа. */
for (;;) {} /* Ошибочный возврат приложения не использует перезаписанное состояние загрузчика. */
} /* Возврат к boot происходит только аппаратным reset с согласованным handoff. */
void F28335Boot_Quiesce(void) /* Перед повторным входом загрузчика его собственные IRQ будут отключены общим Reset. */
{ /* Силовые выходы загрузчик не включает; прикладная остановка выполняется до входа в него. */
CpuTimer2Regs.TCR.bit.TSS = 1; /* Удерживает старый SPI Timer2 остановленным перед watchdog reset. */
} /* Общий аппаратный слой сохранит session и включит watchdog. */
void main(void) /* Постоянный загрузчик запускается аппаратным Flash boot по адресу 33FFF6. */
{ /* Пустая EEPROM и неподтверждённый кандидат оставляют доступным CAN recovery. */
f28335_boot_io_t io; /* Доступ к M95M02 предоставляет существующий переносимый SPI-порт. */
unsigned int slot, session, periph_id; /* Слот, сессия handoff и физический номер PERIPH сохраняются отдельно от адресов памяти. */
uint32_t entry, started; /* Адрес запуска измеряется словами CPU; started хранит миллисекунды стартового окна CAN. */
InitSysCtrl(); /* Повторяет PLL и SYSCLKOUT проекта 167, отключая watchdog на раннем старте. */
DINT; /* Не использует IRQ до настройки таблицы векторов и Timer1. */
IER = 0U; IFR = 0U; /* Исключает доставку старых прерываний после watchdog reset. */
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, &RamfuncsLoadEnd - &RamfuncsLoadStart); /* Переносит InitFlash в RAM до изменения времен доступа Flash. */
InitFlash(); /* Настраивает доступ к постоянному коду по штатной процедуре TI. */
InitPieCtrl(); /* Очищает разрешения и флаги всех групп PIE перед установкой двух собственных векторов. */
InitCpuTimers(); /* Останавливает Timer0/1/2 и сбрасывает их управляющие структуры. */
ConfigCpuTimer(&CpuTimer1, SYSCLKOUT / 1000000L, 1000UL); /* Период 1000 мкс даёт единый миллисекундный tick для протокола и SPI WIP. */
EALLOW; PieVectTable.XINT13 = &boot_tick; EDIS; /* Привязывает прямое прерывание Timer1 к постоянному ISR загрузчика. */
CpuTimer1Regs.TCR.all = 0x4020U; /* Разрешает прерывание Timer1 и запускает счётчик, как приложение 167. */
IER |= M_INT13; /* Разрешает миллисекундные прерывания ядра. */
periph_id=boot_periph_id(); /* Читает реальные перемычки до адресных mailbox и до ответа на ENTER_BOOT после reset. */
boot_can_init(); /* Настраивает трансивер и физическую скорость до общих фильтров и первой передачи. */
session = F28335Boot_RequestedSession(); /* Потребляет только достоверный запрос приложения с magic и XOR-контролем. */
F28335CanBoot_Init(periph_id); /* Открывает журнал и адресные Boot mailbox только для физического PERIPH данной платы. */
PieCtrlRegs.PIECTRL.bit.ENPIE = 1; /* Разрешает таблицу PIE после записи обоих используемых векторов. */
EINT; /* Приём окна CAN продолжается во время синхронных SPI-транзакций main. */
if (session) F28335CanBoot_Resume(session); /* Отвечает ENTER_BOOT после reset с той же session и остаётся в recovery. */
else { /* Обычный reset даёт CAN окно, затем предпочитает проверенную внутреннюю Flash и использует EEPROM как резерв. */
started = F28335Boot_Now(); /* Отсчитывает три секунды от готового CAN, а не от начала настройки PLL и SPI. */
while ((uint32_t)(F28335Boot_Now()-started)<3000UL && !F28335CanBoot_Active()) { F28335CanBoot_Service(); ServiceDog(); } /* ENTER_BOOT удерживает recovery; обычный PING не изменяет выбранный источник запуска. */
F28335CanBoot_Service(); /* Разбирает кадр на границе трёхсекундного окна до последней проверки активного сеанса. */
if (!F28335CanBoot_Active()) { /* Не запускает основную или резервную программу поверх открытого сеанса CAN Boot. */
if (f28335_flash_app_validate(flash_word, 0, &entry)) start_application(entry, F28335_BOOT_FLASH_SLOT); /* Flash приоритетна только при правильном FAB1, допустимых адресах и совпавшей CRC всех LOAD-секций. */
io.read = F28335Boot_Read; io.write = F28335Boot_Write; io.user = 0; /* Передаёт store ту же аппаратную реализацию, что обслуживает CAN. */
if (f28335_boot_open(&image_store, &io) && f28335_boot_select(&image_store, &slot) && slot < 2U && f28335_boot_load(&image_store, slot, ram_word, 0, &entry)) { /* Проверяет CRC/SCI8, сохраняет attempted до пробного запуска и копирует только допустимую RAM. */
start_application(entry, slot); /* Резервный EEPROM-образ получает прежние trial/CONFIRM и автоматический откат A/B. */
} /* При ошибке чтения, CRC, таблицы или журнала не выполняет неизвестный entry. */
F28335CanBoot_Init(periph_id); /* При переходе в recovery перечитывает журнал, сохраняя прежний физический адрес платы. */
} /* Открытый CAN-сеанс сохраняет метаданные, выбранный слот и подтверждения без повторного Init. */
} /* Завершает выбор между адресным входом и обычным запуском приложения. */
F28335Boot_SetRunning(F28335_AB_NONE); /* Отмечает режим загрузчика, сохраняя уже восстановленную session в RAM автомата. */
for (;;) { F28335CanBoot_Service(); ServiceDog(); } /* Обслуживает обновления и остаётся доступным при пустой/повреждённой EEPROM. */
} /* Нормальный выход выполняется только через запуск RAM-приложения либо watchdog reset. */
@@ -0,0 +1,5 @@
#include "../../../src/pcan_boot.c" /* Подключает единственный общий автомат ProtoCAN Boot и CRC32. */
#include "../../../ports/tms320f28335/f28335_boot_store.c" /* Использует проверенный A/B-журнал, readback, SCI8 и откат. */
#include "../../../ports/tms320f28335/f28335_flash_app.c" /* Проверяет FAB1 и CRC приложения ниже сектора A перед выбором основного Flash либо резервной EEPROM. */
#include "../../../ports/tms320f28335/f28335_boot_hw.c" /* Подключает те же SPI, watchdog и handoff, что RAM-приложение. */
#include "../../../ports/tms320f28335/f28335_can_boot.c" /* F28335_BOOT_LOADER=1 разрешает запись слотов только постоянному загрузчику. */
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<configurations XML_version="1.2" id="configurations_0">
<configuration XML_version="1.2" id="Sauris SAU510-USB Iso Plus v.2 Emulator_0">
<instance XML_version="1.2" desc="Sauris SAU510-USB Iso Plus v.2 Emulator_0" href="connections/SAU510USBIsoPlusV2_Connection.xml" id="Sauris SAU510-USB Iso Plus v.2 Emulator_0" xml="SAU510USBIsoPlusV2_Connection.xml" xmlpath="connections"/>
<connection XML_version="1.2" id="Sauris SAU510-USB Iso Plus v.2 Emulator_0">
<instance XML_version="1.2" href="drivers/sau510c28x.xml" id="drivers" xml="sau510c28x.xml" xmlpath="drivers"/>
<platform XML_version="1.2" id="platform_0">
<instance XML_version="1.2" desc="TMS320F28335_0" href="devices/f28335.xml" id="TMS320F28335_0" xml="f28335.xml" xmlpath="devices"/>
</platform>
</connection>
</configuration>
</configurations>
+19 -1
View File
@@ -89,6 +89,17 @@ static bool send_status(pcan_boot_t *boot, pcan_boot_byte_t command, pcan_boot_b
return send_frame(boot, PCAN_BOOT_MSG_STATUS, body, data, 8U); return send_frame(boot, PCAN_BOOT_MSG_STATUS, body, data, 8U);
} }
uint32_t pcan_boot_crc32_update(uint32_t crc, const pcan_boot_byte_t *data, size_t length) /* Публичный readback использует тот же полином и отражение, что приём DATA. */
{ /* Не создаёт второго аппаратно зависимого варианта CRC в портах NOR/EEPROM. */
return crc32_update(crc, data, length); /* Продолжает ранее полученное состояние либо начинает с нуля. */
} /* Сохраняет существующую wire-совместимость всех портов. */
bool pcan_boot_report_busy(pcan_boot_t *boot, pcan_boot_byte_t command, uint32_t now_ms) /* Позволяет синхронному erase отвечать, пока аппаратная операция ещё не завершена. */
{ /* Порт вызывает функцию только в контексте main с живым экземпляром сессии. */
if (boot == NULL) return false; /* Не обращается к неинициализированному экземпляру аппаратного порта. */
boot->now_ms = boot->last_activity_ms = now_ms; /* Продвижение erase/verify считается живой активностью: длинная операция не должна сама истечь по тайм-ауту сессии. */
return send_status(boot, command, PCAN_BOOT_STATUS_BUSY); /* Номер следующего блока и CRC берутся из настоящего состояния ядра. */
} /* Окончательный OK/ошибку по завершении callback отправляет обычный автомат. */
/* IDENTIFY имеет отдельный тип сообщения DISCOVERY и Body=1. Он доступен /* IDENTIFY имеет отдельный тип сообщения DISCOVERY и Body=1. Он доступен
* без открытия сессии, поэтому обнаружение устройства не должно запускать обновление. */ * без открытия сессии, поэтому обнаружение устройства не должно запускать обновление. */
static bool send_identity(pcan_boot_t *boot) static bool send_identity(pcan_boot_t *boot)
@@ -205,7 +216,7 @@ static bool process_control(pcan_boot_t *boot, uint16_t body,
pcan_boot_byte_t command = (pcan_boot_byte_t)(body & 0xFFU); pcan_boot_byte_t command = (pcan_boot_byte_t)(body & 0xFFU);
if (dlc != ((command == PCAN_BOOT_CMD_BEGIN_IMAGE || command == PCAN_BOOT_CMD_BEGIN_COMPAT) ? 8U : if (dlc != ((command == PCAN_BOOT_CMD_BEGIN_IMAGE || command == PCAN_BOOT_CMD_BEGIN_COMPAT) ? 8U :
(command == PCAN_BOOT_CMD_DEVICE_NAME || command == PCAN_BOOT_CMD_MEMORY_INFO) ? 1U : 0U)) { (command == PCAN_BOOT_CMD_DEVICE_NAME || command == PCAN_BOOT_CMD_MEMORY_INFO || command == PCAN_BOOT_CMD_SELECT_MEMORY) ? 1U : 0U)) { /* Выбор памяти имеет ровно один октет и не может читать отсутствующий payload. */
return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_SIZE); return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_SIZE);
} }
if (command == PCAN_BOOT_CMD_PING) { if (command == PCAN_BOOT_CMD_PING) {
@@ -258,6 +269,13 @@ static bool process_control(pcan_boot_t *boot, uint16_t body,
boot->last_activity_ms=boot->now_ms; boot->last_activity_ms=boot->now_ms;
switch (command) { switch (command) {
case PCAN_BOOT_CMD_SELECT_MEMORY: { /* Явное назначение Flash не меняет поведение прежних клиентов без этой команды. */
pcan_boot_status_t status; /* Точный отказ порта передаётся клиенту без подмены успешным ACK. */
if (boot->state != PCAN_BOOT_STATE_METADATA || boot->have_image || boot->have_compat) return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_STATE); /* После начала метаданных, приёма либо проверки запрещает менять цель записи. */
if (!boot->port.select_memory) return send_status(boot, command, PCAN_BOOT_STATUS_INVALID_COMMAND); /* Старый загрузчик отклоняет новую цель до ERASE и передачи образа. */
status = boot->port.select_memory(boot->port_user, data[0], &boot->config); /* Порт проверяет поддержку выбранной физической памяти и задаёт её режим. */
return send_status(boot, command, status); /* Ответ защищён исходной адресацией и текущей ненулевой сессией. */
} /* Остальные команды используют выбранную конфигурацию слотов. */
case PCAN_BOOT_CMD_BEGIN_IMAGE: case PCAN_BOOT_CMD_BEGIN_IMAGE:
if(boot->state==PCAN_BOOT_STATE_READY_TO_ERASE && boot->manifest.image_size==get_u32(data) && if(boot->state==PCAN_BOOT_STATE_READY_TO_ERASE && boot->manifest.image_size==get_u32(data) &&
boot->manifest.image_crc32==get_u32(data+4)) return send_status(boot,command,PCAN_BOOT_STATUS_OK); boot->manifest.image_crc32==get_u32(data+4)) return send_status(boot,command,PCAN_BOOT_STATUS_OK);
@@ -9,5 +9,5 @@ static struct { struct MBOX MBOX3, MBOX4, MBOX6; } ECanaMboxes;
static struct { struct test_reg CANME,CANMD,CANRMP,CANRML,CANMIM,CANTA,CANAA,CANTRS,CANTRR; } ECanaRegs; static struct { struct test_reg CANME,CANMD,CANRMP,CANRML,CANMIM,CANTA,CANAA,CANTRS,CANTRR; } ECanaRegs;
static struct { struct test_reg LAM3,LAM6; } ECanaLAMRegs; static struct { struct test_reg LAM3,LAM6; } ECanaLAMRegs;
static struct { unsigned long InterruptCount; } CpuTimer1; static struct { unsigned long InterruptCount; } CpuTimer1;
static struct { unsigned WDCR; } SysCtrlRegs; /* Watchdog/reset моделируются callbacks; неиспользуемая глобальная копия SysCtrlRegs не требуется. */
#endif #endif
+3 -1
View File
@@ -12,16 +12,18 @@ if not cc:
store = 'ports/tms320f28335/f28335_boot_store.c' store = 'ports/tms320f28335/f28335_boot_store.c'
cases = [ cases = [
('core', [], ['src/pcan_boot.c', 'tests/test_pcan_boot.c']), ('core', [], ['src/pcan_boot.c', 'tests/test_pcan_boot.c']),
('busy', ['-DPCAN_BOOT_WIDE_BYTES'], ['src/pcan_boot.c', 'tests/test_pcan_busy.c']), # Длительный NOR erase с BUSY продлевает session и сохраняет wire-поля ответа.
('store_native', [], [store, 'tests/test_f28335_boot_store.c']), ('store_native', [], [store, 'tests/test_f28335_boot_store.c']),
('store_wide', ['-DPCAN_BOOT_WIDE_BYTES'], [store, 'tests/test_f28335_boot_store.c']), ('store_wide', ['-DPCAN_BOOT_WIDE_BYTES'], [store, 'tests/test_f28335_boot_store.c']),
('loader', ['-DPCAN_BOOT_WIDE_BYTES'], [store, 'src/pcan_boot.c', 'tests/test_f28335_can_boot.c']), ('loader', ['-DPCAN_BOOT_WIDE_BYTES'], [store, 'src/pcan_boot.c', 'tests/test_f28335_can_boot.c']),
('application', ['-DPCAN_BOOT_WIDE_BYTES', '-DF28335_BOOT_LOADER=0'], ('application', ['-DPCAN_BOOT_WIDE_BYTES', '-DF28335_BOOT_LOADER=0'],
[store, 'src/pcan_boot.c', 'tests/test_f28335_can_boot.c']), [store, 'src/pcan_boot.c', 'tests/test_f28335_can_boot.c']),
('f2812_nor', ['-DPCAN_BOOT_WIDE_BYTES', '-DBOOT2812_HOST'], ['src/pcan_boot.c', 'ports/tms320f2812/nor_flash.c', 'ports/tms320f2812/boot_store.c', 'tests/test_f2812_nor.c']), # Проверяет настоящий AMD driver, NOR manifest, SCI8 и восстановление после обрывов записи.
] ]
with tempfile.TemporaryDirectory(prefix='f28335-ab-') as tmp: with tempfile.TemporaryDirectory(prefix='f28335-ab-') as tmp:
for name, defines, sources in cases: for name, defines, sources in cases:
exe = Path(tmp) / (name + '.exe') exe = Path(tmp) / (name + '.exe')
subprocess.run([cc, '-std=c99', '-Wall', '-Wextra', '-Werror', '-Iinclude', subprocess.run([cc, '-std=c99', '-Wall', '-Wextra', '-Werror', '-Wno-misleading-indentation', '-Iinclude', # GCC допускает существующие однострочные циклы старых аппаратных моделей без подавления остальных ошибок.
'-Itests/f28335_stubs', *defines, *sources, '-o', str(exe)], cwd=root, check=True) '-Itests/f28335_stubs', *defines, *sources, '-o', str(exe)], cwd=root, check=True)
sample = os.environ.get('F28335_SAMPLE_IMAGE') if name == 'store_wide' else None sample = os.environ.get('F28335_SAMPLE_IMAGE') if name == 'store_wide' else None
subprocess.run([str(exe), *([sample] if sample else [])], check=True, timeout=30) subprocess.run([str(exe), *([sample] if sample else [])], check=True, timeout=30)
+83
View File
@@ -0,0 +1,83 @@
#include "../ports/tms320f2812/boot2812.h" /* Проверяет реальные callbacks NOR и общий ProtoCAN codec в wide-octet режиме. */
#include <assert.h> /* Любое нарушение границ, публикации или CRC завершает тест ошибкой. */
#include <stdint.h> /* Модель физической x16 памяти использует ровно 16 бит на слово даже на ПК. */
#include <stdio.h> /* Сообщает результат поведенческих сценариев без физического JTAG. */
#include <string.h> /* Подготавливает память и отдельные структуры C-ядра перед серией. */
static uint16_t memory[0x80000]; /* AM29LV800BT содержит 512K слов x16, то есть 1 МиБ. */
static unsigned int state, selected, bad_id, erases, programmed, busy_calls, loaded_words, stuck; /* Состояния относятся только к модели командной шины AMD. */
static long budget = -1; /* Отрицательное значение разрешает записи, ноль моделирует исчезновение питания перед очередным word program. */
static unsigned long clock_ms; /* Детерминированные часы позволяют проверить ограниченный выход из polling. */
unsigned long Boot2812_Now(void) { return clock_ms++; } /* Продвигает миллисекунды без зависимости теста от wall clock ПК. */
void Boot2812_Busy(void) { ++busy_calls; } /* Подтверждает, что длительное ожидание вызывает разрешённый сервис BUSY. */
void NorModel_LoadWord(uint32_t target, unsigned int value) /* Получает только реальные записи валидатора в разрешённую RAM приложения. */
{ /* Тестовый образ ниже содержит пять слов H0. */
assert(target >= 0x3F8000UL && target < 0x3F8005UL); assert(value == 0U); ++loaded_words; /* Неверный адрес либо повреждённый payload не может скрыться в аппаратной заглушке. */
} /* Запись в адресное пространство процесса ПК отсутствует. */
unsigned int NorModel_Read(unsigned long word) /* Имитирует обычное чтение либо режим autoselect чипа. */
{ /* Все обращения обязаны оставаться внутри установленной физической NOR. */
assert(word >= BOOT2812_NOR_BASE && word < BOOT2812_NOR_BASE + 0x80000UL); /* Выход на соседнюю XINTF-память является ошибкой драйвера. */
if (selected) return word == BOOT2812_NOR_BASE ? (bad_id ? 2U : 1U) : 0x22DAU; /* Модель отличает правильный AMD от неподходящего производителя. */
if (stuck && word >= BOOT2812_IMAGE_WORD) return 0U; /* DQ7=0/DQ5=0 удерживают erase busy до программного тайм-аута. */
return memory[word - BOOT2812_NOR_BASE]; /* Возвращает настоящие 16-битные данные модели. */
} /* Чтение не выполняет скрытых записей и не исправляет повреждённые данные. */
void NorModel_Write(unsigned long word, unsigned int value) /* Проверяет настоящий unlock state machine драйвера, а не принимает готовые запросы erase. */
{ /* Командные адреса трактуются как x16 смещения согласно datasheet AMD. */
assert(word >= BOOT2812_NOR_BASE && word < BOOT2812_NOR_BASE + 0x80000UL); /* Любой командный цикл ограничен физическим чипом. */
if (state == 3U) { /* После A0 следующий цикл обязательно содержит программируемое слово данных. */
if (budget != 0) { memory[word - BOOT2812_NOR_BASE] &= (uint16_t)value; ++programmed; if (budget > 0) --budget; } /* NOR программирует только переходы 1→0; обрыв питания оставляет прежнее слово. */
state = 0U; return; /* Программирование одного слова завершает командную последовательность. */
} /* Значение F0 в payload не должно ошибочно интерпретироваться как отдельная команда Reset. */
if (value == 0xF0U) { state = selected = 0U; return; } /* Reset возвращает обычное чтение независимо от предыдущей незавершённой команды. */
if (state == 0U) { assert(word == BOOT2812_NOR_BASE + 0x555UL && value == 0xAAU); state = 1U; } /* Первый unlock-цикл проверяется вместе с адресом. */
else if (state == 1U) { assert(word == BOOT2812_NOR_BASE + 0x2AAUL && value == 0x55U); state = 2U; } /* Второй цикл исключает ошибочную x8 адресацию. */
else if (state == 2U) { /* Третий цикл выбирает только одну из поддерживаемых безопасных команд. */
assert(word == BOOT2812_NOR_BASE + 0x555UL); /* Командный регистр находится по x16 смещению 555h. */
if (value == 0x90U) { selected = 1U; state = 0U; } /* Autoselect не изменяет содержимое памяти. */
else if (value == 0xA0U) state = 3U; /* Следующий цикл будет word program. */
else { assert(value == 0x80U); state = 4U; } /* Стирание требует второй unlock-пары, а не одного произвольного слова. */
} /* Завершает декодирование третьего такта AMD. */
else if (state == 4U) { assert(word == BOOT2812_NOR_BASE + 0x555UL && value == 0xAAU); state = 5U; } /* Проверяет четвёртый цикл Sector Erase. */
else if (state == 5U) { assert(word == BOOT2812_NOR_BASE + 0x2AAUL && value == 0x55U); state = 6U; } /* Проверяет пятый цикл Sector Erase. */
else { /* Шестой цикл выбирает только разрешённый отдельный сектор. */
unsigned long count = word == BOOT2812_META_WORD ? 0x2000UL : 0x8000UL, i; /* Модель различает обычные и последние top-boot сектора. */
assert(value == 0x30U); assert(word == BOOT2812_META_WORD || word == BOOT2812_IMAGE_WORD || word == BOOT2812_IMAGE_WORD + 0x8000UL || word == BOOT2812_IMAGE_WORD + 0x10000UL); /* Запрещает Chip Erase и любые соседние секторы legacy/FPGA. */
for (i = 0; i < count; ++i) memory[word - BOOT2812_NOR_BASE + i] = 0xFFFFU; /* Реально стирает все слова выбранного сектора модели. */
++erases; state = 0U; /* Сохраняет число аппаратных sector erase для проверки отказов до разрушительных циклов. */
} /* Завершает разрешённую операцию command bus. */
} /* Модель не предоставляет драйверу обходного пути прямой записи массива. */
static pcan_boot_byte_t image[40]; /* Небольшой полный SCI8: заголовок 22, секция 6+10, терминатор 2 октета. */
static pcan_boot_manifest_t manifest; /* Metadata используют те же размеры и совместимость, что настоящий клиент. */
static void make_image(void) /* Создаёт независимо определённый SCI8 с entry=3F8000 и пятью нулевыми словами H0. */
{ /* Нулевой payload облегчает точную проверку каждого перенесённого слова. */
memset(image, 0, sizeof(image)); image[0] = 0xAAU; image[1] = 8U; image[18] = 0x3FU; image[21] = 0x80U; image[22] = 5U; image[24] = 0x3FU; image[27] = 0x80U; /* Адрес TI передаётся старшим словом вперёд, внутри слова — little endian. */
memset(&manifest, 0, sizeof(manifest)); manifest.image_size = 40UL; manifest.image_crc32 = pcan_boot_crc32_update(0UL, image, 40U); /* Начальная CRC вычисляется общим codec по независимому массиву файла. */
manifest.product_type = BOOT2812_PRODUCT; manifest.hardware_revision_min = manifest.hardware_revision_max = 1U; /* Проверяет исключительно совместимый профиль F2812. */
} /* Последующие сценарии меняют данные с новой CRC, чтобы отделить ошибки структуры от ошибок передачи. */
static void save_image(void) /* Заполняет слоты через настоящие production callbacks, а не memcpy в образ. */
{ /* Каждая порция соответствует одному восьмиоктетному CAN DATA. */
unsigned int i; assert(Boot2812_Erase(0, 0U)); /* Перед каждой полной передачей удаляет marker и три полных сектора образа. */
for (i = 0; i < 40U; i += 8U) assert(Boot2812_Write(0, 0U, i, image + i, 8U)); /* Проверяет упаковку октетов и readback каждого x16 слова. */
} /* Только после завершения записи разрешены VERIFY и COMMIT. */
int main(void) /* Проверяет драйвер, SCI8, publication и независимость соседних данных платы. */
{ /* Все операции используют модель, физический CAN/JTAG не открывается. */
unsigned long i; uint32_t entry; unsigned int before, cut; /* Счётчики контролируют защищённые диапазоны и обрывы manifest. */
for (i = 0; i < 0x80000UL; ++i) memory[i] = 0x5AA5U; make_image(); /* Заполняет весь чип контрольным значением, включая старые данные и FPGA. */
bad_id = 1U; before = erases; assert(!Boot2812_Erase(0, 0U) && erases == before); bad_id = 0U; /* Неподходящий производитель блокируется до первого sector erase. */
assert(!Boot2812_NorErase(0x100000UL) && !Boot2812_NorErase(BOOT2812_IMAGE_WORD + 1UL)); /* Не разрешает старую область либо адрес внутри разрешённого сектора вместо его точного начала. */
assert(!Boot2812_NorProgram(0x130000UL, 0U)); /* FPGA-образ запрещён даже при ошибочном прямом вызове нижнего драйвера. */
save_image(); assert(Boot2812_Verify(0, 0U, &manifest) == PCAN_BOOT_STATUS_OK); /* Реальный NOR readback и формат SCI8 должны совпасть с входом. */
assert(!Boot2812_Load(&entry)); assert(Boot2812_Commit(0, 0U, &manifest)); loaded_words = 0U; assert(Boot2812_Load(&entry) && entry == 0x3F8000UL && loaded_words == 5U); /* До COMMIT загрузка запрещена, после него переносятся ровно проверенные слова H0. */
before = programmed; assert(!Boot2812_NorProgram(BOOT2812_IMAGE_WORD, 0xFFFFU) && programmed == before); /* Перевод 0→1 отклоняется без лишней попытки аппаратного program. */
for (cut = 0; cut <= 12U; ++cut) { /* Проверяет публикацию при обрыве на каждом месте manifest из двенадцати слов. */
bool committed; save_image(); budget = (long)cut; committed = Boot2812_Commit(0, 0U, &manifest); budget = -1; /* Останавливает только циклы NOR word program, не подменяя механизм публикации. */
loaded_words = 0U; assert(Boot2812_Load(&entry) == committed); /* Незавершённая публикация остаётся recovery; полностью опубликованный образ запускается. */
} /* Предыдущие legacy-данные всё время остаются за пределами разрешённого erase. */
save_image(); memory[BOOT2812_IMAGE_WORD - BOOT2812_NOR_BASE + 15UL] ^= 1U; assert(Boot2812_Verify(0, 0U, &manifest) == PCAN_BOOT_STATUS_CRC_ERROR); /* Порча физической NOR обнаруживается независимо от принятой потоковой CRC. */
make_image(); image[18] = 0U; image[21] = 0x90U; image[24] = 0U; image[27] = 0x90U; manifest.image_crc32 = pcan_boot_crc32_update(0UL, image, 40U); save_image(); /* Формирует целостную, но опасную секцию в L1 работающего загрузчика. */
assert(Boot2812_Verify(0, 0U, &manifest) == PCAN_BOOT_STATUS_INVALID_STATE && !Boot2812_Commit(0, 0U, &manifest)); /* Корректная CRC не разрешает перезапись очереди и состояния сессии. */
make_image(); stuck = 1U; before = busy_calls; assert(!Boot2812_NorErase(BOOT2812_IMAGE_WORD) && busy_calls > before); stuck = 0U; /* Постоянный DQ7 busy даёт ограниченный отказ и вызывает живой сервис BUSY. */
for (i = 0; i < 0x60000UL; ++i) assert(memory[i] == 0x5AA5U); /* Сохраняет весь нижний участок старого firmware, параметров и FPGA, а не одну контрольную точку. */
for (i = 0x78000UL; i < 0x7E000UL; ++i) assert(memory[i] == 0x5AA5U); /* Промежуточные top-boot сектора 15/16/17 также не стираются. */
puts("F2812 NOR: AMD commands, ID, bounds, CRC, SCI8, torn commit, timeout and legacy/FPGA preservation: OK"); /* Перечисляет программно проверенные свойства аппаратного порта. */
return 0; /* Успех означает завершение всех граничных и отказных сценариев. */
} /* Политика аппаратного boot/CPLD дополнительно проверяется на реальной плате. */
+38 -8
View File
@@ -12,34 +12,64 @@ void ServiceDog(void);
static unsigned char memory[0x40000]; static unsigned char memory[0x40000];
static unsigned int running=255,resets,reset_arg,dog_feeds; static unsigned int running=255,resets,reset_arg,dog_feeds;
static int fail_write; static int fail_write;
static unsigned int write_calls; /* Счётчик аппаратных записей доказывает, что чужие CAN-команды не касаются EEPROM. */
void ServiceDog(void) { ++dog_feeds; } void ServiceDog(void) { ++dog_feeds; }
bool F28335Boot_Read(void *u,uint32_t a,pcan_boot_byte_t *p,unsigned int n) bool F28335Boot_Read(void *u,uint32_t a,pcan_boot_byte_t *p,unsigned int n)
{ unsigned i; (void)u; assert(a+n<=sizeof(memory)); for(i=0;i<n;++i)p[i]=memory[a+i]; return true; } { unsigned i; (void)u; assert(a+n<=sizeof(memory)); for(i=0;i<n;++i)p[i]=memory[a+i]; return true; }
bool F28335Boot_Write(void *u,uint32_t a,const pcan_boot_byte_t *p,unsigned int n) bool F28335Boot_Write(void *u,uint32_t a,const pcan_boot_byte_t *p,unsigned int n)
{ unsigned i; (void)u; assert(a+n<=0x3FE00); if(fail_write)return false; { unsigned i; (void)u; ++write_calls; assert(a+n<=0x3FE00); if(fail_write)return false; /* Любой вызов записи учитывается, даже если модель затем возвращает отказ. */
for(i=0;i<n;++i)memory[a+i]=(unsigned char)p[i]; return true; } for(i=0;i<n;++i)memory[a+i]=(unsigned char)p[i]; return true; }
uint32_t F28335Boot_Now(void) { return CpuTimer1.InterruptCount; } uint32_t F28335Boot_Now(void) { return CpuTimer1.InterruptCount; }
unsigned int F28335Boot_RunningSlot(void) { return running; } unsigned int F28335Boot_RunningSlot(void) { return running; }
void F28335Boot_Reset(unsigned int session) { ++resets;reset_arg=session;reset_requested=0; } void F28335Boot_Reset(unsigned int session) { ++resets;reset_arg=session;reset_requested=0; }
static void command(unsigned cmd,const pcan_boot_byte_t *d,unsigned n) static void command(unsigned cmd,const pcan_boot_byte_t *d,unsigned n)
{ tx_busy=0; assert(pcan_boot_process(&boot,pcan_boot_make_id(1,0,3,7,9,0x100|cmd),d,n)); } { tx_busy=0; assert(pcan_boot_process(&boot,pcan_boot_make_id(1,0,1,8,9,0x100|cmd),d,n)); } /* Основные сценарии выполняются по закреплённому адресу задатчика 1/8. */
static void put32(pcan_boot_byte_t *p,uint32_t v) static void put32(pcan_boot_byte_t *p,uint32_t v)
{ unsigned i;for(i=0;i<4;++i)p[i]=(v>>(i*8))&255; } { unsigned i;for(i=0;i<4;++i)p[i]=(v>>(i*8))&255; }
static void address_isolation(void) /* Проверяет все 32 назначения Excel, аппаратный RX-фильтр и защиту записи от соседних плат. */
{ /* Одна модель последовательно представляет каждый физический PERIPH и получает команды всем остальным. */
unsigned int periph,peer,type,command_id,before=write_calls; /* Сохраняет счётчик записи до проверки, чтобы обнаружить любой побочный эффект чужого кадра. */
for(periph=0U;periph<32U;++periph) { /* Покрывает обе границы Type 1/2 и все четырёхбитные Device ID. */
F28335CanBoot_Init(periph); /* Тот же production Init используется RAM-приложением и Flash recovery. */
assert(addressed && boot.config.device_type==1U+periph/16U && boot.config.device_id==periph%16U); /* Сверяет независимую ожидаемую раскладку Excel со всей конфигурацией устройства. */
assert((ECanaMboxes.MBOX3.MSGID.all&0x07F00000UL)==((uint32_t)(1U+periph/16U)<<24|((uint32_t)(periph%16U)<<20))); /* Проверяет аппаратный фильтр, а не только программный parser. */
for(peer=0U;peer<32U;++peer) { /* Включает пары задатчик↔УМП1/УМП2 и совпадающий Device ID в другом Type. */
if(peer==periph) continue; /* Собственный адрес должен обслуживаться штатными сценариями ниже, поэтому здесь проверяются только чужие. */
for(type=9U;type<=11U;++type) { /* Проверяет управляющий сервис и оба пространства данных слотов A/B. */
for(command_id=2U;command_id<=9U;++command_id) { /* ENTER, метаданные, ERASE, VERIFY, COMMIT, CONFIRM и REBOOT должны игнорировать чужой адрес. */
uint32_t id=pcan_boot_make_id(1,0,1U+peer/16U,peer%16U,type,type==9U?0x100U|command_id:0U); /* Формирует реальный 29-битный запрос соседнему PERIPH с ненулевой сессией. */
assert(!pcan_boot_process(&boot,id,0,0)); /* Ядро не должно подтверждать или выполнять команду, адресованную другой плате. */
ECanaRegs.CANRMP.all=8UL; ECanaMboxes.MBOX3.MSGID.all=0x80000000UL|id; /* Моделирует доставку чужого кадра железом вопреки аппаратному фильтру. */
ECanaMboxes.MBOX3.MSGCTRL.all=0U; ECanaMboxes.MBOX3.MSGCTRL.bit.DLC=0U; ECanaMboxes.MBOX3.MSGCTRL.bit.RTR=0U; /* Исключает RTR как причину отказа, проверяя именно адрес. */
F28335CanBoot_RxISR(); assert(head==0U && tail==0U && !tx_busy); /* Дополнительная ISR-защита не ставит чужую команду в очередь и не отправляет ответ. */
} /* Завершает проверку изменяющих команд для выбранного пространства MsgType. */
} /* Завершает проверку данных A/B и управляющего сервиса соседа. */
} /* Переходит к следующему чужому номеру без перезаписи модели EEPROM. */
assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,3,7,9,0x102),0,0)); /* Прежний общий адрес 3/7 больше не разрешает вход в загрузчик ни одной платы. */
} /* Заканчивает проверку уникальности всей таблицы PERIPH. */
F28335CanBoot_Init(32U); assert(!addressed && !(ECanaRegs.CANME.all&88UL)); /* Недопустимый номер выключает Boot mailbox вместо перехода на общий адрес. */
F28335CanBoot_Resume(1U); F28335CanBoot_Service(); assert(write_calls==before); /* Неверный адрес и все чужие команды не выполняют ни одной аппаратной записи. */
} /* Последующие регрессии проверяют успешное обновление задатчика по адресу 1/8. */
int main(void) int main(void)
{ {
pcan_boot_byte_t image[40]={0xAA,8},meta[8],compat[8]={0x33,0x28,1,1,2,0,1,1}; pcan_boot_byte_t image[40]={0xAA,8},meta[8],compat[8]={0x33,0x28,1,1,2,0,1,1};
unsigned i,slot; pcan_boot_manifest_t m; unsigned i,slot; pcan_boot_manifest_t m;
memset(memory,0xA5,sizeof(memory)); image[21]=0x80; image[22]=5; image[27]=0x80; memset(memory,0xA5,sizeof(memory)); image[21]=0x80; image[22]=5; image[27]=0x80;
F28335CanBoot_Init(); assert(boot.config.max_image_size==130560 && boot.config.slot_count==2); address_isolation(); F28335CanBoot_Init(8U); assert(boot.config.max_image_size==130560 && boot.config.slot_count==2); /* Проверяет изоляцию всей шины перед штатной передачей задатчику. */
if(!F28335_BOOT_LOADER) { if(!F28335_BOOT_LOADER) {
/* SPI-ROM application without Flash-loader handoff cannot erase anything. */ /* SPI-ROM application without Flash-loader handoff cannot erase anything. */
command(2,0,0); assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE && !reset_requested); command(2,0,0); assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE && !reset_requested);
running=F28335_BOOT_FLASH_SLOT; F28335CanBoot_Init(8U); /* Достоверный handoff постоянного boot разрешает CAN-сервис защищённому Flash-приложению. */
assert(confirmed && F28335CanBoot_WatchdogAllowed()); /* Flash не выдаётся за неподтверждённый EEPROM-кандидат и сохраняет штатное обслуживание watchdog. */
command(12,0,0); assert(!F28335CanBoot_Active()); /* Диагностический PING не должен открывать сеанс прошивки или удерживать обычный запуск. */
command(2,0,0); assert(reset_requested && reset_session==1U && F28335CanBoot_Active()); /* ENTER_BOOT из Flash планирует переход с той же session без прямой записи EEPROM. */
running=255U; F28335CanBoot_Init(8U); /* Возвращает исходный SPI-ROM сценарий перед прежними тестами trial/CONFIRM и отката. */
memset(&m,0,sizeof(m));m.image_size=40;m.image_crc32=f28335_boot_crc(0,image,40); memset(&m,0,sizeof(m));m.image_size=40;m.image_crc32=f28335_boot_crc(0,image,40);
m.product_type=0x2833;m.hardware_revision_min=m.hardware_revision_max=1; m.product_type=0x2833;m.hardware_revision_min=m.hardware_revision_max=1;
assert(f28335_boot_prepare(&store,0)); assert(f28335_boot_prepare(&store,0));
for(i=0;i<40;i+=8)assert(f28335_boot_write(&store,0,i,image+i,8)); for(i=0;i<40;i+=8)assert(f28335_boot_write(&store,0,i,image+i,8));
assert(f28335_boot_commit(&store,0,&m)); assert(f28335_boot_select(&store,&slot)); assert(f28335_boot_commit(&store,0,&m)); assert(f28335_boot_select(&store,&slot));
running=0; F28335CanBoot_Init(); running=0; F28335CanBoot_Init(8U); /* Пробное приложение сохраняет адрес задатчика после handoff постоянного загрузчика. */
assert(!F28335CanBoot_WatchdogAllowed()); assert(!F28335CanBoot_WatchdogAllowed());
command(8,0,0);assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE); command(8,0,0);assert(boot.last_status==PCAN_BOOT_STATUS_INVALID_STATE);
F28335CanBoot_Ready(); F28335CanBoot_Ready();
@@ -55,7 +85,7 @@ int main(void)
command(3,meta,8);command(4,compat,8);assert(boot.target_slot==0); command(3,meta,8);command(4,compat,8);assert(boot.target_slot==0);
command(5,0,0); command(5,0,0);
for(i=0;i<5;++i) { tx_busy=0; assert(pcan_boot_process(&boot, for(i=0;i<5;++i) { tx_busy=0; assert(pcan_boot_process(&boot,
pcan_boot_make_id(1,0,3,7,10,i),image+i*8,8)); } pcan_boot_make_id(1,0,1,8,10,i),image+i*8,8)); } /* Данные первого слота передаются только адресу задатчика. */
command(6,0,0);assert(boot.state==PCAN_BOOT_STATE_VERIFIED); command(6,0,0);assert(boot.state==PCAN_BOOT_STATE_VERIFIED);
command(7,0,0);assert(store.pending==0 && boot.state==PCAN_BOOT_STATE_COMMITTED); command(7,0,0);assert(store.pending==0 && boot.state==PCAN_BOOT_STATE_COMMITTED);
command(7,0,0);assert(boot.last_status==0); command(7,0,0);assert(boot.last_status==0);
@@ -67,16 +97,16 @@ int main(void)
} }
command(12,0,0); assert((ECanaMboxes.MBOX4.MSGID.all&65535)==12); command(12,0,0); assert((ECanaMboxes.MBOX4.MSGID.all&65535)==12);
command(13,0,0); assert(ECanaMboxes.MBOX4.MDH.all==130560); command(13,0,0); assert(ECanaMboxes.MBOX4.MDH.all==130560);
meta[0]=0;command(14,meta,1); assert(ECanaMboxes.MBOX4.MDL.all==0x33383246UL); /* F283 */ meta[0]=0;command(14,meta,1); assert(ECanaMboxes.MBOX4.MDL.all==0x6164615AUL); /* Первые четыре октета ASCII имени Zadatchik равны «Zada». */
meta[0]=3;command(15,meta,1);assert(ECanaMboxes.MBOX4.MDL.all==0x3FEFCUL); meta[0]=3;command(15,meta,1);assert(ECanaMboxes.MBOX4.MDL.all==0x3FEFCUL);
assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,3,6,9,0x102),0,0)); assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,1,6,9,0x102),0,0)); /* Адрес УМП2 1/6 не должен открывать сессию задатчика 1/8. */
tx_busy=0; tx_busy=0;
assert(pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,13,0),0,0)); assert(pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,13,0),0,0));
assert(boot.discovery_pending); pcan_boot_poll(&boot,boot.discovery_at); assert(boot.discovery_pending); pcan_boot_poll(&boot,boot.discovery_at);
assert(!boot.discovery_pending && (ECanaMboxes.MBOX4.MSGID.all&65535)==1); assert(!boot.discovery_pending && (ECanaMboxes.MBOX4.MSGID.all&65535)==1);
assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,9,0x102),0,0)); assert(!pcan_boot_process(&boot,pcan_boot_make_id(1,0,7,15,9,0x102),0,0));
head=tail=0; ECanaRegs.CANRMP.all=8; head=tail=0; ECanaRegs.CANRMP.all=8;
ECanaMboxes.MBOX3.MSGID.all=0x80000000UL|pcan_boot_make_id(1,0,3,7,9,12); ECanaMboxes.MBOX3.MSGID.all=0x80000000UL|pcan_boot_make_id(1,0,1,8,9,12); /* Собственный PING задатчика проходит очередь после проверки чужих адресов. */
ECanaMboxes.MBOX3.MSGCTRL.bit.DLC=0; ECanaMboxes.MBOX3.MSGCTRL.bit.DLC=0;
F28335CanBoot_RxISR(); assert(head==1 && tail==0); F28335CanBoot_RxISR(); assert(head==1 && tail==0);
tx_busy=0; F28335CanBoot_Service(); assert(tail==1); tx_busy=0; F28335CanBoot_Service(); assert(tail==1);
+22
View File
@@ -0,0 +1,22 @@
#include "../include/pcan_boot.h" /* Проверяет публичный BUSY codec и продление сессии на настоящем ядре. */
#include <assert.h> /* Несовпадение состояния или wire-полей завершает тест ненулевым результатом. */
#include <string.h> /* Инициализирует опциональные поля конфигурации без аппаратных зависимостей. */
static unsigned int status, body; /* Сохраняет наблюдаемые поля последнего настоящего STATUS кадра. */
static bool send_frame(void *user, uint32_t id, const pcan_boot_byte_t *data, pcan_boot_byte_t length) /* Модель заменяет только физическую отправку CAN. */
{ /* Содержимое статуса формирует production send_status, а не этот тест. */
(void)user; assert(length == 8U && pcan_boot_id_msg_type(id) == 12U); status = data[0]; body = pcan_boot_id_msg_body(id); return true; /* Проверяет тип, длину и сохранённую session/command. */
} /* Передача считается физически принятой аппаратным портом. */
static bool erase(void *user, pcan_boot_byte_t slot) { (void)user; return slot == 0U; } /* Минимальный single-slot callback удовлетворяет обязательному контракту init. */
static bool write_data(void *user, pcan_boot_byte_t slot, uint32_t offset, const pcan_boot_byte_t *data, pcan_boot_byte_t length) { (void)user; (void)offset; (void)data; return slot == 0U && length <= 8U; } /* Тест не программирует никакое реальное хранилище. */
int main(void) /* Проверяет, что операция длиннее исходного session timeout остаётся живой при BUSY. */
{ /* Без этой проверки длительный NOR erase мог бы закончиться уже отменённой сессией. */
pcan_boot_t boot; pcan_boot_config_t config; pcan_boot_port_t port; /* Использует тот же экземпляр автомата, что аппаратные проекты. */
memset(&config, 0, sizeof(config)); memset(&port, 0, sizeof(port)); config.slot_count = 1U; config.active_slot = 0U; config.session_timeout_ms = 30000UL; /* Сессия истекает через 30 секунд реального бездействия. */
port.send = send_frame; port.erase_slot = erase; port.write_slot = write_data; assert(pcan_boot_init(&boot, &config, &port, 0)); /* Не обходит production валидацию обязательных callbacks. */
assert(pcan_boot_process(&boot, pcan_boot_make_id(1U, 0U, 0U, 0U, 9U, 0x0102U), 0, 0U)); /* Открывает session=1 штатной командой ENTER_BOOT. */
assert(pcan_boot_report_busy(&boot, 5U, 40000UL) && status == 1U && body == 0x0105U); /* BUSY долгого ERASE содержит исходную session и обновляет часы активности после сорока секунд. */
pcan_boot_poll(&boot, 69999UL); assert(boot.state == PCAN_BOOT_STATE_METADATA); /* Почти 30 секунд после последнего BUSY ещё не означают тайм-аут. */
pcan_boot_poll(&boot, 70000UL); assert(boot.state == PCAN_BOOT_STATE_IDLE); /* После полного интервала без прогресса сессия снова отменяется обычным способом. */
assert(!pcan_boot_report_busy(0, 5U, 0UL)); /* Неинициализированный порт не должен вызывать аппаратный send. */
return 0; /* Все проверки используют одно производственное ядро и его codec. */
} /* Криптография и аппаратные сроки конкретной NOR не моделируются этим unit-тестом. */
+20
View File
@@ -0,0 +1,20 @@
# Поддержка TI C2000 для самостоятельных проектов
Здесь сохранён минимальный необходимый набор device headers, peripheral linker,
GlobalVariableDefs, SysCtrl, CpuTimers, PieCtrl и usDelay. Для F28335 также
подключён ADC_cal. Полные исходные copyright/version comments TI сохранены.
- `f28335`: DSP2833x Header Files/Common Sources **v1.20**, вариант рабочей
платы 167 из `Source/External/v120`. В нём сохранены русские пояснения и
действующие XCLKIN=30 МГц, CLKMULT=2, SYSCLKOUT=60 МГц.
- `f2812`: DSP281x Header Files/Common Sources **v1.20**, вариант рабочей
платы ПМ67 из `22220/ural/TMS_new_bus/Src/v120`. Используется штатный
PLLCR=10 при XCLKIN=30 МГц, SYSCLKOUT=150 МГц. Сохранено исходное имя
регистра `PIECRTL` SDK и секция `.fast_run` у usDelay; linker проекта
размещает её во внутренней Flash для вызовов из раннего InitSysCtrl.
Это существующая поддержка производителя; код аппаратных портов ProtoCAN
находится отдельно в `ports`, а настройки платы — в проектах CCS. Перенос
исходников TI устраняет зависимость от соседнего checkout конкретной прошивки.
Установленный TI compiler/runtime по-прежнему требуется; `libc`/RTS не
копируются в репозиторий.
@@ -0,0 +1,102 @@
/*
// TI File $Revision: /main/4 $
// Checkin $Date: July 9, 2009 17:39:29 $
//###########################################################################
//
// FILE: DSP281x_Headers_nonBIOS.cmd
//
// TITLE: DSP281x Peripheral registers linker command file
//
// DESCRIPTION:
//
// This file is for use in Non-BIOS applications.
//
// Linker command file to place the peripheral structures
// used within the DSP28 headerfiles into the correct memory
// mapped locations.
//
// This version of the file includes the PieVectorTable structure.
// For BIOS applications, please use the DSP281x_Headers_BIOS.cmd file
// which does not include the PieVectorTable structure.
//
//###########################################################################
// $TI Release: DSP281x C/C++ Header Files V1.20 $
// $Release Date: July 27, 2009 $
//###########################################################################
*/
MEMORY
{
PAGE 0: /* Program Memory */
PAGE 1: /* Data Memory */
DEV_EMU : origin = 0x000880, length = 0x000180 /* device emulation registers */
PIE_VECT : origin = 0x000D00, length = 0x000100 /* PIE Vector Table */
FLASH_REGS : origin = 0x000A80, length = 0x000060 /* FLASH registers */
CSM : origin = 0x000AE0, length = 0x000010 /* code security module registers */
XINTF : origin = 0x000B20, length = 0x000020 /* external interface registers */
CPU_TIMER0 : origin = 0x000C00, length = 0x000008 /* CPU Timer0 registers */
CPU_TIMER1 : origin = 0x000C08, length = 0x000008 /* CPU Timer1 registers */
CPU_TIMER2 : origin = 0x000C10, length = 0x000008 /* CPU Timer2 registers */
PIE_CTRL : origin = 0x000CE0, length = 0x000020 /* PIE control registers */
ECANA : origin = 0x006000, length = 0x000040 /* eCAN control and status registers */
ECANA_LAM : origin = 0x006040, length = 0x000040 /* eCAN local acceptance masks */
ECANA_MOTS : origin = 0x006080, length = 0x000040 /* eCAN message object time stamps */
ECANA_MOTO : origin = 0x0060C0, length = 0x000040 /* eCAN object time-out registers */
ECANA_MBOX : origin = 0x006100, length = 0x000100 /* eCAN mailboxes */
SYSTEM : origin = 0x007010, length = 0x000020 /* System control registers */
SPIA : origin = 0x007040, length = 0x000010 /* SPI registers */
SCIA : origin = 0x007050, length = 0x000010 /* SCI-A registers */
XINTRUPT : origin = 0x007070, length = 0x000010 /* external interrupt registers */
GPIOMUX : origin = 0x0070C0, length = 0x000020 /* GPIO mux registers */
GPIODAT : origin = 0x0070E0, length = 0x000020 /* GPIO data registers */
ADC : origin = 0x007100, length = 0x000020 /* ADC registers */
EVA : origin = 0x007400, length = 0x000040 /* Event Manager A registers */
EVB : origin = 0x007500, length = 0x000040 /* Event Manager B registers */
SCIB : origin = 0x007750, length = 0x000010 /* SCI-B registers */
MCBSPA : origin = 0x007800, length = 0x000040 /* McBSP registers */
CSM_PWL : origin = 0x3F7FF8, length = 0x000008 /* Part of FLASHA. CSM password locations. */
}
SECTIONS
{
PieVectTableFile : > PIE_VECT, PAGE = 1
/*** Peripheral Frame 0 Register Structures ***/
DevEmuRegsFile : > DEV_EMU, PAGE = 1
FlashRegsFile : > FLASH_REGS, PAGE = 1
CsmRegsFile : > CSM, PAGE = 1
XintfRegsFile : > XINTF, PAGE = 1
CpuTimer0RegsFile : > CPU_TIMER0, PAGE = 1
CpuTimer1RegsFile : > CPU_TIMER1, PAGE = 1
CpuTimer2RegsFile : > CPU_TIMER2, PAGE = 1
PieCtrlRegsFile : > PIE_CTRL, PAGE = 1
/*** Peripheral Frame 1 Register Structures ***/
ECanaRegsFile : > ECANA, PAGE = 1
ECanaLAMRegsFile : > ECANA_LAM PAGE = 1
ECanaMboxesFile : > ECANA_MBOX PAGE = 1
ECanaMOTSRegsFile : > ECANA_MOTS PAGE = 1
ECanaMOTORegsFile : > ECANA_MOTO PAGE = 1
/*** Peripheral Frame 2 Register Structures ***/
SysCtrlRegsFile : > SYSTEM, PAGE = 1
SpiaRegsFile : > SPIA, PAGE = 1
SciaRegsFile : > SCIA, PAGE = 1
XIntruptRegsFile : > XINTRUPT, PAGE = 1
GpioMuxRegsFile : > GPIOMUX, PAGE = 1
GpioDataRegsFile : > GPIODAT PAGE = 1
AdcRegsFile : > ADC, PAGE = 1
EvaRegsFile : > EVA, PAGE = 1
EvbRegsFile : > EVB, PAGE = 1
ScibRegsFile : > SCIB, PAGE = 1
McbspaRegsFile : > MCBSPA, PAGE = 1
/*** Code Security Module Register Structures ***/
CsmPwlFile : > CSM_PWL, PAGE = 1
}
/******************* end of file ************************/
@@ -0,0 +1,123 @@
// TI File $Revision: /main/2 $
// Checkin $Date: April 28, 2005 15:22:28 $
//###########################################################################
//
// FILE: DSP281x_DefaultIsr.h
//
// TITLE: DSP281x Devices Default Interrupt Service Routines Definitions.
//
//###########################################################################
// $TI Release: DSP281x C/C++ Header Files V1.20 $
// $Release Date: July 27, 2009 $
//###########################################################################
#ifndef DSP281x_DEFAULT_ISR_H
#define DSP281x_DEFAULT_ISR_H
#ifdef __cplusplus
extern "C" {
#endif
//---------------------------------------------------------------------------
// Default Interrupt Service Routine Declarations:
//
// The following function prototypes are for the
// default ISR routines used with the default PIE vector table.
// This default vector table is found in the DSP28_PieVect.h
// file.
//
// Non-Peripheral Interrupts:
interrupt void INT13_ISR(void); // XINT13 or CPU-Timer 1
interrupt void INT14_ISR(void); // CPU-Timer2
interrupt void DATALOG_ISR(void); // Datalogging interrupt
interrupt void RTOSINT_ISR(void); // RTOS interrupt
interrupt void EMUINT_ISR(void); // Emulation interrupt
interrupt void NMI_ISR(void); // Non-maskable interrupt
interrupt void ILLEGAL_ISR(void); // Illegal operation TRAP
interrupt void USER1_ISR(void); // User Defined trap 1
interrupt void USER2_ISR(void); // User Defined trap 2
interrupt void USER3_ISR(void); // User Defined trap 3
interrupt void USER4_ISR(void); // User Defined trap 4
interrupt void USER5_ISR(void); // User Defined trap 5
interrupt void USER6_ISR(void); // User Defined trap 6
interrupt void USER7_ISR(void); // User Defined trap 7
interrupt void USER8_ISR(void); // User Defined trap 8
interrupt void USER9_ISR(void); // User Defined trap 9
interrupt void USER10_ISR(void); // User Defined trap 10
interrupt void USER11_ISR(void); // User Defined trap 11
interrupt void USER12_ISR(void); // User Defined trap 12
// Group 1 PIE Interrupt Service Routines:
interrupt void PDPINTA_ISR(void); // EV-A
interrupt void PDPINTB_ISR(void); // EV-B
interrupt void XINT1_ISR(void);
interrupt void XINT2_ISR(void);
interrupt void ADCINT_ISR(void); // ADC
interrupt void TINT0_ISR(void); // Timer 0
interrupt void WAKEINT_ISR(void); // WD
// Group 2 PIE Interrupt Service Routines:
interrupt void CMP1INT_ISR(void); // EV-A
interrupt void CMP2INT_ISR(void); // EV-A
interrupt void CMP3INT_ISR(void); // EV-A
interrupt void T1PINT_ISR(void); // EV-A
interrupt void T1CINT_ISR(void); // EV-A
interrupt void T1UFINT_ISR(void); // EV-A
interrupt void T1OFINT_ISR(void); // EV-A
// Group 3 PIE Interrupt Service Routines:
interrupt void T2PINT_ISR(void); // EV-A
interrupt void T2CINT_ISR(void); // EV-A
interrupt void T2UFINT_ISR(void); // EV-A
interrupt void T2OFINT_ISR(void); // EV-A
interrupt void CAPINT1_ISR(void); // EV-A
interrupt void CAPINT2_ISR(void); // EV-A
interrupt void CAPINT3_ISR(void); // EV-A
// Group 4 PIE Interrupt Service Routines:
interrupt void CMP4INT_ISR(void); // EV-B
interrupt void CMP5INT_ISR(void); // EV-B
interrupt void CMP6INT_ISR(void); // EV-B
interrupt void T3PINT_ISR(void); // EV-B
interrupt void T3CINT_ISR(void); // EV-B
interrupt void T3UFINT_ISR(void); // EV-B
interrupt void T3OFINT_ISR(void); // EV-B
// Group 5 PIE Interrupt Service Routines:
interrupt void T4PINT_ISR(void); // EV-B
interrupt void T4CINT_ISR(void); // EV-B
interrupt void T4UFINT_ISR(void); // EV-B
interrupt void T4OFINT_ISR(void); // EV-B
interrupt void CAPINT4_ISR(void); // EV-B
interrupt void CAPINT5_ISR(void); // EV-B
interrupt void CAPINT6_ISR(void); // EV-B
// Group 6 PIE Interrupt Service Routines:
interrupt void SPIRXINTA_ISR(void); // SPI
interrupt void SPITXINTA_ISR(void); // SPI
interrupt void MRINTA_ISR(void); // McBSP
interrupt void MXINTA_ISR(void); // McBSP
// Group 9 PIE Interrupt Service Routines:
interrupt void SCIRXINTA_ISR(void); // SCI-A
interrupt void SCITXINTA_ISR(void); // SCI-A
interrupt void SCIRXINTB_ISR(void); // SCI-B
interrupt void SCITXINTB_ISR(void); // SCI-B
interrupt void ECAN0INTA_ISR(void); // eCAN
interrupt void ECAN1INTA_ISR(void); // eCAN
// Catch-all for Reserved Locations For testing purposes:
interrupt void PIE_RESERVED(void); // Reserved for test
interrupt void rsvd_ISR(void); // for test
#ifdef __cplusplus
}
#endif /* extern "C" */
#endif // end of DSP281x_DEFAULT_ISR_H definition
@@ -0,0 +1,88 @@
// TI File $Revision: /main/3 $
// Checkin $Date: April 25, 2007 11:04:51 $
//###########################################################################
//
// FILE: DSP281x_Examples.h
//
// TITLE: DSP281x Device Definitions.
//
//###########################################################################
// $TI Release: DSP281x C/C++ Header Files V1.20 $
// $Release Date: July 27, 2009 $
//###########################################################################
#ifndef DSP281x_EXAMPLES_H
#define DSP281x_EXAMPLES_H
#ifdef __cplusplus
extern "C" {
#endif
/*-----------------------------------------------------------------------------
Specify the clock rate of the CPU (SYSCLKOUT) in nS.
Take into account the input clock frequency and the PLL multiplier
selected in SysCtrl.c (0xA by default).
Use one of the values provided, or define your own.
The trailing L is required tells the compiler to treat
the number as a 64-bit value.
Only one statement should be uncommented.
Example: CLKIN is a 30MHz crystal.
In SysCtrl.c the user specified PLLCR = 0xA for a
150Mhz CPU clock (SYSCLKOUT = 150MHz).
In this case, the CPU_RATE will be 6.667L
Uncomment the line: #define CPU_RATE 6.667L
-----------------------------------------------------------------------------*/
//#define CPU_RATE 6.667L // for a 150MHz CPU clock speed (SYSCLKOUT)
#define CPU_RATE 7.143L // for a 140MHz CPU clock speed (SYSCLKOUT)
//#define CPU_RATE 8.333L // for a 120MHz CPU clock speed (SYSCLKOUT)
//#define CPU_RATE 10.000L // for a 100MHz CPU clock speed (SYSCLKOUT)
//#define CPU_RATE 13.330L // for a 75MHz CPU clock speed (SYSCLKOUT)
//#define CPU_RATE 20.000L // for a 50MHz CPU clock speed (SYSCLKOUT)
//#define CPU_RATE 33.333L // for a 30MHz CPU clock speed (SYSCLKOUT)
//#define CPU_RATE 41.667L // for a 24MHz CPU clock speed (SYSCLKOUT)
//#define CPU_RATE 50.000L // for a 20MHz CPU clock speed (SYSCLKOUT)
//#define CPU_RATE 66.667L // for a 15MHz CPU clock speed (SYSCLKOUT)
//#define CPU_RATE 100.000L // for a 10MHz CPU clock speed (SYSCLKOUT)
//----------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Include Example Header Files:
//
#include "DSP281x_GlobalPrototypes.h" // Prototypes for global functions within the
// .c files.
#include "DSP281x_SWPrioritizedIsrLevels.h" // Used for Software Prioritization of ISR's
// Include files not used with DSP/BIOS
#ifndef DSP28_BIOS
#include "DSP281x_DefaultISR.h"
#endif
// DO NOT MODIFY THIS LINE.
#define DELAY_US(A) DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) - 9.0L) / 5.0L)
#ifdef __cplusplus
}
#endif /* extern "C" */
#endif // end of DSP281x_EXAMPELS_H definition
//===========================================================================
// No more.
//===========================================================================

Some files were not shown because too many files have changed in this diff Show More