Добавить защищённое обновление приложения через RS и CAN с сохранением загрузчика, проверкой CRC, восстановлением передачи и защитой EEPROM. Подключить общий процесс сборки C2000 и автоматический счётчик версии для согласованных RAM, Flash, CAN и паспортов бинарных образов. Уточнить запуск ЦАП, обработку измерений и параметров нагрузки, начальную индикацию и документацию регистров GAS. Дополнить модели аппаратуры и изолировать заголовки CAN в тестах. Проверка: 26 тестов выпуска, 4 теста восстановления CAN и восемь программных моделей CAN, Flash, EEPROM, ЦАП, параметров и TESTLAMP.
208 lines
19 KiB
C
208 lines
19 KiB
C
/* Обмен и индикация пульта. Русские пояснения сохранены в UTF-8. */
|
|
/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */
|
|
#include "can_boot.h" /* До CONFIRM таймер не должен кормить watchdog вместо главного цикла кандидата. */
|
|
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
|
|
/* Подключает "DSP2833x_SWPrioritizedIsrLevels.h": поставляемое TI описание SWPrioritizedIsrLevels для семейства C2833x. */
|
|
#include "DSP2833x_SWPrioritizedIsrLevels.h"
|
|
|
|
/* Подключает "RS485.h": приём и передача SCI-A/SCI-B, упаковка команд и FIFO первого порта. */
|
|
#include "RS485.h"
|
|
/* Подключает "message.h": обработка Modbus, заводские параметры и сохранение настроек. */
|
|
#include "message.h"
|
|
/* Подключает "filter_bat2.h": накопительный фильтр измерительных каналов. */
|
|
#include "filter_bat2.h"
|
|
/* Подключает "measure.h": обработка датчиков, вычисление величин и миллисекундный такт системы. */
|
|
#include "measure.h"
|
|
/* Подключает "package.h": адреса устройств, типы плат и псевдонимы технологических регистров. */
|
|
#include "package.h"
|
|
/* Подключает "pulto.h": обмен и индикация пульта. */
|
|
#include "pulto.h"
|
|
/* Подключает "kanal.h": последовательный вывод данных канала индикации. */
|
|
#include "kanal.h"
|
|
/* Подключает "peripher.h": перемычки режима платы, дискретные входы и выходы. */
|
|
#include "peripher.h"
|
|
|
|
/* Объявляет isMask — is маска. */
|
|
unsigned long isMask = 0; /* Задаёт начальную погашенную фазу тестовых ламп через .cinit, независимо от остатков RAM после JTAG или watchdog reset. */
|
|
/* Объявляет isNumb — данные isNumb. */
|
|
int isNumb = 0; /* До первого периода теста передаёт определённую цифру, а не содержимое неинициализированной COFF .ebss. */
|
|
|
|
/* Объявляет quaLamp — данные quaLamp. Начальное значение задаётся справа от знака равенства. */
|
|
int quaLamp = 6;
|
|
|
|
/* Объявляет Lonely — данные Lonely. Начальное значение задаётся справа от знака равенства. */
|
|
unsigned long Lonely=0;
|
|
|
|
/* Начинает функцию what_is; назначение модуля — обмен и индикация пульта. */
|
|
void what_is()
|
|
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
|
{
|
|
/* Объявляет count_blink — число blink. */
|
|
static unsigned int count_blink = 0; /* Отсчитывает первый BLINK_TIME от запуска теста с известного нуля; явный initializer попадает в таблицу COFF .cinit. */
|
|
/* Объявляет numb — данные numb. Начальное значение задаётся справа от знака равенства. */
|
|
static int numb=0;
|
|
|
|
/* Проверяет if(++count_blink >= BLINK_TIME); последующий оператор выполняется только при истинном условии. */
|
|
if(++count_blink >= BLINK_TIME)
|
|
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
|
{
|
|
/* Записывает count_blink значением 0; число blink. */
|
|
count_blink=0;
|
|
|
|
/* Записывает numb значением 0; данные numb. */
|
|
numb++; if(numb==10) numb=0;
|
|
/* Записывает isNumb значением numb*1000 + numb*100 + numb*10 +numb; данные isNumb. */
|
|
isNumb = numb*1000 + numb*100 + numb*10 +numb;
|
|
|
|
/* Проверяет if(isMask) isMask = 0; последующий оператор выполняется только при истинном условии. */
|
|
if(isMask) isMask = 0;
|
|
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
|
else isMask = 0xFFFFFFFF;
|
|
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
|
} }
|
|
|
|
/* Обслуживает периодический обмен и индикацию пульта вместо измерительной платы. */
|
|
interrupt void cpu_timer1_isr_PULT(void)
|
|
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
|
{
|
|
/* Объявляет cownt — данные cownt; count_bright — число bright. Начальное значение задаётся справа от знака равенства. */
|
|
static int cownt=0,count_bright=0; /* Начинает очередь каналов и десятиступенчатый PWM с определённой фазы, не используя случайный счётчик яркости из RAM. */
|
|
/* Объявляет light — данные light; i — данные i. Начальное значение задаётся справа от знака равенства. */
|
|
unsigned int light=0, i;
|
|
/* Объявляет Alone — данные Alone; READY_FREQ — частота основного такта Timer1 в герцах. Хранит указатель на данные. Начальное значение задаётся справа от знака равенства. */
|
|
unsigned int Alone = 20*READY_FREQ;
|
|
/* Считает непрерывное удержание TESTLAMP в тактах Timer1: READY_FREQ задаёт число тактов за секунду, независимо от занятости main. */
|
|
static unsigned int test_lamp_hold_ticks = 0;
|
|
|
|
/* Разрешение записи в защищённые регистры периферии. */
|
|
EALLOW;
|
|
/* Изменяет счётчик в выражении CpuTimer1.InterruptCount++; на один для следующего шага. */
|
|
CpuTimer1.InterruptCount++;
|
|
/* Оставляет только ранее разрешённые источники более высокого приоритета по маске TI MINT13 и запрещает повторный Timer1 через M_INT13 (бит 12 IER); вложенная передача не должна перемешивать фронты DATA/CLK и менять фазу яркости. IRET восстановит маску вызывающего кода. */
|
|
IER &= (MINT13 & ~M_INT13);
|
|
/* Разрешение маскируемых прерываний ядра. */
|
|
EINT;
|
|
/* Закрытие доступа к защищённым регистрам периферии. */
|
|
EDIS; // This is needed to disable write to EALLOW protected registers
|
|
|
|
/* До подтверждения кандидата только работающий main имеет право кормить watchdog; команда RESET сохраняет приоритет. */
|
|
if(!cReset && F28335CanBoot_WatchdogAllowed()) ServiceDog(); /* Подтверждённое приложение сохраняет прежнее обслуживание из ISR. */
|
|
|
|
/* Проверяет if(++CanPowse >= CANPOWSE); последующий оператор выполняется только при истинном условии. */
|
|
if(++CanPowse >= CANPOWSE)
|
|
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
|
{
|
|
/* Записывает CanPowse значением 0; CAN Powse. */
|
|
CanPowse = 0;
|
|
/* Записывает CanGO значением 1; CAN GO. */
|
|
CanGO = 1;
|
|
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
|
}
|
|
|
|
/* Переключает аппаратный сигнал через toggle_ONLINE();. */
|
|
toggle_ONLINE(); // строб дла ПЛИС
|
|
/* Переключает аппаратный сигнал через toggle_RES_OUT_1();. */
|
|
toggle_RES_OUT_1(); // типа это готовность
|
|
/* Переключает аппаратный сигнал через toggle_RES_OUT_2();. */
|
|
toggle_RES_OUT_2(); // на всакий
|
|
|
|
/* Проверяет if(++Lonely > Alone) Lonely = Alone; последующий оператор выполняется только при истинном условии. */
|
|
if(++Lonely > Alone) Lonely = Alone;
|
|
|
|
/* Проверяет if(++count_bright >= maximum_bright) count_bright = 0; последующий оператор выполняется только при истинном условии. */
|
|
if(++count_bright >= maximum_bright) count_bright = 0 ;
|
|
|
|
/* Цикл for(i=0; i<quaLamp; i++); задаёт начальное значение, условие продолжения и шаг перебора. */
|
|
for(i=0; i<quaLamp; i++)
|
|
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
|
{
|
|
/* Проверяет if(count_bright < Bright[i]) light+=(1<<i); последующий оператор выполняется только при истинном условии. */
|
|
if(count_bright < Bright[i]) light+=(1<<i);
|
|
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
|
}
|
|
|
|
/* Проверяет if(++cownt>2) cownt=0; последующий оператор выполняется только при истинном условии. */
|
|
if(++cownt>2) cownt=0;
|
|
|
|
if(GpioDataRegs.GPADAT.bit.GPIO26) /* Высокий уровень входа означает нажатую физическую кнопку TESTLAMP на плате пульта. */
|
|
{ /* Накапливает только непрерывное удержание; насыщение защищает счётчик от переполнения при долгом нажатии. */
|
|
if(test_lamp_hold_ticks < 2U * (unsigned int)READY_FREQ) /* Порог двух секунд перенесён из 166: короткое нажатие не включает общий тест индикации. */
|
|
test_lamp_hold_ticks++; /* Добавляет один аппаратный такт, поэтому задержка не зависит от обмена и чтения EEPROM в главном цикле. */
|
|
} /* Завершает накопление текущего удержания физической кнопки. */
|
|
else test_lamp_hold_ticks = 0; /* Отпускание сразу отменяет тест и не позволяет суммировать отдельные короткие нажатия. */
|
|
bTestLamp = (test_lamp_hold_ticks >= 2U * (unsigned int)READY_FREQ); /* Обновляет флаг до отправки очередного пакета; удалённая команда cTestLamp сохраняет отдельное управление. */
|
|
|
|
/* Проверяет if(cTestLamp|bTestLamp); последующий оператор выполняется только при истинном условии. */
|
|
if(cTestLamp|bTestLamp)
|
|
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
|
{
|
|
/* Вызывает what_is с аргументами () в текущей последовательности операций. */
|
|
what_is();
|
|
|
|
/* Проверяет if(cownt == 0) kanal_Send(0,isNumb,4); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 0) kanal_Send(0,isNumb,4);
|
|
/* Проверяет if(cownt == 1) kanal_Send(1,isNumb,4); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 1) kanal_Send(1,isNumb,4);
|
|
/* Вызывает kanal_Send с аргументами (2,isMask,0) в текущей последовательности операций. */
|
|
kanal_Send(2,isMask,0);
|
|
/* Проверяет if(cownt == 2) kanal_Send(3,isMask,0); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 2) kanal_Send(3,isMask,0);
|
|
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
|
}
|
|
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
|
else
|
|
/* Проверяет if(cLiteFire); последующий оператор выполняется только при истинном условии. */
|
|
if(cLiteFire)
|
|
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
|
{
|
|
/* Проверяет if(cownt == 0) kanal_Send(0,8888,1); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 0) kanal_Send(0,8888,1);
|
|
/* Проверяет if(cownt == 1) kanal_Send(1,8888,1); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 1) kanal_Send(1,8888,1);
|
|
/* Вызывает kanal_Send с аргументами (2,0xFFFF & light,0) в текущей последовательности операций. */
|
|
kanal_Send(2,0xFFFF & light,0);
|
|
/* Проверяет if(cownt == 2) kanal_Send(3,0xFFFF,0); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 2) kanal_Send(3,0xFFFF,0);
|
|
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
|
}
|
|
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
|
else
|
|
/* Проверяет if((Lonely >= Alone)); последующий оператор выполняется только при истинном условии. */
|
|
if((Lonely >= Alone))
|
|
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
|
{
|
|
/* Проверяет if(cownt == 0) kanal_Send(0,0,0); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 0) kanal_Send(0,0,0);
|
|
/* Проверяет if(cownt == 1) kanal_Send(1,0,0); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 1) kanal_Send(1,0,0);
|
|
/* Вызывает kanal_Send с аргументами (2,0,0) в текущей последовательности операций. */
|
|
kanal_Send(2,0,0);
|
|
/* Проверяет if(cownt == 2) kanal_Send(3,0,0); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 2) kanal_Send(3,0,0);
|
|
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
|
}
|
|
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
|
|
else
|
|
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
|
|
{
|
|
/* Условие компиляции OBOROT == STRAIGHT: выбранный блок включается в текущий вариант прошивки. */
|
|
#if OBOROT == STRAIGHT
|
|
/* Проверяет if(cownt == 0) kanal_Send(0,modbus[0],1); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 0) kanal_Send(0,modbus[0],1);
|
|
/* Проверяет if(cownt == 1) kanal_Send(1,modbus[1],1); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 1) kanal_Send(1,modbus[1],1);
|
|
/* Выбирает альтернативный блок текущего условия компиляции. */
|
|
#else
|
|
/* Проверяет if(cownt == 0) kanal_Send(0,modbus[1],1); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 0) kanal_Send(0,modbus[1],1);
|
|
/* Проверяет if(cownt == 1) kanal_Send(1,modbus[0],1); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 1) kanal_Send(1,modbus[0],1);
|
|
/* Закрывает условный блок препроцессора; дальнейшие строки относятся к внешнему уровню. */
|
|
#endif
|
|
/* Вызывает kanal_Send с аргументами (2,modbus[2] & light,0) в текущей последовательности операций. */
|
|
kanal_Send(2,modbus[2] & light,0);
|
|
/* Проверяет if(cownt == 2) kanal_Send(3,modbus[3],0); последующий оператор выполняется только при истинном условии. */
|
|
if(cownt == 2) kanal_Send(3,modbus[3],0);
|
|
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
|
|
} }
|