diff --git a/Doc/UMP_LOGGER.md b/Doc/UMP_LOGGER.md index dc5dcfa..b6e9910 100644 --- a/Doc/UMP_LOGGER.md +++ b/Doc/UMP_LOGGER.md @@ -35,10 +35,10 @@ EEPROM не используется: под отключением в этой ## Память и точность Использована существующая секция `.logg` по адресу 0x200000: 64000 -16-битных слов. Два банка по 800 записей × 40 слов занимают её целиком. -Текущий банк кольцевой. При триггере сохраняются последние до 399 записей, +16-битных слов. Два банка по 760 записей × 42 слова занимают 63840 слов (160 слов свободны). +Текущий банк кольцевой. При триггере сохраняются последние до 379 записей, добавляется событие отключения, оставшаяся половина банка отведена -постинтервалу. При 20 мс это до примерно 8 секунд до отключения и 1 секунды +постинтервалу. При 20 мс это до примерно 7.6 секунды до отключения и 1 секунды после. Дополнительные события CAN и дискретов сокращают временную глубину. При интенсивном потоке событий или периоде 1 мс постинтервал может заполнить @@ -51,7 +51,7 @@ EEPROM не используется: под отключением в этой одинаковую отметку; порядок сохраняется порядком записей. На перезапуске регистратора счётчик продолжает прежнюю шкалу, при перезагрузке платы — 0. -Онлайн-опрос возвращает три последних записи каждые 40 мс. Он не гарантирует +Онлайн-опрос возвращает две последние записи каждые 40 мс. Он не гарантирует передачу каждого события при высоком CAN-трафике, медленном UART или паузах GUI. Номера записей позволяют убрать дубликаты и явно показать пропуски. Полный сохранившийся фрагмент следует читать кнопкой архива. Частота 20 мс @@ -63,7 +63,7 @@ GUI. Номера записей позволяют убрать дублика EEPROM, выделения памяти или копирования целого банка. Реальную задержку прерываний и длительность критических секций нужно измерить на F28335. -## Состав записи: 40 слов +## Состав записи v3: 42 слова | Слова | Данные | Единицы/смысл | |---|---|---| @@ -91,6 +91,16 @@ EEPROM, выделения памяти или копирования целог | 33–34 | эффективные dac_go/dac_stop + 4 | 0.1 мА после ограничений алгоритма; GUI переводит в мА | | 35 | kod | целочисленное положение, используемое Anal_output | | 36–39 | ADC_table[0..3] | значения таблицы АЦП в исходном масштабе прошивки | +| 40 | ЗПТ1: U1 + U2, ПМ67 регистр 306 / индекс 305 | исходное 16-битное слово без пересчёта | +| 41 | ЗПТ2: U3 + U4, ПМ67 регистр 9 / индекс 8 | исходное 16-битное слово без пересчёта | + +Напряжения принимаются из технологических CAN-кадров с нулевыми индексами +305 и 8. Учитываются все три позиции и биты маски 0x8000/0x4000/0x2000. +Они хранятся отдельно от массива modbus[0..127], обновляются и при выключенном +логгере. Запись содержит последние принятые значения; до первого приёма — 0. +При потере связи остаётся последнее значение: отдельного признака свежести нет. +Масштаб и знаковость физического напряжения не заданы исходной таблицей; +SetGUI показывает исходное беззнаковое слово, коэффициент задаётся в интерфейсе. **Отправленный код ЦАП не является измеренным током выхода.** В этом проекте не установлено, какой вход аппаратно измеряет ток ЦАП. При включённом @@ -116,9 +126,9 @@ FC03, 0x1000, 16 слов: | Смещение | Значение | |---|---| -| 0,1 | 0x554D, версия 2 | +| 0,1 | 0x554D, версия 3 | | 2,3 | состояние и число записей выбранного источника | -| 4,5 | 40 слов в записи, 800 записей в банке | +| 4,5 | 42 слова в записи, 760 записей в банке | | 6 | период периодических снимков, мс | | 7,8 | счётчик времени, младшее/старшее слово | | 9,10 | Desk (требуется 6 / dsk_LOAD), Mode | @@ -133,25 +143,28 @@ FC03, 0x1000, 16 слов: FC06: - 0x1000: 1 — новый текущий журнал, 0 — остановить его; - 0x1001: период 1..1000, менять только при остановленном журнале; -- 0x1002: хронологический индекс первой записи окна 0..799; +- 0x1002: хронологический индекс первой записи окна 0..759; - 0x1003: источник окна, 0 — текущий остановленный банк, 1 — архив отключения. -FC03, 0x1010, до 120 слов: окно до трёх записей от установленного индекса. +FC03, 0x1010, до 120 слов: окно от установленного индекса; для целых записей v3 читать 42 или 84 слова. +CAN допускает 42/84 и прежние размеры 40/80/120; RTU допускает 1..120 слов. Чтение текущего банка этим окном во время записи не выдаёт изменяющиеся данные. GUI сначала останавливает его; архив можно читать при работающем текущем банке. После всех блоков GUI повторно проверяет поколение архива; при замене во время чтения результат не подменяет предыдущий график. FC03, 0x1100, ровно 124 слова: онлайн-блок. Слова 0,1 — 32-битный номер -первой записи, 2 — число записей 0..3, 3 — поколение архива, далее до трёх -записей по 40 слов. Неиспользованные слова равны нулю. Окно онлайн не +первой записи, 2 — число записей 0..2, 3 — поколение архива, далее до двух +записей по 42 слова. Неиспользованные слова равны нулю. Окно онлайн не зависит от курсора/выбора архива. Разделение 0x1010 и 0x1100 предотвращает пересечение двух окон. Недопустимые диапазоны и значения возвращают исключения Modbus 2/3. CRC и разбор стандартного ответа GUI используют существующее общее ядро. -Расширение описано отдельно в core/ump_logger.py, без изменения общей -библиотеки и без необходимости пересобирать её DLL. +SetGUI распознаёт v2 (40 слов, 800 записей) и v3 (42 слова, 760 записей). +Для v2 новые напряжения недоступны (NaN), для v3 доступны графики и CSV. +CAN-валидация общей библиотеки расширена размерами 42/84 слова. +Исходники протокола подключаются к прошивке из templates/c/set-protocol. ## Проверка и запуск @@ -176,3 +189,6 @@ TI. Отдельно выполнена синтаксическая прове подать откл. → через секунду прочитать архив → сверить код ЦАП, ток внешним измерителем и физические входы/выходы; затем повторить с разрывом RS. Период 1 мс проверить отдельно под максимальной CAN-нагрузкой. + +Для сборки v3 нужен templates/main начиная с коммита c0ee7c4 +(поддержка CAN-чтения 42/84 слов и порт TMS320F28335). diff --git a/Source/Internal/Include/log_to_mem.h b/Source/Internal/Include/log_to_mem.h index 94e673d..f03aac9 100644 --- a/Source/Internal/Include/log_to_mem.h +++ b/Source/Internal/Include/log_to_mem.h @@ -33,12 +33,13 @@ extern LOG Log; void clear_mem(); /* Ëîããåð ÓÌÏ: îòäåëüíîå àäðåñíîå ïðîñòðàíñòâî Modbus, áåç èçìåíåíèÿ - * 128 òåõíîëîãè÷åñêèõ ðåãèñòðîâ. Äâà áàíêà ïî 800 çàïèñåé: + * 128 òåõíîëîãè÷åñêèõ ðåãèñòðîâ. Äâà áàíêà ïî 760 çàïèñåé: * òåêóùèé êîëüöåâîé æóðíàë è çàôèêñèðîâàííûé ôðàãìåíò îòêëþ÷åíèÿ. */ #define UMP_LOG_BASE 0x1000U #define UMP_LOG_DATA 0x1010U -#define UMP_LOG_WORDS 40U -#define UMP_LOG_CAPACITY 800U +#define UMP_LOG_WORDS 42U +#define UMP_LOG_CAPACITY 760U +#define UMP_LOG_LIVE_RECORDS (120U / UMP_LOG_WORDS) #define UMP_LOG_LIVE 0x1100U extern unsigned int ump_dac_ramp, ump_dac_duration, ump_dac_go10, ump_dac_stop10, ump_dac_position; void ump_log_tick(void); diff --git a/Source/Internal/log_to_mem.c b/Source/Internal/log_to_mem.c index 3f92ffc..53cd187 100644 --- a/Source/Internal/log_to_mem.c +++ b/Source/Internal/log_to_mem.c @@ -43,6 +43,8 @@ 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; +/* Latest PM67 sums: register 306 (index 305), register 9 (index 8). */ +static unsigned int ump_pm67_voltage[2]; static unsigned int ump_prev_commands, ump_prev_inputs, ump_prev_outputs; extern int CanTimeOutErrorTR; /* Äèàãíîñòèêà âíóòðåííèõ ïåðåìåííûõ ðàçãîíà. Îáíîâëÿåòñÿ ñàìèì Load_runner, @@ -113,6 +115,7 @@ static void ump_capture(unsigned int reason) 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[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; @@ -161,9 +164,20 @@ void ump_log_io(void) * íîâûå êîìàíäû, à òàêæå èñõîäíûé àäðåñ/ìàñêó è âñå òðè ñëîâà êàäðà. */ 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; + unsigned int saved, i, address, mask, data[3]; + if (Desk != dsk_LOAD) return; saved = __disable_interrupts(); + data[0] = a; data[1] = b; data[2] = c; + address = header & 0x1FFFU; + mask = 0x8000U; + /* Track reception even while recording is stopped. Each mask bit + * refers to its own address, including disabled words in between. */ + for (i = 0; i < 3; i++, address++, mask >>= 1) { + if (!(header & mask)) continue; + if (address == 305U) ump_pm67_voltage[0] = data[i]; + if (address == 8U) ump_pm67_voltage[1] = data[i]; + } + if (ump_state != 1) { __restore_interrupts(saved); return; } ump_can_header = header; ump_can_data[0] = a; ump_can_data[1] = b; ump_can_data[2] = c; ump_can_count++; @@ -227,7 +241,7 @@ unsigned int ump_log_read(unsigned int address) unsigned long first; switch (address) { case UMP_LOG_BASE: return 0x554D; - case UMP_LOG_BASE+1: return 2; + case UMP_LOG_BASE+1: return 3; 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; @@ -250,7 +264,7 @@ unsigned int ump_log_read(unsigned int address) /* Ïîñëåäíèå òðè çàïèñè äëÿ îíëàéí-ãðàôèêà, áåç îñòàíîâêè è áåç * èçìåíåíèÿ êóðñîðà àðõèâíîãî ÷òåíèÿ. Ïåðâûå äâà ñëîâà — èõ íîìåð. */ if (address >= UMP_LOG_LIVE && address < UMP_LOG_LIVE+124) { - count = ump_count < 3 ? ump_count : 3; + count = ump_count < UMP_LOG_LIVE_RECORDS ? ump_count : UMP_LOG_LIVE_RECORDS; first = ump_sequence - count; offset = address - UMP_LOG_LIVE; if (offset == 0) return (unsigned int)first; diff --git a/tests/ump_logger/recorder_test.c b/tests/ump_logger/recorder_test.c index c2f4a25..ba5268c 100644 --- a/tests/ump_logger/recorder_test.c +++ b/tests/ump_logger/recorder_test.c @@ -20,12 +20,23 @@ __declspec(dllexport) int run_tests(void) modbus[127] = 0x80; modbus[0x50] = 6; modbus[0x51] = 16; modbus[0x7B] = 1234; modbus[0x1C] = 160; + /* PM67 reception is independent of recording; all three CAN slots work. */ + ump_log_can(0x8000U | 305U, 0xFEDCU, 0, 0); + ump_log_can(0x4000U | 7U, 0, 456, 0); + CHECK(ump_pm67_voltage[0] == 0xFEDCU && ump_pm67_voltage[1] == 456); + ump_log_can(305U, 1, 2, 3); /* Masked-out word must not overwrite. */ + ump_log_can(0x2000U | 303U, 0, 0, 123); + ump_log_can(0x2000U | 6U, 0, 0, 789); + CHECK(ump_pm67_voltage[0] == 123 && ump_pm67_voltage[1] == 789); + ump_log_can(0x8000U | 306U, 999, 0, 0); /* Not a one-based CAN address. */ CHECK(ump_log_write(UMP_LOG_BASE, 1)); + CHECK(ump_word(0, 0, 40) == 123 && ump_word(0, 0, 41) == 789); + CHECK(2UL * UMP_LOG_CAPACITY * UMP_LOG_WORDS <= LOG_PAGE_LEN); CHECK(!ump_log_write(UMP_LOG_BASE, 1)); CHECK(!ump_log_write(UMP_LOG_BASE+1, 20)); for (i=0; i<900; i++) ump_log_tick(); CHECK(ump_count == UMP_LOG_CAPACITY); - CHECK(ump_word(0, 0, 0) == 101); + CHECK(ump_word(0, 0, 0) == 901-UMP_LOG_CAPACITY); CHECK(ump_word(0, UMP_LOG_CAPACITY-1, 0) == 900); CHECK(ump_word(0, 0, 8) == 1234); CHECK(ump_word(0, 0, 24) == 6); @@ -43,6 +54,11 @@ __declspec(dllexport) int run_tests(void) CHECK(ump_word(1, UMP_LOG_CAPACITY/2-1, 2) == 0x102); CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 2) == 0x205); CHECK(ump_count == 0 && ump_state == 1); + CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 40) == 123); + CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 41) == 789); + ump_log_can(0x8000U | 305U, 999, 0, 0); + CHECK(ump_word(0, ump_count-1, 40) == 999); + CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 40) == 123); generation = ump_generation; archived = ump_word(1, UMP_LOG_CAPACITY-1, 0); sequence = ump_sequence; @@ -50,8 +66,8 @@ __declspec(dllexport) int run_tests(void) CHECK(ump_word(1, UMP_LOG_CAPACITY-1, 0) == archived); CHECK(ump_generation == generation); CHECK(ump_sequence == sequence + 200); - CHECK(ump_log_read(UMP_LOG_LIVE+2) == 3); - CHECK(ump_log_read(UMP_LOG_LIVE+4) == ump_time-2); + CHECK(ump_log_read(UMP_LOG_LIVE+2) == UMP_LOG_LIVE_RECORDS); + CHECK(ump_log_read(UMP_LOG_LIVE+4) == ump_time-(UMP_LOG_LIVE_RECORDS-1)); CHECK(ump_log_write(UMP_LOG_BASE+3, 1)); CHECK(ump_log_write(UMP_LOG_BASE+2, UMP_LOG_CAPACITY-1)); CHECK(ump_log_read(UMP_LOG_DATA) == archived); @@ -72,9 +88,15 @@ __declspec(dllexport) int run_tests(void) /* CAN читает те же регистры и формирует цельный снимок из 124 слов. * Запись по старым технологическим адресам через сервис запрещена. */ length = ump_can_prepare(3, UMP_LOG_BASE, 16, reply, &error); - CHECK(!error && length == 16 && reply[0] == 0x554D && reply[1] == 2); + CHECK(!error && length == 16 && reply[0] == 0x554D && reply[1] == 3); length = ump_can_prepare(3, UMP_LOG_LIVE, 124, reply, &error); CHECK(!error && length == 124); + CHECK(reply[2] <= UMP_LOG_LIVE_RECORDS); + for (i=4+reply[2]*UMP_LOG_WORDS; i<124; i++) CHECK(reply[i] == 0); + length = ump_can_prepare(3, UMP_LOG_DATA, 84, reply, &error); + CHECK(!error && length == 84); + length = ump_can_prepare(3, UMP_LOG_DATA, 42, reply, &error); + CHECK(!error && length == 42); ump_can_prepare(3, UMP_LOG_LIVE, 126, reply, &error); CHECK(error == 2); ump_can_prepare(6, 127, 0x80, reply, &error);