Устранена зависимость дискретов СИФУ от основного цикла в 166

Фронты START/STOP обрабатываются при принятии командного слова CAN/RS,
а окончание импульса обслуживается таймером. STOP имеет приоритет,
перекрытие выходов исключено, сохранена защита от самопуска при включении.
Загрузка параметров больше не подменяет живые команды нагрузки.

Добавлены подробные русские комментарии во все собственные C-модули
и основные заголовки, описание поведения и host-тест автомата.
Обновлены файлы прошивки. Полная сборка TI 22.6.1.LTS и тесты пройдены;
проверка на физической плате не выполнялась.
This commit is contained in:
2026-09-23 01:28:11 +03:00
parent 2d7148baa5
commit eb2ff79932
49 changed files with 1564 additions and 950 deletions

View File

@@ -1,3 +1,9 @@
/* Настройка АЦП и обработка аналоговых выборок. adc_isr обновляет
* adc_table_lem[0..3] из ADCRESULT2..5 >> 4 и вызывает расчёт измерений.
* READY в 166 является счётчиком до нуля, не флагом готовности.
* WAKE задаёт отдельное время установления измерительных цепей.
* Не добавлять ожидания EEPROM/UART в обработчик выборок.
*/
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
#include "DSP2833x_Examples.h" // DSP281x Examples Include File
#include "DSP2833x_SWPrioritizedIsrLevels.h"

View File

@@ -1,3 +1,10 @@
/* ЦАП нагрузки и аппаратная обёртка импульсов СИФУ. Load_runner
* вызывается таймером 1 кГц, расчёт ЦАП делится до DAC_FREQ.
* Формула 166 задаёт фиксированный разгон 6..16 мА. DAC_min/max
* переводят положение в код, cCalibrDac выбирает ручной код.
* WAKEpowse относится к ЦАП, не является разрешением дискрета запуска.
* Автомат СИФУ подключён в конце файла через ump_control_impl.h.
*/
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
#include "DSP2833x_SWPrioritizedIsrLevels.h"
#include "filter_bat2.h"
@@ -11,6 +18,7 @@
#include "peripher.h"
#include "log_to_mem.h"
#include "ump_pulse.h"
#define dCLK_1() GpioDataRegs.GPBSET.bit.GPIO63=1
#define dCLK_0() GpioDataRegs.GPBCLEAR.bit.GPIO63=1
@@ -18,9 +26,12 @@
#define dCS_0() GpioDataRegs.GPBCLEAR.bit.GPIO59=1
unsigned long WAKEpowse;
unsigned long IMPowse;
volatile unsigned long IMPowse;
unsigned int period_dac, time_dac;
/* Инициализация, не обработка каждого START. 601 отсчёт при 200 Гц
* дают около 3 секунд до рабочего расчёта ЦАП после включения.
*/
void Setup_DAC_time(void)
{
WAKEpowse = 3L * DAC_FREQ +1;
@@ -65,6 +76,10 @@ void Init_DAC(void)
dSEND(0x9002|0x0000); toggle_RES_OUT_1();
}
/* vrot/maxx — доля диапазона между кодами 4 и 20 мА. Маска 0xFFF
* сохраняет 12 бит, но не является насыщением. modbus[0x1C] содержит
* расчётное задание, не измеренный ток на выходных клеммах.
*/
void Anal_output(long vrot, long maxx)
{
long out;
@@ -101,13 +116,17 @@ Log_to_mem(modbus[0x1D]);
}
/* После половины time_dac счётчик растёт дважды за вызов. Поэтому
* LOAD_TIME=30 даёт примерно 22.5 с до конца разгона при 200 Гц.
* Существующий профиль 166 исправление импульса СИФУ не меняет.
*/
void Load_runner()
{
static unsigned int count_dac=0, count_load=0, x=1;
float sinus=0;
int kod;
if(IMPowse) IMPowse--;
/* IMPowse обновляется UMP_pulse_tick(), а не алгоритмом ЦАП. */
if(++count_dac >= period_dac)
{
count_dac=0;
@@ -158,3 +177,6 @@ void Load_runner()
Anal_output(kod, time_dac);
} } } }
#include "ump_control_impl.h"

View File

@@ -1,3 +1,6 @@
/* Таблицы выборок обновляет ADC ISR. Согласованный снимок нескольких
* каналов требует защиты копирования, одного указателя недостаточно.
*/
extern Uint16 adc_table_lem[];

View File

@@ -1,8 +1,18 @@
/* Èíòåðôåéñ ÖÀÏ è ÑÈÔÓ. Âõîäÿùèå êîìàíäû — UMP_commands_write,
* îêîí÷àíèå èìïóëüñà — UMP_pulse_tick. IMPowse òîëüêî äëÿ äèàãíîñòèêè.
*/
void Load_runner(void);
void Anal_output(long vrot, long maxx);
void Init_DAC(void);
void Setup_DAC_time(void);
/* Ñ÷¸ò÷èê ïóñêîâîãî èìïóëüñà è âûäåðæêè èíèöèàëèçàöèè äîñòóïíû ëîããåðó. */
extern unsigned long IMPowse, WAKEpowse;
extern volatile unsigned long IMPowse;
extern unsigned long WAKEpowse;
extern unsigned int period_dac, time_dac;
/* Âñå îïåðàöèè áåçîïàñíû äëÿ âûçîâà èç main è îáðàáîò÷èêîâ IRQ. */
void UMP_pulse_init(void);
void UMP_commands_write(unsigned int commands);
void UMP_pulse_tick(void);
void UMP_reset_parameter_commands(void);

View File

@@ -1,3 +1,6 @@
/* Направления GPIO для аппаратных исполнений. Единица означает
* выход; активную полярность задают peripher.h и схема платы.
*/
#define COMM_gpio00_dir 0L
#define COMM_gpio01_dir 0L
#define COMM_gpio02_dir 0L

View File

@@ -1,3 +1,6 @@
/* Буферы UART разделяются ISR и main. main обрабатывает
* законченный RS_Header. Размеры сверять с 16-битной ABI DSP.
*/
#ifndef _RS485
#define _RS485

View File

@@ -1,3 +1,6 @@
/* Коды CMD_* являются частью формата обмена с ПК. Новые команды
* добавляются без перенумерации существующих значений.
*/
#ifndef _BIOS_DSP
#define _BIOS_DSP

View File

@@ -1,3 +1,6 @@
/* Заводские калибровки по версии BALSAM и типу платы. Здесь
* определяются массивы, а не только extern; не дублировать подключение.
*/
#if BALSAM == 166 //-------------------------------------------------------------
int def_cal[][8] = {

View File

@@ -1,3 +1,6 @@
/* Собственный, общий и специальные адреса последовательного обмена.
* main задаёт адреса через set_cntrl_addr до начала обмена.
*/
#ifndef _CNTRL_ADR
#define _CNTRL_ADR

View File

@@ -1,3 +1,6 @@
/* Интерфейсы CRC. Различать буфер кадра и массив слов EEPROM;
* результат зависит от порядка обработки байтов.
*/
typedef unsigned short WORD;
typedef unsigned char byte;

View File

@@ -1,3 +1,6 @@
/* Телеметрия eCAN и фоновая выдача ответов логгера.
* UMP_CAN_service вызывается из main, не из приёмного IRQ.
*/
void InitCan(int Port, int DevNum);
void CAN_send(int Port, int data[], int Addr);
extern int CAN_input_data[];

View File

@@ -1,3 +1,6 @@
/* Коэффициенты и изменяемая история фильтра. Каждый независимый
* канал должен иметь отдельный экземпляр FILTERBAT.
*/
#ifndef _FILTER_BAT2
#define _FILTER_BAT2

View File

@@ -1 +1,4 @@
/* Интерфейс канала индикации. Он не формирует START_DPTB
* и не должен использоваться вместо функций управления нагрузкой.
*/
void kanal_Send(int adr, long dat, int dot);

View File

@@ -1,3 +1,6 @@
/* Контракт логгера с SetGUI: размер записи, версия и адреса.
* Чтение целого блока защищается от IRQ на стороне RS/CAN обработчика.
*/
#ifndef _LOG_TO_MEM
#define _LOG_TO_MEM

View File

@@ -1,3 +1,6 @@
/* Частоты и состояния измерений. READY в 166 — счётчик до нуля.
* READY_FREQ задаёт таймер СИФУ, DAC_FREQ — расчёт ЦАП.
*/
#ifndef _MEASURE
#define _MEASURE

View File

@@ -1,3 +1,6 @@
/* Технологические регистры и Modbus. ANSWER_LEN ограничивает
* массив modbus; адресом логгера 0x1000 индексировать его нельзя.
*/
#ifndef MESSAGE_H
#define MESSAGE_H

View File

@@ -1,3 +1,7 @@
/* Ìàêðîñû îáðàùàþòñÿ ê îáùåé êàðòå modbus, íå ê ëîêàëüíûì äàííûì.
* START/STOP ÷èòàþòñÿ ÷åðåç volatile. Âõîäÿùàÿ çàïèñü ñëîâà 127
* äîëæíà ïðîéòè UMP_commands_write äëÿ ôèêñàöèè ôðîíòà.
*/
#ifndef PACKAGE
#define PACKAGE
@@ -131,7 +135,8 @@
#define LastMode Modbus[126].all
#define Commands Modbus[127].all
/* Ñëîâî ìåíÿåòñÿ èç CAN/RS; ÷òåíèå êîìàíäû íå äîëæíî êåøèðîâàòüñÿ. */
#define Commands (((volatile WORDE *)modbus)[127].all)
#define cTestLamp Modbus[127].bit.bit0
#define cDefParam Modbus[127].bit.bit1
#define cSaveParam Modbus[127].bit.bit2
@@ -140,8 +145,8 @@
#define cTermoCal Modbus[127].bit.bit4
#define cKoefCalc Modbus[127].bit.bit5
#define cUMPreset Modbus[127].bit.bit6
#define cUMPstart Modbus[127].bit.bit7
#define cUMPreset (((volatile WORDE *)modbus)[127].bit.bit6)
#define cUMPstart (((volatile WORDE *)modbus)[127].bit.bit7)
#define cInitDac Modbus[127].bit.bit8
#define cCalibrDac Modbus[127].bit.bit9

View File

@@ -1,3 +1,7 @@
/* Физические GPIO с учётом режима и полярности. set означает
* активировать функцию, не всегда выставить 1. START/STOP нагрузки
* активны единицей, RES_OUT_2 нулём. Дискретами владеет автомат СИФУ.
*/
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
extern int Mode,Desk,TermoAD,TermoRS,TermoSW,Kurrent,Kalibro;

View File

@@ -1,3 +1,6 @@
/* Состояния пульта dsk_EPLT. Обработчик таймера нагрузки
* определён отдельно в measure.c.
*/
//void what_is(void);
interrupt void cpu_timer1_isr_PULT(void);

View File

@@ -1,3 +1,6 @@
/* Автомат SPI EEPROM продвигает таймер 2. Синхронное ожидание
* требует разрешённых IRQ. PAGE_LEN/WORD_LEN задают адресацию страниц.
*/
#ifndef __SPISE2P_H__
#define __SPISE2P_H__

View File

@@ -1,3 +1,6 @@
/* Инициализация памяти и задержки. pause_us не использовать
* для длительности дискретов; их отсчитывает аппаратный таймер.
*/
#ifndef TOOLS_H
#define TOOLS_H

View File

@@ -0,0 +1,83 @@
/* Ïîäêëþ÷àåòñÿ òîëüêî èç DAC.c; â host-òåñòå — ñ ïîäìåíîé GPIO/IRQ. */
#ifndef UMP_CONTROL_IMPL_H
#define UMP_CONTROL_IMPL_H
/* Àïïàðàòíàÿ îá¸ðòêà àâòîìàòà. Õðàíèì å¸ â ñóùåñòâóþùåì DAC.c, ÷òîáû
* ñòàðûé ïðîåêò CCS è íîâûé CCS12 ñîáèðàëè îäèíàêîâûé íàáîð èñõîäíèêîâ.
* Âñå âõîäû íèæå ñîõðàíÿþò ïðåæíþþ ìàñêó IRQ; íåëüçÿ ïðîñòî äåëàòü EINT
* ïðè âûõîäå, ïîñêîëüêó âûçîâ âîçìîæåí èç óæå çàùèù¸ííîãî îáðàáîò÷èêà. */
static volatile UMP_PULSE_STATE ump_pulse;
static volatile unsigned int ump_pulse_enabled;
static void UMP_apply_outputs(unsigned int previous_output, unsigned int previous_relay)
{
if (previous_output != ump_pulse.output) {
/* Ñíà÷àëà ñíèìàåì ñòàðûé ñèãíàë, çàòåì âûñòàâëÿåì íîâûé.
* Ïðîìåæóòî÷íîå ñîñòîÿíèå — îáà âûêëþ÷åíû, à íå îáà âêëþ÷åíû. */
clear_START_DPTB();
clear_STOP_DPTB();
if (ump_pulse.output == UMP_PULSE_START) set_START_DPTB();
if (ump_pulse.output == UMP_PULSE_STOP) set_STOP_DPTB();
}
if (previous_relay != ump_pulse.relay) {
if (ump_pulse.relay) set_RES_OUT_2();
else clear_RES_OUT_2();
}
/* Ñòàðîå èìÿ îñòàâëåíî äëÿ ïðîòîêîëà ëîããåðà. Ýòî òåïåðü îòðàæåíèå
* òàéìåðà àâòîìàòà, à íå ïåðåìåííàÿ, êîòîðóþ îäíîâðåìåííî ïðàâèò main. */
IMPowse = ump_pulse.remaining;
}
void UMP_pulse_init(void)
{
unsigned int saved = __disable_interrupts();
if (Desk == dsk_LOAD) {
ump_pulse_init(&ump_pulse, Commands);
clear_START_DPTB(); clear_STOP_DPTB(); clear_RES_OUT_2();
IMPowse = 0;
/* Ðàçðåøàåì îáðàáîòêó òîëüêî ïîñëå çàãðóçêè ïàðàìåòðîâ è íàñòðîéêè
* ÖÀÏ. Êîìàíäû äî ýòîé òî÷êè íå èñïîëíÿþòñÿ çàäíèì ÷èñëîì. */
ump_pulse_enabled = 1;
}
__restore_interrupts(saved);
}
void UMP_commands_write(unsigned int commands)
{
unsigned int saved = __disable_interrupts();
unsigned int output = ump_pulse.output, relay = ump_pulse.relay;
Commands = commands;
if (Desk == dsk_LOAD && ump_pulse_enabled) {
/* Âûïîëíÿåì ôðîíò â ìîìåíò ïðèíÿòèÿ ñëîâà. Íåò î÷åðåäè, êîòîðóþ
* main äîëæåí îïðîñèòü ïîñëå äëèòåëüíîãî îáðàùåíèÿ ê EEPROM.
* Çäåñü òîëüêî íåñêîëüêî îïåðàöèé ñ ïàìÿòüþ/GPIO, áåç îæèäàíèé. */
ump_pulse_accept(&ump_pulse, commands, (unsigned int)READY_FREQ);
UMP_apply_outputs(output, relay);
}
__restore_interrupts(saved);
}
void UMP_pulse_tick(void)
{
unsigned int saved = __disable_interrupts();
unsigned int output = ump_pulse.output, relay = ump_pulse.relay;
if (Desk == dsk_LOAD && ump_pulse_enabled) {
ump_pulse_tick(&ump_pulse);
UMP_apply_outputs(output, relay);
}
__restore_interrupts(saved);
}
void UMP_reset_parameter_commands(void)
{
unsigned int saved = __disable_interrupts();
/* EEPROM ñîäåðæèò ïàðàìåòðû, íî íå ÿâëÿåòñÿ èñòî÷íèêîì êîìàíä ïóñêà.
* Ñîõðàíÿåì ïîñëåäíèå ïðèíÿòûå START/STOP è èñòîðèþ ôðîíòîâ àâòîìàòà.
* Íåëüçÿ îáíóëèòü èõ ïðè Load/Default: òàéìåð ÖÀÏ ÷èòàåò òîò æå óðîâåíü,
* à ñëåäóþùèé ïîâòîð ïàêåòà ñ åäèíèöåé íå äîëæåí ñòàòü ëîæíûì ôðîíòîì.
* Äðóãèå ðåæèìû ïëàòû ñîõðàíÿþò ïðåæíåå ïîâåäåíèå ïîëíîãî ñáðîñà. */
if (Desk == dsk_LOAD) Commands &= UMP_START_MASK | UMP_STOP_MASK;
else Commands = 0;
__restore_interrupts(saved);
}
#endif

View File

@@ -0,0 +1,69 @@
/* Управление импульсами СИФУ. Чистый автомат без доступа к GPIO.
* Один и тот же код используется прошивкой и host-тестом.
* ВАЖНО: вызывающая сторона сериализует init/accept/tick запретом IRQ.
* volatile обеспечивает обращения к общему состоянию, но не заменяет
* критическую секцию: обновление нескольких полей не является атомарным.
*/
#ifndef UMP_PULSE_H
#define UMP_PULSE_H
#define UMP_START_MASK 0x0080U
#define UMP_STOP_MASK 0x0040U
#define UMP_PULSE_NONE 0U
#define UMP_PULSE_START 1U
#define UMP_PULSE_STOP 2U
typedef struct {
unsigned int previous;
unsigned int remaining;
unsigned int output;
unsigned int relay;
} UMP_PULSE_STATE;
static void ump_pulse_init(volatile UMP_PULSE_STATE *s, unsigned int commands)
{
/* Уже активная команда при окончании загрузки не является новым пуском.
* Снимаем физические выходы отдельно в аппаратной обёртке.
* Если начальное слово нулевое, первая свежая единица будет принята:
* больше не нужен случайный проход main, успевший прочитать ноль. */
s->previous = commands;
s->remaining = 0;
s->output = UMP_PULSE_NONE;
s->relay = 0;
}
static void ump_pulse_accept(volatile UMP_PULSE_STATE *s,
unsigned int commands, unsigned int ticks)
{
unsigned int rising = commands & ~s->previous;
/* История относится к каждому принятому слову CAN/RS, а не к редким
* снимкам main. Поэтому даже 1->0->1 между проходами main замечается.
* Повторные пакеты с удерживаемой единицей не продлевают импульс. */
s->previous = commands;
if (commands & UMP_STOP_MASK) {
/* STOP имеет приоритет даже при одновременном фронте START.
* Его удержание запрещает новый START. Запрещённый пуск не ставим
* в очередь: снятие STOP не должно неожиданно запускать СИФУ. */
if (rising & UMP_STOP_MASK) {
s->output = UMP_PULSE_STOP;
s->remaining = ticks;
s->relay = 0;
}
} else if (rising & UMP_START_MASK) {
/* Новый START после снятия команды STOP переключает выходы.
* Новый фронт во время START продлевает существующий импульс,
* как раньше; отдельный электрический фронт здесь не обещается. */
s->output = UMP_PULSE_START;
s->remaining = ticks;
s->relay = 1;
}
}
static void ump_pulse_tick(volatile UMP_PULSE_STATE *s)
{
/* Единственный владелец отсчёта — таймер 1 кГц. main не участвует
* в завершении импульса, поэтому EEPROM не растягивает его.
* RES_OUT_2 сохраняет последнее состояние после конца импульса. */
if (s->remaining && --s->remaining == 0)
s->output = UMP_PULSE_NONE;
}
#endif

View File

@@ -1,3 +1,9 @@
/* Низкоуровневый UART двух портов. RX ISR собирает RS_Header,
* TX ISR продолжает передачу. RS_DataReady передаёт готовый кадр
* в main для проверки CRC; приём байтов ещё не означает исполнения.
* RS_Send содержит ожидания UART и не относится к быстрому пути СИФУ.
* Размеры буферов нужно понимать с учётом 16-битной ABI C2000.
*/
//#include "big_dsp_module.h"
@@ -321,6 +327,9 @@ void RS_SetBitMode(RS_DATA *rs_arr,int n)
@param buf àäðåñ ìàññèâà
@param len êîëè÷åñòâî áàéò
@see RS_BSend, RS_TRANSMIT_INTR */
/* Передачу продолжает TX ISR. Здесь есть старые программные паузы
* и ожидания UART: не вызывать из CAN ISR или секции автомата СИФУ.
*/
int RS_Send(RS_DATA *rs_arr,unsigned int *pBuf,unsigned long len)
{
unsigned int i;

View File

@@ -1,3 +1,9 @@
/* Служебные команды доступа к памяти и загрузки. get_command
* проверяет завершённый RS-кадр и CRC перед диспетчеризацией в main.
* Произвольная запись памяти сервисной командой не проходит
* автомат фронтов СИФУ. Формат CMD_* согласован с загрузчиком ПК;
* нельзя перенумеровывать команды при расширении протокола.
*/
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "RS485.h"
#include "bios_dsp.h"

View File

@@ -1,3 +1,8 @@
/* Адресация последовательного протокола. set_cntrl_addr задаёт
* собственный и общий адрес. CAN ID вычисляется отдельно из Mode.
* Общий RS-адрес не заменяет собственный во всех ответах: для
* логгера SetGUI использовать собственный адрес платы (обычно 5/6).
*/
#include "cntrl_adr.h"
#define ADDR_FOR_ALL_DEF 10

View File

@@ -1,3 +1,9 @@
/* CRC кадров обмена и параметров EEPROM. get_crc_16 работает
* с представлением буфера протокола, get_crc16 обрабатывает оба
* байта каждого слова параметров. Порядок байтов существенен.
* Нельзя заменять эти функции реализацией для ПК без проверки
* представления данных и особенностей 16-битной ABI C2000.
*/
#include "crc16.h"
#define MAKE_TABS 0 /* Builds tables below */
#define FAST_CRC 1 /* If fast CRC should be used */

View File

@@ -1,3 +1,9 @@
/* Команды и телеметрия eCAN. MBOX1 принимает кадры, MBOX0 передаёт
* технологические регистры, MBOX2 выделен под ответы логгера.
* Слово 127 проходит UMP_commands_write непосредственно в CAN ISR.
* Запрос архива ISR лишь ставит на обслуживание; фрагментация
* ответов выполняется UMP_CAN_service из фонового цикла.
*/
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "DSP2833x_SWPrioritizedIsrLevels.h"
@@ -13,6 +19,7 @@
#include "peripher.h"
#include "log_to_mem.h"
#include "ump_can_protocol.h"
#include "DAC.h"
// Prototype statements for functions found within this file.
@@ -162,6 +169,9 @@ void InitCan(int Port, int DevNum)
MessageTransivedCount=0;
}
/* При занятом MBOX0 возвращается без ожидания ACK в цикле.
* Это отличается от блокирующих UART/EEPROM операций main.
*/
void CAN_send(int Port, int data[], int Addr)
{
unsigned long hiword,loword;
@@ -234,9 +244,19 @@ void Handlai(volatile struct ECAN_MBOXES * ECanMboxes)
Data[1] = (loword>>16) & 0xffff;
Data[2] = (loword ) & 0xffff;
if(bit[0]) if(adr < ANSWER_LEN) modbus[adr] = Data[0]; adr++;
if(bit[1]) if(adr < ANSWER_LEN) modbus[adr] = Data[1]; adr++;
if(bit[2]) if(adr < ANSWER_LEN) modbus[adr] = Data[2];
/* Каждое разрешённое слово имеет собственный адрес. Не опрашиваем
* Commands после кадра безусловно: пакет телеметрии не должен
* превращать внутренний сброс параметров в командный фронт.
* Адрес 127 проходит через единый обработчик полного слова. */
{
unsigned int i;
for (i = 0; i < 3; i++, adr++) {
if (bit[i] && adr < ANSWER_LEN) {
if (adr == 127) UMP_commands_write((unsigned int)Data[i]);
else modbus[adr] = Data[i];
}
}
}
/* Ôèêñèðóåì ïðèìåí¸ííóþ êîìàíäó äî âûõîäà èç îáðàáîò÷èêà CAN. */
ump_log_can((unsigned int)(hiword >> 16), Data[0], Data[1], Data[2]);

View File

@@ -1,3 +1,8 @@
/* Рекурсивный фильтр. FILTERBAT хранит коэффициенты и историю
* двух входов/выходов; каждый вызов изменяет переданный экземпляр.
* Независимым каналам нужны отдельные состояния. Синхронизации
* здесь нет: смену коэффициентов согласовывает вызывающий код.
*/
#include "filter_bat2.h"
float filterbat(FILTERBAT *b, float InpVarCurr)

View File

@@ -1,3 +1,8 @@
/* Программный канал индикации. digits/readr задают символы и выбор
* элементов, DCLK/DOUT и kanal_Send формируют последовательность GPIO.
* Это другой интерфейс, чем dCLK/dCS в DAC.c. Похожие имена не
* означают общий ЦАП или общий выход запуска нагрузки.
*/
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
#include "DSP2833x_SWPrioritizedIsrLevels.h"
#include "filter_bat2.h"

View File

@@ -1,3 +1,9 @@
/* Регистратор УМП во внешней памяти .logg: два банка по 800 записей
* из 40 слов для SetGUI. Архив отключения не мешает дальнейшей записи.
* Писатели из main/CAN/таймера защищаются короткими секциями IRQ
* с восстановлением прежней маски. Архив не энергонезависимый.
* clear_mem выполняется при запуске до включения прерываний.
*/
#include "DSP2833x_Device.h"
#include "filter_bat2.h"
#include "measure.h"

View File

@@ -1,3 +1,9 @@
/* Инициализация и фоновый цикл платы. После настройки GPIO, обмена,
* параметров и ЦАП UMP_pulse_init разрешает свежие команды СИФУ.
* В main остаются телеметрия, EEPROM и разбор готовых RS-пакетов.
* CAN-пуск и окончание импульса работают в IRQ, не ожидая main.
* RS-команда ещё должна пройти проверку CRC в get_command из main.
*/
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "cntrl_adr.h"
@@ -39,8 +45,6 @@ void main()
{
int i,j,mask;
static unsigned int cancount[2], cancell[2];
static int preCstart=1,preCstop=1;
int umpstart,umpstop;
RS_DATA * rs;
int presbyt=0;
@@ -96,6 +100,8 @@ void main()
if(Desk==dsk_LOAD)
Setup_DAC_time();
/* Завершена начальная настройка: только теперь разрешаем дискреты. */
UMP_pulse_init();
LastMode = Mode;
EALLOW;
@@ -163,27 +169,8 @@ void main()
presbyt = bTermoCal;
}
if(Desk==dsk_LOAD)
{
umpstart = cUMPstart;
umpstop = cUMPreset;
if(umpstart & !preCstart)
{
set_START_DPTB(); set_RES_OUT_2();
IMPowse = READY_FREQ;
}
preCstart = umpstart;
if(umpstop & !preCstop)
{
set_STOP_DPTB(); clear_RES_OUT_2();
IMPowse = READY_FREQ;
}
preCstop = umpstop;
if(!IMPowse) { clear_START_DPTB(); clear_STOP_DPTB(); }
}
/* START/STOP исполняются при приёме CAN/RS, снимаются таймером.
* Здесь больше нет опроса уровня: main может ожидать EEPROM. */
/* Ñíèìîê ïîñëå îáíîâëåíèÿ âõîäîâ è ôîðìèðîâàíèÿ ïóñêîâûõ âûõîäîâ. */
ump_log_io();

View File

@@ -1,3 +1,9 @@
/* Измерения, диагностика и периодическое обслуживание. ADC ISR
* поставляет выборки; таймер 1 обслуживает индикацию и телеметрию.
* Для dsk_LOAD он сначала завершает импульс СИФУ, затем вызывает
* расчёт ЦАП и снимок логгера. Частоты находятся в measure.h;
* при их изменении требуется пересчитать зависимые интервалы.
*/
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "DSP2833x_SWPrioritizedIsrLevels.h"
#include "filter_bat2.h"
@@ -134,6 +140,8 @@ interrupt void cpu_timer1_isr_SENS(void)
if(Desk==dsk_LOAD)
{
/* Снять истёкший импульс до расчёта ЦАП, независимо от main. */
UMP_pulse_tick();
Load_runner();
/* Áàçà âðåìåíè 1 ìñ; ñíèìîê ñîäåðæèò ðåçóëüòàò òåêóùåãî øàãà ÖÀÏ. */
ump_log_tick();

View File

@@ -1,3 +1,9 @@
/* Параметры и обработчики Modbus после проверки CRC. Массив modbus
* содержит обычные адреса 0..127, область 0x1000 обслуживает логгер.
* EEPROM хранит параметры, но не является источником START/STOP:
* при загрузке сохраняется последняя живая команда нагрузки.
* Функции вызываются из main; EEPROM блокирует этот контекст.
*/
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "package.h"
#include "RS485.h"
@@ -18,6 +24,7 @@
#include "caliber.h"
#include "log_to_mem.h"
#include "DAC.h"
int modbus[ANSWER_LEN+1];
unsigned int param[ANSWER_LEN+1];
@@ -40,9 +47,11 @@ void Default_params()
for(i=0;i<ANSWER_LEN;i++)
{
Modbus[i].all = 0;
/* Команда нагрузки не является параметром по умолчанию. */
if (Desk != dsk_LOAD || i != 127) Modbus[i].all = 0;
}
UMP_reset_parameter_commands();
LastMode = Mode;
if(Desk == dsk_EPLT)
@@ -130,6 +139,10 @@ void Default_params()
Init_sensors_more();
}
/* CRC и Mode проверяются до применения EEPROM. Слово 127
* нагрузки не копируется даже временно: ISR не должен увидеть
* старый START из EEPROM либо потерять текущую CAN-команду.
*/
void Load_params()
{
unsigned int i,crc;
@@ -140,13 +153,15 @@ void Load_params()
(crc !=0xFFFF) &&
(Mode == param[126]))
{
for(i=0;i<ANSWER_LEN;i++) modbus[i] = param[i];
Commands=0;
/* Не восстанавливать START/STOP из EEPROM даже на один тик ISR. */
for(i=0;i<ANSWER_LEN;i++)
if (Desk != dsk_LOAD || i != 127) modbus[i] = param[i];
UMP_reset_parameter_commands();
}
else
{
Default_params();
Commands=0;
UMP_reset_parameter_commands();
Save_params();
if(Desk == dsk_COMM)
{
@@ -154,6 +169,10 @@ void Load_params()
Caliber_time = 0xFFFF;
} } }
/* ISR продолжает менять измерения во время сбора param. CRC
* относится к собранному массиву, а не атомарному снимку всей платы.
* Не вызывать сохранение из критического пути дискретов.
*/
void Save_params()
{
unsigned int i,dif=0;
@@ -270,8 +289,12 @@ void ReceiveCommandModbus6(RS_DATA *rs_arr)
modbus_exception(rs_arr, CMD_MODBUS_6, 3); return;
}
} else if (Address_MB < ANSWER_LEN) {
Modbus[Address_MB].all = Data_MB;
if (Address_MB == 127) ump_log_rs();
/* RS и CAN используют одну историю фронтов. Чередование каналов
* не создаёт двух независимых повторных запусков. */
if (Address_MB == 127) {
UMP_commands_write(Data_MB);
ump_log_rs();
} else Modbus[Address_MB].all = Data_MB;
} else { modbus_exception(rs_arr, CMD_MODBUS_6, 2); return; }
rs_arr->flag_TIMEOUT_to_Send=true;

View File

@@ -1,3 +1,9 @@
/* Выбор типа платы, направления GPIO и чтение входов. get_Mode
* читает аппаратный адрес и выбирает Desk. Один вывод в разных
* режимах может иметь разное назначение. Для нагрузки START=GPIO62,
* STOP=GPIO58, RES_OUT_2=GPIO3 (активный ноль). Направления заданы
* в GPIO_table.h; изменение распиновки требует сверки со схемой.
*/
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
#include "filter_bat2.h"
#include "measure.h"

View File

@@ -1,3 +1,8 @@
/* Логика пульта и индикации. cpu_timer1_isr_PULT выбирается
* только для dsk_EPLT; для нагрузки работает обработчик из measure.c.
* Lonely относится к активности обмена, не к задержке пуска СИФУ.
* Не смешивать функции двух режимов при изменении общего таймера.
*/
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "DSP2833x_SWPrioritizedIsrLevels.h"

View File

@@ -1,3 +1,9 @@
/* SPI EEPROM. Seeprom_read/write разбивают запрос на страницы
* и синхронно ждут spiSe2pFree. SPI-автомат продвигает таймер 2
* каждые 100 мкс. При запрете этого IRQ ожидание не завершится.
* Тайм-аут в старом драйвере отсутствует. Дискреты СИФУ теперь
* не зависят от того, завершилось ли это ожидание в main.
*/
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "spise2p.h"
@@ -19,6 +25,9 @@ int ccc=0;
/******* SPI bus Serial EEPROM driver Initialization routine ********/
/********************************************************************/
/* Блокирует main до завершения страниц. Запрет IRQ остановит
* SPI-автомат. CAN и таймер СИФУ должны прерывать это ожидание.
*/
void Seeprom_write( unsigned int adres,
unsigned int buf[],
unsigned int size)
@@ -50,6 +59,9 @@ void Seeprom_write( unsigned int adres,
CpuTimer2Regs.TCR.all = 0x4010; // Use write-only instruction to set TSS bit = 1
}
/* Чтение также синхронное для main, тайм-аут не реализован.
* При зависании проверить step/SPI и работу таймера 2.
*/
void Seeprom_read( unsigned int adres,
unsigned int buf[],
unsigned int size)

View File

@@ -1,3 +1,8 @@
/* Внешняя память и программные задержки. init_zone7 готовит XINTF
* до первого обращения к .logg; времена шины зависят от частоты DSP
* и аппаратной памяти. pause_us занимает CPU циклом и используется
* при инициализации. Длительность СИФУ должна задаваться таймером.
*/
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
// Configure the timing paramaters for Zone 7.