feat: add M95M02-only GAS and EEPROM profiles
Expose the existing registers through Modbus and service CAN using one GAS provider only in M95M02 builds. Include the EEPROM layout/driver, LOAD protection and calibration, firmware identity and shared CCS build workflow. Add transport/profile and SCI8 validation tests, documentation and the checked M95M02 firmware image.
This commit is contained in:
@@ -31,17 +31,15 @@ void clear_mem()
|
||||
for (i=Log.Start; i<Log.Finis; i++)
|
||||
*(volatile int *)i = 0;
|
||||
}
|
||||
/* Два банка используют уже выделенную внешнюю RAM .logg (64000 слов).
|
||||
* Активный банк кольцевой. Через 1000 мс после команды отключения он
|
||||
* становится архивом, а запись продолжается во втором банке. Переключение
|
||||
* занимает постоянное время: копирования 30 тысяч слов под запретом IRQ нет.
|
||||
* Архив переживает разрыв RS-связи, но НЕ исчезновение питания платы. */
|
||||
/* Two RAM banks: freeze after 10% of bank capacity is recorded after stop. */
|
||||
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_source, ump_post;
|
||||
#define UMP_POST_POINTS (UMP_LOG_CAPACITY / 10U)
|
||||
static void ump_freeze(void);
|
||||
static unsigned int ump_can_header, ump_can_data[3], ump_can_count;
|
||||
/* Latest PM67 sums: register 306 (index 305), register 9 (index 8). */
|
||||
static unsigned int ump_pm67_voltage[2];
|
||||
@@ -62,7 +60,7 @@ void ump_log_init(void)
|
||||
ump_time = 0; ump_sequence = 0;
|
||||
ump_bank = 0; ump_archive_bank = 1;
|
||||
ump_archive_count = 0; ump_archive_next = 0; ump_generation = 0;
|
||||
ump_source = 0; ump_post = 0; ump_post_dropped = 0;
|
||||
ump_source = 0; ump_post = 0;
|
||||
ump_can_header = 0; ump_can_count = 0;
|
||||
for (i = 0; i < 3; i++) ump_can_data[i] = 0;
|
||||
for (i = 0; i < 2; i++) ump_pm67_voltage[i] = 0;
|
||||
@@ -95,32 +93,30 @@ static unsigned int ump_outputs(void)
|
||||
static void ump_capture(unsigned int reason)
|
||||
{
|
||||
volatile unsigned int *p;
|
||||
unsigned int i, commands;
|
||||
unsigned int i, commands, inputs, outputs;
|
||||
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;
|
||||
inputs = ump_inputs(); outputs = ump_outputs();
|
||||
/* Freeze only an actual running-to-stopped output transition.
|
||||
* STOP is set before RES_OUT_2 is cleared in main; an interrupt can
|
||||
* observe these writes separately, so require its level, not its edge.
|
||||
* Repeated reset/STOP pulses while already stopped leave the archive. */
|
||||
if (!ump_post && (ump_prev_outputs & 4U) && !(outputs & 4U) &&
|
||||
(outputs & 2U)) {
|
||||
/* Keep 90% including the trigger; reserve 10% for later records. */
|
||||
if (ump_count >= UMP_LOG_CAPACITY - UMP_POST_POINTS)
|
||||
ump_count = UMP_LOG_CAPACITY - UMP_POST_POINTS - 1;
|
||||
ump_post = UMP_POST_POINTS;
|
||||
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;
|
||||
ump_prev_commands = commands; ump_prev_inputs = inputs; ump_prev_outputs = outputs;
|
||||
/* Every stored point counts, including CAN and I/O, except the trigger. */
|
||||
if (ump_post && !(reason & 0x100) && --ump_post == 0) reason = 5;
|
||||
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[4] = inputs; p[5] = 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]; }
|
||||
@@ -136,11 +132,11 @@ static void ump_capture(unsigned int reason)
|
||||
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[i];
|
||||
p[40] = ump_pm67_voltage[0]; p[41] = ump_pm67_voltage[1];
|
||||
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++;
|
||||
if (reason == 5) ump_freeze();
|
||||
}
|
||||
|
||||
/* Çàâåðø¸ííûé áàíê áîëüøå íå èçìåíÿåòñÿ äî ñëåäóþùåãî îòêëþ÷åíèÿ.
|
||||
@@ -160,10 +156,6 @@ void ump_log_tick(void)
|
||||
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);
|
||||
}
|
||||
@@ -224,6 +216,7 @@ int ump_log_write(unsigned int address, unsigned int value)
|
||||
ump_count = 0; ump_next = 0; ump_cursor = 0; ump_divider = 0; ump_post = 0;
|
||||
ump_source = 0;
|
||||
ump_prev_commands = Commands;
|
||||
ump_prev_inputs = ump_inputs(); ump_prev_outputs = ump_outputs();
|
||||
no_write = 0; never_write = 0;
|
||||
ump_state = 1;
|
||||
ump_capture(1);
|
||||
@@ -274,7 +267,11 @@ unsigned int ump_log_read(unsigned int address)
|
||||
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;
|
||||
/* Preserve the legacy millisecond status field as an upper estimate.
|
||||
* Additional event records may finish the post interval sooner. */
|
||||
case UMP_LOG_BASE+14:
|
||||
first = (unsigned long)ump_post * ump_period;
|
||||
return first > 65535UL ? 65535U : (unsigned int)first;
|
||||
case UMP_LOG_BASE+15: return ump_state;
|
||||
}
|
||||
if (address >= UMP_LOG_DATA && address < UMP_LOG_DATA+120 && (ump_source || ump_state != 1)) {
|
||||
|
||||
Reference in New Issue
Block a user