Compare commits
6
Commits
pysetterminal
...
ump-v4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41e24629ce | ||
|
|
a5e46d4627 | ||
|
|
95c8b8ac7d | ||
|
|
bbb4bc2b9d | ||
|
|
20454ff7fa | ||
|
|
3c0f6fd9e6 |
@@ -9,5 +9,5 @@ if(NOT WIN32)
|
|||||||
endif()
|
endif()
|
||||||
add_library(candle SHARED candle.c candle_ctrl_req.c candle.def)
|
add_library(candle SHARED candle.c candle_ctrl_req.c candle.def)
|
||||||
target_compile_definitions(candle PRIVATE UNICODE _UNICODE)
|
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})
|
target_include_directories(candle PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|||||||
+149
-4
@@ -34,6 +34,86 @@
|
|||||||
#include "candle_defs.h"
|
#include "candle_defs.h"
|
||||||
#include "candle_ctrl_req.h"
|
#include "candle_ctrl_req.h"
|
||||||
#include "ch_9.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);
|
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)
|
bool __stdcall DLL candle_dev_get_timestamp_us(candle_handle hdev, uint32_t *timestamp_us)
|
||||||
{
|
{
|
||||||
return candle_ctrl_get_timestamp(hdev, 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);
|
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.
|
/* Write len bytes from buf to the OUT pipe, aborting after 300 ms.
|
||||||
* Writes are serialised by writeMutex in CandleApiInterface so dev->txEvent
|
* Writes are serialised by writeMutex in CandleApiInterface so dev->txEvent
|
||||||
* is never accessed by two threads simultaneously. */
|
* 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;
|
dev->rxurbs[urb_num].pending = false;
|
||||||
|
|
||||||
/* Minimum: classic CAN header (12 bytes) + at least 8 data bytes = 20 bytes */
|
const DWORD header_size = 12; /* Заголовок gs_usb занимает 12 байт в Classic и FD; короткий FD может не содержать восьми байтов данных. */
|
||||||
static const DWORD classic_min = sizeof(candle_frame_t) - 4;
|
if (bytes_transfered < header_size) { /* До чтения flags и DLC проверяем наличие полного заголовка. */
|
||||||
if (bytes_transfered < classic_min) {
|
|
||||||
candle_prepare_read(dev, urb_num);
|
candle_prepare_read(dev, urb_num);
|
||||||
candle_logf(L"fd read too small urb=%u bytes=%lu min=%lu",
|
candle_logf(L"fd read too small urb=%u bytes=%lu min=%lu",
|
||||||
urb_num,
|
urb_num,
|
||||||
bytes_transfered,
|
bytes_transfered,
|
||||||
classic_min);
|
header_size); /* Минимальная длина здесь относится к заголовку, а payload проверяется после определения формата. */
|
||||||
dev->last_error = CANDLE_ERR_READ_SIZE;
|
dev->last_error = CANDLE_ERR_READ_SIZE;
|
||||||
return false;
|
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) {
|
if (is_fd_frame) {
|
||||||
/* can_dlc is at byte offset 8 in both classic and FD wire frames. */
|
/* 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];
|
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 data_len = candle_dlc_to_len(raw_dlc);
|
||||||
const DWORD min_size = 12 + data_len; /* header + data, without timestamp */
|
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: timestamp stays zero from memset above */
|
||||||
} else {
|
} 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 */
|
/* Classic CAN frame — copy into FD struct, fixing the timestamp position */
|
||||||
candle_frame_t classic;
|
candle_frame_t classic;
|
||||||
DWORD copy_len = (bytes_transfered < sizeof(classic)) ? bytes_transfered : sizeof(classic);
|
DWORD copy_len = (bytes_transfered < sizeof(classic)) ? bytes_transfered : sizeof(classic);
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
; прикладные регистры SETProtocol.
|
; прикладные регистры SETProtocol.
|
||||||
|
|
||||||
EXPORTS
|
EXPORTS
|
||||||
|
candle_dev_get_product ; Имя продукта из USB-дескриптора прошивки для списка адаптеров SETGUI.
|
||||||
|
candle_dev_enter_dfu ; Переход через отдельный DFU runtime-интерфейс того же физического USB-адаптера.
|
||||||
candle_list_scan
|
candle_list_scan
|
||||||
candle_list_free
|
candle_list_free
|
||||||
candle_list_length
|
candle_list_length
|
||||||
@@ -31,3 +33,13 @@ EXPORTS
|
|||||||
candle_frame_data
|
candle_frame_data
|
||||||
candle_frame_timestamp_us
|
candle_frame_timestamp_us
|
||||||
candle_dev_last_error
|
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.
|
||||||
|
|||||||
@@ -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(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);
|
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);
|
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);
|
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_get_timestamp_us(candle_handle hdev, uint32_t *timestamp_us);
|
||||||
bool __stdcall DLL candle_dev_close(candle_handle hdev);
|
bool __stdcall DLL candle_dev_close(candle_handle hdev);
|
||||||
bool __stdcall DLL candle_dev_free(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_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_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_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_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);
|
bool __stdcall DLL candle_frame_read(candle_handle hdev, candle_frame_t *frame, uint32_t timeout_ms);
|
||||||
|
|||||||
@@ -39,8 +39,10 @@ enum {
|
|||||||
CANDLE_TIMESTAMP_GET = 6,
|
CANDLE_TIMESTAMP_GET = 6,
|
||||||
/* 7: IDENTIFY, 8: GET_USER_ID, 9: SET_USER_ID (not used here) */
|
/* 7: IDENTIFY, 8: GET_USER_ID, 9: SET_USER_ID (not used here) */
|
||||||
CANDLE_BREQ_DATA_BITTIMING = 10,
|
CANDLE_BREQ_DATA_BITTIMING = 10,
|
||||||
/* 11: SET_TERMINATION, not used here */
|
CANDLE_BREQ_BT_CONST_EXT = 11, /* Расширенные пределы номинальной и быстрой фазы согласно gs_usb. */
|
||||||
CANDLE_BREQ_GET_STATE = 12,
|
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,
|
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;
|
dev->last_error = rc ? CANDLE_ERR_OK : CANDLE_ERR_SET_DEVICE_MODE;
|
||||||
return rc;
|
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-контроллера. */
|
||||||
|
} /* Завершение управления встроенным окончанием шины. */
|
||||||
|
|||||||
@@ -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_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_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_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 — включён. */
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import tempfile # Резервирует номер сборки через временный файл на том же диске, как общий итератор ветки 166.
|
||||||
|
|
||||||
|
|
||||||
def git_state(repository: Path) -> dict:
|
def git_state(repository: Path) -> dict:
|
||||||
@@ -36,20 +37,46 @@ def git_state(repository: Path) -> dict:
|
|||||||
def write_atomic(path: Path, text: str):
|
def write_atomic(path: Path, text: str):
|
||||||
path.parent.mkdir(parents=True, exist_ok=True)
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
temporary = path.with_name(path.name + ".tmp")
|
temporary = path.with_name(path.name + ".tmp")
|
||||||
temporary.write_text(text, encoding="utf-8", newline="\n")
|
with open(temporary, "w", encoding="utf-8", newline="\n") as stream: # Сохраняет UTF-8 и LF также на Python 3.8, где Path.write_text ещё не принимает newline.
|
||||||
|
stream.write(text) # Полностью записывает заголовок или паспорт перед атомарной заменой целевого файла.
|
||||||
temporary.replace(path)
|
temporary.replace(path)
|
||||||
|
|
||||||
|
|
||||||
def prepare(repository: Path, templates: Path, config: Path, output: Path) -> dict:
|
def next_version(version): # Повторяет общий итератор 166 и переносит переполнение младшего разряда в старший.
|
||||||
settings = json.loads(config.read_text(encoding="utf-8"))
|
result = list(version) # Не изменяет исходный номер до проверки полного переполнения.
|
||||||
version = settings["version"]
|
for index, limit in ((2, 999), (1, 255), (0, 255)): # Контракт firmware-info v1 допускает patch 0..999 и major/minor 0..255.
|
||||||
if (len(version) != 3 or any(type(v) is not int for v in version)
|
if result[index] < limit: # Выбирает младший разряд, который ещё допускает увеличение.
|
||||||
or not all(0 <= v <= limit for v, limit in zip(version, (255, 255, 999)))):
|
result[index] += 1 # Занимает следующий номер попытки сборки ровно один раз.
|
||||||
raise ValueError("version must be [major 0..255, minor 0..255, patch 0..999]")
|
return result # Возвращает новый номер с сохранёнными старшими и обнулёнными переполненными младшими разрядами.
|
||||||
|
result[index] = 0 # Переносит единицу к следующему разряду при достижении предела текущего.
|
||||||
|
raise ValueError("Firmware version exhausted at 255.255.999") # Не допускает повторного использования версии после полного переполнения контракта.
|
||||||
|
|
||||||
|
|
||||||
|
def prepare(repository: Path, templates: Path, config: Path, output: Path) -> dict: # Формирует один паспорт текущей попытки после сохранения номера автоматической сборки.
|
||||||
|
settings = json.loads(config.read_text(encoding="utf-8-sig")) # Принимает исходный JSON в UTF-8, включая старые файлы Windows с BOM.
|
||||||
|
version = settings["version"] # Начальный номер берётся из единственного сохраняемого источника проекта.
|
||||||
|
if not isinstance(version, list) or len(version) != 3 or any(type(value) is not int or not 0 <= value <= limit for value, limit in zip(version, (255, 255, 999))): # Проверяет три целых разряда и пределы протокола до изменения JSON.
|
||||||
|
raise ValueError("version must be [major 0..255, minor 0..255, patch 0..999]") # Останавливает prebuild при неверном формате счётчика.
|
||||||
|
if type(settings.get("increment_version", False)) is not bool: # Старые проекты сохраняют ручной режим; автоматический требует настоящего логического true.
|
||||||
|
raise ValueError("increment_version must be true or false") # Не принимает строки и числа вместо явной настройки счётчика.
|
||||||
for field in ("product", "target"):
|
for field in ("product", "target"):
|
||||||
if not isinstance(settings.get(field), str) or not settings[field].strip():
|
if not isinstance(settings.get(field), str) or not settings[field].strip():
|
||||||
raise ValueError(f"missing {field}")
|
raise ValueError(f"missing {field}")
|
||||||
source, dependency = git_state(repository), git_state(templates)
|
if settings.get("increment_version", False): # Увеличение выполняется только при подготовке основного проекта, а не при упаковке RAM, CAN и Flash.
|
||||||
|
version = settings["version"] = next_version(version) # Один вычисленный номер используется исходным JSON, генерируемым заголовком и паспортом.
|
||||||
|
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", newline="\n", dir=config.parent, prefix=".firmware-version-", delete=False) as stream: # Временный файл рядом с JSON позволяет атомарную замену счётчика на том же диске.
|
||||||
|
temporary = Path(stream.name) # Запоминает только собственный файл для очистки при отказе сохранения.
|
||||||
|
try: # Ошибка записи должна сохранить исходный JSON и удалить незавершённый временный файл.
|
||||||
|
stream.write(json.dumps(settings, ensure_ascii=False, indent=2) + "\n") # Сохраняет новый номер и все дополнительные настройки проекта в UTF-8.
|
||||||
|
except BaseException: # Освобождает собственный файл также при прерывании процесса записи.
|
||||||
|
stream.close() # Windows разрешает удалить временный файл после закрытия его дескриптора.
|
||||||
|
temporary.unlink() # Удаляет только незавершённый файл этой попытки резервирования номера.
|
||||||
|
raise # Возвращает исходную ошибку вместо продолжения сборки с несохранённой версией.
|
||||||
|
try: # Номер должен быть надёжно занят до генерации выходов и начала компиляции.
|
||||||
|
temporary.replace(config) # Атомарно фиксирует счётчик, чтобы следующая попытка не повторила номер при последующей ошибке сборки.
|
||||||
|
finally: # При неудачной замене исходный JSON остаётся прежним, а собственный временный файл очищается.
|
||||||
|
temporary.unlink(missing_ok=True) # После успешного переименования файла уже нет; Python 3.8 поддерживает missing_ok.
|
||||||
|
source, dependency = git_state(repository), git_state(templates) # Отмечает изменённый счётчик в происхождении текущего выпуска после резервирования номера.
|
||||||
# A clean application built with a modified templates checkout is dirty too.
|
# A clean application built with a modified templates checkout is dirty too.
|
||||||
known = source["commit"] is not None and dependency["commit"] is not None
|
known = source["commit"] is not None and dependency["commit"] is not None
|
||||||
dirty = bool(source["dirty"] or dependency["dirty"])
|
dirty = bool(source["dirty"] or dependency["dirty"])
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# Результаты отдельных конфигураций CCS воспроизводятся установленным TI compiler.
|
||||||
|
/projects/ccs/*/Debug/
|
||||||
|
/projects/ccs/*/Release/
|
||||||
|
# Служебные локальные настройки IDE и launch не входят в переносимый проект.
|
||||||
|
/projects/ccs/*/.settings/
|
||||||
|
/projects/ccs/*/.launches/
|
||||||
|
# Python cache не является исходником общего модуля или проекта.
|
||||||
|
**/__pycache__/
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Сборка библиотеки protocan_boot. Состав исходников и публичные include-пути задают
|
# Общая C99-библиотека ProtoCAN Boot и аппаратно независимые host-тесты.
|
||||||
# подключение к проекту потребителя. Файл также собирает и регистрирует хостовые проверки;
|
# Каждый контроллер сохраняет собственное состояние и отдельный аппаратный порт.
|
||||||
# запускать их следует через CTest из каталога сборки.
|
# Дополнительные проекты CCS находятся в projects/ccs и не требуют CMake для TI-сборки.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
project(protocan_boot C)
|
project(protocan_boot C)
|
||||||
@@ -17,10 +17,40 @@ else()
|
|||||||
target_compile_options(protocan_boot PRIVATE -Wall -Wextra -Wpedantic)
|
target_compile_options(protocan_boot PRIVATE -Wall -Wextra -Wpedantic)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(PCAN_BOOT_BUILD_TESTS "Собирать тесты ProtoCAN boot" ON)
|
option(PCAN_BOOT_BUILD_TESTS "Собирать тесты ProtoCAN Boot" ON) # Не включает host-модели в код MCU.
|
||||||
if(PCAN_BOOT_BUILD_TESTS)
|
if(PCAN_BOOT_BUILD_TESTS)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_executable(test_pcan_boot tests/test_pcan_boot.c)
|
add_executable(test_pcan_boot tests/test_pcan_boot.c)
|
||||||
target_link_libraries(test_pcan_boot PRIVATE protocan_boot)
|
target_link_libraries(test_pcan_boot PRIVATE protocan_boot)
|
||||||
add_test(NAME pcan_boot COMMAND test_pcan_boot)
|
add_test(NAME pcan_boot COMMAND test_pcan_boot)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(PCAN_BOOT_BUILD_TESTS)
|
||||||
|
add_executable(test_f28335_can_boot tests/test_f28335_can_boot.c src/pcan_boot.c ports/tms320f28335/f28335_boot_store.c)
|
||||||
|
target_compile_definitions(test_f28335_can_boot PRIVATE PCAN_BOOT_WIDE_BYTES)
|
||||||
|
target_include_directories(test_f28335_can_boot PRIVATE tests/f28335_stubs)
|
||||||
|
add_test(NAME f28335_can_boot COMMAND test_f28335_can_boot)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(PCAN_BOOT_BUILD_TESTS)
|
||||||
|
add_executable(test_f28335_application tests/test_f28335_can_boot.c src/pcan_boot.c ports/tms320f28335/f28335_boot_store.c)
|
||||||
|
target_compile_definitions(test_f28335_application PRIVATE PCAN_BOOT_WIDE_BYTES F28335_BOOT_LOADER=0)
|
||||||
|
target_include_directories(test_f28335_application PRIVATE tests/f28335_stubs)
|
||||||
|
add_test(NAME f28335_application COMMAND test_f28335_application)
|
||||||
|
foreach(width native wide)
|
||||||
|
add_executable(test_f28335_store_${width} tests/test_f28335_boot_store.c ports/tms320f28335/f28335_boot_store.c)
|
||||||
|
if(width STREQUAL "wide")
|
||||||
|
target_compile_definitions(test_f28335_store_${width} PRIVATE PCAN_BOOT_WIDE_BYTES)
|
||||||
|
endif()
|
||||||
|
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-модель в прошивку.
|
||||||
|
|||||||
@@ -97,7 +97,8 @@ typedef struct {
|
|||||||
} pcan_boot_port_t;
|
} pcan_boot_port_t;
|
||||||
```
|
```
|
||||||
|
|
||||||
Обязательны `send`, `erase_slot`, `write_slot` и `set_pending_slot`.
|
Обязательны `send`, `erase_slot`, `write_slot`; в A/B также `set_pending_slot`.
|
||||||
|
В single-slot этот callback необязателен и может завершать активацию образа.
|
||||||
`authorize` проверяет политику до стирания (тип, версия, anti-rollback).
|
`authorize` проверяет политику до стирания (тип, версия, anti-rollback).
|
||||||
`verify_image` выполняет платформенную проверку подписанного контейнера после
|
`verify_image` выполняет платформенную проверку подписанного контейнера после
|
||||||
CRC32. Если callbacks отсутствуют, соответствующие дополнительные проверки
|
CRC32. Если callbacks отсутствуют, соответствующие дополнительные проверки
|
||||||
@@ -175,5 +176,18 @@ ctest --test-dir build --output-on-failure
|
|||||||
- включить watchdog и rollback при неподтверждённом запуске;
|
- включить watchdog и rollback при неподтверждённом запуске;
|
||||||
- согласовать фильтры CAN для `MsgType=0x9..0xD`.
|
- согласовать фильтры CAN для `MsgType=0x9..0xD`.
|
||||||
|
|
||||||
Проект пока не подключён ни к одной конкретной плате; это самостоятельный
|
Ядро поддерживает платформенные порты; особенности интеграции перечислены ниже.
|
||||||
шаблон для интеграции в будущие загрузчики приборов SET.
|
|
||||||
|
## F28335 / большая EEPROM
|
||||||
|
|
||||||
|
[Порт 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).
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ BlockIndex = 0x0000…0xFFFF
|
|||||||
| `0x09` | `REBOOT` | 0 | отсутствует | активная сессия |
|
| `0x09` | `REBOOT` | 0 | отсутствует | активная сессия |
|
||||||
| `0x0A` | `ABORT` | 0 | отсутствует | активная сессия |
|
| `0x0A` | `ABORT` | 0 | отсутствует | активная сессия |
|
||||||
| `0x0B` | `QUERY_PROGRESS` | 0 | отсутствует | активная сессия |
|
| `0x0B` | `QUERY_PROGRESS` | 0 | отсутствует | активная сессия |
|
||||||
|
| `0x0C` | `PING` | 0 | отсутствует | любое |
|
||||||
|
| `0x0D` | `CAPABILITIES` | 0 | отсутствует | любое, при поддержке порта |
|
||||||
|
| `0x0E` | `DEVICE_NAME` | 1 | номер страницы имени | любое, при поддержке порта |
|
||||||
|
| `0x0F` | `MEMORY_INFO` | 1 | номер страницы памяти | любое, при поддержке порта |
|
||||||
|
|
||||||
### `BEGIN_IMAGE`
|
### `BEGIN_IMAGE`
|
||||||
|
|
||||||
@@ -81,7 +85,8 @@ DATA[4..7] FirmwareVersion, uint32 little-endian
|
|||||||
```
|
```
|
||||||
|
|
||||||
До `ERASE` прибор обязан получить обе части метаданных и проверить размер,
|
До `ERASE` прибор обязан получить обе части метаданных и проверить размер,
|
||||||
тип изделия, аппаратную ревизию, версию и политику anti-rollback.
|
тип изделия и аппаратную ревизию. Проверка версии/anti-rollback выполняется
|
||||||
|
только при наличии соответствующей политики платформы (callback authorize).
|
||||||
|
|
||||||
## `BOOT_STATUS`
|
## `BOOT_STATUS`
|
||||||
|
|
||||||
@@ -181,3 +186,16 @@ Boot metadata должна атомарно хранить:
|
|||||||
5. ПМ выполняет `ERASE` и передаёт `BOOT_DATA_A` либо `BOOT_DATA_B`.
|
5. ПМ выполняет `ERASE` и передаёт `BOOT_DATA_A` либо `BOOT_DATA_B`.
|
||||||
6. ПМ выполняет `VERIFY`, затем `COMMIT` и `REBOOT`.
|
6. ПМ выполняет `VERIFY`, затем `COMMIT` и `REBOOT`.
|
||||||
7. Новое приложение после самопроверки выполняет `CONFIRM`.
|
7. Новое приложение после самопроверки выполняет `CONFIRM`.
|
||||||
|
|
||||||
|
## F28335 M95M02
|
||||||
|
|
||||||
|
Реализованы отдельный Flash-загрузчик, A/B по 130560 байт, журнал, пробный запуск
|
||||||
|
и откат. Подробная раскладка памяти, сервисных ответов и первичная установка:
|
||||||
|
[README порта](../ports/tms320f28335/README.md).
|
||||||
|
|
||||||
|
Общий discovery: Route=0, DeviceType=7, DeviceID=15, MsgType=D, Body=0, DLC=0.
|
||||||
|
Он только запрашивает IDENTIFY; операции изменения всегда адресные.
|
||||||
|
ENTER_BOOT может отложить ACK до готовности отдельного загрузчика после reset.
|
||||||
|
CONFIRM с ненулевой session может обрабатываться приложением без ENTER_BOOT.
|
||||||
|
`pcan_boot_poll` обслуживает задержку discovery и тайм-аут сессии, если он задан
|
||||||
|
портом. Старым портам с timeout=0 периодический вызов нужен только для discovery.
|
||||||
|
|||||||
@@ -11,6 +11,13 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* C28x has 16-bit addressable chars; wire octets use the low eight bits. */
|
||||||
|
#if defined(__TMS320C28XX__) || defined(PCAN_BOOT_WIDE_BYTES)
|
||||||
|
typedef unsigned int pcan_boot_byte_t;
|
||||||
|
#else
|
||||||
|
typedef uint8_t pcan_boot_byte_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -41,7 +48,12 @@ typedef enum {
|
|||||||
PCAN_BOOT_CMD_CONFIRM = 0x08U,
|
PCAN_BOOT_CMD_CONFIRM = 0x08U,
|
||||||
PCAN_BOOT_CMD_REBOOT = 0x09U,
|
PCAN_BOOT_CMD_REBOOT = 0x09U,
|
||||||
PCAN_BOOT_CMD_ABORT = 0x0AU,
|
PCAN_BOOT_CMD_ABORT = 0x0AU,
|
||||||
PCAN_BOOT_CMD_QUERY_PROGRESS = 0x0BU
|
PCAN_BOOT_CMD_QUERY_PROGRESS = 0x0BU,
|
||||||
|
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_SELECT_MEMORY = 0x10U /* Выбирает 0=штатное хранилище, 1=внутренняя Flash до передачи метаданных. */
|
||||||
} pcan_boot_command_t;
|
} pcan_boot_command_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -66,7 +78,8 @@ typedef enum {
|
|||||||
PCAN_BOOT_STATE_READY_TO_ERASE,
|
PCAN_BOOT_STATE_READY_TO_ERASE,
|
||||||
PCAN_BOOT_STATE_RECEIVING,
|
PCAN_BOOT_STATE_RECEIVING,
|
||||||
PCAN_BOOT_STATE_VERIFIED,
|
PCAN_BOOT_STATE_VERIFIED,
|
||||||
PCAN_BOOT_STATE_FAILED
|
PCAN_BOOT_STATE_FAILED,
|
||||||
|
PCAN_BOOT_STATE_COMMITTED
|
||||||
} pcan_boot_state_t;
|
} pcan_boot_state_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -74,36 +87,48 @@ typedef struct {
|
|||||||
uint32_t image_crc32;
|
uint32_t image_crc32;
|
||||||
uint32_t firmware_version;
|
uint32_t firmware_version;
|
||||||
uint16_t product_type;
|
uint16_t product_type;
|
||||||
uint8_t hardware_revision_min;
|
pcan_boot_byte_t hardware_revision_min;
|
||||||
uint8_t hardware_revision_max;
|
pcan_boot_byte_t hardware_revision_max;
|
||||||
} pcan_boot_manifest_t;
|
} pcan_boot_manifest_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t device_type;
|
pcan_boot_byte_t device_type;
|
||||||
uint8_t device_id;
|
pcan_boot_byte_t device_id;
|
||||||
uint16_t product_type;
|
uint16_t product_type;
|
||||||
uint8_t hardware_revision;
|
pcan_boot_byte_t hardware_revision;
|
||||||
uint32_t firmware_version;
|
uint32_t firmware_version;
|
||||||
uint8_t active_slot;
|
pcan_boot_byte_t active_slot;
|
||||||
/** 1 for an in-place/single-slot target, 2 for A/B. Zero keeps legacy A/B. */
|
/** 1 for an in-place/single-slot target, 2 for A/B. Zero keeps legacy A/B. */
|
||||||
uint8_t slot_count;
|
pcan_boot_byte_t slot_count;
|
||||||
/** Writable image capacity. Zero uses PCAN_BOOT_SLOT_SIZE. */
|
/** Writable image capacity. Zero uses PCAN_BOOT_SLOT_SIZE. */
|
||||||
uint32_t max_image_size;
|
uint32_t max_image_size;
|
||||||
uint8_t ack_window; /**< 1 — ACK каждого блока, 16 — ACK каждых 16 блоков. */
|
pcan_boot_byte_t ack_window; /**< 1 — ACK каждого блока, 16 — ACK каждых 16 блоков. */
|
||||||
|
uint32_t session_timeout_ms; /**< 0 disables timeout for legacy ports. */
|
||||||
} pcan_boot_config_t;
|
} pcan_boot_config_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool (*send)(void *user, uint32_t can_id, const uint8_t *data, uint8_t dlc);
|
bool (*send)(void *user, uint32_t can_id, const pcan_boot_byte_t *data, pcan_boot_byte_t dlc);
|
||||||
bool (*erase_slot)(void *user, uint8_t slot);
|
bool (*erase_slot)(void *user, pcan_boot_byte_t slot);
|
||||||
bool (*write_slot)(void *user, uint8_t slot, uint32_t offset,
|
bool (*write_slot)(void *user, pcan_boot_byte_t slot, uint32_t offset,
|
||||||
const uint8_t *data, uint8_t length);
|
const pcan_boot_byte_t *data, pcan_boot_byte_t length);
|
||||||
bool (*authorize)(void *user, const pcan_boot_manifest_t *manifest);
|
bool (*authorize)(void *user, const pcan_boot_manifest_t *manifest);
|
||||||
bool (*verify_image)(void *user, uint8_t slot,
|
bool (*verify_image)(void *user, pcan_boot_byte_t slot,
|
||||||
const pcan_boot_manifest_t *manifest);
|
const pcan_boot_manifest_t *manifest);
|
||||||
bool (*set_pending_slot)(void *user, uint8_t slot,
|
/** A/B metadata, or optional single-slot activation after verification. */
|
||||||
|
bool (*set_pending_slot)(void *user, pcan_boot_byte_t slot,
|
||||||
const pcan_boot_manifest_t *manifest);
|
const pcan_boot_manifest_t *manifest);
|
||||||
bool (*confirm_running_slot)(void *user);
|
bool (*confirm_running_slot)(void *user);
|
||||||
void (*reboot)(void *user);
|
void (*reboot)(void *user);
|
||||||
|
/** ENTER: 0 ready, 1 deferred ACK after reset, 2 denied. NULL = legacy ready. */
|
||||||
|
unsigned int (*enter_boot)(void *user, pcan_boot_byte_t session);
|
||||||
|
bool (*can_reboot)(void *user);
|
||||||
|
/** Eight-octet service response, addressed by command + page. */
|
||||||
|
bool (*service_info)(void *user, pcan_boot_byte_t command,
|
||||||
|
pcan_boot_byte_t page, pcan_boot_byte_t *out);
|
||||||
|
/** 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;
|
} pcan_boot_port_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -115,11 +140,13 @@ typedef struct {
|
|||||||
uint32_t running_crc32;
|
uint32_t running_crc32;
|
||||||
uint32_t bytes_received;
|
uint32_t bytes_received;
|
||||||
uint16_t next_block;
|
uint16_t next_block;
|
||||||
uint8_t session_id;
|
pcan_boot_byte_t session_id;
|
||||||
uint8_t target_slot;
|
pcan_boot_byte_t target_slot;
|
||||||
uint8_t last_status;
|
pcan_boot_byte_t last_status;
|
||||||
bool have_image;
|
bool have_image;
|
||||||
bool have_compat;
|
bool have_compat;
|
||||||
|
uint32_t now_ms, last_activity_ms, discovery_at;
|
||||||
|
bool discovery_pending;
|
||||||
} pcan_boot_t;
|
} pcan_boot_t;
|
||||||
|
|
||||||
/** Инициализирует экземпляр. Все обязательные callbacks должны быть заданы. */
|
/** Инициализирует экземпляр. Все обязательные callbacks должны быть заданы. */
|
||||||
@@ -134,16 +161,22 @@ void pcan_boot_abort(pcan_boot_t *boot);
|
|||||||
* Возвращает true, если кадр принадлежал загрузочному сервису этого прибора.
|
* Возвращает true, если кадр принадлежал загрузочному сервису этого прибора.
|
||||||
*/
|
*/
|
||||||
bool pcan_boot_process(pcan_boot_t *boot, uint32_t can_id,
|
bool pcan_boot_process(pcan_boot_t *boot, uint32_t can_id,
|
||||||
const uint8_t *data, uint8_t dlc);
|
const pcan_boot_byte_t *data, pcan_boot_byte_t dlc);
|
||||||
|
|
||||||
|
/** 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. */
|
/** Переносимые операции с 29-битным ProtoCAN ID. */
|
||||||
uint32_t pcan_boot_make_id(uint8_t priority, uint8_t route,
|
uint32_t pcan_boot_make_id(pcan_boot_byte_t priority, pcan_boot_byte_t route,
|
||||||
uint8_t device_type, uint8_t device_id,
|
pcan_boot_byte_t device_type, pcan_boot_byte_t device_id,
|
||||||
uint8_t msg_type, uint16_t msg_body);
|
pcan_boot_byte_t msg_type, uint16_t msg_body);
|
||||||
uint8_t pcan_boot_id_route(uint32_t can_id);
|
pcan_boot_byte_t pcan_boot_id_route(uint32_t can_id);
|
||||||
uint8_t pcan_boot_id_device_type(uint32_t can_id);
|
pcan_boot_byte_t pcan_boot_id_device_type(uint32_t can_id);
|
||||||
uint8_t pcan_boot_id_device_id(uint32_t can_id);
|
pcan_boot_byte_t pcan_boot_id_device_id(uint32_t can_id);
|
||||||
uint8_t pcan_boot_id_msg_type(uint32_t can_id);
|
pcan_boot_byte_t pcan_boot_id_msg_type(uint32_t can_id);
|
||||||
uint16_t pcan_boot_id_msg_body(uint32_t can_id);
|
uint16_t pcan_boot_id_msg_body(uint32_t can_id);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -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. */
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
# F28335 + M95M02: CAN, отдельный загрузчик и A/B
|
||||||
|
|
||||||
|
Реализация состоит из Flash-загрузчика `projects/ccs/f28335`, переносимого
|
||||||
|
`f28335_boot_store.c`, аппаратного `f28335_boot_hw.c` и адаптера
|
||||||
|
`f28335_can_boot.c`. Приложение подключает общий `f28335_can_application.c`
|
||||||
|
прямой ссылкой linked resource из templates в CCS Debug/Release.
|
||||||
|
В сборке `EEPROM_M95M02=0` CAN Boot отключён. Для установленной M95M02 — значение 1.
|
||||||
|
|
||||||
|
## Адрес и формат
|
||||||
|
|
||||||
|
Адрес определяется физическим номером **PERIPH 0–31** по новой Excel-таблице:
|
||||||
|
Type = 1 + PERIPH / 16 (целая часть), Device ID = PERIPH mod 16.
|
||||||
|
**УМП1 — 1/5, УМП2 — 1/6, задатчик — 1/8**. Product **0x2833**, HW **1**
|
||||||
|
описывают существующую аппаратную совместимость F28335 и не являются CAN-адресом.
|
||||||
|
Имена паспорта для назначенных плат — `UMP1`, `UMP2`, `Zadatchik`.
|
||||||
|
Приложение передаёт Mode в `F28335CanBoot_Init(Mode)`. Загрузчик независимо
|
||||||
|
читает те же активные низким уровнем GPIO21/20/22/51 с весами 1/2/4/8 и базой 1.
|
||||||
|
Поэтому существующие перемычки ПМ35 задают номера 1–16; номера 0 и 17–31
|
||||||
|
поддерживаются адресным контрактом, но требуют другого источника физического номера.
|
||||||
|
Общий адрес 3/7 больше не принимается. Чужие адреса отбрасываются аппаратным
|
||||||
|
mailbox, ISR и ядром до записи EEPROM, включая данные A/B и управляющие команды.
|
||||||
|
В приложении FW берётся из `firmware_version.h`, формат `major<<24 | minor<<16 | patch`;
|
||||||
|
для версии 1.1.2 это `0x01010002`. Загрузчик сообщает версию подтверждённого образа
|
||||||
|
из журнала, при отсутствии такого образа — 0. Версия кандидата передаётся в BEGIN_COMPAT.
|
||||||
|
CAN **250000 бит/с**, Extended ID, окно **16 блоков по 8 октетов**.
|
||||||
|
Для задатчика и session=1: ENTER_BOOT `0x11890102`, STATUS `0x198C0102`.
|
||||||
|
|
||||||
|
## Общий запуск Flash и резервной EEPROM
|
||||||
|
|
||||||
|
Сектор A и аппаратный boot `0x33FFF6` принадлежат постоянному загрузчику.
|
||||||
|
Flash-приложение использует `[0x300000,0x338000)`: первые 16 слов — описание
|
||||||
|
FAB1, остальные — собственные LOAD-секции. `f28335_flash_app.c` проверяет
|
||||||
|
magic/version, entry, границы, инверсию entry, маркеры и CRC32 IEEE всего
|
||||||
|
диапазона после заголовка, включая промежутки, заполненные `0xFFFF`.
|
||||||
|
Python-контракт `python/protocan/f28335_flash.py` заполняет зарезервированные
|
||||||
|
32 октета COFF по смещению, подтверждённому TI OFD, после линковки.
|
||||||
|
|
||||||
|
Загрузчик даёт трёхсекундное окно CAN, затем запускает исправную внутреннюю
|
||||||
|
Flash в приоритете. Отсутствующая/повреждённая Flash ведёт к прежнему выбору
|
||||||
|
EEPROM A/B с trial/CONFIRM/rollback. ENTER_BOOT удерживает CAN recovery.
|
||||||
|
Handoff running=`0xFE` обозначает проверенную внутреннюю Flash; 0/1 — EEPROM
|
||||||
|
A/B, `0xFF` — отсутствие запущенного приложения. Flash-приложение обслуживает
|
||||||
|
PING и ENTER_BOOT, но не подменяет подтверждение EEPROM-кандидата.
|
||||||
|
Обновление EEPROM по CAN не меняет приоритет исправной Flash после reset.
|
||||||
|
|
||||||
|
RS Flash должен стирать только B–H, публиковать FAB1 после проверки остальных
|
||||||
|
данных и запрещать любые адреса сектора A. В SETGUI соответствующие JTAG
|
||||||
|
маски задаются явными TI `FlashSectorA..H`: A для установки boot, B–H для
|
||||||
|
приложения. Полное стирание чипа внешним программатором не ограничивается linker.
|
||||||
|
Старая самостоятельная Flash-сборка с codestart `0x33FFF6` несовместима с этим
|
||||||
|
размещением и не должна передаваться как обновление приложения.
|
||||||
|
|
||||||
|
|
||||||
|
Образ — SCI8 BIN (`AA 08`), чётная длина от 24 до **130560 байт** включительно.
|
||||||
|
Числа в протоколе little endian. Адреса внутри SCI8: сначала старшее 16-битное
|
||||||
|
слово, затем младшее; каждое слово little endian. В C28x `char` 16-битный,
|
||||||
|
поэтому `pcan_boot_byte_t` хранит октет в младших 8 битах.
|
||||||
|
|
||||||
|
## Разметка EEPROM, байтовые адреса
|
||||||
|
|
||||||
|
| Область | Начало | Конец включительно | Размер |
|
||||||
|
|---|---:|---:|---:|
|
||||||
|
| Журнал 0 | 0x00000 | 0x000FF | 256 |
|
||||||
|
| Журнал 1 | 0x00100 | 0x001FF | 256 |
|
||||||
|
| Slot A | 0x00200 | 0x1FFFF | 130560 |
|
||||||
|
| Slot B | 0x20000 | 0x3FDFF | 130560 |
|
||||||
|
| Резерв | 0x3FE00 | 0x3FEFB | 252 |
|
||||||
|
| Параметры | 0x3FEFC | 0x3FFFD | 258 |
|
||||||
|
| Последнее слово | 0x3FFFE | 0x3FFFF | 2 |
|
||||||
|
|
||||||
|
В каждой странице журнала первые 64 октета содержат magic `FAB2`, версию 1,
|
||||||
|
sequence, active/pending/attempted, два manifest, CRC32 первых 56 октетов и
|
||||||
|
commit marker в октетах 60..63. Сначала обнуляется marker запасной страницы,
|
||||||
|
затем записывается тело с проверкой чтением, последним — marker. Предыдущая
|
||||||
|
страница остаётся действующей до полной публикации новой. Выбор sequence
|
||||||
|
учитывает переполнение u32. После ошибки публикации журнал перечитывается;
|
||||||
|
ошибка чтения блокирует последующие записи.
|
||||||
|
|
||||||
|
## Сценарий обновления и отката
|
||||||
|
|
||||||
|
1. Приложение принимает ENTER_BOOT, останавливает управление нагрузкой, выставляет 4 мА и выдерживает
|
||||||
|
секундный STOP, затем сохраняет session в NOINIT RAM 0x50..0x57. Watchdog выполняет reset.
|
||||||
|
ACK ENTER_BOOT отправляет уже Flash-загрузчик; приложение ничего не стирает.
|
||||||
|
2. BEGIN_IMAGE/BEGIN_COMPAT проверяют размер, Product, HW и сессию. Неактивный
|
||||||
|
слот выбирается автоматически; при первом образе это A. ERASE инвалидирует
|
||||||
|
только его manifest. Полного стирания EEPROM не требуется.
|
||||||
|
3. Последовательные DATA_A/B записываются с немедленным readback. VERIFY
|
||||||
|
проверяет потоковый CRC32, CRC32 EEPROM и полную таблицу SCI8.
|
||||||
|
Разрешена загрузка только в CPU word RAM `[0x8000,0xE000)`: максимум 64 секции,
|
||||||
|
без пересечений, усечений и хвостовых данных; entry должен попасть в секцию.
|
||||||
|
Запись в Flash, периферию, стек, RAM загрузчика и handoff запрещена.
|
||||||
|
4. COMMIT повторно проверяет образ и публикует pending в журнале. Подтверждённый
|
||||||
|
слот сохраняется. Повтор COMMIT безопасен. REBOOT выполняется после физического
|
||||||
|
CAN ACK ответа. Потеря ACK/тайм-аут передачи отменяет запрос reset.
|
||||||
|
5. Перед первым запуском кандидата загрузчик сохраняет attempted=1, затем
|
||||||
|
проверяет и копирует SCI8 в RAM. Следующий reset без CONFIRM сбрасывает pending
|
||||||
|
и запускает прежний active. Если прежнего образа нет — остаётся CAN recovery.
|
||||||
|
6. Новое приложение включает watchdog в начале запуска. До подтверждения
|
||||||
|
прерывания не кормят watchdog вместо основного цикла. После READY, 100 проходов
|
||||||
|
main и 5 секунд выполняется автоматический CONFIRM. Неудача сохранения
|
||||||
|
подтверждения через 10 секунд прекращает кормление watchdog, вызывая откат.
|
||||||
|
Адресная команда CONFIRM с ненулевой session также разрешена после READY.
|
||||||
|
CONFIRM в загрузчике и до первого запуска кандидата отклоняется.
|
||||||
|
|
||||||
|
PING, IDENTIFY и паспорт доступны без ENTER_BOOT. QUERY_PROGRESS/ABORT привязаны
|
||||||
|
к сессии. Сессия в RAM истекает через 30 секунд без подходящих команд/данных.
|
||||||
|
После reset передачу начинают заново; параметры и подтверждённый образ остаются.
|
||||||
|
ABORT после COMMIT не отменяет опубликованный pending. Для его пробного запуска
|
||||||
|
можно открыть новую сессию и отправить REBOOT. Pending запрещено перезаписывать.
|
||||||
|
Повторы ENTER_BOOT, метаданных, ERASE до первого блока, VERIFY и COMMIT учитывают
|
||||||
|
потерю ответа. Broadcast никогда не разрешает запись.
|
||||||
|
|
||||||
|
## Сервисные команды
|
||||||
|
|
||||||
|
Запрос: MsgType=9, Body=`session<<8 | command`. IDENTIFY/PING/паспорт не требуют сессии.
|
||||||
|
Ответ паспорта: MsgType=D, Body=`page<<8 | command`, DLC=8.
|
||||||
|
|
||||||
|
| Код | Имя | DLC запроса | Ответ |
|
||||||
|
|---:|---|---:|---|
|
||||||
|
| 01 | IDENTIFY | 0 | Product:u16, HW:u8, protocol:u8, FW:u32; Body=1 |
|
||||||
|
| 0C | PING | 0 | protocol, state, active, target, session, slot_count, last_status, 0 |
|
||||||
|
| 0D | CAPABILITIES | 0 | flags:u32, slot_capacity:u32 |
|
||||||
|
| 0E | DEVICE_NAME | 1 (page) | 8 ASCII-октетов имени; последний фрагмент с NUL |
|
||||||
|
| 0F | MEMORY_INFO | 1 (page) | Страницы ниже |
|
||||||
|
|
||||||
|
MEMORY_INFO 0: EEPROM bytes:u32, page bytes:u16, mode:u8 (0 app/1 boot), running:u8.
|
||||||
|
Страница 1: адреса A:u32, B:u32. Страница 2: active, pending, attempted, storage_healthy,
|
||||||
|
session_timeout_ms:u32. Страница 3: parameters_offset:u32, parameters_bytes:u32.
|
||||||
|
Слот FF означает отсутствие образа/запущенного приложения.
|
||||||
|
CAPABILITIES bits 0..11: ping, discovery, identify, name, memory, A/B, confirm,
|
||||||
|
rollback, separate loader, session timeout, readback, SCI8 validation.
|
||||||
|
Приложение, запущенное старым SPI ROM без handoff загрузчика, сообщает только
|
||||||
|
базовые сервисы (0x1F) и отклоняет ENTER_BOOT.
|
||||||
|
|
||||||
|
Обнаружение: MsgType=D, Body=0, DLC=0, Route=0. Адресный запрос или общий
|
||||||
|
DeviceType=7/DeviceID=15. Ответ IDENTIFY приходит с адреса прибора через
|
||||||
|
`2*(1+16*DeviceType+DeviceID)` мс. При нескольких одинаковых адресах конфликт
|
||||||
|
остаётся: каждому физическому устройству нужен уникальный адрес.
|
||||||
|
Python API: `protocan.can_boot.CanBootServices` — запросы и разбор паспорта;
|
||||||
|
`CanBootTransfer` — загрузка. Кнопка «Пинг» доступна в режиме ProtoCAN Boot
|
||||||
|
окна прошивки SETGUI. Для ENTER/VERIFY/COMMIT клиент ждёт до 15 секунд.
|
||||||
|
|
||||||
|
## Аппаратная интеграция
|
||||||
|
|
||||||
|
MBOX3 — адресные входящие Boot; MBOX4 — ответы; MBOX6 — точный broadcast discovery.
|
||||||
|
MBOX0..2 сохраняют legacy/UMP, MBOX5 загрузчик не использует. ISR помещает сообщения
|
||||||
|
в очередь на 31 кадр. Чужие адреса, RTR и неподходящие типы отбрасываются до очереди.
|
||||||
|
При переполнении/потере mailbox сессия отменяется; повторная запись начинается заново.
|
||||||
|
SPI-драйвер загрузчика имеет ограничение ожидания байта и WIP, 24-битный адрес,
|
||||||
|
разбиение по страницам 256 байт и восстановление конфигурации SPI приложения.
|
||||||
|
Он работает только при остановленном Timer2. Обычный Seeprom_write приложения
|
||||||
|
ограничен областью параметров; старый RS EXTEND 0x44 запрещён для A/B.
|
||||||
|
|
||||||
|
Загрузчик исполняется из внутренней Flash A 0x338000..0x33FF7F, entry 0x33FFF6.
|
||||||
|
Его RAM — 0xE000..0xFFFF; стек — 0x400..0x7FF. Приложение M95M02 использует
|
||||||
|
0x8000..0xD7FF для кода, 0xD800..0xDFFF для констант/инициализации,
|
||||||
|
0xE000..0xFFFF для .ebss после перехода в C runtime. Linker резервирует
|
||||||
|
NOINIT handoff в обоих проектах. 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.
|
||||||
|
|
||||||
|
## Первичная установка
|
||||||
|
|
||||||
|
1. Собрать приложение с EEPROM_M95M02=1 и обновлённым F28335.cmd; получить SCI8 BIN.
|
||||||
|
Старые BIN/OUT автоматически не заменены. Приложение должно содержать интеграцию
|
||||||
|
READY/CONFIRM, иначе на следующем reset оно останется неподтверждённым кандидатом.
|
||||||
|
2. Собрать отдельный загрузчик TI C2000 COFF compiler:
|
||||||
|
`python c/protocan-boot/projects/build.py --device f28335 --compiler <путь-к-ti-cgt-c2000>`.
|
||||||
|
Результат — `projects/ccs/f28335/Debug/F28335_CAN_AB.out` и MAP.
|
||||||
|
3. Установить обновлённый OUT через JTAG и выбрать аппаратный Flash boot
|
||||||
|
согласно схеме платы. При переходе с общего адреса 3/7 обновить и приложение,
|
||||||
|
и загрузчик: старый загрузчик не перейдёт на новый адрес после reset сам.
|
||||||
|
В SETCAN выбрать «Прошивка → CAN / ProtoCAN Boot → Устройство PERIPH»
|
||||||
|
и нужное назначение. Не загружать поверх загрузчика старый application OUT с
|
||||||
|
секцией codestart во Flash.
|
||||||
|
4. После reset пустая EEPROM или старая разметка автоматически ведут в CAN recovery.
|
||||||
|
Передать новое приложение через ProtoCAN Boot, дождаться пробного запуска и
|
||||||
|
проверить MEMORY_INFO page 2: pending=FF, active=A. Затем проверить обновление в B.
|
||||||
|
|
||||||
|
Старая SPI-ROM разметка с AA08 по адресу 0 несовместима с новым журналом.
|
||||||
|
Первое обновление заменяет её; параметры по прежнему адресу сохраняются.
|
||||||
|
Загрузчик не выполняет скрытую миграцию и не меняет boot pins программно.
|
||||||
|
|
||||||
|
## Проверки и границы проверенного
|
||||||
|
|
||||||
|
`python c/protocan-boot/tests/run_tests.py` (переменная CC — clang/gcc) проверяет
|
||||||
|
ядро, приложение/загрузчик, wide-octet режим, журнал, обрыв публикации на каждом
|
||||||
|
из 69 возможных положений, пробный запуск, CONFIRM, откат, SCI8 и границы памяти.
|
||||||
|
Python-тесты проверяют клиентские запросы, паспорт, фильтрацию ответов и лимит A/B.
|
||||||
|
Проверка синтаксиса использует настоящие DSP2833x headers. Импорт и сборка TI/CCS,
|
||||||
|
раскладка MAP и реальные COFF LOAD-адреса проверены; физические CAN/SPI/reset
|
||||||
|
на плате требуют стендовой проверки. Отдельные проекты и команды сборки описаны
|
||||||
|
в [инструкции CCS](../../projects/README.md).
|
||||||
|
|
||||||
|
CRC32 защищает от повреждения, криптографической подписи и anti-rollback по
|
||||||
|
версии в этом порту нет. Удалённый CONFIRM подтверждает готовность приложения,
|
||||||
|
но не заменяет проверку датчиков/силовой части на стенде.
|
||||||
|
|
||||||
|
Аппаратный формат SPI boot описан в [TI Boot ROM Reference Guide](https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/171/2742.Boot-ROM.pdf).
|
||||||
|
В A/B-схеме ROM выбирает Flash, а разбор EEPROM выполняет этот загрузчик.
|
||||||
|
|
||||||
|
Проект предоставляет `f28335_can_application_config.h` в include paths.
|
||||||
|
Он задаёт `F28335_CAN_BOOT_APPLICATION_ENABLED` (0/1) и при включённом модуле
|
||||||
|
`F28335_CAN_BOOT_FIRMWARE_VERSION` из версии приложения. В 167 это ручной
|
||||||
|
`firmware_version.h`; профиль включён только при M95M02 без `FLASH_BOOT`.
|
||||||
|
Локальный `Source/Internal/can_boot.c` содержит только `F28335Boot_Quiesce`
|
||||||
|
со штатной остановкой нагрузки. Общие `.c` повторно включать в него не нужно:
|
||||||
|
они компилируются единственным linked resource общей библиотеки.
|
||||||
|
Постоянный Flash-загрузчик по-прежнему собирается отдельным проектом
|
||||||
|
`projects/ccs/f28335` и не линкуется в RAM-приложение.
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
/* Shared by the application and the separate Flash bootloader. */
|
||||||
|
/* Аппаратный слой: общая RAM между reset, watchdog и SPI EEPROM.
|
||||||
|
* Один исходник компилируется и в приложение, и в отдельный Flash-загрузчик.
|
||||||
|
* В отличие от store.c этот файл требует настоящих регистров F28335. */
|
||||||
|
#include "DSP2833x_Device.h"
|
||||||
|
#include "f28335_boot_platform.h"
|
||||||
|
#include "f28335_can_boot.h"
|
||||||
|
|
||||||
|
/* Must be NOINIT in BOTH linkers, outside ROM scratch and application payload. */
|
||||||
|
#pragma DATA_SECTION(boot_handoff,".boot_shared")
|
||||||
|
/* 8 слов NOINIT по адресу 0x50, одинаково зарезервированных обоими linker-файлами.
|
||||||
|
* [0..1] magic; [2] запрошенная session; [3] запущенный слот; [4..6] служебные
|
||||||
|
* поля; [7] XOR-контроль. Это кратковременная передача контекста через watchdog
|
||||||
|
* reset, а не замена энергонезависимого журнала EEPROM. */
|
||||||
|
static volatile unsigned int boot_handoff[8];
|
||||||
|
/* Проверяем magic и XOR прежде, чем трактовать RAM как запрос входа в boot.
|
||||||
|
* После включения питания содержимое NOINIT может быть произвольным. */
|
||||||
|
static unsigned int handoff_valid(void)
|
||||||
|
{
|
||||||
|
unsigned int i,sum=0;
|
||||||
|
for(i=0;i<8;++i) sum^=boot_handoff[i];
|
||||||
|
return boot_handoff[0]==0xB283 && boot_handoff[1]==0x4D7C && sum==0xA95B;
|
||||||
|
}
|
||||||
|
/* Сначала снимаем признак действительности, затем заполняем поля и контроль.
|
||||||
|
* Первый magic записываем последним; volatile сохраняет обращения к общей RAM.
|
||||||
|
* request=0 означает обычный запуск, ненулевая session — явный ENTER_BOOT. */
|
||||||
|
static void handoff_set(unsigned int request,unsigned int running)
|
||||||
|
{
|
||||||
|
unsigned int i,sum=0;
|
||||||
|
boot_handoff[0]=0; boot_handoff[1]=0x4D7C;
|
||||||
|
boot_handoff[2]=request; boot_handoff[3]=running;
|
||||||
|
boot_handoff[4]=0xF335; boot_handoff[5]=0x0CCA; boot_handoff[6]=1;
|
||||||
|
sum=0xB283;
|
||||||
|
for(i=1;i<7;++i) sum^=boot_handoff[i];
|
||||||
|
boot_handoff[7]=sum^0xA95B;
|
||||||
|
boot_handoff[0]=0xB283; /* publish last */
|
||||||
|
}
|
||||||
|
/* Приложение узнаёт свой слот из handoff, а не предполагает, что оно active:
|
||||||
|
* во время пробного запуска выполняется pending, active ещё указывает на старый образ. */
|
||||||
|
unsigned int F28335Boot_RunningSlot(void)
|
||||||
|
{ return handoff_valid()?boot_handoff[3]:F28335_AB_NONE; }
|
||||||
|
unsigned int F28335Boot_RequestedSession(void)
|
||||||
|
{ return handoff_valid() && boot_handoff[2]<256?boot_handoff[2]:0; }
|
||||||
|
/* Одновременно публикуем выбранный слот и потребляем запрос ENTER_BOOT:
|
||||||
|
* он не должен повторяться при следующем обычном reset. */
|
||||||
|
void F28335Boot_SetRunning(unsigned int slot) { handoff_set(0,slot); }
|
||||||
|
/* Timer1 должен давать 1 мс на InterruptCount и в приложении, и в загрузчике.
|
||||||
|
* Тайм-ауты используют разность unsigned-счётчиков для переноса через wrap. */
|
||||||
|
uint32_t F28335Boot_Now(void) { return CpuTimer1.InterruptCount; }
|
||||||
|
/* Вызвать сразу после InitSysCtrl, который штатно отключает watchdog.
|
||||||
|
* Сбрасываем разрешение кормления из ISR до полной инициализации CAN-сервиса.
|
||||||
|
* Для приложения, запущенного нашим загрузчиком, включаем watchdog с делителем. */
|
||||||
|
void F28335Boot_StartupWatchdog(void)
|
||||||
|
{
|
||||||
|
F28335CanBoot_EarlyInit();
|
||||||
|
if(F28335Boot_RunningSlot()<2) {
|
||||||
|
EALLOW; SysCtrlRegs.WDKEY=0x55; SysCtrlRegs.WDKEY=0xAA;
|
||||||
|
SysCtrlRegs.WDCR=0x002F; EDIS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Платформенный Quiesce останавливает управление выходами перед reset.
|
||||||
|
* Session сохраняется до включения watchdog; ненулевую session загрузчик
|
||||||
|
* использует для отложенного ACK ENTER_BOOT. В бесконечном цикле watchdog
|
||||||
|
* намеренно не обслуживается — выход из функции должен произойти через reset. */
|
||||||
|
void F28335Boot_Reset(unsigned int session)
|
||||||
|
{
|
||||||
|
F28335Boot_Quiesce();
|
||||||
|
DINT;
|
||||||
|
handoff_set(session,F28335_AB_NONE);
|
||||||
|
EALLOW; SysCtrlRegs.WDCR=0x0028; EDIS;
|
||||||
|
for(;;) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main context only. Legacy Timer2 EEPROM driver must be idle/stopped. Save
|
||||||
|
* its SPI configuration: it changes the character width during transactions. */
|
||||||
|
typedef struct { unsigned int ccr,ctl,brr,tx,rx,ct,pri; } boot_spi_saved;
|
||||||
|
static void spi_cs(unsigned int high)
|
||||||
|
{ if(high) GpioDataRegs.GPASET.bit.GPIO19=1; else GpioDataRegs.GPACLEAR.bit.GPIO19=1; }
|
||||||
|
/* Доступ разрешён только из main при остановленном Timer2 старого SPI-драйвера.
|
||||||
|
* Это проверка занятости в однопоточном приложении, не универсальный mutex.
|
||||||
|
* Сохраняем режим SPI, поскольку штатный драйвер меняет разрядность передачи.
|
||||||
|
* CS сначала поднимаем, затем переключаем SPI на 8-битные транзакции. */
|
||||||
|
static bool spi_take(boot_spi_saved *s)
|
||||||
|
{
|
||||||
|
volatile unsigned int discard;
|
||||||
|
if(!CpuTimer2Regs.TCR.bit.TSS) return false;
|
||||||
|
s->ccr=SpiaRegs.SPICCR.all; s->ctl=SpiaRegs.SPICTL.all; s->brr=SpiaRegs.SPIBRR;
|
||||||
|
s->tx=SpiaRegs.SPIFFTX.all; s->rx=SpiaRegs.SPIFFRX.all;
|
||||||
|
s->ct=SpiaRegs.SPIFFCT.all; s->pri=SpiaRegs.SPIPRI.all;
|
||||||
|
EALLOW;
|
||||||
|
GpioCtrlRegs.GPAMUX2.bit.GPIO16=1; GpioCtrlRegs.GPAMUX2.bit.GPIO17=1;
|
||||||
|
GpioCtrlRegs.GPAMUX2.bit.GPIO18=1; GpioCtrlRegs.GPAMUX2.bit.GPIO19=0;
|
||||||
|
GpioDataRegs.GPASET.bit.GPIO19=1; GpioCtrlRegs.GPADIR.bit.GPIO19=1;
|
||||||
|
GpioCtrlRegs.GPAQSEL2.bit.GPIO17=3;
|
||||||
|
EDIS;
|
||||||
|
SpiaRegs.SPICCR.all=7; SpiaRegs.SPICTL.all=0x0E; /* master, phase=1, IRQ off */
|
||||||
|
SpiaRegs.SPIBRR=CLKMULT*6+1;
|
||||||
|
SpiaRegs.SPIFFTX.all=0x8000; SpiaRegs.SPIFFRX.all=0; SpiaRegs.SPIFFCT.all=0;
|
||||||
|
SpiaRegs.SPIPRI.all=0x10; SpiaRegs.SPICCR.all=0x87;
|
||||||
|
/* Снимаем оставшийся RX/INT_FLAG от прежней операции, чтобы первый обмен
|
||||||
|
* не принял старое содержимое RXBUF за ответ EEPROM. */
|
||||||
|
discard=SpiaRegs.SPIRXBUF; (void)discard;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/* Выход и при успехе, и при ошибке: CS не должен остаться активным.
|
||||||
|
* Настройки возвращаются при удержании SPI в reset; исходный SPISWRESET
|
||||||
|
* восстанавливается последним, после остальных регистров. */
|
||||||
|
static void spi_release(const boot_spi_saved *s)
|
||||||
|
{
|
||||||
|
volatile unsigned int discard;
|
||||||
|
spi_cs(1); discard=SpiaRegs.SPIRXBUF; (void)discard;
|
||||||
|
SpiaRegs.SPICCR.all=s->ccr&0x7FU; SpiaRegs.SPICTL.all=s->ctl;
|
||||||
|
SpiaRegs.SPIBRR=s->brr; SpiaRegs.SPIFFTX.all=s->tx; SpiaRegs.SPIFFRX.all=s->rx;
|
||||||
|
SpiaRegs.SPIFFCT.all=s->ct; SpiaRegs.SPIPRI.all=s->pri; SpiaRegs.SPICCR.all=s->ccr;
|
||||||
|
}
|
||||||
|
/* У F28335 8-битный символ для передачи выравнивается в старшие биты TXBUF.
|
||||||
|
* Полученный октет читается из младших битов RXBUF. Счётчик budget ограничивает
|
||||||
|
* ожидание даже при неработающем Timer1; это число итераций, а не миллисекунды. */
|
||||||
|
static bool spi_octet(unsigned int tx,unsigned int *rx)
|
||||||
|
{
|
||||||
|
uint32_t budget=100000UL;
|
||||||
|
SpiaRegs.SPITXBUF=(tx&255U)<<8;
|
||||||
|
while(!SpiaRegs.SPISTS.bit.INT_FLAG) if(--budget==0) return false;
|
||||||
|
*rx=SpiaRegs.SPIRXBUF&255U; return true;
|
||||||
|
}
|
||||||
|
/* Команда EEPROM и 24-битный байтовый адрес, старший октет адреса первым.
|
||||||
|
* CS удерживается вызывающей функцией на всю команду и полезные данные. */
|
||||||
|
static bool spi_prefix(unsigned int command,uint32_t address)
|
||||||
|
{
|
||||||
|
unsigned int discard;
|
||||||
|
return spi_octet(command,&discard) && spi_octet((unsigned int)(address>>16),&discard) &&
|
||||||
|
spi_octet((unsigned int)(address>>8),&discard) && spi_octet((unsigned int)address,&discard);
|
||||||
|
}
|
||||||
|
/* RDSR (05h): WIP в бите 0 означает незавершённую внутреннюю запись EEPROM.
|
||||||
|
* Ожидание ограничено и 50 мс, и числом опросов на случай остановки tick.
|
||||||
|
* После каждого чтения статуса CS снимается, в том числе при ошибке SPI. */
|
||||||
|
static bool spi_ready(void)
|
||||||
|
{
|
||||||
|
unsigned int status,discard; uint32_t started=F28335Boot_Now(),budget=20000UL;
|
||||||
|
do {
|
||||||
|
spi_cs(0);
|
||||||
|
if(!spi_octet(5,&discard) || !spi_octet(255,&status)) { spi_cs(1); return false; }
|
||||||
|
spi_cs(1);
|
||||||
|
if(!(status&1U)) return true;
|
||||||
|
} while(--budget && (uint32_t)(F28335Boot_Now()-started)<50UL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Читать разрешено всю физическую EEPROM, включая параметры. Проверка
|
||||||
|
* через вычитание защищает от переполнения адреса. spi_release обязателен
|
||||||
|
* после успешного захвата SPI независимо от результата последующего обмена. */
|
||||||
|
bool F28335Boot_Read(void *u,uint32_t address,pcan_boot_byte_t *p,unsigned int n)
|
||||||
|
{
|
||||||
|
boot_spi_saved saved; unsigned int i,value; bool ok; (void)u;
|
||||||
|
if(address>0x40000UL || n>0x40000UL-address || !spi_take(&saved)) return false;
|
||||||
|
ok=spi_ready();
|
||||||
|
spi_cs(0); if(ok) ok=spi_prefix(3,address);
|
||||||
|
for(i=0;ok && i<n;++i) { ok=spi_octet(255,&value); p[i]=value; }
|
||||||
|
spi_release(&saved); return ok;
|
||||||
|
}
|
||||||
|
/* Нижний аппаратный барьер записи: разрешены журнал и слоты до 0x3FE00.
|
||||||
|
* Резерв, параметры и последнее слово нельзя изменить даже ошибочным вызовом
|
||||||
|
* этой функции. Защита активного слота дополнительно выполняется в store.c. */
|
||||||
|
bool F28335Boot_Write(void *u,uint32_t address,const pcan_boot_byte_t *p,unsigned int n)
|
||||||
|
{
|
||||||
|
boot_spi_saved saved; unsigned int i,chunk,discard; bool ok; (void)u;
|
||||||
|
/* This driver cannot overwrite parameters, even if a caller is defective. */
|
||||||
|
if(address>0x3FE00UL || n>0x3FE00UL-address || !spi_take(&saved)) return false;
|
||||||
|
ok=spi_ready();
|
||||||
|
while(ok && n) {
|
||||||
|
/* Нельзя пересекать страницу одной командой WRITE: EEPROM может завернуть
|
||||||
|
* адрес внутри страницы. Для каждого фрагмента заново выдаём WREN (06h),
|
||||||
|
* WRITE (02h) и ждём снятия WIP. Сравнение readback выполняет верхний слой. */
|
||||||
|
chunk=256U-(unsigned int)(address&255U); if(chunk>n) chunk=n;
|
||||||
|
spi_cs(0); ok=spi_octet(6,&discard); spi_cs(1); /* WREN */
|
||||||
|
spi_cs(0); if(ok) ok=spi_prefix(2,address);
|
||||||
|
for(i=0;ok && i<chunk;++i) ok=spi_octet(p[i],&discard);
|
||||||
|
spi_cs(1); if(ok) ok=spi_ready();
|
||||||
|
n-=chunk; p+=chunk; address+=chunk;
|
||||||
|
}
|
||||||
|
spi_release(&saved); return ok;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#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
|
||||||
|
bool F28335Boot_Read(void *u,uint32_t address,pcan_boot_byte_t *p,unsigned int n);
|
||||||
|
bool F28335Boot_Write(void *u,uint32_t address,const pcan_boot_byte_t *p,unsigned int n);
|
||||||
|
uint32_t F28335Boot_Now(void);
|
||||||
|
void F28335Boot_Reset(unsigned int session);
|
||||||
|
unsigned int F28335Boot_RunningSlot(void);
|
||||||
|
unsigned int F28335Boot_RequestedSession(void);
|
||||||
|
void F28335Boot_SetRunning(unsigned int slot);
|
||||||
|
void F28335Boot_StartupWatchdog(void);
|
||||||
|
/* Application hook must stop outputs before reset. No EEPROM operations here. */
|
||||||
|
void F28335Boot_Quiesce(void);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
/* Хранилище A/B без зависимости от регистров F28335.
|
||||||
|
* Здесь находятся правила сохранения образа при сбое питания и выбора слота.
|
||||||
|
* CAN отвечает за порядок команд; этот слой повторно защищает active/pending
|
||||||
|
* и границы EEPROM, даже если вызывающий код передал неверные параметры.
|
||||||
|
* Адрес EEPROM измеряется в октетах, адрес назначения SCI8 — в словах CPU. */
|
||||||
|
#include "f28335_boot_store.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Формат журнала фиксирован: u32 little endian. Нельзя сохранять C-структуру
|
||||||
|
* через memcpy: выравнивание и sizeof на C28x отличаются от обычного ПК. */
|
||||||
|
static uint32_t bs_get32(const pcan_boot_byte_t *p)
|
||||||
|
{ return (uint32_t)p[0] | ((uint32_t)p[1]<<8) | ((uint32_t)p[2]<<16) | ((uint32_t)p[3]<<24); }
|
||||||
|
static void bs_put32(pcan_boot_byte_t *p, uint32_t v)
|
||||||
|
{ unsigned int i; for(i=0;i<4;++i) p[i]=(pcan_boot_byte_t)((v>>(8*i))&255U); }
|
||||||
|
/* Потоковый CRC32: первый вызов получает crc=0, следующие — предыдущий результат.
|
||||||
|
* Внутренняя инверсия позволяет считать один CRC по нескольким порциям EEPROM.
|
||||||
|
* Маска 255 исключает старшие биты 16-битного представления октета на C28x.
|
||||||
|
* Это проверка повреждения данных, а не криптографическая подпись. */
|
||||||
|
uint32_t f28335_boot_crc(uint32_t crc, const pcan_boot_byte_t *p, unsigned int n)
|
||||||
|
{ unsigned int i,b; crc=~crc; for(i=0;i<n;++i) { crc^=p[i]&255U;
|
||||||
|
for(b=0;b<8;++b) crc=(crc>>1)^((crc&1U)?0xEDB88320UL:0); } return ~crc; }
|
||||||
|
static uint32_t bs_base(unsigned int slot) { return slot?F28335_AB_SLOT_B:F28335_AB_SLOT_A; }
|
||||||
|
/* Принимаем запись только при совпадении magic, версии, marker и CRC.
|
||||||
|
* Дополнительно проверяем смысл номеров слотов: pending не может быть active.
|
||||||
|
* Наличие правильного marker без правильного CRC не разрешает запуск. */
|
||||||
|
static bool bs_record_valid(const pcan_boot_byte_t *p)
|
||||||
|
{
|
||||||
|
return bs_get32(p)==0x32424146UL && bs_get32(p+4)==1 &&
|
||||||
|
bs_get32(p+60)==0x51AFC03DUL && bs_get32(p+56)==f28335_boot_crc(0,p,56) &&
|
||||||
|
(p[12]<2 || p[12]==F28335_AB_NONE) &&
|
||||||
|
(p[13]<2 || p[13]==F28335_AB_NONE) && p[14]<=1 &&
|
||||||
|
(p[13]==F28335_AB_NONE || p[13]!=p[12]);
|
||||||
|
}
|
||||||
|
/* Карта записи, смещения в октетах:
|
||||||
|
* 0..3 magic FAB2; 4..7 версия; 8..11 sequence; 12 active; 13 pending;
|
||||||
|
* 14 attempted; 15 резерв; 16..35 manifest A; 36..55 manifest B;
|
||||||
|
* 56..59 CRC первых 56 октетов; 60..63 marker завершённой публикации.
|
||||||
|
* Manifest: size, CRC, FW (по u32), Product (u16), HW min/max, 4 октета резерва. */
|
||||||
|
static void bs_decode(f28335_boot_store_t *s, const pcan_boot_byte_t *p)
|
||||||
|
{
|
||||||
|
unsigned int i; s->sequence=bs_get32(p+8); s->active=p[12];
|
||||||
|
s->pending=p[13]; s->attempted=p[14];
|
||||||
|
for(i=0;i<2;++i) {
|
||||||
|
const pcan_boot_byte_t *q=p+16+i*20;
|
||||||
|
s->image[i].image_size=bs_get32(q); s->image[i].image_crc32=bs_get32(q+4);
|
||||||
|
s->image[i].firmware_version=bs_get32(q+8);
|
||||||
|
s->image[i].product_type=(uint16_t)(q[12]|(q[13]<<8));
|
||||||
|
s->image[i].hardware_revision_min=q[14]; s->image[i].hardware_revision_max=q[15];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Читаем обе копии журнала. Нераспознанная разметка допускает CAN recovery
|
||||||
|
* с active=NONE; ошибка чтения запрещает запись, поскольку реальный active неизвестен.
|
||||||
|
* Эта функция не преобразует старый SCI8 по адресу 0 в новую A/B-разметку. */
|
||||||
|
bool f28335_boot_open(f28335_boot_store_t *s, const f28335_boot_io_t *io)
|
||||||
|
{
|
||||||
|
pcan_boot_byte_t a[64],b[64]; bool va,vb;
|
||||||
|
if(!s || !io || !io->read || !io->write) return false;
|
||||||
|
memset(s,0,sizeof(*s)); s->io=*io; s->active=s->pending=F28335_AB_NONE;
|
||||||
|
if(!io->read(io->user,0,a,64) || !io->read(io->user,256,b,64)) { s->io_fault=true; return false; }
|
||||||
|
va=bs_record_valid(a); vb=bs_record_valid(b);
|
||||||
|
if(!va && !vb) return true;
|
||||||
|
/* Сравнение sequence по модулю 2^32: разность менее половины диапазона
|
||||||
|
* считается более новой записью. При равенстве выбирается страница 1.
|
||||||
|
* Соседние публикации отличаются на единицу, в том числе после переполнения. */
|
||||||
|
s->page=vb && (!va || (uint32_t)(bs_get32(b+8)-bs_get32(a+8))<0x80000000UL)?1:0;
|
||||||
|
bs_decode(s,s->page?b:a); s->valid=true; return true;
|
||||||
|
}
|
||||||
|
/* Публикация выполняется в другую страницу, текущую действующую не трогаем.
|
||||||
|
* Порядок принципиален: обнулить marker -> проверить -> записать тело ->
|
||||||
|
* проверить тело -> записать marker последним -> проверить всю запись.
|
||||||
|
* При обрыве питания загрузчик выбирает прежнюю либо полностью новую запись.
|
||||||
|
* Каждый memcmp учитывает sizeof элемента, поскольку элемент здесь — октет
|
||||||
|
* протокола, но на C28x занимает адресуемое 16-битное слово. */
|
||||||
|
static bool bs_save(f28335_boot_store_t *s)
|
||||||
|
{
|
||||||
|
pcan_boot_byte_t p[64],check[64],invalid[4]={0,0,0,0}; unsigned int i;
|
||||||
|
unsigned int page=s->valid?(s->page^1U):0;
|
||||||
|
uint32_t addr=(uint32_t)page*256;
|
||||||
|
memset(p,0,sizeof(p)); bs_put32(p,0x32424146UL); bs_put32(p+4,1);
|
||||||
|
bs_put32(p+8,s->sequence+1); p[12]=s->active; p[13]=s->pending; p[14]=s->attempted;
|
||||||
|
for(i=0;i<2;++i) {
|
||||||
|
pcan_boot_byte_t *q=p+16+i*20;
|
||||||
|
bs_put32(q,s->image[i].image_size); bs_put32(q+4,s->image[i].image_crc32);
|
||||||
|
bs_put32(q+8,s->image[i].firmware_version);
|
||||||
|
q[12]=s->image[i].product_type&255U; q[13]=(s->image[i].product_type>>8)&255U;
|
||||||
|
q[14]=s->image[i].hardware_revision_min; q[15]=s->image[i].hardware_revision_max;
|
||||||
|
}
|
||||||
|
bs_put32(p+56,f28335_boot_crc(0,p,56)); bs_put32(p+60,0x51AFC03DUL);
|
||||||
|
/* The old page is never erased. A torn write cannot publish a partial record. */
|
||||||
|
if(!s->io.write(s->io.user,addr+60,invalid,4) ||
|
||||||
|
!s->io.read(s->io.user,addr+60,check,4) || memcmp(check,invalid,sizeof(invalid)) ||
|
||||||
|
!s->io.write(s->io.user,addr,p,60) ||
|
||||||
|
!s->io.read(s->io.user,addr,check,60) || memcmp(p,check,60*sizeof(*p)) ||
|
||||||
|
!s->io.write(s->io.user,addr+60,p+60,4) ||
|
||||||
|
!s->io.read(s->io.user,addr,check,64) || memcmp(p,check,sizeof(p))) return false;
|
||||||
|
s->page=page; s->sequence++; s->valid=true; return true;
|
||||||
|
}
|
||||||
|
/* Изменения сначала готовятся в копии состояния next. Рабочее состояние
|
||||||
|
* заменяем только после публикации. Если запись/контрольное чтение сорвались,
|
||||||
|
* перечитываем журнал: marker мог успеть записаться до ошибки readback.
|
||||||
|
* После неудачи чтения io_fault блокирует дальнейшие изменения хранилища. */
|
||||||
|
static bool bs_publish(f28335_boot_store_t *s, f28335_boot_store_t *next)
|
||||||
|
{
|
||||||
|
if(bs_save(next)) { *s=*next; return true; }
|
||||||
|
/* A failed final read may still have committed: reload before any more writes. */
|
||||||
|
{ f28335_boot_io_t io=s->io; if(!f28335_boot_open(s,&io)) {
|
||||||
|
s->valid=false; s->io_fault=true; return false; } }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Логический ERASE: обнуляем manifest неактивного слота в журнале.
|
||||||
|
* Саму EEPROM стирать целиком не требуется — каждый байт будет перезаписан.
|
||||||
|
* Active защищён всегда; наличие pending запрещает начало новой записи,
|
||||||
|
* пока кандидат не подтверждён либо не снят при следующем выборе загрузки. */
|
||||||
|
bool f28335_boot_prepare(f28335_boot_store_t *s, unsigned int slot)
|
||||||
|
{
|
||||||
|
f28335_boot_store_t next=*s;
|
||||||
|
if(s->io_fault || slot>1 || slot==s->active || s->pending!=F28335_AB_NONE) return false;
|
||||||
|
memset(&next.image[slot],0,sizeof(next.image[slot]));
|
||||||
|
return bs_publish(s,&next);
|
||||||
|
}
|
||||||
|
/* Записываем не более одного CAN-блока и немедленно сравниваем прочитанное.
|
||||||
|
* Проверка n <= capacity-off выполняется после off <= capacity: это исключает
|
||||||
|
* переполнение суммы off+n и выход из слота в соседний слот или параметры. */
|
||||||
|
bool f28335_boot_write(f28335_boot_store_t *s, unsigned int slot, uint32_t off,
|
||||||
|
const pcan_boot_byte_t *p, unsigned int n)
|
||||||
|
{
|
||||||
|
pcan_boot_byte_t check[8];
|
||||||
|
if(s->io_fault || slot>1 || slot==s->active || s->pending!=F28335_AB_NONE || !n || n>8 ||
|
||||||
|
off>F28335_AB_SLOT_BYTES || n>F28335_AB_SLOT_BYTES-off) return false;
|
||||||
|
return s->io.write(s->io.user,bs_base(slot)+off,p,n) &&
|
||||||
|
s->io.read(s->io.user,bs_base(slot)+off,check,n) && !memcmp(check,p,n*sizeof(*p));
|
||||||
|
}
|
||||||
|
/* Слово SCI8 занимает два октета файла, младший октет идёт первым.
|
||||||
|
* Смещение увеличиваем только после успешного чтения; усечённый файл отклоняем. */
|
||||||
|
static bool bs_u16(f28335_boot_store_t *s,uint32_t base,uint32_t size,uint32_t *off,uint16_t *v)
|
||||||
|
{
|
||||||
|
pcan_boot_byte_t p[2]; if(*off>size || size-*off<2 ||
|
||||||
|
!s->io.read(s->io.user,base+*off,p,2)) return false;
|
||||||
|
*v=(uint16_t)(p[0]|(p[1]<<8)); *off+=2; return true;
|
||||||
|
}
|
||||||
|
/* Особенность таблицы TI: адрес u32 передаётся старшим словом вперёд,
|
||||||
|
* при этом внутри каждого слова остаётся little endian. Не заменять на get32. */
|
||||||
|
static bool bs_addr(f28335_boot_store_t *s,uint32_t base,uint32_t size,uint32_t *off,uint32_t *v)
|
||||||
|
{
|
||||||
|
uint16_t hi,lo; if(!bs_u16(s,base,size,off,&hi) || !bs_u16(s,base,size,off,&lo)) return false;
|
||||||
|
*v=((uint32_t)hi<<16)|lo; return true;
|
||||||
|
}
|
||||||
|
/* The complete table is validated before any application RAM is written.
|
||||||
|
* Loader RAM is E000..FFFF and M0/M1. Flash, peripherals and XINTF are forbidden. */
|
||||||
|
/* writer=NULL: только разбираем и проверяем таблицу, RAM приложения не меняем.
|
||||||
|
* writer задан: повторно проверяем таблицу и переносим слова в разрешённую RAM.
|
||||||
|
* Массивы starts/ends ограничены MAX_SECTIONS; они нужны для обнаружения
|
||||||
|
* пересекающихся секций, в том числе секций с разным порядком адресов. */
|
||||||
|
static bool bs_table(f28335_boot_store_t *s,unsigned int slot,uint32_t size,
|
||||||
|
f28335_boot_ram_writer writer,void *user,uint32_t *entry)
|
||||||
|
{
|
||||||
|
uint32_t starts[F28335_AB_MAX_SECTIONS],ends[F28335_AB_MAX_SECTIONS];
|
||||||
|
uint32_t off=0,addr,end,base=bs_base(slot); unsigned int sections=0,i;
|
||||||
|
uint16_t count,word; bool entry_loaded=false;
|
||||||
|
if(!bs_u16(s,base,size,&off,&word) || word!=0x08AA) return false;
|
||||||
|
/* После ключа AA 08 пропускаем 16 резервных октетов; далее расположен entry.
|
||||||
|
* Нулевой count завершает таблицу строго на конце файла, без хвостовых данных. */
|
||||||
|
off=18; if(!bs_addr(s,base,size,&off,entry)) return false;
|
||||||
|
for(;;) {
|
||||||
|
if(!bs_u16(s,base,size,&off,&count)) return false;
|
||||||
|
if(!count) return off==size && entry_loaded;
|
||||||
|
if(sections==F28335_AB_MAX_SECTIONS || !bs_addr(s,base,size,&off,&addr)) return false;
|
||||||
|
end=addr+count;
|
||||||
|
/* Разрешён только полуинтервал RAM [0x8000,0xE000) в словах CPU.
|
||||||
|
* Верхняя граница защищает RAM работающего загрузчика; нижняя — стек,
|
||||||
|
* handoff и регистры. Проверка размера payload использует уже октеты файла. */
|
||||||
|
if(addr<0x8000UL || end>0xE000UL || end<=addr ||
|
||||||
|
off>size || (uint32_t)count*2>size-off) return false;
|
||||||
|
for(i=0;i<sections;++i) if(addr<ends[i] && end>starts[i]) return false;
|
||||||
|
starts[sections]=addr; ends[sections++]=end;
|
||||||
|
if(*entry>=addr && *entry<end) entry_loaded=true;
|
||||||
|
if(writer) { for(i=0;i<count;++i) {
|
||||||
|
if(!bs_u16(s,base,size,&off,&word) || !writer(user,addr+i,word)) return false;
|
||||||
|
} } else off+=(uint32_t)count*2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* VERIFY проверяет содержимое самой EEPROM, а не только CRC принятого потока.
|
||||||
|
* Затем проверяется структура SCI8 и попадание entry в загружаемую секцию.
|
||||||
|
* Выходной entry необязателен: COMMIT нужна проверка, но не адрес перехода. */
|
||||||
|
bool f28335_boot_verify(f28335_boot_store_t *s,unsigned int slot,
|
||||||
|
const pcan_boot_manifest_t *m,uint32_t *entry)
|
||||||
|
{
|
||||||
|
uint32_t off,crc=0,local_entry; unsigned int n; pcan_boot_byte_t p[32];
|
||||||
|
if(slot>1 || m->image_size<24 || m->image_size>F28335_AB_SLOT_BYTES ||
|
||||||
|
(m->image_size&1) || m->product_type!=0x2833 ||
|
||||||
|
m->hardware_revision_min>1 || m->hardware_revision_max<1) return false;
|
||||||
|
for(off=0;off<m->image_size;off+=n) {
|
||||||
|
n=(m->image_size-off<32)?(unsigned int)(m->image_size-off):32;
|
||||||
|
if(!s->io.read(s->io.user,bs_base(slot)+off,p,n)) return false;
|
||||||
|
crc=f28335_boot_crc(crc,p,n);
|
||||||
|
}
|
||||||
|
if(crc!=m->image_crc32 || !bs_table(s,slot,m->image_size,0,0,&local_entry)) return false;
|
||||||
|
if(entry) *entry=local_entry;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/* COMMIT публикует проверенный образ как pending, не меняя active.
|
||||||
|
* Повторная проверка EEPROM непосредственно перед публикацией не позволяет
|
||||||
|
* назначить кандидатом образ, испорченный после предыдущего VERIFY. */
|
||||||
|
bool f28335_boot_commit(f28335_boot_store_t *s,unsigned int slot,const pcan_boot_manifest_t *m)
|
||||||
|
{
|
||||||
|
f28335_boot_store_t next=*s;
|
||||||
|
if(s->io_fault || slot>1 || slot==s->active || s->pending!=F28335_AB_NONE ||
|
||||||
|
!f28335_boot_verify(s,slot,m,0)) return false;
|
||||||
|
next.image[slot]=*m; next.pending=slot; next.attempted=0;
|
||||||
|
return bs_publish(s,&next);
|
||||||
|
}
|
||||||
|
/* Подтверждать можно только действительно выбранный для пробного запуска слот.
|
||||||
|
* Требование attempted исключает подтверждение ещё ни разу не запускавшегося
|
||||||
|
* кандидата. Повтор CONFIRM уже активного слота возвращает успех без записи. */
|
||||||
|
bool f28335_boot_confirm(f28335_boot_store_t *s,unsigned int running_slot)
|
||||||
|
{
|
||||||
|
f28335_boot_store_t next=*s;
|
||||||
|
if(s->io_fault || running_slot>1) return false;
|
||||||
|
if(s->pending==F28335_AB_NONE) return s->valid && s->active==running_slot;
|
||||||
|
if(s->pending!=running_slot || !s->attempted) return false;
|
||||||
|
next.active=running_slot; next.pending=F28335_AB_NONE; next.attempted=0;
|
||||||
|
return bs_publish(s,&next);
|
||||||
|
}
|
||||||
|
/* Выбор выполняется при старте загрузчика. attempted сохраняется ДО перехода
|
||||||
|
* в приложение: после зависания, watchdog reset или потери питания следующий
|
||||||
|
* старт уже знает о незавершённой пробе и возвращает прежний active.
|
||||||
|
* Успех функции с slot=NONE означает recovery, а не разрешение перехода в RAM. */
|
||||||
|
bool f28335_boot_select(f28335_boot_store_t *s,unsigned int *slot)
|
||||||
|
{
|
||||||
|
f28335_boot_store_t next=*s; *slot=F28335_AB_NONE;
|
||||||
|
if(s->io_fault) return false;
|
||||||
|
if(s->pending!=F28335_AB_NONE) {
|
||||||
|
if(!s->attempted && f28335_boot_verify(s,s->pending,&s->image[s->pending],0)) {
|
||||||
|
next.attempted=1;
|
||||||
|
if(!bs_publish(s,&next)) return false;
|
||||||
|
*slot=s->pending; return true;
|
||||||
|
}
|
||||||
|
/* Кандидат уже запускался без подтверждения либо не прошёл проверку.
|
||||||
|
* Снимаем pending отдельной публикацией; подтверждённый active остаётся прежним. */
|
||||||
|
next.pending=F28335_AB_NONE; next.attempted=0;
|
||||||
|
if(!bs_publish(s,&next)) return false;
|
||||||
|
}
|
||||||
|
if(s->active<2 && f28335_boot_verify(s,s->active,&s->image[s->active],0)) *slot=s->active;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/* Сначала полная проверка CRC и всех адресов без записи, затем перенос слов.
|
||||||
|
* Платформа вызывает entry только при true; частичная загрузка при ошибке I/O
|
||||||
|
* не даёт разрешения на запуск приложения. */
|
||||||
|
bool f28335_boot_load(f28335_boot_store_t *s,unsigned int slot,
|
||||||
|
f28335_boot_ram_writer writer,void *user,uint32_t *entry)
|
||||||
|
{
|
||||||
|
return slot<2 && writer && entry && f28335_boot_verify(s,slot,&s->image[slot],entry) &&
|
||||||
|
bs_table(s,slot,s->image[slot].image_size,writer,user,entry);
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#ifndef F28335_BOOT_STORE_H
|
||||||
|
#define F28335_BOOT_STORE_H
|
||||||
|
#include "../../include/pcan_boot.h"
|
||||||
|
|
||||||
|
/* All EEPROM offsets/lengths below are OCTETS, CPU destinations are WORDS. */
|
||||||
|
/* Физическая EEPROM 256 КиБ: две страницы журнала по 256 октетов,
|
||||||
|
* два слота по 130560 октетов. С 0x3FE00 начинается резерв, с 0x3FEFC —
|
||||||
|
* прежняя область параметров. Константы ниже не являются CPU word-адресами. */
|
||||||
|
#define F28335_AB_SLOT_BYTES 0x1FE00UL
|
||||||
|
#define F28335_AB_SLOT_A 0x00200UL
|
||||||
|
#define F28335_AB_SLOT_B 0x20000UL
|
||||||
|
#define F28335_AB_PARAMS 0x3FEFCUL
|
||||||
|
#define F28335_AB_NONE 0xFFU
|
||||||
|
#define F28335_AB_RECORD 64U
|
||||||
|
#define F28335_AB_MAX_SECTIONS 64U
|
||||||
|
|
||||||
|
/* Контракт I/O: address и n измеряются в октетах, независимо от sizeof(char).
|
||||||
|
* true означает, что выполнена вся операция; короткий обмен должен вернуть false.
|
||||||
|
* Callbacks вызываются синхронно из main, а user передаётся им без изменений. */
|
||||||
|
typedef struct {
|
||||||
|
bool (*read)(void *, uint32_t, pcan_boot_byte_t *, unsigned int);
|
||||||
|
bool (*write)(void *, uint32_t, const pcan_boot_byte_t *, unsigned int);
|
||||||
|
void *user;
|
||||||
|
} f28335_boot_io_t;
|
||||||
|
typedef struct {
|
||||||
|
f28335_boot_io_t io;
|
||||||
|
/* sequence — номер последней публикации; page — выбранная копия журнала.
|
||||||
|
* active — подтверждённый слот; pending — кандидат; attempted — уже была проба.
|
||||||
|
* valid показывает наличие распознанной записи, io_fault запрещает изменения
|
||||||
|
* после ошибки чтения. Отсутствующий слот обозначается NONE, а не нулём. */
|
||||||
|
uint32_t sequence;
|
||||||
|
unsigned int page, active, pending, attempted;
|
||||||
|
bool valid, io_fault;
|
||||||
|
pcan_boot_manifest_t image[2];
|
||||||
|
} f28335_boot_store_t;
|
||||||
|
|
||||||
|
uint32_t f28335_boot_crc(uint32_t crc, const pcan_boot_byte_t *p, unsigned int n);
|
||||||
|
bool f28335_boot_open(f28335_boot_store_t *s, const f28335_boot_io_t *io);
|
||||||
|
/* Blank/unrecognised EEPROM opens successfully with active=NONE. I/O errors fail. */
|
||||||
|
bool f28335_boot_prepare(f28335_boot_store_t *s, unsigned int slot);
|
||||||
|
bool f28335_boot_write(f28335_boot_store_t *s, unsigned int slot, uint32_t offset,
|
||||||
|
const pcan_boot_byte_t *data, unsigned int n);
|
||||||
|
bool f28335_boot_verify(f28335_boot_store_t *s, unsigned int slot,
|
||||||
|
const pcan_boot_manifest_t *m, uint32_t *entry);
|
||||||
|
bool f28335_boot_commit(f28335_boot_store_t *s, unsigned int slot,
|
||||||
|
const pcan_boot_manifest_t *m);
|
||||||
|
bool f28335_boot_confirm(f28335_boot_store_t *s, unsigned int running_slot);
|
||||||
|
/* Records a trial BEFORE returning it; a second unconfirmed boot rolls back. */
|
||||||
|
bool f28335_boot_select(f28335_boot_store_t *s, unsigned int *slot);
|
||||||
|
/* Запись одного проверенного слова приложения по CPU word-адресу.
|
||||||
|
* Должна вернуть false при невозможности записи; после отказа запуск запрещён. */
|
||||||
|
typedef bool (*f28335_boot_ram_writer)(void *, uint32_t, uint16_t);
|
||||||
|
bool f28335_boot_load(f28335_boot_store_t *s, unsigned int slot,
|
||||||
|
f28335_boot_ram_writer write_word, void *user, uint32_t *entry);
|
||||||
|
#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, а не этим прикладным модулем. */
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
/* Separate Flash recovery loader and application service adapter. */
|
||||||
|
#include "DSP2833x_Device.h"
|
||||||
|
#include "f28335_can_boot.h"
|
||||||
|
#if EEPROM_M95M02
|
||||||
|
#include "f28335_boot_platform.h"
|
||||||
|
#include <string.h>
|
||||||
|
/* boot хранит текущую CAN-сессию в RAM, store — прочитанное состояние журнала.
|
||||||
|
* Сброс сессии не удаляет 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. */
|
||||||
|
static volatile unsigned int head,tail,overflow;
|
||||||
|
static struct { uint32_t id; unsigned int dlc; pcan_boot_byte_t data[8]; } queue[32];
|
||||||
|
/* reset_requested только планирует reset; Service ждёт завершения TX.
|
||||||
|
* ready сообщает об окончании старта приложения, confirmed — о сохранённом
|
||||||
|
* подтверждении слота. healthy отражает результат открытия журнала при Init. */
|
||||||
|
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 — следующие четыре, младшим вперёд.
|
||||||
|
* Запрос CANTRS ещё не означает успешную доставку: CANTA проверяется в Service.
|
||||||
|
* Аппаратный CAN ACK не является отдельным прикладным подтверждением от ПК. */
|
||||||
|
static bool transmit(void *u, uint32_t id, const pcan_boot_byte_t *d, pcan_boot_byte_t n)
|
||||||
|
{
|
||||||
|
unsigned int i; unsigned long lo=0, hi=0; (void)u;
|
||||||
|
if (tx_busy) return false;
|
||||||
|
for(i=0;i<n;++i) {
|
||||||
|
if(i<4) lo|=(unsigned long)(d[i]&255U)<<(8U*i);
|
||||||
|
else hi|=(unsigned long)(d[i]&255U)<<(8U*(i-4U));
|
||||||
|
}
|
||||||
|
EALLOW;
|
||||||
|
ECanaRegs.CANME.all &= ~16UL;
|
||||||
|
ECanaMboxes.MBOX4.MSGID.all=0x80000000UL|id;
|
||||||
|
ECanaMboxes.MBOX4.MSGCTRL.all=n;
|
||||||
|
ECanaMboxes.MBOX4.MDL.all=lo; ECanaMboxes.MBOX4.MDH.all=hi;
|
||||||
|
ECanaRegs.CANME.all |=16UL;
|
||||||
|
ECanaRegs.CANTA.all=16UL; ECanaRegs.CANAA.all=16UL;
|
||||||
|
ECanaRegs.CANTRS.all=16UL;
|
||||||
|
EDIS;
|
||||||
|
sent_at=F28335Boot_Now(); tx_busy=1; tx_canceling=0; return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Изменение образа разрешено только сборке Flash-загрузчика. В приложении
|
||||||
|
* эти callbacks возвращают отказ, даже если им удастся передать команду записи.
|
||||||
|
* ERASE для EEPROM означает инвалидирование manifest выбранного слота. */
|
||||||
|
static bool erase(void *u,pcan_boot_byte_t 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)
|
||||||
|
{ /* 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 отдельными статусами протокола не различаются. */
|
||||||
|
static pcan_boot_status_t verify(void *u,pcan_boot_byte_t slot,const pcan_boot_manifest_t *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)
|
||||||
|
{ /* 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 открываем только после записи журнала. */
|
||||||
|
static bool confirm(void *u)
|
||||||
|
{
|
||||||
|
unsigned int running=F28335Boot_RunningSlot(); (void)u;
|
||||||
|
if(F28335_BOOT_LOADER || !healthy || !ready || running>1) return false;
|
||||||
|
if(!f28335_boot_confirm(&store,running)) return false;
|
||||||
|
boot.config.active_slot=running; confirmed=1; return true;
|
||||||
|
}
|
||||||
|
static bool can_reboot(void *u) { (void)u; return healthy; }
|
||||||
|
static void reboot(void *u) { (void)u; reset_session=0; reset_requested=1; }
|
||||||
|
/* Контракт enter_boot: 0 — загрузчик готов и ядро может отправить ACK;
|
||||||
|
* 1 — переход отложен, ACK придёт после reset; 2 — вход запрещён.
|
||||||
|
* Приложение требует handoff нашего загрузчика и подтверждённый текущий слот,
|
||||||
|
* чтобы не начать обновление из старого SPI-ROM старта или незавершённой пробы. */
|
||||||
|
static unsigned int enter(void *u,pcan_boot_byte_t session)
|
||||||
|
{
|
||||||
|
(void)u;
|
||||||
|
if(!healthy) return 2;
|
||||||
|
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 && 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)
|
||||||
|
{ unsigned int i; for(i=0;i<4;++i) p[i]=(pcan_boot_byte_t)((v>>(i*8))&255U); }
|
||||||
|
/* Паспорт помещается в classic CAN по страницам из восьми октетов.
|
||||||
|
* NAME возвращает фрагменты строки с завершающим NUL; неизвестная страница
|
||||||
|
* отклоняется. MEMORY: 0 — ёмкость/страница/режим/running, 1 — базы A/B,
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
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 || 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>=name_size) return false; /* Страница после конца выбранного имени не является допустимой частью паспорта. */
|
||||||
|
for(i=0;i<8;++i) { index=(unsigned int)page*8U+i;
|
||||||
|
out[i]=index<name_size?(pcan_boot_byte_t)name[index]:0; } /* Дополняет последнюю восьмибайтовую страницу нулями без выхода за строку. */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(command!=PCAN_BOOT_CMD_MEMORY_INFO) return false;
|
||||||
|
if(page==0) { info32(out,0x40000UL); out[4]=0; out[5]=1;
|
||||||
|
out[6]=F28335_BOOT_LOADER?1:0; out[7]=F28335Boot_RunningSlot(); return true; }
|
||||||
|
if(page==1) { info32(out,F28335_AB_SLOT_A); info32(out+4,F28335_AB_SLOT_B); return true; }
|
||||||
|
if(page==2) { out[0]=store.active; out[1]=store.pending; out[2]=store.attempted;
|
||||||
|
out[3]=healthy?1:0; info32(out+4,boot.config.session_timeout_ms); return true; }
|
||||||
|
if(page==3) { info32(out,F28335_AB_PARAMS); info32(out+4,258); return true; }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Вызывается до разрешения прикладных IRQ. Нельзя полагаться на случайное
|
||||||
|
* содержимое RAM или оставшееся состояние confirmed от предыдущей программы. */
|
||||||
|
void F28335CanBoot_EarlyInit(void) { confirmed=0; ready=0; }
|
||||||
|
/* Общий Init для приложения и загрузчика: открываем журнал, привязываем
|
||||||
|
* callbacks, задаём идентификацию, ёмкость слота, окно 16 и тайм-аут 30 секунд.
|
||||||
|
* В загрузчике FW берётся из active manifest; приложение сообщает версию сборки. */
|
||||||
|
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=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;
|
||||||
|
#else
|
||||||
|
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=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,
|
||||||
|
* чтобы слишком широкая маска Boot не перехватывала сообщения приложения.
|
||||||
|
* 72=8+64 — оба RX, 16 — TX. Регистры флагов очищаются записью единицы. */
|
||||||
|
ECanaRegs.CANME.all &= ~88UL;
|
||||||
|
ECanaMboxes.MBOX3.MSGID.all=0xC0000000UL|pcan_boot_make_id(0,0,cfg.device_type,cfg.device_id,0,0);
|
||||||
|
ECanaLAMRegs.LAM3.all=0x100FFFFFUL;
|
||||||
|
ECanaMboxes.MBOX3.MSGCTRL.all=8;
|
||||||
|
/* MBOX5 belongs to the application's heartbeat. MBOX6 is discovery only. */
|
||||||
|
ECanaMboxes.MBOX6.MSGID.all=0xC0000000UL|pcan_boot_make_id(0,0,7,15,13,0);
|
||||||
|
ECanaLAMRegs.LAM6.all=0x10000000UL; /* Ignore priority only. */
|
||||||
|
ECanaMboxes.MBOX6.MSGCTRL.all=0;
|
||||||
|
ECanaRegs.CANMD.all=(ECanaRegs.CANMD.all|72UL)&~16UL;
|
||||||
|
ECanaRegs.CANRMP.all=72UL;
|
||||||
|
ECanaRegs.CANMIM.all |=72UL;
|
||||||
|
ECanaRegs.CANME.all |=88UL;
|
||||||
|
EDIS;
|
||||||
|
}
|
||||||
|
/* ISR только проверяет заголовок и копирует кадр. Чужие адреса и RTR
|
||||||
|
* отбрасываются до очереди. Глобальный адрес допускается только для discovery;
|
||||||
|
* DLC и смысл команды окончательно проверит ядро в основном цикле. */
|
||||||
|
static void receive_box(volatile struct MBOX *box,uint32_t mask)
|
||||||
|
{
|
||||||
|
unsigned int next=(head+1U)&31U, i;
|
||||||
|
unsigned long lo, hi;
|
||||||
|
uint32_t id; unsigned int type;
|
||||||
|
if(!(ECanaRegs.CANRMP.all&mask)) return;
|
||||||
|
if(box->MSGCTRL.bit.RTR) { ECanaRegs.CANRMP.all=mask; return; }
|
||||||
|
id=box->MSGID.all&0x1FFFFFFFUL;
|
||||||
|
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)==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;
|
||||||
|
else {
|
||||||
|
queue[head].id=box->MSGID.all&0x1FFFFFFFUL;
|
||||||
|
queue[head].dlc=box->MSGCTRL.bit.DLC;
|
||||||
|
lo=box->MDL.all; hi=box->MDH.all;
|
||||||
|
for(i=0;i<4;++i) { queue[head].data[i]=(lo>>(8U*i))&255U;
|
||||||
|
queue[head].data[i+4]=(hi>>(8U*i))&255U; }
|
||||||
|
head=next;
|
||||||
|
}
|
||||||
|
ECanaRegs.CANRMP.all=mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void F28335CanBoot_RxISR(void)
|
||||||
|
{
|
||||||
|
if(!addressed) return; /* Неверный или ещё не настроенный номер PERIPH не должен принимать даже оставшиеся флаги RX. */
|
||||||
|
receive_box(&ECanaMboxes.MBOX3,8UL);
|
||||||
|
receive_box(&ECanaMboxes.MBOX6,64UL);
|
||||||
|
}
|
||||||
|
/* Вызывать после инициализации параметров, датчиков и прикладного режима.
|
||||||
|
* От этого момента отсчитывается интервал наблюдения перед авто-CONFIRM. */
|
||||||
|
void F28335CanBoot_Ready(void)
|
||||||
|
{ ready=1; ready_at=F28335Boot_Now(); }
|
||||||
|
/* Используется таймерными ISR приложения. Во время пробы кормление watchdog
|
||||||
|
* должно доказывать выполнение main: работа одного ISR не доказывает готовность.
|
||||||
|
* Старый старт без handoff сохраняет прежнюю политику watchdog. */
|
||||||
|
unsigned int F28335CanBoot_WatchdogAllowed(void)
|
||||||
|
{ return F28335Boot_RunningSlot()>1 || confirmed; }
|
||||||
|
/* Неблокирующий диспетчер относительно ожидания 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.
|
||||||
|
* Если до 10 секунд сохранение не удалось, main перестаёт кормить watchdog,
|
||||||
|
* что позволяет следующему старту откатиться к подтверждённому образу. */
|
||||||
|
if((uint32_t)(now-ready_at)<10000UL) ServiceDog();
|
||||||
|
if(main_passes<100) ++main_passes;
|
||||||
|
if(main_passes==100 && (uint32_t)(now-ready_at)>=5000UL) (void)confirm(0);
|
||||||
|
}
|
||||||
|
if(tx_busy) {
|
||||||
|
/* После CANTRR ждём завершения отмены или запоздавшего ACK, прежде чем
|
||||||
|
* повторно использовать mailbox. reset_requested к этому моменту уже снят,
|
||||||
|
* поэтому позднее подтверждение не должно перезапустить устройство. */
|
||||||
|
if(tx_canceling) {
|
||||||
|
if(!((ECanaRegs.CANAA.all|ECanaRegs.CANTA.all)&16UL)) return;
|
||||||
|
ECanaRegs.CANAA.all=16UL; ECanaRegs.CANTA.all=16UL;
|
||||||
|
tx_busy=tx_canceling=0;
|
||||||
|
} else if((uint32_t)(now-sent_at)>250UL) {
|
||||||
|
/* Cancel reset immediately, even if a late CAN ACK races CANTRR. */
|
||||||
|
reset_requested=0; pcan_boot_abort(&boot); tail=head;
|
||||||
|
tx_canceling=1; ECanaRegs.CANTRR.all=16UL; return;
|
||||||
|
} else if(ECanaRegs.CANTA.all&16UL) {
|
||||||
|
ECanaRegs.CANTA.all=16UL; tx_busy=0;
|
||||||
|
} else return;
|
||||||
|
}
|
||||||
|
if(reset_requested) { F28335Boot_Reset(reset_session); return; }
|
||||||
|
pcan_boot_poll(&boot,now);
|
||||||
|
if(tx_busy) return;
|
||||||
|
/* После потери кадра нельзя молча продолжать запись: сбрасываем RAM-сессию
|
||||||
|
* и накопленную очередь. Подтверждённый образ и опубликованный pending сохраняются. */
|
||||||
|
if(overflow || (ECanaRegs.CANRML.all&72UL)) {
|
||||||
|
overflow=0; ECanaRegs.CANRML.all=72UL;
|
||||||
|
pcan_boot_abort(&boot); tail=head; return;
|
||||||
|
}
|
||||||
|
if(tail!=head) {
|
||||||
|
pcan_boot_process(&boot,queue[tail].id,queue[tail].data,queue[tail].dlc);
|
||||||
|
tail=(tail+1U)&31U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Используем session из NOINIT только для нового ENTER_BOOT после reset.
|
||||||
|
* Это отправка отложенного ACK готовности, а не восстановление принятых блоков
|
||||||
|
* или CRC незавершённой передачи: данные сессии через reset не сохраняются. */
|
||||||
|
void F28335CanBoot_Resume(unsigned int session)
|
||||||
|
{
|
||||||
|
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(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; }
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef F28335_CAN_BOOT_H
|
||||||
|
#define F28335_CAN_BOOT_H
|
||||||
|
#include "../../include/pcan_boot.h"
|
||||||
|
/* Приложение задаёт версию из firmware_version.h до подключения этого заголовка.
|
||||||
|
* Формат поля FW: major[31:24], minor[23:16], patch[15:0]. Ноль — запасное
|
||||||
|
* значение при отсутствии версии сборки, а не прошитая здесь версия устройства. */
|
||||||
|
#ifndef F28335_CAN_BOOT_FIRMWARE_VERSION
|
||||||
|
#define F28335_CAN_BOOT_FIRMWARE_VERSION 0UL /* Board supplies the build identity. */
|
||||||
|
#endif
|
||||||
|
/* Адрес ProtoCAN состоит из Device Type (3 бита) и Device ID (4 бита).
|
||||||
|
* ProductType — отдельный код совместимости прошивки; это не CAN ID и не RS-адрес. */
|
||||||
|
#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"
|
||||||
|
/* Порядок интеграции приложения:
|
||||||
|
* StartupWatchdog/EarlyInit сразу после InitSysCtrl; Init после настройки
|
||||||
|
* таймера и EEPROM; Ready после старта прикладных подсистем; Service в main.
|
||||||
|
* RxISR вызывается из CAN ISR, WatchdogAllowed проверяется перед кормлением
|
||||||
|
* watchdog таймерным ISR. Resume применяется только отдельным загрузчиком. */
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
@@ -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. */
|
||||||
@@ -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 и поведение конкретной платы при отключении питания требуют стенда;
|
||||||
|
физическое программирование этим комплектом автоматически не выполнялось.
|
||||||
@@ -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 <file> (--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 <dir> 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 <file> (--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 <file> (--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 <dir> 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 <file> (--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>
|
||||||
@@ -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 <file> (--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 <dir> 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 <file> (--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 <file> (--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 <dir> 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 <file> (--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-параметры не программируются. */
|
||||||
@@ -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>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user