Author SHA1 Message Date
Andrey 41e24629ce Расширить DEIF, загрузку CAN и общую обработку сигналов
Добавить общее ядро DEIF, эмуляцию приборов и переносимые панели Python/Qt.
Расширить загрузчики F2812 и F28335, обновление Flash и профиль STM Invertor.
Добавить альтернативный МНК Eigen, модели неисправностей и диагностику сигналов.
Обновить справочники устройств, проекты CCS и регрессионные проверки.
2026-10-24 15:40:51 +03:00
Andrey a5e46d4627 Расширить обмен по шинам, CAN-адаптеры и обработку графиков
Добавить очереди операций PBUS/SBUS, общую консоль, настройки Candle и SLCAN, декодеры DSView и обработку плотных графиков. Обновить протокол Бальзам и проверки общих компонентов.
2026-10-17 14:36:14 +03:00
Andrey 95c8b8ac7d Поддержать компактные записи логгера УМП v4
Разрешить 12-словные записи в запросах RTU и CAN. Распознавать статус v4 и декодировать оставшиеся сигналы с сохранением поддержки архивов v2/v3.
2026-10-12 12:26:37 +03:00
238 changed files with 48215 additions and 1027 deletions
+1 -1
View File
@@ -9,5 +9,5 @@ if(NOT WIN32)
endif()
add_library(candle SHARED candle.c candle_ctrl_req.c candle.def)
target_compile_definitions(candle PRIVATE UNICODE _UNICODE)
target_link_libraries(candle PRIVATE setupapi winusb ole32 advapi32)
target_link_libraries(candle PRIVATE setupapi winusb ole32 advapi32 cfgmgr32) # Configuration Manager сопоставляет интерфейсы CAN и DFU по родительскому USB-узлу.
target_include_directories(candle PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+149 -4
View File
@@ -34,6 +34,86 @@
#include "candle_defs.h"
#include "candle_ctrl_req.h"
#include "ch_9.h"
#include <cfgmgr32.h> /* Сопоставляет интерфейсы CAN и DFU по общему родительскому USB-устройству Windows. */
static DWORD candle_dfu_parent(const wchar_t *path, DEVINST *parent) /* Возвращает родителя интерфейса, чтобы команда не попала в другой подключённый адаптер. */
{ /* Начало поиска физического USB-устройства по пути выбранного CAN-интерфейса. */
HDEVINFO devices = SetupDiCreateDeviceInfoList(NULL, NULL); /* Создаёт временный набор SetupAPI без перечисления посторонних устройств. */
if (devices == INVALID_HANDLE_VALUE) return GetLastError(); /* Сохраняет причину отказа создания набора Windows. */
SP_DEVICE_INTERFACE_DATA iface = {0}; /* Подготавливает описание интерфейса для открытия по точному пути. */
iface.cbSize = sizeof(iface); /* Передаёт SetupAPI размер структуры текущей разрядности процесса. */
SP_DEVINFO_DATA info = {0}; /* Получает идентификатор узла PnP выбранного интерфейса. */
info.cbSize = sizeof(info); /* Указывает размер структуры устройства согласно контракту SetupAPI. */
DWORD size = 0, error = ERROR_SUCCESS; /* Хранит требуемое число байтов и итоговый код Windows. */
if (!SetupDiOpenDeviceInterfaceW(devices, path, 0, &iface)) error = GetLastError(); /* Открывает только заданный путь, сохраняя ошибку исчезнувшего устройства. */
if (!error) SetupDiGetDeviceInterfaceDetailW(devices, &iface, NULL, 0, &size, NULL); /* Узнаёт объём буфера переменной длины для пути USB-интерфейса. */
PSP_DEVICE_INTERFACE_DETAIL_DATA_W detail = size ? malloc(size) : NULL; /* Выделяет буфер только после успешного определения его размера. */
if (!error && !detail) error = size ? ERROR_NOT_ENOUGH_MEMORY : GetLastError(); /* Отличает нехватку памяти от ошибки поиска описания. */
if (detail) { /* Обрабатывает описание только при наличии выделенного буфера. */
detail->cbSize = sizeof(*detail); /* Согласует размер заголовка с архитектурой Win32 или Win64. */
if (!SetupDiGetDeviceInterfaceDetailW(devices, &iface, detail, size, NULL, &info)) error = GetLastError(); /* Получает узел интерфейса из SetupAPI. */
else if (CM_Get_Parent(parent, info.DevInst, 0) != CR_SUCCESS) error = ERROR_NOT_FOUND; /* Получает общий родительский узел составного USB-адаптера. */
free(detail); /* Освобождает описание после получения идентификатора родителя. */
} /* Завершает работу с описанием интерфейса. */
SetupDiDestroyDeviceInfoList(devices); /* Освобождает набор SetupAPI при любом результате поиска. */
return error; /* Возвращает ноль при успехе либо причину отказа Windows. */
} /* Завершает сопоставление интерфейса с физическим USB-устройством. */
uint32_t __stdcall candle_dev_enter_dfu(const wchar_t *can_path, uint8_t status[6]) /* Возвращает код Windows и шестибайтовый DFU_GETSTATUS согласно DFU 1.1. */
{ /* Начало отдельного сеанса управляющего интерфейса обновления. */
if (!can_path || !status) return ERROR_INVALID_PARAMETER; /* Запрещает отсутствие точного пути адаптера или выходного буфера статуса. */
memset(status, 0, 6); /* Исключает использование неинициализированных полей ответа при ошибке USB. */
DEVINST wanted_parent = 0; /* Запоминает физический адаптер, выбранный пользователем до остановки CAN. */
DWORD error = candle_dfu_parent(can_path, &wanted_parent); /* Ищет родителя по сохранённому пути CAN, не заменяя его первым найденным устройством. */
if (error) return error; /* Прерывает переход, если выбранный адаптер уже исчез из PnP. */
GUID guid = {0xc25b4308, 0x04d3, 0x11e6, {0xb3, 0xea, 0x60, 0x57, 0x18, 0x9e, 0x64, 0x43}}; /* GUID интерфейса обновления из дескриптора CANable 2.5. */
HDEVINFO devices = SetupDiGetClassDevsW(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); /* Перечисляет только подключённые интерфейсы обновления CANable 2.5. */
if (devices == INVALID_HANDLE_VALUE) return GetLastError(); /* Возвращает отказ SetupAPI без попытки послать команду. */
error = ERROR_NOT_FOUND; /* Отсутствие интерфейса обновления не считается успешным входом в DFU. */
for (DWORD index = 0; ; ++index) { /* Проверяет интерфейсы до точного совпадения физического устройства. */
SP_DEVICE_INTERFACE_DATA iface = {0}; /* Создаёт независимое описание очередного DFU-интерфейса. */
iface.cbSize = sizeof(iface); /* Задаёт обязательный размер структуры SetupAPI. */
if (!SetupDiEnumDeviceInterfaces(devices, NULL, &guid, index, &iface)) { /* Завершает обход либо сообщает ошибку перечисления. */
if (GetLastError() != ERROR_NO_MORE_ITEMS) error = GetLastError(); /* Отличает штатный конец списка от отказа Windows. */
break; /* Выходит из обхода после исчерпания интерфейсов или ошибки. */
} /* Завершает проверку результата перечисления. */
DWORD size = 0; /* Хранит размер описания очередного интерфейса в байтах. */
SetupDiGetDeviceInterfaceDetailW(devices, &iface, NULL, 0, &size, NULL); /* Определяет буфер для полного пути интерфейса обновления. */
if (!size) { error = GetLastError(); break; } /* Не продолжает работу с неполным результатом SetupAPI. */
PSP_DEVICE_INTERFACE_DETAIL_DATA_W detail = malloc(size); /* Выделяет описание с достаточным местом для USB-пути. */
if (!detail) { error = ERROR_NOT_ENOUGH_MEMORY; break; } /* Не допускает обращения к отсутствующему буферу. */
detail->cbSize = sizeof(*detail); /* Сохраняет ABI описания интерфейса Windows. */
if (!SetupDiGetDeviceInterfaceDetailW(devices, &iface, detail, size, NULL, NULL)) { /* Получает путь, который можно передать CreateFileW. */
error = GetLastError(); free(detail); break; /* Сохраняет ошибку и освобождает буфер перед выходом. */
} /* Завершает чтение пути интерфейса. */
DEVINST parent = 0; /* Хранит родителя текущего кандидата на обновление. */
if (candle_dfu_parent(detail->DevicePath, &parent) || parent != wanted_parent) { /* Исключает каждый интерфейс другого физического адаптера. */
free(detail); continue; /* Освобождает описание неподходящего кандидата и продолжает поиск. */
} /* Завершает проверку принадлежности выбранному USB-адаптеру. */
HANDLE file = CreateFileW(detail->DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); /* Эксклюзивно открывает интерфейс обновления выбранного устройства для WinUSB. */
free(detail); /* Путь больше не нужен после открытия системного дескриптора. */
if (file == INVALID_HANDLE_VALUE) { error = GetLastError(); break; } /* Не скрывает отсутствие доступа или занятость интерфейса. */
WINUSB_INTERFACE_HANDLE usb = NULL; /* Хранит отдельный WinUSB-сеанс интерфейса обновления без CAN bulk endpoint. */
error = ERROR_SUCCESS; /* Сбрасывает исходное отсутствие интерфейса после точного совпадения устройства. */
if (!WinUsb_Initialize(file, &usb)) error = GetLastError(); /* Проверяет наличие рабочего WinUSB-драйвера DFU runtime. */
USB_INTERFACE_DESCRIPTOR descriptor = {0}; /* Получает реальный номер и класс открытого интерфейса. */
if (!error && !WinUsb_QueryInterfaceSettings(usb, 0, &descriptor)) error = GetLastError(); /* Не предполагает, что произвольный WinUSB-интерфейс поддерживает DFU. */
if (!error && (descriptor.bInterfaceClass != 0xFE || descriptor.bInterfaceSubClass != 1 || descriptor.bInterfaceProtocol != 1)) error = ERROR_NOT_SUPPORTED; /* Проверяет класс приложения, подкласс DFU и runtime-протокол по DFU 1.1. */
ULONG timeout = 500, transferred = 0; /* Ограничивает управляющий USB-запрос 500 миллисекундами и учитывает длину ответа. */
if (!error && !WinUsb_SetPipePolicy(usb, 0, PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout)) error = GetLastError(); /* Устанавливает тайм-аут endpoint 0, чтобы отсутствующий ответ не блокировал программу. */
WINUSB_SETUP_PACKET packet = {0}; /* Обнуляет поля USB SETUP перед запросом перехода в загрузчик. */
packet.RequestType = 0x21; packet.Request = 0; packet.Value = 1000; packet.Index = descriptor.bInterfaceNumber; /* DFU_DETACH: class/interface OUT, запрос 0, ожидаемое время отключения 1000 мс. */
if (!error && !WinUsb_ControlTransfer(usb, packet, NULL, 0, &transferred, NULL)) error = GetLastError(); /* Отправляет DETACH и требует подтверждённой USB-транзакции. */
packet.RequestType = 0xA1; packet.Request = 3; packet.Value = 0; packet.Length = 6; /* DFU_GETSTATUS: class/interface IN, запрос 3, ответ ровно 6 байт по DFU 1.1. */
if (!error && !WinUsb_ControlTransfer(usb, packet, status, 6, &transferred, NULL)) error = GetLastError(); /* Проверяет результат до отложенного перехода прошивки через 300 мс. */
if (!error && transferred != 6) error = ERROR_INVALID_DATA; /* Не трактует укороченный ответ как подтверждение входа в загрузчик. */
if (usb) WinUsb_Free(usb); /* Освобождает WinUSB до появления загрузчика с другим VID/PID. */
CloseHandle(file); /* Освобождает файловый дескриптор после успеха и при любой ошибке USB. */
break; /* Не отправляет DETACH повторно и не переключается на другой адаптер при отказе. */
} /* Завершает поиск и обработку единственного выбранного адаптера. */
SetupDiDestroyDeviceInfoList(devices); /* Освобождает перечень интерфейсов при любом результате. */
return error; /* Статус прошивки возвращается отдельно от системной ошибки USB. */
} /* Завершает управление DFU runtime без записи flash или изменения образа. */
static bool candle_dev_interal_open(candle_handle hdev);
@@ -656,6 +736,30 @@ bool __stdcall DLL candle_dev_open(candle_handle hdev)
}
bool __stdcall DLL candle_dev_get_product(candle_handle hdev, wchar_t *product, uint32_t capacity) /* Читает USB Product String открытого адаптера в буфер UTF-16; capacity измеряется в wchar_t, включая завершающий ноль. */
{ /* Начало чтения отображаемого имени без изменения режима CAN. */
if (!product || !capacity) return false; /* Не пишет в отсутствующий либо пустой выходной буфер. */
product[0] = 0; /* Сохраняет пустую строку при любом отказе чтения дескриптора. */
candle_device_t *dev = (candle_device_t*)hdev; /* Получает уже открытый WinUSB-сеанс выбранного физического адаптера. */
if (!dev || !dev->winUSBHandle) return false; /* Не открывает устройство заново и не обращается к закрытому интерфейсу. */
USB_DEVICE_DESCRIPTOR descriptor = {0}; /* Получает индекс строки продукта из стандартного дескриптора устройства. */
ULONG received = 0; /* Хранит фактически полученное количество байтов управляющего ответа. */
if (!WinUsb_GetDescriptor(dev->winUSBHandle, 1, 0, 0, (PUCHAR)&descriptor, sizeof(descriptor), &received) || received != sizeof(descriptor)) return false; /* Тип 1 обозначает Device Descriptor по USB 2.0; неполный ответ не используется. */
UCHAR string_index = descriptor.iProduct; /* Для обычных адаптеров использует объявленный устройством индекс USB Product String. */
if (descriptor.idVendor == 0x1D50 && descriptor.idProduct == 0x606F) string_index = 2; /* В CANable Candlelight имя продукта имеет индекс 2; WinUSB может подменять iProduct индексом имени интерфейса, как описано в штатном примере проекта. */
if (!string_index) return false; /* Нулевой iProduct означает, что устройство не предоставляет имя продукта. */
UCHAR raw[256] = {0}; /* Буфер вмещает строковый дескриптор USB, чей однобайтовый bLength ограничен 255 байтами. */
USHORT language = 0x0409; /* Использует английский идентификатор USB как резервный вариант для устройств без списка языков. */
if (WinUsb_GetDescriptor(dev->winUSBHandle, 3, 0, 0, raw, sizeof(raw), &received) && received >= 4 && raw[0] >= 4 && raw[1] == 3) language = (USHORT)(raw[2] | ((USHORT)raw[3] << 8)); /* Тип 3 и индекс 0 возвращают список LANGID; выбирает первый язык, предоставленный адаптером. */
if (!WinUsb_GetDescriptor(dev->winUSBHandle, 3, string_index, language, raw, sizeof(raw), &received)) return false; /* Читает именно строку продукта на поддерживаемом устройством языке. */
if (received < 2 || raw[1] != 3 || raw[0] < 2 || raw[0] > received || (raw[0] & 1)) return false; /* Проверяет тип, размер и чётное число байтов UTF-16 перед копированием в выходной буфер. */
uint32_t count = (raw[0] - 2) / 2; /* Исключает двухбайтовый заголовок и переводит длину UTF-16LE из байтов в число кодовых единиц. */
if (count >= capacity) return false; /* Не обрезает индивидуальный номер в конце имени и оставляет место для завершающего нуля. */
for (uint32_t index = 0; index < count; ++index) product[index] = (wchar_t)(raw[2 + index * 2] | ((USHORT)raw[3 + index * 2] << 8)); /* Явно собирает кодовые единицы UTF-16LE без предположений о выравнивании массива байтов. */
product[count] = 0; /* Завершает строку для безопасного чтения через ctypes и отображения в Qt. */
return count > 0; /* Пустое имя оставляет интерфейсу стандартную резервную подпись адаптера. */
} /* Завершает получение настоящего имени из прошивки USB-адаптера. */
bool __stdcall DLL candle_dev_get_timestamp_us(candle_handle hdev, uint32_t *timestamp_us)
{
return candle_ctrl_get_timestamp(hdev, timestamp_us);
@@ -823,6 +927,38 @@ bool __stdcall DLL candle_channel_stop(candle_handle hdev, uint8_t ch)
return candle_ctrl_set_device_mode(dev, ch, CANDLE_DEVMODE_RESET, 0);
}
bool __stdcall DLL candle_channel_start_configured(candle_handle hdev, uint8_t ch, uint32_t flags) /* Новый вход сохраняет прежний ABI start и позволяет отключать HW_TIMESTAMP. */
{ /* Явно выбранные Python-флаги должны попасть в прошивку без автоматического дополнения. */
return candle_ctrl_set_device_mode((candle_device_t*)hdev, ch, CANDLE_DEVMODE_START, flags); /* Передаём точную маску после проверки возможностей на уровне транспорта. */
} /* Завершение запуска с явно заданными параметрами. */
bool __stdcall DLL candle_channel_get_data_capabilities(candle_handle hdev, uint8_t ch, candle_capability_t *cap) /* Экспортируем чтение FD-пределов для расчёта тайминга на любой частоте CAN. */
{ /* Общая форма capability позволяет повторно использовать валидатор номинального тайминга. */
return candle_ctrl_data_capability((candle_device_t*)hdev, ch, cap); /* USB-запрос возвращает реальные пределы выбранного канала. */
} /* Завершение получения возможностей быстрой фазы. */
bool __stdcall DLL candle_channel_set_termination(candle_handle hdev, uint8_t ch, uint32_t state) /* Значения 0 и 1 соответствуют OFF и ON стандарта gs_usb. */
{ /* Проверка исключает отправку неопределённого состояния в прошивку. */
return state <= 1 && candle_ctrl_termination((candle_device_t*)hdev, ch, &state, true); /* Выполняем запись только для допустимого состояния. */
} /* Завершение переключения терминатора. */
bool __stdcall DLL candle_channel_get_termination(candle_handle hdev, uint8_t ch, uint32_t *state) /* Чтение состояния не меняет топологию CAN. */
{ /* Используем тот же формат 32-битного значения, что и при записи. */
return candle_ctrl_termination((candle_device_t*)hdev, ch, state, false); /* false выбирает USB_DIR_IN и GET_TERMINATION. */
} /* Завершение чтения терминатора. */
bool __stdcall DLL candle_channel_get_diagnostics(candle_handle hdev, uint8_t ch, uint32_t *state, uint32_t *rxerr, uint32_t *txerr) /* Сохраняем счётчики, которые старый get_state отбрасывал. */
{ /* Диагностика выполняется только для уже открытого устройства. */
candle_device_state_t data = {0}; /* Полная структура протокола содержит три слова: состояние, RX и TX. */
if (!candle_ctrl_get_state((candle_device_t*)hdev, ch, &data)) { /* Не возвращаем нулевые счётчики как будто запрос был успешным. */
return false; /* Причина USB-отказа уже записана управляющим запросом. */
} /* Дальнейшее копирование относится только к подтверждённому ответу. */
*state = data.state; /* Сохраняем состояние Error-active, Warning, Passive, Bus-off, Stopped или Sleeping. */
*rxerr = data.rxerr; /* Счётчик ошибок приёма измеряется в единицах CAN-контроллера. */
*txerr = data.txerr; /* Счётчик ошибок передачи помогает отличать отсутствие ACK от ошибок приёма. */
return true; /* Все три выходных значения относятся к одному USB-ответу. */
} /* Завершение расширенной диагностики канала. */
/* Write len bytes from buf to the OUT pipe, aborting after 300 ms.
* Writes are serialised by writeMutex in CandleApiInterface so dev->txEvent
* is never accessed by two threads simultaneously. */
@@ -1017,14 +1153,13 @@ bool __stdcall DLL candle_fd_frame_read(candle_handle hdev, candle_fd_frame_t *f
}
dev->rxurbs[urb_num].pending = false;
/* Minimum: classic CAN header (12 bytes) + at least 8 data bytes = 20 bytes */
static const DWORD classic_min = sizeof(candle_frame_t) - 4;
if (bytes_transfered < classic_min) {
const DWORD header_size = 12; /* Заголовок gs_usb занимает 12 байт в Classic и FD; короткий FD может не содержать восьми байтов данных. */
if (bytes_transfered < header_size) { /* До чтения flags и DLC проверяем наличие полного заголовка. */
candle_prepare_read(dev, urb_num);
candle_logf(L"fd read too small urb=%u bytes=%lu min=%lu",
urb_num,
bytes_transfered,
classic_min);
header_size); /* Минимальная длина здесь относится к заголовку, а payload проверяется после определения формата. */
dev->last_error = CANDLE_ERR_READ_SIZE;
return false;
}
@@ -1047,6 +1182,11 @@ bool __stdcall DLL candle_fd_frame_read(candle_handle hdev, candle_fd_frame_t *f
if (is_fd_frame) {
/* can_dlc is at byte offset 8 in both classic and FD wire frames. */
const uint8_t raw_dlc = dev->rxurbs[urb_num].buf[8];
if (raw_dlc > 15) { /* FD DLC является четырёхбитным кодом и не может содержать значения выше 15. */
candle_prepare_read(dev, urb_num); /* Повреждённый USB-пакет не должен останавливать последующий приём. */
dev->last_error = CANDLE_ERR_READ_SIZE; /* Неверный DLC считается ошибкой формата входного кадра. */
return false; /* Не превращаем повреждённый DLC в пустой успешный FD-кадр. */
} /* Далее длина безопасно вычисляется по таблице CAN FD. */
const DWORD data_len = candle_dlc_to_len(raw_dlc);
const DWORD min_size = 12 + data_len; /* header + data, without timestamp */
@@ -1077,6 +1217,11 @@ bool __stdcall DLL candle_fd_frame_read(candle_handle hdev, candle_fd_frame_t *f
}
/* else: timestamp stays zero from memset above */
} else {
if (bytes_transfered < sizeof(candle_frame_t) - sizeof(uint32_t)) { /* Classic-пакет обязан содержать весь восьмибайтовый буфер данных, даже при меньшем DLC. */
candle_prepare_read(dev, urb_num); /* Возобновляем соответствующий URB после отклонения неполного пакета. */
dev->last_error = CANDLE_ERR_READ_SIZE; /* Не допускаем чтение неполученных данных из локальной структуры. */
return false; /* Повреждённый Classic-пакет не попадает в Python через FD API. */
} /* Минимальный размер Classic теперь проверен отдельно от коротких FD. */
/* Classic CAN frame — copy into FD struct, fixing the timestamp position */
candle_frame_t classic;
DWORD copy_len = (bytes_transfered < sizeof(classic)) ? bytes_transfered : sizeof(classic);
+12
View File
@@ -3,6 +3,8 @@
; прикладные регистры SETProtocol.
EXPORTS
candle_dev_get_product ; Имя продукта из USB-дескриптора прошивки для списка адаптеров SETGUI.
candle_dev_enter_dfu ; Переход через отдельный DFU runtime-интерфейс того же физического USB-адаптера.
candle_list_scan
candle_list_free
candle_list_length
@@ -31,3 +33,13 @@ EXPORTS
candle_frame_data
candle_frame_timestamp_us
candle_dev_last_error
candle_channel_start_configured ; Точная маска запуска с управляемыми аппаратными метками.
candle_channel_get_data_capabilities ; Пределы тайминга быстрой фазы CAN FD.
candle_channel_set_termination ; Переключение встроенного терминатора.
candle_channel_get_termination ; Чтение состояния встроенного терминатора.
candle_channel_get_diagnostics ; Состояние и счётчики ошибок CAN.
candle_channel_set_data_timing ; Тайминг фазы данных CAN FD.
candle_fd_frame_send ; Отправка полного кадра CAN FD до 64 байт.
candle_fd_frame_read ; Приём FD и Classic без обрезания данных.
candle_fd_frame_type ; Различение RX, TX echo и ошибок FD.
candle_fd_frame_id ; Получение CAN ID из структуры FD.
+7
View File
@@ -246,7 +246,9 @@ bool __stdcall DLL candle_list_length(candle_list_handle list, uint8_t *len);
bool __stdcall DLL candle_dev_get(candle_list_handle list, uint8_t dev_num, candle_handle *hdev);
bool __stdcall DLL candle_dev_get_state(candle_handle hdev, candle_devstate_t *state);
wchar_t * __stdcall DLL candle_dev_get_path(candle_handle hdev);
bool __stdcall DLL candle_dev_get_product(candle_handle hdev, wchar_t *product, uint32_t capacity); /* Возвращает USB Product String в UTF-16; capacity включает завершающий ноль и измеряется в wchar_t. */
bool __stdcall DLL candle_dev_open(candle_handle hdev);
uint32_t __stdcall DLL candle_dev_enter_dfu(const wchar_t *can_path, uint8_t status[6]); /* Переводит выбранный физический адаптер в DFU и возвращает Win32-код плюс ответ DFU_GETSTATUS. */
bool __stdcall DLL candle_dev_get_timestamp_us(candle_handle hdev, uint32_t *timestamp_us);
bool __stdcall DLL candle_dev_close(candle_handle hdev);
bool __stdcall DLL candle_dev_free(candle_handle hdev);
@@ -259,6 +261,11 @@ bool __stdcall DLL candle_channel_set_timing(candle_handle hdev, uint8_t ch, can
bool __stdcall DLL candle_channel_set_bitrate(candle_handle hdev, uint8_t ch, uint32_t bitrate);
bool __stdcall DLL candle_channel_start(candle_handle hdev, uint8_t ch, uint32_t flags);
bool __stdcall DLL candle_channel_stop(candle_handle hdev, uint8_t ch);
bool __stdcall DLL candle_channel_start_configured(candle_handle hdev, uint8_t ch, uint32_t flags); /* Запускаем с точной маской без принудительного включения аппаратных меток. */
bool __stdcall DLL candle_channel_get_data_capabilities(candle_handle hdev, uint8_t ch, candle_capability_t *cap); /* Возвращаем пределы тайминга быстрой фазы FD. */
bool __stdcall DLL candle_channel_set_termination(candle_handle hdev, uint8_t ch, uint32_t state); /* Состояние терминатора: 0 — выключен, 1 — включён. */
bool __stdcall DLL candle_channel_get_termination(candle_handle hdev, uint8_t ch, uint32_t *state); /* Чтение не меняет подключение встроенного резистора. */
bool __stdcall DLL candle_channel_get_diagnostics(candle_handle hdev, uint8_t ch, uint32_t *state, uint32_t *rxerr, uint32_t *txerr); /* Передаём состояние CAN и оба счётчика ошибок без потери данных ответа. */
bool __stdcall DLL candle_frame_send(candle_handle hdev, uint8_t ch, candle_frame_t *frame);
bool __stdcall DLL candle_frame_read(candle_handle hdev, candle_frame_t *frame, uint32_t timeout_ms);
+23 -2
View File
@@ -39,8 +39,10 @@ enum {
CANDLE_TIMESTAMP_GET = 6,
/* 7: IDENTIFY, 8: GET_USER_ID, 9: SET_USER_ID (not used here) */
CANDLE_BREQ_DATA_BITTIMING = 10,
/* 11: SET_TERMINATION, not used here */
CANDLE_BREQ_GET_STATE = 12,
CANDLE_BREQ_BT_CONST_EXT = 11, /* Расширенные пределы номинальной и быстрой фазы согласно gs_usb. */
CANDLE_BREQ_SET_TERMINATION = 12, /* Запрос gs_usb 12 переключает встроенный резистор окончания шины. */
CANDLE_BREQ_GET_TERMINATION = 13, /* Запрос gs_usb 13 читает текущее состояние терминатора. */
CANDLE_BREQ_GET_STATE = 14, /* Стандартный GET_STATE имеет номер 14; номер 12 принадлежит терминатору. */
CANDLE_BREQ_BUS_OFF_RECOVERY = 32,
};
@@ -237,3 +239,22 @@ bool candle_ctrl_bus_off_recover(candle_device_t *dev, uint8_t channel)
dev->last_error = rc ? CANDLE_ERR_OK : CANDLE_ERR_SET_DEVICE_MODE;
return rc;
}
bool candle_ctrl_data_capability(candle_device_t *dev, uint8_t channel, candle_capability_t *cap) /* Структура gs_usb BT_CONST_EXT содержит десять общих и восемь быстрых полей uint32. */
{ /* Используем массив, поскольку протокол содержит только однородные 32-битные значения без отступов. */
uint32_t fields[18] = {0}; /* 18 полей по 4 байта образуют стандартный ответ размером 72 байта. */
bool rc = usb_control_msg(dev->winUSBHandle, CANDLE_BREQ_BT_CONST_EXT, USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, channel, 0, fields, sizeof(fields)); /* Запрашиваем пределы именно выбранного CAN-канала. */
if (rc) { /* Выходная структура должна меняться только после успешного USB-ответа. */
memcpy(cap, fields, 2 * sizeof(uint32_t)); /* Маска функций и частота CAN общие для обеих фаз. */
memcpy(&cap->tseg1_min, &fields[10], 8 * sizeof(uint32_t)); /* Поля DTSEG1…DBRP_INC заменяют номинальные пределы структуры capability. */
} /* При отказе вызывающий код получит false и не использует нулевые пределы. */
dev->last_error = rc ? CANDLE_ERR_OK : CANDLE_ERR_GET_BITTIMING_CONST; /* Сохраняем диагностический код чтения аппаратных ограничений. */
return rc; /* Успех означает наличие полной структуры пределов быстрой фазы. */
} /* Завершение запроса расширенных возможностей FD. */
bool candle_ctrl_termination(candle_device_t *dev, uint8_t channel, uint32_t *state, bool write) /* Переключение терминатора использует стандартные SET=12 и GET=13. */
{ /* Состояние передаётся одним 32-битным словом согласно протоколу gs_usb. */
bool rc = usb_control_msg(dev->winUSBHandle, write ? CANDLE_BREQ_SET_TERMINATION : CANDLE_BREQ_GET_TERMINATION, (write ? USB_DIR_OUT : USB_DIR_IN)|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, channel, 0, state, sizeof(*state)); /* Номер CAN-канала передаётся в wValue, а wIndex равен нулю по спецификации. */
dev->last_error = rc ? CANDLE_ERR_OK : CANDLE_ERR_SET_DEVICE_MODE; /* Ошибка настройки доступна Python через candle_dev_last_error. */
return rc; /* Не выдаём успешное переключение при отказе USB-контроллера. */
} /* Завершение управления встроенным окончанием шины. */
+2
View File
@@ -51,4 +51,6 @@ bool candle_ctrl_set_data_bittiming(candle_device_t *dev, uint8_t channel, candl
bool candle_ctrl_get_timestamp(candle_device_t *dev, uint32_t *current_timestamp);
bool candle_ctrl_get_state(candle_device_t *dev, uint8_t channel, candle_device_state_t *data);
bool candle_ctrl_bus_off_recover(candle_device_t *dev, uint8_t channel);
bool candle_ctrl_data_capability(candle_device_t *dev, uint8_t channel, candle_capability_t *cap); /* Читаем пределы быстрой фазы CAN FD отдельным запросом расширенной структуры. */
bool candle_ctrl_termination(candle_device_t *dev, uint8_t channel, uint32_t *state, bool write); /* Передаём состояние терминатора: 0 — выключен, 1 — включён. */
+35 -8
View File
@@ -13,6 +13,7 @@ import json
import os
from pathlib import Path
import subprocess
import tempfile # Резервирует номер сборки через временный файл на том же диске, как общий итератор ветки 166.
def git_state(repository: Path) -> dict:
@@ -36,20 +37,46 @@ def git_state(repository: Path) -> dict:
def write_atomic(path: Path, text: str):
path.parent.mkdir(parents=True, exist_ok=True)
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)
def prepare(repository: Path, templates: Path, config: Path, output: Path) -> dict:
settings = json.loads(config.read_text(encoding="utf-8"))
version = settings["version"]
if (len(version) != 3 or any(type(v) is not int for v in version)
or not all(0 <= v <= limit for v, limit in zip(version, (255, 255, 999)))):
raise ValueError("version must be [major 0..255, minor 0..255, patch 0..999]")
def next_version(version): # Повторяет общий итератор 166 и переносит переполнение младшего разряда в старший.
result = list(version) # Не изменяет исходный номер до проверки полного переполнения.
for index, limit in ((2, 999), (1, 255), (0, 255)): # Контракт firmware-info v1 допускает patch 0..999 и major/minor 0..255.
if result[index] < limit: # Выбирает младший разряд, который ещё допускает увеличение.
result[index] += 1 # Занимает следующий номер попытки сборки ровно один раз.
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"):
if not isinstance(settings.get(field), str) or not settings[field].strip():
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.
known = source["commit"] is not None and dependency["commit"] is not None
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-пути задают
# подключение к проекту потребителя. Файл также собирает и регистрирует хостовые проверки;
# запускать их следует через CTest из каталога сборки.
# Общая C99-библиотека ProtoCAN Boot и аппаратно независимые host-тесты.
# Каждый контроллер сохраняет собственное состояние и отдельный аппаратный порт.
# Дополнительные проекты CCS находятся в projects/ccs и не требуют CMake для TI-сборки.
cmake_minimum_required(VERSION 3.13)
project(protocan_boot C)
@@ -17,7 +17,7 @@ else()
target_compile_options(protocan_boot PRIVATE -Wall -Wextra -Wpedantic)
endif()
option(PCAN_BOOT_BUILD_TESTS "Собирать тесты ProtoCAN boot" ON)
option(PCAN_BOOT_BUILD_TESTS "Собирать тесты ProtoCAN Boot" ON) # Не включает host-модели в код MCU.
if(PCAN_BOOT_BUILD_TESTS)
enable_testing()
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})
endforeach()
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
[Порт M95M02](ports/tms320f28335/README.md) подключён в `tms_periph/periph_167`.
[Порт M95M02](ports/tms320f28335/README.md) подключён в `28335_periph`, ветка 167.
Использует отдельный Flash-загрузчик и два слота EEPROM по 130560 байт.
Реализованы readback/CRC, проверка SCI8, журнал метаданных, пробный запуск,
CONFIRM/откат, PING/discovery и сервисный паспорт. Первичная установка Flash-
загрузчика и выбор 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_CAPABILITIES = 0x0DU,
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;
typedef enum {
@@ -127,6 +128,7 @@ typedef struct {
/** Optional precise result, replacing legacy boolean verify_image. */
pcan_boot_status_t (*verify_status)(void *user, pcan_boot_byte_t slot,
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;
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. */
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. */
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,
@@ -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
Реализация состоит из Flash-загрузчика `periph_167/Bootloader`, переносимого
Реализация состоит из Flash-загрузчика `projects/ccs/f28335`, переносимого
`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.
## Адрес и формат
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`;
для версии 1.1.2 это `0x01010002`. Загрузчик сообщает версию подтверждённого образа
из журнала, при отсутствии такого образа — 0. Версия кандидата передаётся в BEGIN_COMPAT.
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 байт** включительно.
Числа в протоколе little endian. Адреса внутри SCI8: сначала старшее 16-битное
@@ -106,7 +143,7 @@ Python API: `protocan.can_boot.CanBootServices` — запросы и разбо
## Аппаратная интеграция
MBOX3 — адресные входящие Boot; MBOX4 — ответы; MBOX6 — точный broadcast discovery.
MBOX0..2 сохраняют legacy/UMP, MBOX5 остаётся heartbeat. ISR помещает сообщения
MBOX0..2 сохраняют legacy/UMP, MBOX5 загрузчик не использует. ISR помещает сообщения
в очередь на 31 кадр. Чужие адреса, RTR и неподходящие типы отбрасываются до очереди.
При переполнении/потере mailbox сессия отменяется; повторная запись начинается заново.
SPI-драйвер загрузчика имеет ограничение ожидания байта и WIP, 24-битный адрес,
@@ -118,7 +155,31 @@ SPI-драйвер загрузчика имеет ограничение ожи
Его RAM — 0xE000..0xFFFF; стек — 0x400..0x7FF. Приложение M95M02 использует
0x8000..0xD7FF для кода, 0xD800..0xDFFF для констант/инициализации,
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 автоматически не заменены. Приложение должно содержать интеграцию
READY/CONFIRM, иначе на следующем reset оно останется неподтверждённым кандидатом.
2. Собрать отдельный загрузчик TI C2000 COFF compiler:
`Bootloader/build.ps1 -CompilerRoot <путь-к-ti-cgt-c2000>`.
Результат — `Bootloader/build/F28335_CAN_AB.out` и MAP.
3. Один раз установить этот OUT через JTAG и выбрать аппаратный Flash boot
согласно схеме платы. Не загружать поверх него старый application OUT с
`python c/protocan-boot/projects/build.py --device f28335 --compiler <путь-к-ti-cgt-c2000>`.
Результат — `projects/ccs/f28335/Debug/F28335_CAN_AB.out` и MAP.
3. Установить обновлённый OUT через JTAG и выбрать аппаратный Flash boot
согласно схеме платы. При переходе с общего адреса 3/7 обновить и приложение,
и загрузчик: старый загрузчик не перейдёт на новый адрес после reset сам.
В SETCAN выбрать «Прошивка → CAN / ProtoCAN Boot → Устройство PERIPH»
и нужное назначение. Не загружать поверх загрузчика старый application OUT с
секцией codestart во Flash.
4. После reset пустая EEPROM или старая разметка автоматически ведут в CAN recovery.
Передать новое приложение через ProtoCAN Boot, дождаться пробного запуска и
@@ -145,8 +209,10 @@ NOINIT handoff в обоих проектах. CAN не содержит опе
ядро, приложение/загрузчик, wide-octet режим, журнал, обрыв публикации на каждом
из 69 возможных положений, пробный запуск, CONFIRM, откат, SCI8 и границы памяти.
Python-тесты проверяют клиентские запросы, паспорт, фильтрацию ответов и лимит A/B.
Проверка синтаксиса использует настоящие DSP2833x headers. Сборка TI/CCS,
раскладка итогового MAP и физические CAN/SPI/reset на плате ещё не подтверждены.
Проверка синтаксиса использует настоящие DSP2833x headers. Импорт и сборка TI/CCS,
раскладка MAP и реальные COFF LOAD-адреса проверены; физические CAN/SPI/reset
на плате требуют стендовой проверки. Отдельные проекты и команды сборки описаны
в [инструкции CCS](../../projects/README.md).
CRC32 защищает от повреждения, криптографической подписи и anti-rollback по
версии в этом порту нет. Удалённый 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).
В 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
#define F28335_BOOT_PLATFORM_H
#include "f28335_boot_store.h"
#include "f28335_flash_app.h" /* Общий handoff различает EEPROM A/B, защищённое Flash-приложение и неизвестный запуск. */
#ifndef F28335_BOOT_LOADER
#define F28335_BOOT_LOADER 0
#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. */
static pcan_boot_t boot;
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 элементов
* используется 31, чтобы head==tail однозначно означало пустую очередь.
* Долгие операции 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.
* ready сообщает об окончании старта приложения, confirmed — о сохранённом
* подтверждении слота. 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 unsigned int main_passes;
static unsigned int addressed; /* Разрешает обслуживание только после проверки номера PERIPH и установки согласованных фильтров CAN. */
static int tx_busy,tx_canceling;
/* Один исходящий mailbox исключает перезапись ещё передаваемого ответа.
* MDL содержит первые четыре октета, MDH — следующие четыре, младшим вперёд.
@@ -48,9 +64,19 @@ static bool transmit(void *u, uint32_t id, const pcan_boot_byte_t *d, pcan_boot_
* эти callbacks возвращают отказ, даже если им удастся передать команду записи.
* ERASE для EEPROM означает инвалидирование manifest выбранного слота. */
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)
{ (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_ERROR как общий отказ проверки образа; причины внутри
* парсера SCI8 отдельными статусами протокола не различаются. */
@@ -58,10 +84,21 @@ static pcan_boot_status_t verify(void *u,pcan_boot_byte_t slot,const pcan_boot_m
{
(void)u;
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;
}
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. Загрузчик не может
* подтвердить кандидата сам: иначе исчезнет смысл проверки пробного запуска.
* Разрешение кормления watchdog из ISR открываем только после записи журнала. */
@@ -82,9 +119,14 @@ static unsigned int enter(void *u,pcan_boot_byte_t session)
{
(void)u;
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. */
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;
}
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 — область параметров. */
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;
unsigned int i,index; (void)u;
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,name_size=(unsigned int)strlen(name)+1U; (void)u; /* Длина включает завершающий NUL, чтобы последняя страница имени однозначно завершала чтение. */
if(command==PCAN_BOOT_CMD_CAPABILITIES && page==0) {
/* bits: ping, discovery, identity, name, memory, A/B, confirm, rollback,
* separate loader, session timeout, readback, SCI8 validation. */
info32(out,(F28335_BOOT_LOADER || F28335Boot_RunningSlot()<2)?0xFFFUL:0x1FUL);
info32(out+4,F28335_AB_SLOT_BYTES); return true;
info32(out,(F28335_BOOT_LOADER || F28335Boot_RunningSlot()<2 || F28335Boot_RunningSlot()==F28335_BOOT_FLASH_SLOT)?0xFFFUL:0x1FUL); /* Flash-приложение с достоверным handoff поддерживает вход в постоянный CAN Boot так же, как подтверждённый EEPROM-образ. */
#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((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;
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;
}
if(command!=PCAN_BOOT_CMD_MEMORY_INFO) return false;
@@ -124,14 +169,16 @@ void F28335CanBoot_EarlyInit(void) { confirmed=0; ready=0; }
/* Общий Init для приложения и загрузчика: открываем журнал, привязываем
* callbacks, задаём идентификацию, ёмкость слота, окно 16 и тайм-аут 30 секунд.
* В загрузчике FW берётся из active manifest; приложение сообщает версию сборки. */
void F28335CanBoot_Init(void)
void F28335CanBoot_Init(unsigned int periph_id) /* Один номер платы преобразуется одинаково в приложении и постоянном загрузчике. */
{
pcan_boot_config_t cfg; pcan_boot_port_t port;
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));
io.read=F28335Boot_Read; io.write=F28335Boot_Write; io.user=0;
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;
#if F28335_BOOT_LOADER
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;
#endif
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.slot_count=2; cfg.max_image_size=F28335_AB_SLOT_BYTES; cfg.ack_window=16;
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.verify_status=verify; port.set_pending_slot=commit; port.reboot=reboot;
port.confirm_running_slot=confirm; port.enter_boot=enter;
port.can_reboot=can_reboot; port.service_info=info;
if(!pcan_boot_init(&boot,&cfg,&port,0)) return;
addressed=1U; /* Дальнейшие ISR, основной цикл и handoff используют только успешно созданную адресную конфигурацию. */
EALLOW;
/* Меняем только MBOX3/4/6: маска 88=8+16+64. MBOX0..2 — старый обмен,
* 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);
if(!(box->MSGID.all&0x80000000UL) || pcan_boot_id_route(id)!=0 ||
(type!=9 && type!=10 && type!=11 && type!=13) ||
!((pcan_boot_id_device_type(id)==F28335_CAN_BOOT_DEVICE_TYPE &&
pcan_boot_id_device_id(id)==F28335_CAN_BOOT_DEVICE_ID) ||
!((pcan_boot_id_device_type(id)==boot.config.device_type && /* Сравнивает тип именно этой платы, а не прежнюю общую константу 3. */
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 &&
pcan_boot_id_msg_body(id)==0))) { ECanaRegs.CANRMP.all=mask; return; }
if(next==tail) overflow=1;
@@ -199,6 +251,7 @@ static void receive_box(volatile struct MBOX *box,uint32_t mask)
void F28335CanBoot_RxISR(void)
{
if(!addressed) return; /* Неверный или ещё не настроенный номер PERIPH не должен принимать даже оставшиеся флаги RX. */
receive_box(&ECanaMboxes.MBOX3,8UL);
receive_box(&ECanaMboxes.MBOX6,64UL);
}
@@ -214,9 +267,11 @@ unsigned int F28335CanBoot_WatchdogAllowed(void)
/* Неблокирующий диспетчер относительно ожидания CAN: вызывать в каждом проходе main.
* Сами callbacks проверки/записи EEPROM синхронные. Порядок здесь важен:
* проба приложения -> завершение 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)
{
uint32_t now=F28335Boot_Now();
if(!addressed) return; /* Не обслуживает старую RAM-сессию после отказа повторной инициализации адреса. */
if(!F28335_BOOT_LOADER && ready && !confirmed && healthy && F28335Boot_RunningSlot()<2) {
/* A trial must keep executing main, not merely a timer ISR. */
/* После 100 проходов main и 5 секунд пробуем сохранить CONFIRM.
@@ -261,15 +316,16 @@ void F28335CanBoot_Service(void)
* или CRC незавершённой передачи: данные сессии через reset не сохраняются. */
void F28335CanBoot_Resume(unsigned int session)
{
if(F28335_BOOT_LOADER && session && session<256)
(void)pcan_boot_process(&boot,pcan_boot_make_id(1,0,
F28335_CAN_BOOT_DEVICE_TYPE,F28335_CAN_BOOT_DEVICE_ID,9,(session<<8)|2),0,0);
if(addressed && F28335_BOOT_LOADER && session && session<256) /* Восстанавливает только допустимую сессию адресованного загрузчика после reset. */
(void)pcan_boot_process(&boot,pcan_boot_make_id(1,0, /* ACK относится к тому же физическому PERIPH, который принимал ENTER_BOOT в приложении. */
boot.config.device_type,boot.config.device_id,9,(session<<8)|2),0,0); /* MsgType 9, команда 2 и исходный SessionID сохраняют протокол handoff. */
}
#else
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_Service(void) {}
unsigned int F28335CanBoot_Active(void) { return 0U; } /* Профиль без M95M02 не создаёт CAN-сеанс и не удерживает старт общего загрузчика. */
void F28335CanBoot_Ready(void) {}
unsigned int F28335CanBoot_WatchdogAllowed(void) { return 1; }
void F28335CanBoot_Resume(unsigned int session) { (void)session; }
@@ -9,8 +9,7 @@
#endif
/* Адрес ProtoCAN состоит из Device Type (3 бита) и Device ID (4 бита).
* ProductType — отдельный код совместимости прошивки; это не CAN ID и не RS-адрес. */
#define F28335_CAN_BOOT_DEVICE_TYPE 3U
#define F28335_CAN_BOOT_DEVICE_ID 7U
#define F28335_CAN_BOOT_PERIPH_COUNT 32U /* Лист «Интерфейс протокола», строки 45–76: PERIPH 0–31 занимают два типа по 16 экземпляров. */
#define F28335_CAN_BOOT_PRODUCT 0x2833U
#define F28335_CAN_BOOT_DEVICE_NAME "F28335-M95M02"
/* Порядок интеграции приложения:
@@ -18,10 +17,11 @@
* таймера и EEPROM; Ready после старта прикладных подсистем; Service в main.
* RxISR вызывается из CAN ISR, WatchdogAllowed проверяется перед кормлением
* 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_RxISR(void);
void F28335CanBoot_Service(void);
unsigned int F28335CanBoot_Active(void); /* Удерживает загрузчик в CAN recovery после ENTER_BOOT, не запуская приложение по окончании стартового окна. */
void F28335CanBoot_Ready(void);
void F28335CanBoot_Resume(unsigned int session);
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);
}
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. Он доступен
* без открытия сессии, поэтому обнаружение устройства не должно запускать обновление. */
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);
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);
}
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;
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:
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);
@@ -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 LAM3,LAM6; } ECanaLAMRegs;
static struct { unsigned long InterruptCount; } CpuTimer1;
static struct { unsigned WDCR; } SysCtrlRegs;
/* Watchdog/reset моделируются callbacks; неиспользуемая глобальная копия SysCtrlRegs не требуется. */
#endif
+3 -1
View File
@@ -12,16 +12,18 @@ if not cc:
store = 'ports/tms320f28335/f28335_boot_store.c'
cases = [
('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_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']),
('application', ['-DPCAN_BOOT_WIDE_BYTES', '-DF28335_BOOT_LOADER=0'],
[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:
for name, defines, sources in cases:
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)
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)
+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 дополнительно проверяется на реальной плате. */

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