Files
Balsam_166/Source/Internal/log_to_mem.c
andrey eb2ff79932 Устранена зависимость дискретов СИФУ от основного цикла в 166
Фронты START/STOP обрабатываются при принятии командного слова CAN/RS,
а окончание импульса обслуживается таймером. STOP имеет приоритет,
перекрытие выходов исключено, сохранена защита от самопуска при включении.
Загрузка параметров больше не подменяет живые команды нагрузки.

Добавлены подробные русские комментарии во все собственные C-модули
и основные заголовки, описание поведения и host-тест автомата.
Обновлены файлы прошивки. Полная сборка TI 22.6.1.LTS и тесты пройдены;
проверка на физической плате не выполнялась.
2026-09-23 01:28:11 +03:00

273 lines
11 KiB
C

/* Ðåãèñòðàòîð ÓÌÏ âî âíåøíåé ïàìÿòè .logg: äâà áàíêà ïî 800 çàïèñåé
* èç 40 ñëîâ äëÿ SetGUI. Àðõèâ îòêëþ÷åíèÿ íå ìåøàåò äàëüíåéøåé çàïèñè.
* Ïèñàòåëè èç main/CAN/òàéìåðà çàùèùàþòñÿ êîðîòêèìè ñåêöèÿìè IRQ
* ñ âîññòàíîâëåíèåì ïðåæíåé ìàñêè. Àðõèâ íå ýíåðãîíåçàâèñèìûé.
* clear_mem âûïîëíÿåòñÿ ïðè çàïóñêå äî âêëþ÷åíèÿ ïðåðûâàíèé.
*/
#include "DSP2833x_Device.h"
#include "filter_bat2.h"
#include "measure.h"
#include "package.h"
#include "RS485.h"
#include "message.h"
#include "peripher.h"
#include "DAC.h"
#include "ADC.h"
#include "log_to_mem.h"
int no_write = 0,
never_write = 0; // Ôëàãè, ÷òîáû íå ïèñàòü (åñëè ÷òî)
#pragma DATA_SECTION(logs_block,".logg");
unsigned int logs_block[0xFA00];
LOG Log;
unsigned int flog=0;
// Î÷èùåíèå ïàìàòè, ãäå ëîãè ëåæàò
void clear_mem()
{
unsigned long i;
Log.Start = LOG_PAGE_START;
Log.Finis = LOG_PAGE_START + LOG_PAGE_LEN;
Log.Adres = Log.Start;
Log.Circl = 0;
for (i=Log.Start; i<Log.Finis; i++)
*(volatile int *)i = 0;
}
/* Äâà áàíêà èñïîëüçóþò óæå âûäåëåííóþ âíåøíþþ RAM .logg (64000 ñëîâ).
* Àêòèâíûé áàíê êîëüöåâîé. ×åðåç 1000 ìñ ïîñëå êîìàíäû îòêëþ÷åíèÿ îí
* ñòàíîâèòñÿ àðõèâîì, à çàïèñü ïðîäîëæàåòñÿ âî âòîðîì áàíêå. Ïåðåêëþ÷åíèå
* çàíèìàåò ïîñòîÿííîå âðåìÿ: êîïèðîâàíèÿ 30 òûñÿ÷ ñëîâ ïîä çàïðåòîì IRQ íåò.
* Àðõèâ ïåðåæèâàåò ðàçðûâ RS-ñâÿçè, íî ÍÅ èñ÷åçíîâåíèå ïèòàíèÿ ïëàòû. */
static volatile unsigned int ump_state, ump_count, ump_cursor, ump_next;
static volatile unsigned int ump_period = 20, ump_divider;
static volatile unsigned long ump_time, ump_sequence;
static unsigned int ump_bank, ump_archive_bank = 1;
static unsigned int ump_archive_count, ump_archive_next, ump_generation;
static unsigned int ump_source, ump_post, ump_post_dropped;
static unsigned int ump_can_header, ump_can_data[3], ump_can_count;
static unsigned int ump_prev_commands, ump_prev_inputs, ump_prev_outputs;
extern int CanTimeOutErrorTR;
/* Äèàãíîñòèêà âíóòðåííèõ ïåðåìåííûõ ðàçãîíà. Îáíîâëÿåòñÿ ñàìèì Load_runner,
* íå ïåðåñ÷èòûâàåò è íå èçìåíÿåò óïðàâëÿþùèé àëãîðèòì. */
unsigned int ump_dac_ramp, ump_dac_duration, ump_dac_go10, ump_dac_stop10, ump_dac_position;
/* Ëîãè÷åñêèå óðîâíè âõîäîâ ïëàòû íàãðóçêè: ôèçè÷åñêèé íîëü îçíà÷àåò 1.
* ×òåíèå GPIO íåïîñðåäñòâåííî çäåñü ïîçâîëÿåò çàïèñàòü âõîä äî ñëåäóþùåãî
* îáíîâëåíèÿ ðåãèñòðà Inputs â îñíîâíîì öèêëå. */
static unsigned int ump_inputs(void)
{
return (!GpioDataRegs.GPADAT.bit.GPIO6) |
((!GpioDataRegs.GPADAT.bit.GPIO8) << 1) |
((!GpioDataRegs.GPADAT.bit.GPIO11) << 2);
}
/* START/STOP àêòèâíû åäèíèöåé; RES_OUT_2 àêòèâåí ôèçè÷åñêèì íóë¸ì. */
static unsigned int ump_outputs(void)
{
return GpioDataRegs.GPBDAT.bit.GPIO62 |
(GpioDataRegs.GPBDAT.bit.GPIO58 << 1) |
((!GpioDataRegs.GPADAT.bit.GPIO3) << 2);
}
/* Âûçûâàåòñÿ òîëüêî âíóòðè êîðîòêîé êðèòè÷åñêîé ñåêöèè. Âñå òðè èñòî÷íèêà
* çàïèñåé (main, CAN ISR, timer ISR) èñïîëüçóþò îäíó áëîêèðîâêó IRQ ñ
* âîññòàíîâëåíèåì ïðåæíåãî ñîñòîÿíèÿ, âêëþ÷àÿ âûçîâû èç ïðåðûâàíèÿ. */
static void ump_capture(unsigned int reason)
{
volatile unsigned int *p;
unsigned int i, commands;
if (ump_state != 1 || Desk != dsk_LOAD || READY) return;
if (no_write || never_write) { ump_state = 3; return; }
commands = Commands;
/* Îòêëþ÷åíèå: ôðîíò cUMPreset (áèò 6) ëèáî ñïàä cUMPstart (áèò 7).
* Ïîâòîðíûå êîìàíäû íå ñäâèãàþò êîíåö óæå íà÷àòîãî ïîñòèíòåðâàëà. */
if (!ump_post && (((commands & 0x40) && !(ump_prev_commands & 0x40)) ||
(!(commands & 0x80) && (ump_prev_commands & 0x80)))) {
/* Ïîëîâèíó áàíêà ðåçåðâèðóåì ïîä ïîñòèíòåðâàë. Äàæå ïðè ïåðèîäå
* 1 ìñ èëè øêâàëå CAN ñîáûòèå îòêëþ÷åíèÿ íå âûòåñíÿåòñÿ êîëüöîì. */
if (ump_count >= UMP_LOG_CAPACITY/2) ump_count = UMP_LOG_CAPACITY/2-1;
ump_post_dropped = 0;
ump_post = 1000;
reason |= 0x100;
}
/* Ïîñëåäíåå ìåñòî îñòàâëÿåì äëÿ ñíèìêà êîíöà ïîñòèíòåðâàëà. Ïðè
* ïåðåïîëíåíèè ÷åñòíî îòìå÷àåì óñå÷åíèå áèòîì 0x200 â êîíå÷íîé çàïèñè. */
if (ump_post && ump_count >= UMP_LOG_CAPACITY-1) {
ump_post_dropped = 1;
return;
}
if (reason == 5 && ump_post_dropped) reason |= 0x200;
p = logs_block + ((unsigned long)ump_bank * UMP_LOG_CAPACITY + ump_next) * UMP_LOG_WORDS;
p[0] = (unsigned int)ump_time; p[1] = (unsigned int)(ump_time >> 16);
p[2] = reason; p[3] = commands;
p[4] = ump_inputs(); p[5] = ump_outputs();
p[6] = (unsigned int)IMPowse; p[7] = (unsigned int)WAKEpowse;
p[8] = modbus[0x7B]; p[9] = modbus[0x1C];
for (i = 0; i < 4; i++) { p[10+i] = sens_data[i]; p[14+i] = modbus[i]; }
p[18] = ump_can_header;
p[19] = ump_can_data[0]; p[20] = ump_can_data[1]; p[21] = ump_can_data[2];
p[22] = ump_can_count; p[23] = CanTimeOutErrorTR;
/* Èñõîäíûå óñòàâêè — ìÀ; ýôôåêòèâíûå óñòàâêè ïîñëå îãðàíè÷åíèé — 0.1 ìÀ.
* p[8] — îòïðàâëåííûé êîä, à p[9] — ðàñ÷¸òíîå çàäàíèå, ÍÅ èçìåðåíèå òîêà. */
/* 166: fixed ramp endpoints; no configurable DAC_go/DAC_stop. */
p[24] = 6; p[25] = 16;
p[26] = DAC_min(); p[27] = DAC_max(); p[28] = DAC_cal();
p[29] = DAC_04; p[30] = DAC_20;
p[31] = ump_dac_ramp; p[32] = ump_dac_duration;
p[33] = ump_dac_go10; p[34] = ump_dac_stop10; p[35] = ump_dac_position;
for (i = 0; i < 4; i++) p[36+i] = adc_table_lem[i];
ump_prev_commands = commands; ump_prev_inputs = p[4]; ump_prev_outputs = p[5];
ump_next++;
if (ump_next == UMP_LOG_CAPACITY) ump_next = 0;
if (ump_count < UMP_LOG_CAPACITY) ump_count++;
ump_sequence++;
}
/* Çàâåðø¸ííûé áàíê áîëüøå íå èçìåíÿåòñÿ äî ñëåäóþùåãî îòêëþ÷åíèÿ.
* Íîìåð ïîêîëåíèÿ ïîçâîëÿåò GUI îáíàðóæèòü çàìåíó àðõèâà âî âðåìÿ ÷òåíèÿ. */
static void ump_freeze(void)
{
ump_archive_bank = ump_bank;
ump_archive_count = ump_count; ump_archive_next = ump_next;
ump_generation++;
ump_bank ^= 1;
ump_count = 0; ump_next = 0; ump_post = 0;
}
void ump_log_tick(void)
{
unsigned int saved = __disable_interrupts();
if (ump_state == 1) {
ump_time++;
if (++ump_divider >= ump_period) { ump_divider = 0; ump_capture(1); }
if (ump_post && --ump_post == 0) {
ump_capture(5);
ump_freeze();
}
}
__restore_interrupts(saved);
}
/* Äîïîëíèòåëüíûé ñíèìîê òîëüêî ïðè èçìåíåíèè êîìàíä, âõîäîâ èëè âûõîäîâ.
* Ýòî íå çàìåíÿåò ïåðèîäè÷åñêóþ çàïèñü àíàëîãîâûõ âåëè÷èí â òàéìåðå. */
void ump_log_io(void)
{
unsigned int saved;
if (ump_state != 1 || Desk != dsk_LOAD) return;
saved = __disable_interrupts();
if (Commands != ump_prev_commands || ump_inputs() != ump_prev_inputs ||
ump_outputs() != ump_prev_outputs) ump_capture(3);
__restore_interrupts(saved);
}
/* Âûçûâàåòñÿ ïîñëå ïðèìåíåíèÿ ñëîâ ïðèíÿòîãî CAN-êàäðà: ñíèìîê ñîäåðæèò
* íîâûå êîìàíäû, à òàêæå èñõîäíûé àäðåñ/ìàñêó è âñå òðè ñëîâà êàäðà. */
void ump_log_can(unsigned int header, unsigned int a, unsigned int b, unsigned int c)
{
unsigned int saved;
if (ump_state != 1 || Desk != dsk_LOAD) return;
saved = __disable_interrupts();
ump_can_header = header;
ump_can_data[0] = a; ump_can_data[1] = b; ump_can_data[2] = c;
ump_can_count++;
ump_capture(2);
__restore_interrupts(saved);
}
void ump_log_rs(void)
{
unsigned int saved = __disable_interrupts();
ump_capture(4);
__restore_interrupts(saved);
}
/* Óïðàâëåíèå æóðíàëîì îòäåëåíî îò òåõíîëîãè÷åñêèõ êîìàíä: íà÷àëî çàïèñè
* ÍÅ çàïóñêàåò ÓÌÏ. Âûáîð àðõèâà íå îñòàíàâëèâàåò òåêóùóþ çàïèñü. */
int ump_log_write(unsigned int address, unsigned int value)
{
unsigned int saved, valid = 1;
saved = __disable_interrupts();
if (address == UMP_LOG_BASE && value == 0) {
ump_state = 3; ump_post = 0;
} else if (address == UMP_LOG_BASE && value == 1 && Desk == dsk_LOAD && !READY && ump_state != 1) {
ump_count = 0; ump_next = 0; ump_cursor = 0; ump_divider = 0; ump_post = 0;
ump_source = 0;
ump_prev_commands = Commands;
no_write = 0; never_write = 0;
ump_state = 1;
ump_capture(1);
}
else if (address == UMP_LOG_BASE+1 && ump_state != 1 && value >= 1 && value <= 1000)
ump_period = value;
else if (address == UMP_LOG_BASE+2 && value < UMP_LOG_CAPACITY)
ump_cursor = value;
else if (address == UMP_LOG_BASE+3 && value <= 1) ump_source = value;
else valid = 0;
__restore_interrupts(saved);
return valid;
}
/* Ïðåîáðàçîâàíèå õðîíîëîãè÷åñêîãî èíäåêñà â ôèçè÷åñêóþ ïîçèöèþ êîëüöà.
* Äëÿ àðõèâà ñîõðàíåíû ñîáñòâåííûå count/next, íåçàâèñèìûå îò æèâîãî áàíêà. */
static unsigned int ump_word(unsigned int archived, unsigned int record, unsigned int word)
{
unsigned int count = archived ? ump_archive_count : ump_count;
unsigned int next = archived ? ump_archive_next : ump_next;
unsigned int bank = archived ? ump_archive_bank : ump_bank;
unsigned int slot;
if (record >= count) return 0;
slot = next + UMP_LOG_CAPACITY - count + record;
while (slot >= UMP_LOG_CAPACITY) slot -= UMP_LOG_CAPACITY;
return logs_block[((unsigned long)bank * UMP_LOG_CAPACITY + slot) * UMP_LOG_WORDS + word];
}
/* Âåñü Modbus-áëîê ÷èòàåòñÿ âûçûâàþùèì êîäîì ïîä îäíîé áëîêèðîâêîé IRQ.
* Ïîýòîìó timestamp/äàííûå è çàãîëîâîê îíëàéí-áëîêà îòíîñÿòñÿ ê îäíîìó
* ñîñòîÿíèþ êîëüöà, äàæå åñëè â ýòîò ìîìåíò ïðèõîäèò íîâàÿ CAN-êîìàíäà. */
unsigned int ump_log_read(unsigned int address)
{
unsigned int offset, count;
unsigned long first;
switch (address) {
case UMP_LOG_BASE: return 0x554D;
case UMP_LOG_BASE+1: return 2;
case UMP_LOG_BASE+2: return ump_source ? 3 : ump_state;
case UMP_LOG_BASE+3: return ump_source ? ump_archive_count : ump_count;
case UMP_LOG_BASE+4: return UMP_LOG_WORDS;
case UMP_LOG_BASE+5: return UMP_LOG_CAPACITY;
case UMP_LOG_BASE+6: return ump_period;
case UMP_LOG_BASE+7: return (unsigned int)ump_time;
case UMP_LOG_BASE+8: return (unsigned int)(ump_time >> 16);
case UMP_LOG_BASE+9: return Desk;
case UMP_LOG_BASE+10: return Mode;
case UMP_LOG_BASE+11: return (unsigned int)READY_FREQ;
case UMP_LOG_BASE+12: return ump_generation;
case UMP_LOG_BASE+13: return ump_archive_count;
case UMP_LOG_BASE+14: return ump_post;
case UMP_LOG_BASE+15: return ump_state;
}
if (address >= UMP_LOG_DATA && address < UMP_LOG_DATA+120 && (ump_source || ump_state != 1)) {
offset = address - UMP_LOG_DATA;
return ump_word(ump_source, ump_cursor + offset / UMP_LOG_WORDS, offset % UMP_LOG_WORDS);
}
/* Ïîñëåäíèå òðè çàïèñè äëÿ îíëàéí-ãðàôèêà, áåç îñòàíîâêè è áåç
* èçìåíåíèÿ êóðñîðà àðõèâíîãî ÷òåíèÿ. Ïåðâûå äâà ñëîâà — èõ íîìåð. */
if (address >= UMP_LOG_LIVE && address < UMP_LOG_LIVE+124) {
count = ump_count < 3 ? ump_count : 3;
first = ump_sequence - count;
offset = address - UMP_LOG_LIVE;
if (offset == 0) return (unsigned int)first;
if (offset == 1) return (unsigned int)(first >> 16);
if (offset == 2) return count;
if (offset == 3) return ump_generation;
offset -= 4;
if (offset / UMP_LOG_WORDS < count)
return ump_word(0, ump_count - count + offset / UMP_LOG_WORDS, offset % UMP_LOG_WORDS);
}
return 0;
}