Files
Andrey 05be38a04a Обновить Flash/CAN, версии сборок и управление периферией
Добавить защищённое обновление приложения через RS и CAN с сохранением
загрузчика, проверкой CRC, восстановлением передачи и защитой EEPROM.
Подключить общий процесс сборки C2000 и автоматический счётчик версии
для согласованных RAM, Flash, CAN и паспортов бинарных образов.

Уточнить запуск ЦАП, обработку измерений и параметров нагрузки,
начальную индикацию и документацию регистров GAS.
Дополнить модели аппаратуры и изолировать заголовки CAN в тестах.

Проверка: 26 тестов выпуска, 4 теста восстановления CAN и восемь
программных моделей CAN, Flash, EEPROM, ЦАП, параметров и TESTLAMP.
2026-11-06 16:11:11 +03:00

344 lines
29 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Порядок запуска периферии и обслуживание команд в главном цикле. Русские пояснения сохранены в UTF-8. */
/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include <string.h> /* Предоставляет memset для начального обнуления карты регистров и memcpy для переноса ramfuncs из Flash в RAM. */
extern unsigned int RamfuncsLoadStart, RamfuncsLoadEnd, RamfuncsRunStart; /* Оба linker-варианта экспортируют границы копирования в адресуемых словах C28x. */
/* Подключает "cntrl_adr.h": собственный и универсальный адрес устройства. */
#include "cntrl_adr.h"
/* Подключает "RS485.h": приём и передача SCI-A/SCI-B, упаковка команд и FIFO первого порта. */
#include "RS485.h"
/* Подключает "BIOS_DSP.h": настройки и интерфейс BIOS_DSP. */
#include "BIOS_DSP.h"
/* Подключает "Message.h": настройки и интерфейс Message. */
#include "Message.h"
/* Подключает "filter_bat2.h": накопительный фильтр измерительных каналов. */
#include "filter_bat2.h"
/* Подключает "measure.h": обработка датчиков, вычисление величин и миллисекундный такт системы. */
#include "measure.h"
/* Подключает "package.h": адреса устройств, типы плат и псевдонимы технологических регистров. */
#include "package.h"
/* Подключает "spise2p.h": драйвер SPI EEPROM, адресация, страницы и автомат завершения операций. */
#include "spise2p.h"
/* Подключает "tools.h": настройка внешней памяти и служебные задержки. */
#include "tools.h"
/* Подключает "peripher.h": перемычки режима платы, дискретные входы и выходы. */
#include "peripher.h"
/* Подключает "ADC.h": настройка АЦП, обработка преобразований и первичная фильтрация измерений. */
#include "ADC.h"
/* Подключает "DAC.h": выход ЦАП и автомат защиты нагрузки с проверкой напряжения и свежести CAN. */
#include "DAC.h"
/* Подключает "ecan.h": штатный eCAN и отдельный служебный обмен УМП/GAS. */
#include "ecan.h"
#include "can_boot.h" /* Подключает готовые CAN Boot, handoff и контроль подтверждения приложения. */
/* Подключает "kanal.h": последовательный вывод данных канала индикации. */
#include "kanal.h"
/* Подключает "pulto.h": обмен и индикация пульта. */
#include "pulto.h"
/* Подключает "log_to_mem.h": двухбанковый регистратор событий нагрузки во внешней RAM. */
#include "log_to_mem.h"
/* Подключает "measure.h": обработка датчиков, вычисление величин и миллисекундный такт системы. */
#include "measure.h"
/* Объявляет интерфейс функции DSP28x_usDelay; реализация вызывается через этот прототип. */
extern void DSP28x_usDelay(Uint32 Count);
/* Назначает обработчик Timer1 по типу платы и задаёт период основного такта. */
void timer_Init()
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Разрешение записи в защищённые регистры периферии. */
EALLOW; // This is needed to write to EALLOW protected registers
/* Проверяет if(Desk==dsk_EPLT) PieVectTable.XINT13 = &cpu_timer1_isr_PULT; последующий оператор выполняется только при истинном условии. */
if(Desk==dsk_EPLT) PieVectTable.XINT13 = &cpu_timer1_isr_PULT;
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
else PieVectTable.XINT13 = &cpu_timer1_isr_SENS;
/* Закрытие доступа к защищённым регистрам периферии. */
EDIS; // This is needed to disable write to EALLOW protected registers
/* Вызывает ConfigCpuTimer с аргументами (&CpuTimer1, SYSCLKOUT/1000000, 1000000/READY_FREQ) в текущей последовательности операций. */
ConfigCpuTimer(&CpuTimer1, SYSCLKOUT/1000000, 1000000/READY_FREQ);
/* Записывает CpuTimer1Regs.TCR.all значением 0x4020; представление регистра целым словом без разбиения на битовые поля. */
CpuTimer1Regs.TCR.all = 0x4020; // Use write-only instruction to set TSS bit = 0
/* Устанавливает биты IER значением M_INT13; регистр разрешения прерываний ядра C28x. */
IER |= M_INT13;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Точка входа: настраивает периферию, загружает параметры и обслуживает команды в главном цикле. */
void main()
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Объявляет i — данные i; j — данные j; mask — маска. */
int i,j; /* Счётчики обслуживают RS-порты; курсоры CAN и маски теперь принадлежат независимому сервису телеметрии. */
/* Делитель внешнего Modbus-опроса принадлежит main; состояние рассылки CAN хранится и сбрасывается в ecan.c. */
static unsigned int rscount; /* Сохраняет только делитель опроса OWEN; частота CAN больше не зависит от этого счётчика. */
/* Объявляет rs — данные rs. Хранит указатель на данные. */
RS_DATA * rs;
/* Объявляет presbyt — данные presbyt. Начальное значение задаётся справа от знака равенства. */
int presbyt=0;
DINT; /* Запрещает IRQ до очистки рабочих регистров: Timer1 и приём CAN не должны читать или менять частично инициализированную карту. */
memset(modbus, 0, (ANSWER_LEN + 1U) * sizeof(modbus[0])); /* Обнуляет все 129 адресуемых слов до настройки периферии: COFF startup не очищает .ebss, а initializer {0} у TI заполняет только первый явно указанный элемент. */
/* Инициализирует модуль вызовом InitSysCtrl(); перед его дальнейшим использованием. */
InitSysCtrl();
F28335Boot_StartupWatchdog(); /* Сразу включает watchdog кандидата и запрещает ISR скрывать зависание main до CONFIRM. */
if (&RamfuncsLoadStart != &RamfuncsRunStart) /* RAM-образ не копирует одинаковые диапазоны; Flash-образ переносит InitFlash перед изменением wait states. */
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, &RamfuncsLoadEnd - &RamfuncsLoadStart); /* Размер равен разности адресуемых 16-битных слов TI, а не физическим октетам ПК. */
InitFlash(); /* Вызывает находящийся в RAM код настройки Flash-пайплайна и задержек для штатного SYSCLKOUT. */
// Disable CPU interrupts and clear all CPU interrupt flags:
/* Запрет маскируемых прерываний ядра. */
DINT;
/* Инициализирует модуль вызовом InitPieCtrl(); перед его дальнейшим использованием. */
InitPieCtrl();
/* Записывает IER значением 0x0000; регистр разрешения прерываний ядра C28x. */
IER = 0x0000;
/* Записывает IFR значением 0x0000; регистр ожидающих прерываний ядра C28x. */
IFR = 0x0000;
/* Инициализирует модуль вызовом InitPieVectTable(); перед его дальнейшим использованием. */
InitPieVectTable();
/* Вызывает init_zone7. Настраивает временные параметры внешней шины XINTF Zone7 для RAM регистратора. */
init_zone7();
/* Вызывает get_Mode. Определяет адрес и тип платы по аппаратным перемычкам и задаёт рабочий режим. */
get_Mode();
/* Вызывает InitCan. Настраивает eCAN, скорость, почтовые ящики и маршрутизацию прерываний для выбранного режима платы. */
InitCan(0,Mode);
/* Вызывает create_uart_vars. Инициализирует структуры обоих SCI и таблицу длин команд. */
create_uart_vars(sizeof(CMD_TO_TMS));
/* Вызывает setup_uart. Настраивает выбранный SCI, скорость и обработчики прерываний. */
setup_uart(COM_1,115200);
/* Проверяет if(Owen)setup_uart(COM_2,57600); последующий оператор выполняется только при истинном условии. */
if(Owen)setup_uart(COM_2,9600);
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
else setup_uart(COM_2,115200);
/* Инициализирует модуль вызовом InitSeeprom(); перед его дальнейшим использованием. */
InitSeeprom();
/* Вызывает setup_leds_line с аргументами () в текущей последовательности операций. */
setup_leds_line();
/* Вызывает led1_on с аргументами () в текущей последовательности операций. */
led1_on();
/* Вызывает led2_off с аргументами () в текущей последовательности операций. */
led2_off();
/* Цикл for (i=0;i<10;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
for (i=0;i<10;i++)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Вызывает pause_us. Формирует задержку в микросекундах через калиброванную функцию DSP28x_usDelay. */
pause_us(50000);
ServiceDog(); /* Подтверждает продвижение раннего main каждые 50 мс; до CONFIRM кандидат не получает кормление из ISR. */
/* Вызывает led2_toggle с аргументами () в текущей последовательности операций. */
led2_toggle();
/* Вызывает led1_toggle с аргументами () в текущей последовательности операций. */
led1_toggle();
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Вызывает led1_off с аргументами () в текущей последовательности операций. */
led1_off();
/* Вызывает led2_off с аргументами () в текущей последовательности операций. */
led2_off();
/* Вызывает unsetup_leds_line с аргументами () в текущей последовательности операций. */
unsetup_leds_line();
/* Вызывает clear_mem. Обнуляет выделенный диапазон внешней RAM журнала и задаёт границы кольцевого буфера. */
clear_mem();
/* Вызывает ump_log_init. Явно инициализирует оба банка регистратора до включения IRQ; повторный старт записи архив не стирает. */
ump_log_init();
Load_control_init(); /* Explicit initialization before IRQ. */ /* Вызывает Load_control_init. Сбрасывает все переменные автомата нагрузки до разрешения прерываний; COFF не обнуляет всю .ebss. */
/* Вызывает set_cntrl_addr. Устанавливает собственный и универсальный адрес для проверки адресованных команд. */
set_cntrl_addr(Mode,16);
rscount = 0U; /* Обнуляет делитель OWEN до Timer1, чтобы остатки RAM не задержали первый опрос внешнего прибора. */
/* Назначает обработчик Timer1 по типу платы и задаёт период основного такта после сброса программных делителей. */
timer_Init();
/* Вызывает EnableInterrupts с аргументами () в текущей последовательности операций. */
EnableInterrupts();
/* Проверяет if(Desk!=dsk_EPLT); последующий оператор выполняется только при истинном условии. */
if(Desk!=dsk_EPLT)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Вызывает setup_adc. Настраивает каналы, последовательность преобразований и запуск АЦП. */
setup_adc();
/* Инициализирует модуль вызовом Init_sensors(); перед его дальнейшим использованием. */
Init_sensors();
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Инициализирует модуль вызовом Init_packMask(); перед его дальнейшим использованием. */
Init_packMask();
/* Вызывает Load_params. Читает сохранённые регистры из области параметров EEPROM и применяет настройки платы. */
Load_params();
/* Инициализирует модуль вызовом Init_sensors_more(); перед его дальнейшим использованием. */
Init_sensors_more();
/* Проверяет if(Desk==dsk_LOAD); последующий оператор выполняется только при истинном условии. */
if(Desk==dsk_LOAD)
/* Вызывает Setup_DAC_time. Вычисляет такты ЦАП; для недопустимого сохранённого тайм-аута CAN возвращает 600 мс. */
Setup_DAC_time();
/* Записывает LastMode значением Mode; последний режим платы, технологический регистр 126. */
LastMode = Mode;
/* Разрешение записи в защищённые регистры периферии. */
EALLOW;
/* Записывает SysCtrlRegs.WDCR значением 0x2F; данные WDCR. */
SysCtrlRegs.WDCR= 0x2F;
/* Закрытие доступа к защищённым регистрам периферии. */
EDIS;
/* Записывает READY значением 1; данные READY. */
F28335CanBoot_Init(Mode); /* Передаёт аппаратный номер PERIPH из get_Mode: задатчик 8, УМП1 5 и УМП2 6 получают разные Boot-адреса до включения mailbox. */
READY=1;
F28335CanBoot_Ready(); /* Отмечает завершение загрузки параметров, датчиков и ЦАП для проверки пробного запуска. */
/* Повторяет или ожидает, пока выполняется while(1). */
while(1)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Чтение логгера по CAN не блокирует цикл управления. */
/* Вызывает UMP_CAN_service. В главном цикле готовит замороженный ответ служебного CAN и отправляет его двухсловными фрагментами. */
F28335CanBoot_Service(); /* Выполняет очередь CAN Boot и подтверждает кандидата только из работающего главного цикла. */
UMP_CAN_service();
CAN_telemetry_service(); /* Обслуживает heartbeat 1 Гц, изменения и повторы 1,3 с независимо от делителя OWEN и состояния CanGO. */
if (CanGO) { /* Миллисекундный Timer1 по-прежнему выдаёт один флаг каждые CANPOWSE=20 мс для внешнего опроса. */
CanGO = 0; /* Поглощает текущий такт опроса, не ограничивая выдачу уже готовой очереди CAN. */
if (Owncount && ++rscount >= Owncount) { /* Нулевой период отключает OWEN; ненулевой задаёт прежнее число шагов по 20 мс. */
rscount = 0U; /* Начинает очередной интервал после отправки запроса внешнему регулятору. */
SendCommandModbus4(&rs_b); /* Сохраняет добавленный в 167 опрос измерений OWEN по второму UART. */
} /* Заканчивает обслуживание делителя внешнего прибора без блокирующих ожиданий CAN. */
} /* Следующие фоновые операции выполняются при любом состоянии флага периодического опроса. */
if(cDefParam) /* Применяет заводские параметры по команде, сохраняя действующие биты управления нагрузкой в обработчике параметров. */
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Записывает cDefParam значением 0; данные cDefParam. */
cDefParam=0;
/* По команде восстановления записывает заводские параметры; для LOAD тайм-аут свежести CAN становится 2000 мс. */
Default_params();
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Проверяет if(cSaveParam); последующий оператор выполняется только при истинном условии. */
if(cSaveParam)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Записывает cSaveParam значением 0; данные cSaveParam. */
cSaveParam=0;
/* Вызывает Save_params. Сохраняет технологические регистры в область параметров, отделённую от загрузочного образа EEPROM. */
Save_params();
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Проверяет if(cLoadParam); последующий оператор выполняется только при истинном условии. */
if(cLoadParam)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Записывает cLoadParam значением 0; данные cLoadParam. */
cLoadParam=0;
/* Вызывает Load_params. Читает сохранённые регистры из области параметров EEPROM и применяет настройки платы. */
Load_params();
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Проверяет if(cKoefCalc); последующий оператор выполняется только при истинном условии. */
if(cKoefCalc)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Записывает cKoefCalc значением 0; данные cKoefCalc. */
cKoefCalc=0;
/* Вызывает calc_sensor_koef с аргументами () в текущей последовательности операций. */
calc_sensor_koef();
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Вызывает get_Buttons. Считывает кнопки, обновляет флаги команд и учитывает текущий тип платы. */
get_Buttons();
/* Проверяет if(Desk==dsk_COMM); последующий оператор выполняется только при истинном условии. */
if(Desk==dsk_COMM)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Проверяет if(!bTermoCal & presbyt) cSaveParam=1; последующий оператор выполняется только при истинном условии. */
if(!bTermoCal & presbyt) cSaveParam=1;
/* Записывает presbyt значением bTermoCal; данные presbyt. */
presbyt = bTermoCal;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Timer1 owns START/STOP/permission and the DAC ramp together.
* Main must not re-enable the output during a protected reload. */
/* Снимок после обновления входов и формирования пусковых выходов. */
/* Вызывает ump_log_io. Обслуживает изменения дискретных входов и выходов из главного цикла. */
ump_log_io();
/* Цикл for(i=0;i<2;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
for(i=0;i<2;i++)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Проверяет if(i) rs = &rs_a; последующий оператор выполняется только при истинном условии. */
if(i) rs = &rs_a;
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
else rs = &rs_b;
/* Записывает j значением get_command(rs); данные j. */
j = get_command(rs);
/* Проверяет if(j!=-1); последующий оператор выполняется только при истинном условии. */
if(j!=-1)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Записывает Lonely значением 0; данные Lonely. */
Lonely=0;
/* Вызывает led2_toggle с аргументами () в текущей последовательности операций. */
led2_toggle();
/* Вызывает switch с аргументами (j) в текущей последовательности операций. */
switch(j)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Ветвь выбора для CMD_INIT; выполняется при совпадении селектора switch. */
case CMD_INIT: init(rs); break; // начальные установки
/* Ветвь выбора для CMD_INITLOAD; выполняется при совпадении селектора switch. */
case CMD_INITLOAD: initload(rs); break; // настройка загрузки
/* Ветвь выбора для CMD_RUN; выполняется при совпадении селектора switch. */
case CMD_RUN: run(rs); break; // загрузить блок
/* Ветвь выбора для CMD_LOAD; выполняется при совпадении селектора switch. */
case CMD_LOAD: load(rs); break; // загрузить блок
/* Ветвь выбора для CMD_PEEK; выполняется при совпадении селектора switch. */
case CMD_PEEK: peek(rs); break; // прочитать ачейку памати
/* Ветвь выбора для CMD_POKE; выполняется при совпадении селектора switch. */
case CMD_POKE: poke(rs); break; // записать в ачейку памати
/* Ветвь выбора для CMD_UPLOAD; выполняется при совпадении селектора switch. */
case CMD_UPLOAD: upload(rs); break; // передать блок памати
/* Ветвь выбора для CMD_EXTEND; выполняется при совпадении селектора switch. */
case CMD_EXTEND: extendbios(rs); break; // расширенные команды дла биоса
/* Ветвь выбора для CMD_TFLASH; выполняется при совпадении селектора switch. */
case CMD_TFLASH: tflash(rs); break; // прошить TMS
/* Ветвь выбора для CMD_MODBUS_3; выполняется при совпадении селектора switch. */
case CMD_MODBUS_3: ReceiveCommandModbus3(rs); break;
/* Ветвь выбора для CMD_MODBUS_6; выполняется при совпадении селектора switch. */
case CMD_MODBUS_6: ReceiveCommandModbus6(rs); break;
/* Ветвь выбора для ANS_MODBUS_4; выполняется при совпадении селектора switch. */
case ANS_MODBUS_4: ReceiveAnswerModbus4(rs); break;
/* Обрабатывает значения селектора, для которых нет отдельной ветви case. */
default: break;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
} } } } }