Добавить защищённое обновление приложения через RS и CAN с сохранением загрузчика, проверкой CRC, восстановлением передачи и защитой EEPROM. Подключить общий процесс сборки C2000 и автоматический счётчик версии для согласованных RAM, Flash, CAN и паспортов бинарных образов. Уточнить запуск ЦАП, обработку измерений и параметров нагрузки, начальную индикацию и документацию регистров GAS. Дополнить модели аппаратуры и изолировать заголовки CAN в тестах. Проверка: 26 тестов выпуска, 4 теста восстановления CAN и восемь программных моделей CAN, Flash, EEPROM, ЦАП, параметров и TESTLAMP.
201 lines
33 KiB
C
201 lines
33 KiB
C
#if defined(FLASH_BOOT) /* Подключает Flash API только к образу, исполняемому из внутренней Flash. */
|
|
#include "DSP2833x_Device.h" /* Предоставляет регистры SCI, watchdog, CSM и действующую частоту SYSCLKOUT в герцах. */
|
|
#include "flash_rs.h" /* Связывает алгоритм с существующим загрузчиком RAM и выбранным RS-портом. */
|
|
#include "bios_dsp.h" /* Использует неизменный номер CMD_TFLASH действующего BIOS-протокола. */
|
|
#include "DAC.h" /* Проверяет завершённую штатную остановку нагрузки до отключения Timer1 на время стирания. */
|
|
#include "Flash2833x_API_Library.h" /* Вызывает официальный алгоритм TI v2.10 для стирания, записи и проверки F28335. */
|
|
#include <string.h> /* Переносит код и константы Flash API во внутреннюю RAM до изменения Flash. */
|
|
#include "../protocan-boot/ports/tms320f28335/f28335_flash_app.c" /* Путь разрешается от штатного include c/set-protocol; общий FAB1/CRC проверяется до первого стирания Flash. */
|
|
extern void ServiceDog(void); /* Во время длительных предварительных CRC прерывания уже запрещены, поэтому watchdog обслуживается из проверяемого главного контекста. */
|
|
extern Uint16 FlashRsLoadStart, FlashRsLoadEnd, FlashRsRunStart; /* Границы отдельной секции задаёт F28335_flash.cmd в адресуемых 16-битных словах. */
|
|
static Uint16 program_buffer[128]; /* Буфер на 128 слов хранится во внутренней RAM; он не зависит от стираемых секторов или порядка байтов RS. */
|
|
static FLASH_ST api_status; /* Внутренняя RAM сохраняет адрес и данные первой ошибки официального Flash API. */
|
|
static unsigned int flash_load_guard(unsigned long length) /* Проверяет разрешение записи до CRC/erase, сохраняя безопасную пробу поддержки с нулевой длиной. */
|
|
{ /* Делегирует состояние нагрузки её единственному владельцу, не дублируя управление GPIO внутри загрузчика. */
|
|
return length && !Load_flash_safe() ? 0x1005U : 0U; /* Статус 0x1005 требует штатного STOP и подтверждённых 4 мА; probe длины ноль никогда не останавливает работу нагрузки. */
|
|
} /* После положительной проверки вызывающий код удерживает IRQ заблокированными до автономной записи. */
|
|
#pragma CODE_SECTION(byte_at, "flash_rs") /* Размещает декодер упакованных RS-байтов в копируемой секции RAM. */
|
|
static Uint16 byte_at(const Uint16 *data, Uint32 offset) /* Читает октет из старшего байта чётного слова и младшего байта нечётного, как RS_RX_Handler. */
|
|
{ /* Начинает независимый от Flash декодер входного блока. */
|
|
return (offset & 1UL) ? (data[offset >> 1] & 255U) : (data[offset >> 1] >> 8); /* Преобразует упаковку RS в октеты без обращения к таблицам или runtime. */
|
|
} /* Завершает чтение одного октета. */
|
|
#pragma CODE_SECTION(word_at, "flash_rs") /* Делает декодирование формата SCI8 доступным после стирания Flash. */
|
|
static Uint16 word_at(const Uint16 *data, Uint32 offset) /* Читает слово TI boot table, в котором младший октет передаётся первым. */
|
|
{ /* Начинает объединение двух октетов. */
|
|
return byte_at(data, offset) | (byte_at(data, offset + 1UL) << 8); /* Восстанавливает 16-битное слово, сохраняя отличие от внутренней упаковки RS. */
|
|
} /* Завершает чтение слова SCI8. */
|
|
#pragma CODE_SECTION(long_at, "flash_rs") /* Декодирует адреса без обращения к коду стираемой программы. */
|
|
static Uint32 long_at(const Uint16 *data, Uint32 offset) /* Формат TI передаёт старшее 16-битное слово адреса перед младшим. */
|
|
{ /* Начинает чтение 32-битного адреса в словах C28x. */
|
|
return ((Uint32)word_at(data, offset) << 16) | word_at(data, offset + 2UL); /* Объединяет два слова без зависимости от порядка байтов процессора ПК. */
|
|
} /* Завершает декодирование адреса. */
|
|
#pragma CODE_SECTION(crc_byte, "flash_rs") /* Вычисляет CRC без таблицы crc16, расположенной в стираемом секторе G. */
|
|
static Uint16 crc_byte(Uint16 crc, Uint16 value) /* Продвигает стандартный CRC16 Modbus, используемый существующим RS-протоколом. */
|
|
{ /* Начинает обработку одного октета сообщения. */
|
|
Uint16 bit; /* Счётчик восьми битов октета не требует библиотечной арифметики. */
|
|
crc ^= value; /* Добавляет младший октет к состоянию отражённого CRC. */
|
|
for (bit = 0; bit < 8U; ++bit) /* Полином применяется ровно к восьми передаваемым битам. */
|
|
crc = (crc & 1U) ? ((crc >> 1) ^ 0xA001U) : (crc >> 1); /* 0xA001 — отражённый полином CRC16 Modbus, совпадающий с проверкой GUI. */
|
|
return crc; /* Возвращает состояние без вызовов функции из Flash. */
|
|
} /* Завершает шаг CRC. */
|
|
typedef struct { const Uint16 *data; Uint32 length; } flash_image_source; /* Описывает проверенную таблицу SCI8 в staging RAM без доступа к настоящей Flash. */
|
|
static uint16_t image_read_word(void *user, uint32_t wanted) /* Предоставляет общему валидатору будущие Flash-слова, включая стёртые промежутки. */
|
|
{ /* Вызывается только после проверки границ и отсутствия пересечений в validate_image. */
|
|
flash_image_source *source = (flash_image_source *)user; /* Контекст ограничивает чтение фактической длиной загруженной таблицы. */
|
|
Uint32 offset = 22UL, address; Uint16 count; /* Заголовок TI занимает 22 октета; адреса назначения выражены словами C28x. */
|
|
if (!(wanted & 255UL)) ServiceDog(); /* Подтверждает продвижение CRC каждые 256 слов до erase, пока обычный таймерный ISR отключён. */
|
|
while (offset + 2UL <= source->length) { /* Ищет слово только среди полностью проверенных блоков. */
|
|
count = word_at(source->data, offset); offset += 2UL; /* Нулевой размер завершает таблицу без адресного поля. */
|
|
if (!count) break; /* Отсутствующее слово должно остаться стёртым после обновления приложения. */
|
|
address = long_at(source->data, offset); offset += 4UL; /* Восстанавливает абсолютный LOAD-адрес секции. */
|
|
if (wanted >= address && wanted - address < count) return word_at(source->data, offset + 2UL * (wanted - address)); /* Читает запрошенное слово в упаковке действующего RS LOAD. */
|
|
offset += 2UL * count; /* Пропускает проверенные октеты текущего блока. */
|
|
} /* Промежутки не наследуют старую прошивку, поскольку все секторы приложения будут стёрты. */
|
|
return 0xFFFFU; /* Стёртое слово входит в общую CRC FAB1 по его двум физическим октетам. */
|
|
} /* Callback не изменяет staging RAM, EEPROM или внутреннюю Flash. */
|
|
#pragma CODE_SECTION(reply_status, "flash_rs") /* Передаёт итог даже после удаления старой программы и её ISR. */
|
|
static void reply_status(RS_DATA *rs, Uint16 status) /* Ответ содержит адрес, команду, 16-битный статус и CRC; SCI и RS485 обслуживаются опросом. */
|
|
{ /* Начинает автономную передачу подтверждения из RAM. */
|
|
Uint16 frame[8], crc = 0xFFFFU, i; /* Шесть октетов кадра и два завершающих нуля соответствуют традиционным ответам BIOS. */
|
|
volatile Uint32 guard; /* Ограничивает ожидание SCI, чтобы отказ передатчика не блокировал завершение навсегда. */
|
|
frame[0] = rs->addr_recive; /* Отвечает на фактический адрес запроса, поддерживая обычный и сервисный адрес платы. */
|
|
frame[1] = CMD_TFLASH; /* Номер 55 сохраняет совместимость с таблицей длин существующего загрузчика. */
|
|
frame[2] = status & 255U; /* Передаёт младший октет результата TI API либо ошибки проверки образа. */
|
|
frame[3] = status >> 8; /* Передаёт старший октет статуса для различения ошибок загрузчика и API. */
|
|
for (i = 0; i < 4U; ++i) crc = crc_byte(crc, frame[i]); /* Контрольная сумма защищает и адрес, и конкретный результат записи. */
|
|
frame[4] = crc & 255U; /* CRC Modbus передаёт младший октет первым. */
|
|
frame[5] = crc >> 8; /* Передаёт старший октет контрольной суммы. */
|
|
frame[6] = frame[7] = 0; /* Сохраняет два завершающих нуля действующего RS-протокола. */
|
|
rs->SciRegs->SCICTL2.bit.TXINTENA = 0; /* Передача не должна вызывать ISR из удаляемой Flash. */
|
|
rs->SciRegs->SCICTL2.bit.RXBKINTENA = 0; /* Приём во время итогового ответа также не обращается к старому обработчику. */
|
|
rs->SciRegs->SCIFFTX.bit.TXFFIENA = 0; /* Отключает FIFO-прерывание для автономной передачи опросом. */
|
|
rs->SciRegs->SCIFFRX.bit.RXFFIENA = 0; /* Исключает FIFO RX ISR до восстановления обычного приёма или перезапуска. */
|
|
rs->SciRegs->SCICCR.bit.PARITYENA = 0; /* Ответ передаётся в режиме 8N1, принятом в обычном подтверждении BIOS. */
|
|
if (rs->commnumber == COM_2) GpioDataRegs.GPBDAT.bit.GPIO34 = 0; /* На этой плате низкий GPIO34 включает передатчик RS485, как RS_Line_to_send. */
|
|
for (i = 0; i < 8U; ++i) /* Последовательно отправляет кадр и завершающие байты без прерываний. */
|
|
{ /* Начинает ожидание свободного места в передатчике. */
|
|
guard = 10000000UL; /* Десять миллионов опросов дают запас на восемь байтов при штатных скоростях RS. */
|
|
while (!rs->SciRegs->SCICTL2.bit.TXRDY && --guard) {} /* Не переписывает SCITXBUF, пока предыдущее слово не принято передатчиком. */
|
|
if (!guard) break; /* Завершает попытку при неисправном или отключённом SCI. */
|
|
rs->SciRegs->SCITXBUF = frame[i]; /* Передаёт один восьмибитный октет по выбранному SCI-A или SCI-B. */
|
|
} /* Завершает отправку кадра. */
|
|
guard = 10000000UL; /* Ограничивает ожидание ухода последнего стопового бита тем же запасом. */
|
|
while ((rs->SciRegs->SCIFFTX.bit.TXFFST || !rs->SciRegs->SCICTL2.bit.TXEMPTY) && --guard) {} /* Для FIFO SCI-A ждёт также опустошения очереди, чтобы не потерять конец кадра при выключении RS485 или reset. */
|
|
if (rs->commnumber == COM_2) GpioDataRegs.GPBDAT.bit.GPIO34 = 1; /* Возвращает направление RS485 к приёму после завершения кадра. */
|
|
} /* Завершает автономный ответ. */
|
|
#pragma CODE_SECTION(validate_image, "flash_rs") /* Проверка таблицы также находится в RAM и не зависит от Flash API. */
|
|
static Uint16 validate_image(const Uint16 *data, Uint32 length) /* Проверяет весь образ до первого стирания, включая загрузочный переход и запрещённые адреса CSM. */
|
|
{ /* Начинает проверку структуры таблицы TI SCI8. */
|
|
Uint32 offset = 22UL, address, bytes, entry_address, prior, prior_address; /* Заголовок TI занимает 11 слов; дополнительные курсоры проверяют перекрытия и наличие данных по адресу входа. */
|
|
Uint16 count, boot = 0, entry = 0, prior_count; /* Требует один полный FAB1 и явный блок исполняемого кода по адресу входа. */
|
|
flash_image_source source; Uint32 checked_entry; /* Общий валидатор пересчитает CRC будущего приложения до стирания. */
|
|
if (length < 24UL || (length & 1UL) || word_at(data, 0) != 0x08AAU) return 0x1002U; /* Ключ SCI8 и чётный размер исключают обычный плоский EEPROM BIN. */
|
|
address = long_at(data, 18UL); /* Адрес входа следует после восьми резервных слов заголовка TI. */
|
|
entry_address = address; /* Сохраняет адрес для проверки наличия соответствующих исполняемых слов в таблице. */
|
|
if (address < F28335_FLASH_APP_DATA || address >= F28335_FLASH_APP_STOP) return 0x1002U; /* Точка входа следует после FAB1; весь сектор постоянного boot исключён. */
|
|
while (offset + 2UL <= length) /* Читает блоки только в пределах подтверждённого загрузчиком массива. */
|
|
{ /* Начинает проверку очередного блока. */
|
|
count = word_at(data, offset); /* Размер блока выражен в 16-битных словах C28x, а не октетах RS. */
|
|
offset += 2UL; /* Продвигает курсор за поле длины. */
|
|
if (!count) { /* После структурной проверки таблицы подтверждает общий контракт FAB1 и CRC будущей Flash. */
|
|
if (offset != length || boot != 1U || !entry) return 0x1002U; /* Хвост, отсутствующее описание или отсутствующий код не допускаются. */
|
|
source.data = data; source.length = length; /* Передаёт общему валидатору только проверенный staging-блок. */
|
|
return f28335_flash_app_validate(image_read_word, &source, &checked_entry) && checked_entry == entry_address ? 0U : 0x1002U; /* Повреждение описания, диапазона или данных выявляется до Flash_Erase. */
|
|
} /* Только полностью проверенный образ допускает обновление приложения. */
|
|
if (offset + 4UL > length) return 0x1002U; /* Не читает обрезанный 32-битный адрес назначения. */
|
|
address = long_at(data, offset); /* Читает адрес в формате старшее слово, затем младшее. */
|
|
offset += 4UL; /* Переводит курсор к первому слову данных блока. */
|
|
bytes = (Uint32)count << 1; /* Каждое слово программы соответствует двум октетам файла. */
|
|
if (bytes > length - offset) return 0x1002U; /* Проверяет остаток файла без возможности выхода за границы массива. */
|
|
if (address < F28335_FLASH_APP_START || address >= F28335_FLASH_APP_STOP || (Uint32)count > F28335_FLASH_APP_STOP - address) return 0x1002U; /* Весь сектор A, включая аппаратный вход 0x33FFF6, защищён независимо от типа блока. */
|
|
if (address == F28335_FLASH_APP_START) { if (count < F28335_FLASH_APP_HEADER_WORDS) return 0x1002U; ++boot; } /* Все 16 слов FAB1 должны находиться вместе для публикации описания последней стадией. */
|
|
if (entry_address >= address && entry_address < address + count) entry = 1U; /* Подтверждает, что после boot-перехода процессор получит код из текущего образа. */
|
|
prior = 22UL; /* Начинает сравнение диапазона с уже проверенными блоками таблицы. */
|
|
while (prior < offset - 6UL) /* Повторно рассматривает только заголовки, прошедшие проверки границ выше. */
|
|
{ /* Начинает проверку одного предыдущего диапазона. */
|
|
prior_count = word_at(data, prior); /* Предыдущая длина уже подтверждена и не может вывести курсор за массив. */
|
|
prior_address = long_at(data, prior + 2UL); /* Читает ранее проверенный Flash-адрес. */
|
|
if (address < prior_address + prior_count && prior_address < address + count) return 0x1002U; /* Не разрешает повторную запись слова Flash из разных блоков даже при корректном CRC. */
|
|
prior += 6UL + ((Uint32)prior_count << 1); /* Пропускает предыдущий заголовок и все его октеты данных. */
|
|
} /* Завершает сравнение с предыдущими секциями. */
|
|
offset += bytes; /* Переходит к следующему полностью проверенному блоку. */
|
|
} /* Завершает обход блоков. */
|
|
return 0x1002U; /* Отсутствие нулевого терминатора делает образ неполным. */
|
|
} /* Завершает проверку адресов и структуры. */
|
|
#pragma CODE_SECTION(program_image, "flash_rs") /* Весь участок от стирания до завершения выполняется из внутренней RAM. */
|
|
static void program_image(RS_DATA *rs, const Uint16 *data, Uint32 length) /* Никогда не возвращается в удалённую программу после первого вызова Flash_Erase. */
|
|
{ /* Начинает автономный алгоритм записи и проверки. */
|
|
Uint32 offset = 22UL, address, boot_offset = 0UL; /* Хранит курсоры данных и отложенного загрузочного перехода во внутренней RAM. */
|
|
Uint16 count, chunk, i, status; /* Состояние API и размеры блоков не зависят от внешних таблиц. */
|
|
status = Flash_Erase(0x00FEU, &api_status); /* TI v2.10: бит 0 — сектор A; маска FE стирает только B–H и сохраняет постоянный CAN boot вместе с аппаратным входом. */
|
|
while (!status && offset < length) /* Программирует блоки только после успешного стирания всех секторов. */
|
|
{ /* Начинает обработку очередной секции изображения. */
|
|
count = word_at(data, offset); /* Использует размер, уже проверенный до входа в критический участок. */
|
|
offset += 2UL; /* Пропускает поле количества слов. */
|
|
if (!count) break; /* Нулевой блок означает конец файла TI. */
|
|
address = long_at(data, offset); /* Восстанавливает Flash-адрес текущей секции. */
|
|
offset += 4UL; /* Переводит курсор к полезным словам секции. */
|
|
if (address == F28335_FLASH_APP_START) { boot_offset = offset; offset += 2UL * F28335_FLASH_APP_HEADER_WORDS; address += F28335_FLASH_APP_HEADER_WORDS; count -= F28335_FLASH_APP_HEADER_WORDS; } /* Откладывает 16 слов FAB1; соседний код того же блока программируется обычным порядком. */
|
|
while (count && !status) /* Делит большие секции на буферные порции без переполнения RAM. */
|
|
{ /* Начинает запись очередной порции. */
|
|
chunk = count > 128U ? 128U : count; /* Ограничение совпадает с размером внутреннего программирующего буфера в словах. */
|
|
for (i = 0; i < chunk; ++i) program_buffer[i] = word_at(data, offset + ((Uint32)i << 1)); /* Распаковывает байты RS в слова, ожидаемые Flash API. */
|
|
status = Flash_Program((Uint16 *)address, program_buffer, chunk, &api_status); /* Использует официальный алгоритм записи F28335 вместо обычной записи указателем. */
|
|
if (!status) status = Flash_Verify((Uint16 *)address, program_buffer, chunk, &api_status); /* Подтверждает записанные слова чтением из Flash до перехода к следующей порции. */
|
|
offset += (Uint32)chunk << 1; /* Продвигает курсор файла на фактически обработанные октеты. */
|
|
address += chunk; /* Продвигает Flash-адрес на количество адресуемых слов C28x. */
|
|
count -= chunk; /* Уменьшает остаток текущей секции. */
|
|
} /* Завершает запись секции. */
|
|
} /* Завершает запись обычных блоков. */
|
|
if (!status && boot_offset) /* Разрешает запуск нового образа только после проверки всех предыдущих секций. */
|
|
{ /* Начинает фиксацию аппаратной точки входа. */
|
|
for (i = 0; i < F28335_FLASH_APP_HEADER_WORDS; ++i) program_buffer[i] = word_at(data, boot_offset + 2UL * i); /* Восстанавливает FAB1 только после записи и проверки всех LOAD-секций приложения. */
|
|
status = Flash_Program((Uint16 *)F28335_FLASH_APP_START, program_buffer, F28335_FLASH_APP_HEADER_WORDS, &api_status); /* Публикует CRC и entry в секторе H, не меняя аппаратный boot сектора A. */
|
|
if (!status) status = Flash_Verify((Uint16 *)F28335_FLASH_APP_START, program_buffer, F28335_FLASH_APP_HEADER_WORDS, &api_status); /* Подтверждает весь заголовок чтением до watchdog reset. */
|
|
} /* Завершает фиксацию загрузочного перехода. */
|
|
reply_status(rs, status); /* Отправляет конкретный результат после записи и аппаратной проверки. */
|
|
if (!status) { EALLOW; SysCtrlRegs.WDCR = 0x0028U; EDIS; } /* Успех включает watchdog для аппаратного перезапуска; режим загрузки задают GPIO84–87. */
|
|
for (;;) {} /* Не возвращается в удалённый код; при успехе watchdog перезапустит устройство, при ошибке требуется восстановление. */
|
|
} /* Завершает автономный алгоритм. */
|
|
void FlashRs_Command(RS_DATA *rs) /* До стирания проверяет исходный блок и копирует все необходимые функции во внутреннюю RAM. */
|
|
{ /* Начинает обработку команды действующего загрузчика. */
|
|
Uint32 source, length, destination, i; /* Адреса и длина команды передаются младшим октетом вперёд в BIOS-протоколе. */
|
|
Uint16 status = 0U, crc, saved; /* Сохраняет код API, CRC и прежнюю маску IRQ для безопасного возврата после пробы либо отказа до стирания. */
|
|
source = (Uint32)rs->RS_Header[6] | ((Uint32)rs->RS_Header[7] << 8) | ((Uint32)rs->RS_Header[8] << 16) | ((Uint32)rs->RS_Header[9] << 24); /* Поле источника задаёт адрес ранее загруженного блока RAM. */
|
|
length = (Uint32)rs->RS_Header[10] | ((Uint32)rs->RS_Header[11] << 8) | ((Uint32)rs->RS_Header[12] << 16) | ((Uint32)rs->RS_Header[13] << 24); /* Поле длины выражено в октетах файла, как команда INITLOAD. */
|
|
destination = (Uint32)rs->RS_Header[2] | ((Uint32)rs->RS_Header[3] << 8) | ((Uint32)rs->RS_Header[4] << 16) | ((Uint32)rs->RS_Header[5] << 24); /* Адрес 0x300000 подтверждает назначение команды внутренней Flash. */
|
|
memcpy(&FlashRsRunStart, &FlashRsLoadStart, &FlashRsLoadEnd - &FlashRsLoadStart); /* Копирует функции, константы и библиотеку TI до возможного стирания их загрузочного сектора. */
|
|
saved = __disable_interrupts(); /* Не позволяет CAN/таймеру регистратора изменить внешний RAM-буфер между повторной проверкой CRC и передачей управления автономному загрузчику. */
|
|
if (CsmRegs.CSMSCR.bit.SECURE) status = 0x1004U; /* Защищённое устройство не должно переходить к стиранию без корректного разблокирования CSM. */
|
|
if (!status) status = flash_load_guard(length); /* Активная/неостановленная нагрузка получает отказ до доступа к Flash API; GPIO и уставку меняет только штатный автомат Timer1. */
|
|
if (!status && (source || length || destination)) /* Нулевая тройка параметров — только проверка поддержки, без доступа к буферу и стирания. */
|
|
{ /* Начинает проверку команды программирования. */
|
|
if (destination != 0x300000UL || source < 0x200000UL || source >= 0x20FC00UL || length < 24UL || length > ((0x20FC00UL - source) << 1) - 2UL || !rs->BS_LoadOK || (Uint32)rs->pRecvPtr != source || rs->RS_Length != length + 2UL) status = 0x1003U; /* Принимает лишь CRC-подтверждённый блок в штатной внешней RAM, включая место для принятого CRC. */
|
|
if (!status) /* Перепроверяет байты буфера после LOAD, защищая от изменения RAM до стирания. */
|
|
{ /* Начинает повторное вычисление CRC исходного кадра LOAD. */
|
|
crc = crc_byte(crc_byte(0xFFFFU, rs->addr_recive), CMD_LOAD); /* CRC включает тот же адрес и номер команды, что и первоначальная передача блока. */
|
|
for (i = 0; i < length; ++i) { crc = crc_byte(crc, byte_at((Uint16 *)source, i)); if (!(i & 255UL)) ServiceDog(); } /* Повторная CRC LOAD проверяет каждую октету и обслуживает watchdog при уже запрещённых ISR до стирания. */
|
|
if (crc != word_at((Uint16 *)source, length)) status = 0x1003U; /* Запрещает стирание, если блок RAM отличается от подтверждённого загрузчиком. */
|
|
else status = validate_image((Uint16 *)source, length); /* Подтверждает все адреса ниже сектора A, полное FAB1 и CRC будущего Flash-приложения до erase. */
|
|
} /* Завершает проверки буфера. */
|
|
} /* Завершает предварительную проверку команды. */
|
|
if (!status && length) /* Входит в автономный участок только для полностью проверенной ненулевой записи. */
|
|
{ /* Начинает остановку обычного приложения перед обновлением. */
|
|
Flash_CPUScaleFactor = (Uint32)(1048576.0L * (200.0L * (long double)SYSCLKOUT / 1000000000.0L)); /* Формула TI IQ20 использует реальный SYSCLKOUT в герцах вместо ошибочного фиксированного значения 150 МГц. */
|
|
Flash_CallbackPtr = 0; /* Исключает callback из стираемой программы во время операции Flash API. */
|
|
DINT; /* Запрещает все обычные ISR, размещённые в обновляемой Flash. */
|
|
EALLOW; /* Разрешает запись защищённых регистров watchdog и аварийного отключения PWM. */
|
|
SysCtrlRegs.WDCR = 0x0068U; /* Отключает watchdog на время стирания, которое может длиться несколько секунд. */
|
|
EPwm1Regs.TZCTL.all = EPwm2Regs.TZCTL.all = EPwm3Regs.TZCTL.all = EPwm4Regs.TZCTL.all = EPwm5Regs.TZCTL.all = EPwm6Regs.TZCTL.all = 0x000AU; /* Коды TZA=2 и TZB=2 переводят оба PWM-выхода в низкий уровень при аварийном отключении. */
|
|
EPwm1Regs.TZFRC.bit.OST = EPwm2Regs.TZFRC.bit.OST = EPwm3Regs.TZFRC.bit.OST = EPwm4Regs.TZFRC.bit.OST = EPwm5Regs.TZFRC.bit.OST = EPwm6Regs.TZFRC.bit.OST = 1; /* Принудительно блокирует PWM до перезапуска новой прошивки. */
|
|
EDIS; /* Завершает доступ к защищённым регистрам перед вызовом TI API. */
|
|
program_image(rs, (Uint16 *)source, length); /* После первого стирания управление остаётся в RAM до ответа и перезапуска. */
|
|
} /* Завершает путь программирования. */
|
|
reply_status(rs, status); /* Проба поддержки и ошибки до стирания возвращают короткий проверяемый ответ. */
|
|
RS_SetBitMode(rs, 9); /* Восстанавливает стандартный приём BIOS после безопасного отказа или пробы возможностей. */
|
|
rs->SciRegs->SCICTL2.bit.RXBKINTENA = 1; /* Возвращает обычное обслуживание следующих запросов RS. */
|
|
if (rs->commnumber == COM_1) rs->SciRegs->SCIFFRX.bit.RXFFIENA = 1; /* SCI-A в существующем драйвере принимает данные через FIFO-прерывание. */
|
|
__restore_interrupts(saved); /* При пробе или отказе до стирания возвращает ровно прежнее состояние прерываний приложения. */
|
|
} /* Завершает команду до стирания; после стирания эта функция не получает управление. */
|
|
#endif /* Обычный EEPROM/RAM-образ не включает объёмную библиотеку программирования Flash. */
|