Добавить защищённое обновление приложения через RS и CAN с сохранением загрузчика, проверкой CRC, восстановлением передачи и защитой EEPROM. Подключить общий процесс сборки C2000 и автоматический счётчик версии для согласованных RAM, Flash, CAN и паспортов бинарных образов. Уточнить запуск ЦАП, обработку измерений и параметров нагрузки, начальную индикацию и документацию регистров GAS. Дополнить модели аппаратуры и изолировать заголовки CAN в тестах. Проверка: 26 тестов выпуска, 4 теста восстановления CAN и восемь программных моделей CAN, Flash, EEPROM, ЦАП, параметров и TESTLAMP.
344 lines
29 KiB
C
344 lines
29 KiB
C
/* Порядок запуска периферии и обслуживание команд в главном цикле. Русские пояснения сохранены в 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;
|
||
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
||
} } } } }
|
||
|