diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..769f60d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Windows cmd.exe должен получать BAT с CRLF: русские комментарии в UTF-8 при одних LF могут нарушать разбор строк команд. +*.bat text eol=crlf diff --git a/.gitignore b/.gitignore index 031575a..a263d91 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,23 @@ /UKSSTMS320F28335.paf2 /UKSSTMS320F28335.sbl /Bin/UKSSTMS320F28335_*.bin +# Локальные разовые проверки, резервные копии и экспериментальные результаты сохраняются вне истории исходников. +/.ui_patch/ +# Кэш pytest создаётся повторно при запуске тестов и не является частью прошивки. +/.pytest_cache/ +# Загруженные исполняемые файлы и зависимости Doxygen остаются локальными инструментами. +/Doc/.tools/ +# HTML, JavaScript и журналы генерации документации восстанавливаются из исходников. +/Doc/build/ +# Каталог Release этого CCS-проекта содержит генерируемые make-файлы и объектные файлы. +/UKSSTMS320F28335/Release/ +# Скомпилированный кэш Python восстанавливается автоматически и не содержит самостоятельных исходников. +__pycache__/ +# Новые карты памяти формируются линкером; уже отслеживаемые карты остаются в истории. +/Bin/*.map +# Паспорт сопровождает генерируемый BIN и сохраняется рядом с ним в локальном выпуске. +/Bin/*.bin.manifest.json +# Контрольная сумма относится к конкретному генерируемому BIN и не является исходным файлом. +/Bin/*.bin.sha256 +# Именованные экспериментальные Flash-варианты сохраняются локально; основные отслеживаемые OUT остаются в истории. +/Bin/UKSSTMS320F28335_flash_*.out diff --git a/Doc/UMP_LOGGER.md b/Doc/UMP_LOGGER.md index a05af57..1f37188 100644 --- a/Doc/UMP_LOGGER.md +++ b/Doc/UMP_LOGGER.md @@ -2,7 +2,7 @@ Текущая логика дискретов описана в [SIFU_START_STOP.md](SIFU_START_STOP.md): CAN-фронты обрабатываются при приёме, импульсы снимаются таймером, STOP -имеет приоритет. Формат записи v2 и интерфейс SetGUI сохранены. +имеет приоритет. Компактный формат записи v4 совпадает с исполнением 167. ## Назначение и работа оператора @@ -13,8 +13,9 @@ CAN-фронты обрабатываются при приёме, импуль Общий RS-адрес 16 здесь не рекомендуется: ответ содержит собственный адрес, и SetGUI проверяет совпадение адресов. CAN-настройки: [PERIPH28335_CAN.md](PERIPH28335_CAN.md). -Перенесён протокол v2 из 167: 40 слов на запись, два банка по 800 записей. -Существующий SetGUI понимает эту прошивку без изменений программы. +Используется формат v4 из 167: 12 слов на запись вместо прежних 40; +ёмкость исполнения 166 сохранена — два банка по 800 записей. +Для чтения нужен SetGUI с поддержкой компактного формата v4, как для 167. Кнопки записи управляют регистратором; команду запуска УМП подаёт контроллер. 1. **Начать запись** включает только регистратор, не пуск УМП. @@ -45,7 +46,8 @@ EEPROM не используется: под отключением в этой ## Память и точность Использована существующая секция `.logg` по адресу 0x200000: 64000 -16-битных слов. Два банка по 800 записей × 40 слов занимают её целиком. +16-битных слов. Два банка по 800 записей × 12 слов используют 19200 слов; +размер выделенной секции сохранён. Одна запись занимает 24 байта вместо 80. Текущий банк кольцевой. При триггере сохраняются последние до 399 записей, добавляется событие отключения, оставшаяся половина банка отведена постинтервалу. При 20 мс это до примерно 8 секунд до отключения и 1 секунды @@ -61,7 +63,7 @@ EEPROM не используется: под отключением в этой одинаковую отметку; порядок сохраняется порядком записей. На перезапуске регистратора счётчик продолжает прежнюю шкалу, при перезагрузке платы — 0. -Онлайн-опрос возвращает три последних записи каждые 40 мс. Он не гарантирует +Онлайн-опрос возвращает до десяти последних записей каждые 40 мс. Он не гарантирует передачу каждого события при высоком CAN-трафике, медленном UART или паузах GUI. Номера записей позволяют убрать дубликаты и явно показать пропуски. Полный сохранившийся фрагмент следует читать кнопкой архива. Частота 20 мс @@ -73,7 +75,12 @@ GUI. Номера записей позволяют убрать дублика EEPROM, выделения памяти или копирования целого банка. Реальную задержку прерываний и длительность критических секций нужно измерить на F28335. -## Состав записи: 40 слов +## Состав записи v4: 12 слов + +Состав и позиции полей совпадают с компактным логгером 167. Убраны сырые +данные АЦП и CAN, ошибки, счётчики, код и калибровки ЦАП, состояние разгона +и прочие дополнительные диагностические поля. Управление нагрузкой 166, +ёмкость банка и секундный постинтервал отключения сохранены. | Слова | Данные | Единицы/смысл | |---|---|---| @@ -81,33 +88,21 @@ EEPROM, выделения памяти или копирования целог | 2 | Событие | 1 период, 2 CAN RX, 3 изменение I/O, 4 RS-команда, 5 конец постинтервала | | 2, бит 8 | Триггер отключения | флаг поверх причины события | | 2, бит 9 | Усечён постинтервал | установлен в конечном снимке | -| 3 | Commands / modbus[0x7F] | все 16 бит, в том числе пуск, сброс, инициализация и калибровка ЦАП | +| 3 | Commands & 0xC0 | только пуск УМП (бит 7) и сброс УМП (бит 6) | | 4 | Входы OMEGA, Start_1, Res_in | биты 0,1,2, активный уровень приведён к 1 | | 5 | START_DPTB, STOP_DPTB, RES_OUT_2 | биты 0,1,2, активный уровень приведён к 1 | -| 6 | IMPowse | остаток импульса, мс | -| 7 | WAKEpowse | остаток инициализации, тики DAC_FREQ | -| 8 | modbus[0x7B] | 12-битный код, переданный функцией dSEND в ЦАП | -| 9 | modbus[0x1C] | расчётное задание в 0.1 мА; GUI/CSV переводит в мА | -| 10–13 | sens_data[0..3] | измеренные сигналы, знаковое 16-битное значение в исходном масштабе | -| 14–17 | modbus[0..3] | маски ошибок измерений | -| 18 | CAN заголовок | адрес регистра в младших 13 битах и маска трёх слов в старших | -| 19–21 | Три слова последнего принятого CAN-кадра | без преобразования | -| 22 | Счётчик записанных CAN RX | младшие 16 бит | -| 23 | CanTimeOutErrorTR | младшие 16 бит счётчика тайм-аутов CAN TX | -| 24–25 | Фиксированные границы разгона 166 | 6 и 16 мА; это не регистры настройки | -| 26–28 | DAC_min(), DAC_max(), DAC_cal() | коды калибровки и ручного задания ЦАП | -| 29–30 | DAC_04, DAC_20 | значения соответствующих регистров | -| 31–32 | count_load, time_dac | положение и длительность разгона в тиках | -| 33–34 | Эффективные границы разгона 166 | 60 и 160 в 0.1 мА; GUI показывает 6 и 16 мА | -| 35 | kod | целочисленное положение, используемое Anal_output | -| 36–39 | adc_table_lem[0..3] | ADCRESULT2..5 после сдвига на 4, диапазон 0..4095 | +| 6 | modbus[0x1C] | расчётное задание в 0.1 мА; GUI/CSV переводит в мА | +| 7–8 | Фиксированные начальная и конечная уставки 166 | 6 и 16 мА; это не регистры настройки | +| 9 | ЗПТ1: U1 + U2 | ПМ67, регистр 306 / нулевой CAN-индекс 305, В | +| 10 | ЗПТ2: U3 + U4 | ПМ67, регистр 9 / нулевой CAN-индекс 8, В | +| 11 | Резерв | всегда ноль; чётная длина нужна для парной передачи CAN | -**Отправленный код ЦАП не является измеренным током выхода.** В этом проекте -не установлено, какой вход аппаратно измеряет ток ЦАП. При включённом +**Расчётное задание тока не является измеренным током выхода.** При включённом `cCalibrDac` отправляется `DAC_cal()`, а расчётное задание 0x1C остаётся -результатом алгоритма разгона. Для диагностики это различие сохранено. -В 166 каналы «АЦП 0..3» берутся из `adc_table_lem`, обновляемой в режиме -нагрузки. Таблица `adc_table_tpl` в этом режиме не обновляется и не используется. +результатом алгоритма разгона. Сырой код ЦАП и каналы АЦП в запись v4 не входят. +Напряжения обновляются по подтверждённым маской словам CAN даже при остановленной +записи: первый снимок содержит последние принятые значения. До первого приёма +они равны нулю; отдельного флага свежести в формате v4 нет. Управляющая формула 166 сохранена: `sinus = 10/16 * count_load + 2/16 * time_dac`. Регулируемый разгон и ограничители 167 не переносились. Поля границ показывают @@ -128,9 +123,9 @@ FC03, 0x1000, 16 слов: | Смещение | Значение | |---|---| -| 0,1 | 0x554D, версия 2 | +| 0,1 | 0x554D, версия 4 | | 2,3 | состояние и число записей выбранного источника | -| 4,5 | 40 слов в записи, 800 записей в банке | +| 4,5 | 12 слов в записи, 800 записей в банке | | 6 | период периодических снимков, мс | | 7,8 | счётчик времени, младшее/старшее слово | | 9,10 | Desk (требуется 6 / dsk_LOAD), Mode | @@ -148,15 +143,17 @@ FC06: - 0x1002: хронологический индекс первой записи окна 0..799; - 0x1003: источник окна, 0 — текущий остановленный банк, 1 — архив отключения. -FC03, 0x1010, до 120 слов: окно до трёх записей от установленного индекса. +FC03, 0x1010, до 120 слов: окно до десяти записей от установленного индекса. +Для CAN длина должна быть кратна 12 словам: 12, 24, ..., 120; прежние +блоки v2 по 40 или 80 слов отклоняются как обрывающие компактную запись. Чтение текущего банка этим окном во время записи не выдаёт изменяющиеся данные. GUI сначала останавливает его; архив можно читать при работающем текущем банке. После всех блоков GUI повторно проверяет поколение архива; при замене во время чтения результат не подменяет предыдущий график. FC03, 0x1100, ровно 124 слова: онлайн-блок. Слова 0,1 — 32-битный номер -первой записи, 2 — число записей 0..3, 3 — поколение архива, далее до трёх -записей по 40 слов. Неиспользованные слова равны нулю. Окно онлайн не +первой записи, 2 — число записей 0..10, 3 — поколение архива, далее до десяти +записей по 12 слов. Неиспользованные слова равны нулю. Окно онлайн не зависит от курсора/выбора архива. Разделение 0x1010 и 0x1100 предотвращает пересечение двух окон. @@ -167,7 +164,19 @@ CRC и разбор стандартного ответа GUI использую ## Проверка и запуск -Перенесены регистратор и RS/CAN-доступ из коммитов 167 `df71922` и `a3633d8`. +Для компактного формата v4 пройден host-тест настоящего `log_to_mem.c` +с MSVC 14.30.30705. Модули `log_to_mem.c`, `ecan.c` и `message.c` +скомпилированы TI C2000 22.6.0.LTS с COFF, FPU32 и O1 без ошибок. +После выбора исполнения 166 и периода CAN пульта 200 мс выполнена независимая +компиляция всех 27 C/ASM-модулей и линковка TI C2000 22.6.0.LTS с COFF, +FPU32 и O1. Загрузочный SCI8-образ занимает 30036 байт и побайтно совпадает +с образом, полученным из сохранённого `Bin/UKSSTMS320F28335.out`. +Проверено соответствие сохранённого HEX этому OUT. Сохранились пять +предупреждений в существующих `measure.c` и `peripher.c`; на плате не проверено. + +Первоначально регистратор и RS/CAN-доступ перенесены из коммитов 167 +`df71922` и `a3633d8`. Приведённые ниже результаты полной сборки относятся +к исходному формату v2 до сокращения полей. Сборка всех 27 C/ASM-файлов и линковка TI C2000 22.6.1.LTS (Debug, COFF, FPU32, O1) прошли. Остались шесть прежних предупреждений в measure.c/peripher.c. В MAP: RAML0 занято 0x38D1 из 0x4000 слов, .ebss — 0xFA9 из 0x3000, @@ -176,8 +185,10 @@ FPU32, O1) прошли. Остались шесть прежних предуп Сборка проверки лежит вне репозитория, штатные файлы Bin не заменены. Host-тест компилирует настоящий log_to_mem.c с подменой GPIO/IRQ. -Проверяет кольцо, архив, переполнение постинтервала, онлайн-окно, CAN-протокол, -готовность именно 166, фиксированные границы и четыре канала АЦП. +Проверяет кольцо, архив, переполнение постинтервала, онлайн-окно из десяти +12-словных записей, CAN-протокол v4, готовность именно 166, фиксированные +уставки 6/16 мА, маску команд и получение ЗПТ из трёх позиций CAN-кадра. +Сторожевые значения контролируют границу записи и разделение банков. Запуск из корня 166: `py -3 tests/ump_logger/run_test.py` (Clang/lld или MSVC в PATH); при необходимости передать `--compiler "полный путь к cl.exe"`. Тест не проверяет физические GPIO, тайминги прерываний и 16-битную ABI TI. @@ -186,7 +197,7 @@ Host-тест компилирует настоящий log_to_mem.c с подм начать запись → подать CAN-пуск → подать отключение → через секунду прочитать архив. Сверить START/STOP с физическими выходами и измерениями, повторить с разрывом RS/CAN. Проверить период 1 мс и задержки IRQ под нагрузкой. -Тесты существующего SetGUI (`test_ump_logger.py`, `test_ump_logger_can.py`, +Для первоначального формата v2 тесты SetGUI (`test_ump_logger.py`, `test_ump_logger_can.py`, `test_periph28335_tab.py`) в окружении Qt 5: **47 passed**. Проверены протокол, онлайн/архив, CAN-фрагменты, графики, курсоры и CSV. Проверка на устройстве не выполнялась. diff --git a/Source/Internal/ADC.c b/Source/Internal/ADC.c index 753f799..a46ab7e 100644 --- a/Source/Internal/ADC.c +++ b/Source/Internal/ADC.c @@ -1,8 +1,8 @@ -/* Íàñòðîéêà ÀÖÏ è îáðàáîòêà àíàëîãîâûõ âûáîðîê. adc_isr îáíîâëÿåò - * adc_table_lem[0..3] èç ADCRESULT2..5 >> 4 è âûçûâàåò ðàñ÷¸ò èçìåðåíèé. - * READY â 166 ÿâëÿåòñÿ ñ÷¸ò÷èêîì äî íóëÿ, íå ôëàãîì ãîòîâíîñòè. - * WAKE çàäà¸ò îòäåëüíîå âðåìÿ óñòàíîâëåíèÿ èçìåðèòåëüíûõ öåïåé. - * Íå äîáàâëÿòü îæèäàíèÿ EEPROM/UART â îáðàáîò÷èê âûáîðîê. +/* Настройка АЦП и обработка аналоговых выборок. 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 @@ -21,7 +21,7 @@ #include "peripher.h" Uint16 adc_table_lem[4]; -Uint16 adc_table_tpl[28]; // Ïîòîìó ÷òî +4 êàëèáð +Uint16 adc_table_tpl[28]; // Потому что +4 калибр unsigned long COUNT_WAIT_ONE_CANAL; @@ -63,12 +63,12 @@ void setup_adc() { AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0x0005; // Setup 2 conv's on SEQ1 - AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x3; // òåìïåðàòóðà (êîòîðîé íåò) - AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x1; // îìåãà - AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x5; // íàïðóãà 1 - AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0x4; // íàïðóãà 2 - AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0x7; // òîê 1 - AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0x2; // òîê 2 + AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x3; // температура (которой нет) + AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x1; // омега + AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x5; // напруга 1 + AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0x4; // напруга 2 + AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0x7; // ток 1 + AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0x2; // ток 2 } if(Desk==dsk_BKST) @@ -82,7 +82,7 @@ void setup_adc() if(Desk==dsk_COMM) { AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0x0006; // Setup 2 conv's on SEQ1 - AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x5; // ñíà÷àëà òîæå áóäóò òåìïåðàòóðû + AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x5; // сначала тоже будут температуры AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x4; // Setup ADCINA2 as 2nd SEQ1 conv. AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x7; // Setup ADCINA2 as 2nd SEQ1 conv. AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0x2; // Setup ADCINA2 as 2nd SEQ1 conv. @@ -100,23 +100,23 @@ void setup_adc() if(Desk==dsk_SHKF) { AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0x000F; // Setup 2 conv's on SEQ1 - AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x2; // 380 Ô1 - AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x3; // 380 Ô2 - AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x6; // 31 Ô1 - AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0xC; // 31 Ô2 ? - AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0xA; // 31 UC1 - AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0xB; // 31 UC2 - AdcRegs.ADCCHSELSEQ2.bit.CONV06 = 0x7; // 24 ÏÓ - AdcRegs.ADCCHSELSEQ2.bit.CONV07 = 0x4; // 24 ÏÓ + AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x2; // 380В Ф1 + AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x3; // 380В Ф2 + AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x6; // 31В Ф1 + AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0xC; // 31В Ф2 ? + AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0xA; // 31В UC1 + AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0xB; // 31В UC2 + AdcRegs.ADCCHSELSEQ2.bit.CONV06 = 0x7; // 24В ПУ + AdcRegs.ADCCHSELSEQ2.bit.CONV07 = 0x4; // 24В ПУ - AdcRegs.ADCCHSELSEQ3.bit.CONV08 = 0x5; // 24 ÏÊ áûëî 5 - AdcRegs.ADCCHSELSEQ3.bit.CONV09 = 0x1; // 15 Äð - AdcRegs.ADCCHSELSEQ3.bit.CONV10 = 0xE; // +24 Äò - AdcRegs.ADCCHSELSEQ3.bit.CONV11 = 0x0; // +24 Äò - AdcRegs.ADCCHSELSEQ4.bit.CONV12 = 0x8; // -24 Äò áûëî 8 + AdcRegs.ADCCHSELSEQ3.bit.CONV08 = 0x5; // 24В ПК было 5 + AdcRegs.ADCCHSELSEQ3.bit.CONV09 = 0x1; // 15В Др + AdcRegs.ADCCHSELSEQ3.bit.CONV10 = 0xE; // +24В Дт + AdcRegs.ADCCHSELSEQ3.bit.CONV11 = 0x0; // +24В Дт + AdcRegs.ADCCHSELSEQ4.bit.CONV12 = 0x8; // -24В Дт было 8 - AdcRegs.ADCCHSELSEQ4.bit.CONV13 = 0xF;//0xF; // ÄҰ 1 - AdcRegs.ADCCHSELSEQ4.bit.CONV14 = 0xD;//0xD; // ÄҰ 2 + AdcRegs.ADCCHSELSEQ4.bit.CONV13 = 0xF;//0xF; // ДТ° 1 + AdcRegs.ADCCHSELSEQ4.bit.CONV14 = 0xD;//0xD; // ДТ° 2 AdcRegs.ADCCHSELSEQ4.bit.CONV15 = 0x9;//0x9; } @@ -206,7 +206,7 @@ interrupt void adc_isr(void) { if (++cownt_cans>=tpl_cans) cownt_cans=0; -// Èìåííî çäåñü íåò äûð +// Именно здесь нет дыр // if(sens_type[cownt_cans]) { i++; @@ -244,7 +244,7 @@ interrupt void adc_isr(void) if(TermoAD) { if(cownt_cans == TPL_CANS ) code_tpl_canal = TERMOPAIR-1; - if(cownt_cans == TPL_CANS+1) code_tpl_canal = TERMOPAIR-2; // ïîòîìó ÷òî 300 è 400 íàîáîðîò + if(cownt_cans == TPL_CANS+1) code_tpl_canal = TERMOPAIR-2; // потому что 300 и 400 наоборот } select_tpl_canal(code_tpl_canal); diff --git a/Source/Internal/DAC.c b/Source/Internal/DAC.c index 5a67284..f333ced 100644 --- a/Source/Internal/DAC.c +++ b/Source/Internal/DAC.c @@ -1,9 +1,9 @@ -/* ÖÀÏ íàãðóçêè è àïïàðàòíàÿ îá¸ðòêà èìïóëüñîâ ÑÈÔÓ. Load_runner - * âûçûâàåòñÿ òàéìåðîì 1 êÃö, ðàñ÷¸ò ÖÀÏ äåëèòñÿ äî DAC_FREQ. - * Ôîðìóëà 166 çàäà¸ò ôèêñèðîâàííûé ðàçãîí 6..16 ìÀ. DAC_min/max - * ïåðåâîäÿò ïîëîæåíèå â êîä, cCalibrDac âûáèðàåò ðó÷íîé êîä. - * WAKEpowse îòíîñèòñÿ ê ÖÀÏ, íå ÿâëÿåòñÿ ðàçðåøåíèåì äèñêðåòà çàïóñêà. - * Àâòîìàò ÑÈÔÓ ïîäêëþ÷¸í â êîíöå ôàéëà ÷åðåç ump_control_impl.h. +/* ЦАП нагрузки и аппаратная обёртка импульсов СИФУ. 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" @@ -29,8 +29,8 @@ unsigned long WAKEpowse; volatile unsigned long IMPowse; unsigned int period_dac, time_dac; -/* Èíèöèàëèçàöèÿ, íå îáðàáîòêà êàæäîãî START. 601 îòñ÷¸ò ïðè 200 Ãö - * äàþò îêîëî 3 ñåêóíä äî ðàáî÷åãî ðàñ÷¸òà ÖÀÏ ïîñëå âêëþ÷åíèÿ. +/* Инициализация, не обработка каждого START. 601 отсчёт при 200 Гц + * дают около 3 секунд до рабочего расчёта ЦАП после включения. */ void Setup_DAC_time(void) { @@ -76,9 +76,9 @@ void Init_DAC(void) dSEND(0x9002|0x0000); toggle_RES_OUT_1(); } -/* vrot/maxx — äîëÿ äèàïàçîíà ìåæäó êîäàìè 4 è 20 ìÀ. Ìàñêà 0xFFF - * ñîõðàíÿåò 12 áèò, íî íå ÿâëÿåòñÿ íàñûùåíèåì. modbus[0x1C] ñîäåðæèò - * ðàñ÷¸òíîå çàäàíèå, íå èçìåðåííûé òîê íà âûõîäíûõ êëåììàõ. +/* vrot/maxx — доля диапазона между кодами 4 и 20 мА. Маска 0xFFF + * сохраняет 12 бит, но не является насыщением. modbus[0x1C] содержит + * расчётное задание, не измеренный ток на выходных клеммах. */ void Anal_output(long vrot, long maxx) { @@ -87,7 +87,7 @@ void Anal_output(long vrot, long maxx) out = DAC_min() + vrot * DAC_max() / maxx - vrot * DAC_min() / maxx ; - x=0;// !x; òùåòíî áûòèå + x=0;// !x; тщетно бытие if(cCalibrDac) out=DAC_cal(); @@ -116,9 +116,9 @@ Log_to_mem(modbus[0x1D]); } -/* Ïîñëå ïîëîâèíû time_dac ñ÷¸ò÷èê ðàñò¸ò äâàæäû çà âûçîâ. Ïîýòîìó - * LOAD_TIME=30 äà¸ò ïðèìåðíî 22.5 ñ äî êîíöà ðàçãîíà ïðè 200 Ãö. - * Ñóùåñòâóþùèé ïðîôèëü 166 èñïðàâëåíèå èìïóëüñà ÑÈÔÓ íå ìåíÿåò. +/* После половины time_dac счётчик растёт дважды за вызов. Поэтому + * LOAD_TIME=30 даёт примерно 22.5 с до конца разгона при 200 Гц. + * Существующий профиль 166 исправление импульса СИФУ не меняет. */ void Load_runner() { @@ -126,7 +126,7 @@ void Load_runner() float sinus=0; int kod; - /* IMPowse îáíîâëÿåòñÿ UMP_pulse_tick(), à íå àëãîðèòìîì ÖÀÏ. */ + /* IMPowse обновляется UMP_pulse_tick(), а не алгоритмом ЦАП. */ if(++count_dac >= period_dac) { count_dac=0; diff --git a/Source/Internal/Include/ADC.h b/Source/Internal/Include/ADC.h index 9d9ba53..5f76b40 100644 --- a/Source/Internal/Include/ADC.h +++ b/Source/Internal/Include/ADC.h @@ -1,5 +1,5 @@ -/* Òàáëèöû âûáîðîê îáíîâëÿåò ADC ISR. Ñîãëàñîâàííûé ñíèìîê íåñêîëüêèõ - * êàíàëîâ òðåáóåò çàùèòû êîïèðîâàíèÿ, îäíîãî óêàçàòåëÿ íåäîñòàòî÷íî. +/* Таблицы выборок обновляет ADC ISR. Согласованный снимок нескольких + * каналов требует защиты копирования, одного указателя недостаточно. */ diff --git a/Source/Internal/Include/DAC.h b/Source/Internal/Include/DAC.h index 7c960a1..a168adf 100644 --- a/Source/Internal/Include/DAC.h +++ b/Source/Internal/Include/DAC.h @@ -1,17 +1,17 @@ -/* Èíòåðôåéñ ÖÀÏ è ÑÈÔÓ. Âõîäÿùèå êîìàíäû — UMP_commands_write, - * îêîí÷àíèå èìïóëüñà — UMP_pulse_tick. IMPowse òîëüêî äëÿ äèàãíîñòèêè. +/* Интерфейс ЦАП и СИФУ. Входящие команды — 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 volatile unsigned long IMPowse; extern unsigned long WAKEpowse; extern unsigned int period_dac, time_dac; -/* Âñå îïåðàöèè áåçîïàñíû äëÿ âûçîâà èç main è îáðàáîò÷èêîâ IRQ. */ +/* Все операции безопасны для вызова из main и обработчиков IRQ. */ void UMP_pulse_init(void); void UMP_commands_write(unsigned int commands); void UMP_pulse_tick(void); diff --git a/Source/Internal/Include/GPIO_table.h b/Source/Internal/Include/GPIO_table.h index 6a40e7d..9edf76b 100644 --- a/Source/Internal/Include/GPIO_table.h +++ b/Source/Internal/Include/GPIO_table.h @@ -1,5 +1,5 @@ -/* Íàïðàâëåíèÿ GPIO äëÿ àïïàðàòíûõ èñïîëíåíèé. Åäèíèöà îçíà÷àåò - * âûõîä; àêòèâíóþ ïîëÿðíîñòü çàäàþò peripher.h è ñõåìà ïëàòû. +/* Направления GPIO для аппаратных исполнений. Единица означает + * выход; активную полярность задают peripher.h и схема платы. */ #define COMM_gpio00_dir 0L #define COMM_gpio01_dir 0L @@ -14,7 +14,7 @@ #define COMM_gpio10_dir 0L #define COMM_gpio11_dir 0L -#define COMM_gpio19_dir 1L // 63 — SPI +#define COMM_gpio19_dir 1L // 63 — SPI #define COMM_gpio20_dir 0L // 64 2:9B mode 2 #define COMM_gpio21_dir 0L // 65 2:9A mode 4 #define COMM_gpio22_dir 0L // 66 2:12C mode 1 @@ -26,7 +26,7 @@ #define COMM_gpio32_dir 1L // 74 2:10B DIOD green #define COMM_gpio33_dir 0L -#define COMM_gpio34_dir 1L // 142 — SCI +#define COMM_gpio34_dir 1L // 142 — SCI #define COMM_gpio48_dir 1L // 88 2:14C DIOD red #define COMM_gpio49_dir 1L // 89 2:14B select @@ -57,7 +57,7 @@ #define BKSD_gpio10_dir 0L // 19 2:6C oil #define BKSD_gpio11_dir 1L // 20 2:3C select -#define BKSD_gpio19_dir 1L // 63 — SPI +#define BKSD_gpio19_dir 1L // 63 — SPI #define BKSD_gpio20_dir 0L // 64 2:9B mode 2 #define BKSD_gpio21_dir 0L // 65 2:9A mode 4 #define BKSD_gpio22_dir 0L // 66 2:12C mode 1 @@ -69,7 +69,7 @@ #define BKSD_gpio32_dir 1L // 74 2:10B DIOD green #define BKSD_gpio33_dir 0L -#define BKSD_gpio34_dir 1L // 142 — SCI +#define BKSD_gpio34_dir 1L // 142 — SCI #define BKSD_gpio48_dir 1L // 88 2:14C DIOD red #define BKSD_gpio49_dir 0L // 89 2:14B input 2 @@ -100,7 +100,7 @@ #define BKST_gpio10_dir 0L #define BKST_gpio11_dir 1L // 20 2:3C select -#define BKST_gpio19_dir 1L // 63 — SPI +#define BKST_gpio19_dir 1L // 63 — SPI #define BKST_gpio20_dir 0L // 64 2:9B mode 2 #define BKST_gpio21_dir 0L // 65 2:9A mode 4 #define BKST_gpio22_dir 0L // 66 2:12C mode 1 @@ -112,7 +112,7 @@ #define BKST_gpio32_dir 1L // 74 2:10B DIOD green #define BKST_gpio33_dir 0L -#define BKST_gpio34_dir 1L // 142 — SCI +#define BKST_gpio34_dir 1L // 142 — SCI #define BKST_gpio48_dir 1L // 88 2:14C DIOD red #define BKST_gpio49_dir 0L @@ -143,7 +143,7 @@ #define PULT_gpio10_dir 0L #define PULT_gpio11_dir 0L -#define PULT_gpio19_dir 1L // 63 — SPI +#define PULT_gpio19_dir 1L // 63 — SPI #define PULT_gpio20_dir 0L // 64 2:9B mode 2 #define PULT_gpio21_dir 0L // 65 2:9A mode 4 #define PULT_gpio22_dir 0L // 66 2:12C mode 1 @@ -155,7 +155,7 @@ #define PULT_gpio32_dir 1L // 74 2:10B DIOD green #define PULT_gpio33_dir 0L -#define PULT_gpio34_dir 1L // 142 — SCI +#define PULT_gpio34_dir 1L // 142 — SCI #define PULT_gpio48_dir 1L // 88 2:14C DIOD red #define PULT_gpio49_dir 0L // 89 2:14B button @@ -186,7 +186,7 @@ #define PLT2_gpio10_dir 0L #define PLT2_gpio11_dir 0L -#define PLT2_gpio19_dir 1L // 63 × SPI +#define PLT2_gpio19_dir 1L // 63 Ч SPI #define PLT2_gpio20_dir 0L // 64 2:9B mode 2 #define PLT2_gpio21_dir 0L // 65 2:9A mode 4 #define PLT2_gpio22_dir 0L // 66 2:12C mode 1 @@ -198,7 +198,7 @@ #define PLT2_gpio32_dir 1L // 74 2:10B DIOD green #define PLT2_gpio33_dir 0L // 75 2:10C button -#define PLT2_gpio34_dir 1L // 142 × SCI +#define PLT2_gpio34_dir 1L // 142 Ч SCI #define PLT2_gpio48_dir 0L // 88 2:14C button #define PLT2_gpio49_dir 0L // 89 2:14B button @@ -229,7 +229,7 @@ #define SHKF_gpio10_dir 0L // 19 2:6C input #define SHKF_gpio11_dir 0L // 20 2:3C input -#define SHKF_gpio19_dir 1L // 63 — SPI +#define SHKF_gpio19_dir 1L // 63 — SPI #define SHKF_gpio20_dir 0L // 64 2:9B mode 2 #define SHKF_gpio21_dir 0L // 65 2:9A mode 4 #define SHKF_gpio22_dir 0L // 66 2:12C mode 1 @@ -241,7 +241,7 @@ #define SHKF_gpio32_dir 0L // 74 2:10B input #define SHKF_gpio33_dir 0L // 75 2:10C input -#define SHKF_gpio34_dir 1L // 142 — SCI +#define SHKF_gpio34_dir 1L // 142 — SCI #define SHKF_gpio48_dir 1L // 88 2:14C DIOD red #define SHKF_gpio49_dir 0L // 89 2:14B input @@ -272,7 +272,7 @@ #define LOAD_gpio10_dir 0L #define LOAD_gpio11_dir 0L // 20 2:3C res_in 0 -#define LOAD_gpio19_dir 1L // 63 — SPI +#define LOAD_gpio19_dir 1L // 63 — SPI #define LOAD_gpio20_dir 0L // 64 2:9B mode 2 #define LOAD_gpio21_dir 0L // 65 2:9A mode 4 #define LOAD_gpio22_dir 0L // 66 2:12C mode 1 @@ -284,7 +284,7 @@ #define LOAD_gpio32_dir 1L // 74 2:10B DIOD green #define LOAD_gpio33_dir 0L -#define LOAD_gpio34_dir 1L // 142 — SCI +#define LOAD_gpio34_dir 1L // 142 — SCI #define LOAD_gpio48_dir 1L // 88 2:14C DIOD red #define LOAD_gpio49_dir 0L diff --git a/Source/Internal/Include/RS485.h b/Source/Internal/Include/RS485.h index 3cb18d4..4c40c52 100644 --- a/Source/Internal/Include/RS485.h +++ b/Source/Internal/Include/RS485.h @@ -1,5 +1,5 @@ -/* Áóôåðû UART ðàçäåëÿþòñÿ ISR è main. main îáðàáàòûâàåò - * çàêîí÷åííûé RS_Header. Ðàçìåðû ñâåðÿòü ñ 16-áèòíîé ABI DSP. +/* Буферы UART разделяются ISR и main. main обрабатывает + * законченный RS_Header. Размеры сверять с 16-битной ABI DSP. */ #ifndef _RS485 #define _RS485 @@ -32,30 +32,30 @@ typedef struct { volatile struct SCI_REGS *SciRegs; - unsigned int commnumber; // Íîìåð ïîðòà - unsigned long RS_Length; // Äëèíà ïàêåòà + unsigned int commnumber; // Номер порта + unsigned long RS_Length; // Длина пакета - unsigned int *pRS_RecvPtr; // Áóôåð ïðèåìà - unsigned int *pRS_SendPtr; // Áóôåð ïîñûëêè + unsigned int *pRS_RecvPtr; // Буфер приема + unsigned int *pRS_SendPtr; // Буфер посылки unsigned int *pRecvPtr; - unsigned int RS_PrevCmd; // Ïðåäûäóùàà êîììàíäà - unsigned int RS_Cmd; // Òåêóùàà êîììàíäà - unsigned int RS_Header[MAX_RECEIVE_LENGTH]; // Çàãîëîâîê - unsigned int flag_TIMEOUT_to_Send; // Ôëàã îæèäàíèà òàéìàóòà íà îòñûëêó - unsigned int flag_TIMEOUT_to_Receive; // Ôëàã îæèäàíèà òàéìàóòà íà ïðèåì - unsigned int RS_DataReady; // Ôëàã ãîòîâíîñòè RS äàííûõ - unsigned int buffer[MAX_SEND_LENGTH]; // Áóôåð äëà îòñûëêè ïî RS + unsigned int RS_PrevCmd; // Предыдущаа комманда + unsigned int RS_Cmd; // Текущаа комманда + unsigned int RS_Header[MAX_RECEIVE_LENGTH]; // Заголовок + unsigned int flag_TIMEOUT_to_Send; // Флаг ожиданиа таймаута на отсылку + unsigned int flag_TIMEOUT_to_Receive; // Флаг ожиданиа таймаута на прием + unsigned int RS_DataReady; // Флаг готовности RS данных + unsigned int buffer[MAX_SEND_LENGTH]; // Буфер дла отсылки по RS - unsigned int addr_answer; // àäðåñ êóäà îòâå÷àòü â ðåæèìå âåäóùåãî - unsigned int addr_recive; // àäðåñ ïî êîòîðîìó íàñ çàïðîñèëè - unsigned int flag_LEADING; // Ôëàã ðåæèìà êîíòðîëëåðà (ïî óìîë÷àíèþ âåäîìûé) + unsigned int addr_answer; // адрес куда отвечать в режиме ведущего + unsigned int addr_recive; // адрес по которому нас запросили + unsigned int flag_LEADING; // Флаг режима контроллера (по умолчанию ведомый) unsigned long RS_RecvLen; - unsigned long RS_SLength; // Äëèíà ïàêåòà äëà ïîñûëêè - unsigned long RS_SendLen; // Êîëè÷åñòâî áàéò óæå ïåðåäàëè - char RS_SendBlockMode; // Ðåæèì ïåðåäà÷è - char RS_Flag9bit; // äëà RS485???????? - int BS_LoadOK; // Ôëàã óñïåøíîñòè ïðèåìà áëîêà + unsigned long RS_SLength; // Длина пакета дла посылки + unsigned long RS_SendLen; // Количество байт уже передали + char RS_SendBlockMode; // Режим передачи + char RS_Flag9bit; // дла RS485???????? + int BS_LoadOK; // Флаг успешности приема блока int RS_FlagBegin; int RS_HeaderCnt; int RS_FlagSkiping; @@ -67,39 +67,39 @@ typedef struct extern RS_DATA rs_a,rs_b; extern unsigned int - RS_Len[70]; /* Äåéñòâèòåëüíàà äëèíà êîìàíäû (îòëàäî÷íîé) + 1 */ + RS_Len[70]; /* Действительнаа длина команды (отладочной) + 1 */ interrupt void RSA_RX_Handler(void); interrupt void RSA_TX_Handler(void); interrupt void RSB_RX_Handler(void); interrupt void RSB_TX_Handler(void); -/* èíèöèëèçàöèà ïåðåìåííûõ rs_a,rs_b*/ +/* иницилизациа переменных rs_a,rs_b*/ void create_uart_vars(char size_cmd15); -/** Ïîâòîðíàà èíèöèàëèçàöèà ïîñëåäîâàòåëüíîãî ïîðòà, èñïîëüçóåòñà ïîñëå ïîäâèñà */ -/** Íàñòðîéêà ðåæèìà ïðèåìà/ïåðåäà÷è */ +/** Повторнаа инициализациа последовательного порта, используетса после подвиса */ +/** Настройка режима приема/передачи */ void RS_SetBitMode(RS_DATA *rs_arr, int n); -/** Ïîñûëêà áëîêà áàéòîâ. - Ïîñûëàåò ìàññèâà 32-áèòíûõ öåëûõ ÷èñåë ñòàðøèå áèòû äîëæíû áûòü 0. - @precondition Ðàáîòà ô-öèè çàâèñèò îò ìàêðî RS_TRANSMIT_INTR - @param buf àäðåñ ìàññèâà - @param len êîëè÷åñòâî áàéò +/** Посылка блока байтов. + Посылает массива 32-битных целых чисел старшие биты должны быть 0. + @precondition Работа ф-ции зависит от макро RS_TRANSMIT_INTR + @param buf адрес массива + @param len количество байт @see RS_BSend, RS_TRANSMIT_INTR */ int RS_Send(RS_DATA *rs_arr,unsigned int *pBuf, unsigned long len); -/** Ïîñûëêà áëîêà óïàêîâàííûõ áàéòîâ. - @precondition Ðàáîòà ô-öèè çàâèñèò îò ìàêðî RS_TRANSMIT_INTR - @param buf àäðåñ ìàññèâà - @param len êîëè÷åñòâî 8-áèòíûõ áàéò +/** Посылка блока упакованных байтов. + @precondition Работа ф-ции зависит от макро RS_TRANSMIT_INTR + @param buf адрес массива + @param len количество 8-битных байт @see RS_Send, RS_TRANSMIT_INTR */ int RS_BSend(RS_DATA *rs_arr,unsigned int *pBuf, unsigned long len); -/** Èíèöèàëèçàöèà ïîñëåäîâàòåëüíîãî ïîðòà */ -void setup_uart(char commnumber,unsigned long speed_baud); /* speed_baud - ñêîðîñòü ëèíèè â áîäàõ */ +/** Инициализациа последовательного порта */ +void setup_uart(char commnumber,unsigned long speed_baud); /* speed_baud - скорость линии в бодах */ void RS_SetLineMode(RS_DATA *rs_arr, int bit, char parity, int stop); void RS_SetLineSpeed(RS_DATA *rs_arr, unsigned long speed); @@ -107,17 +107,17 @@ void RS_SetLineSpeed(RS_DATA *rs_arr, unsigned long speed); // Transmit a character from the SCI' #define SCI_send(x,y) x->SciRegs->SCITXBUF=(unsigned char)(y) -// Îæèäàíèå çàâåðøåíèà ïåðåäà÷è UART +// Ожидание завершениа передачи UART // wait for TRDY =1 for empty state #define RS_Wait4OK(x) while(!(x->SciRegs->SCICTL2.bit.TXEMPTY)) -/** Ïåðåêëþ÷åíèå ëèíèè íà ïðèåì */ +/** Переключение линии на прием */ #define RS_Line_to_receive(x) if(x->commnumber==COM_2) GpioDataRegs.GPBDAT.bit.GPIO34 = 1; -/** Ïåðåêëþ÷åíèå ëèíèè íà ïåðåäà÷ó */ +/** Переключение линии на передачу */ #define RS_Line_to_send(x) if(x->commnumber==COM_2) GpioDataRegs.GPBDAT.bit.GPIO34 = 0; -/** Ðàçðåøåíèå ïðåðûâàíèé ïî ïîëó÷åíèþ ñèìâîëà è îøèáêàì îò UART */ +/** Разрешение прерываний по получению символа и ошибкам от UART */ #define enableUARTInt(x) x->SciRegs->SCICTL2.all=2 #define enableUARTIntW(x) x->SciRegs->SCICTL2.all=1 @@ -129,4 +129,3 @@ void test_rs_live(RS_DATA *rs_arr); #endif #endif /* _RS485 */ - diff --git a/Source/Internal/Include/bios_dsp.h b/Source/Internal/Include/bios_dsp.h index 71c3c3b..7cfb2c3 100644 --- a/Source/Internal/Include/bios_dsp.h +++ b/Source/Internal/Include/bios_dsp.h @@ -1,5 +1,5 @@ -/* Êîäû CMD_* ÿâëÿþòñÿ ÷àñòüþ ôîðìàòà îáìåíà ñ ÏÊ. Íîâûå êîìàíäû - * äîáàâëÿþòñÿ áåç ïåðåíóìåðàöèè ñóùåñòâóþùèõ çíà÷åíèé. +/* Коды CMD_* являются частью формата обмена с ПК. Новые команды + * добавляются без перенумерации существующих значений. */ #ifndef _BIOS_DSP #define _BIOS_DSP @@ -36,67 +36,67 @@ enum { CMD_VECTOR=61, CMD_IMPULSE, - /* ñòàíäàðòíûå êîìàíäû */ + /* стандартные команды */ CMD_STD=65, CMD_STD_ANS }; enum {false=0, true}; -/** Âîçâðàùàåò íîìåð êîììàíäû, åñëè åñòü èëè -1 åñëè òðàíçàêöèé íå áûëî */ +/** Возвращает номер комманды, если есть или -1 если транзакций не было */ int get_command(RS_DATA *rs_arr); -/** Ñòàíäàðòíûé îòâåò, áåç ïàðàìåòðîâ */ +/** Стандартный ответ, без параметров */ void Answer(RS_DATA *rs_arr,int n); -/* íà÷àëüíûå óñòàíîâêè (íå ðàáîòàåò)*/ +/* начальные установки (не работает)*/ void init(RS_DATA *rs_arr); -/**@name Êîììàíäû -* Êîììàíäû, âûçûâàåìûå ÷åðåç ïîñëåäîâàòåëüíûé êàíàë*/ +/**@name Комманды +* Комманды, вызываемые через последовательный канал*/ //@{ -/** Èíèöèèðîâàòü çàãðóçêó áëîêà. - Íàñòðàèâàåò ïðèåì áëîêà äàííûõ */ +/** Инициировать загрузку блока. + Настраивает прием блока данных */ void initload(RS_DATA *rs_arr); -/** Çàãðóçêà áëîêà. - Âûçûâàåòñà ïîñëå çàãðóçêè áëîêà ÷åðåç RS */ +/** Загрузка блока. + Вызываетса после загрузки блока через RS */ void load(RS_DATA *rs_arr); -/** Âûïîëíèòü ïðîãðàììó â ôîðìàòå Serial Boot. - @precondition Äîëæíà áûòü ïðîèçâåäåíà çàãðóçêà áëîêà - Àäðåñ ïðîãðàììû áåðåòñà èç çàãîëîâêà è - ñðàâíèâàåòñà ñ ïåðåìåííîé RecvPtr, çàïîëíàåìîé â ô-öèè load +/** Выполнить программу в формате Serial Boot. + @precondition Должна быть произведена загрузка блока + Адрес программы беретса из заголовка и + сравниваетса с переменной RecvPtr, заполнаемой в ф-ции load @see load */ void run (RS_DATA *rs_arr); -/** Ïðî÷èòàòü à÷åéêó ïàìàòè */ +/** Прочитать ачейку памати */ void peek(RS_DATA *rs_arr); -/** Çàïèñàòü â à÷åéêó ïàìàòè */ +/** Записать в ачейку памати */ void poke(RS_DATA *rs_arr); -/** Ïåðåäàòü áëîê ïàìàòè */ +/** Передать блок памати */ void upload(RS_DATA *rs_arr); -/** Ïðîøèòü XILINX. - @precondition Äîëæíà áûòü ïðîèçâåäåíà çàãðóçêà áëîêà - Àäðåñ è äëèíà ïðîøèâêè áåðåòñà èç çàãîëîâêà è - ñðàâíèâàåòñà ñ ïåðåìåííûìè RecvPtr è Length, çàïîëíàåìûìè â ô-öèè load, - òàê æå ñìîòðèò ìàãè÷åñêîå ñëîâî â íà÷àëå ïðîøèâêè +/** Прошить XILINX. + @precondition Должна быть произведена загрузка блока + Адрес и длина прошивки беретса из заголовка и + сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load, + так же смотрит магическое слово в начале прошивки @see load */ void xflash(RS_DATA *rs_arr); -/** Ïðîøèòü TMS. - @precondition Äîëæíà áûòü ïðîèçâåäåíà çàãðóçêà áëîêà - Àäðåñ è äëèíà ïðîøèâêè áåðåòñà èç çàãîëîâêà è - ñðàâíèâàåòñà ñ ïåðåìåííûìè RecvPtr è Length, çàïîëíàåìûìè â ô-öèè load +/** Прошить TMS. + @precondition Должна быть произведена загрузка блока + Адрес и длина прошивки беретса из заголовка и + сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load @see load */ void tflash(RS_DATA *rs_arr); -/* ðàñøèðåííûå êîìàíäû äëà áèîñà */ +/* расширенные команды дла биоса */ void extendbios(RS_DATA *rs_arr); diff --git a/Source/Internal/Include/caliber.h b/Source/Internal/Include/caliber.h index 4e7ed21..c8121e5 100644 --- a/Source/Internal/Include/caliber.h +++ b/Source/Internal/Include/caliber.h @@ -1,48 +1,48 @@ -/* Çàâîäñêèå êàëèáðîâêè ïî âåðñèè BALSAM è òèïó ïëàòû. Çäåñü - * îïðåäåëÿþòñÿ ìàññèâû, à íå òîëüêî extern; íå äóáëèðîâàòü ïîäêëþ÷åíèå. +/* Заводские калибровки по версии BALSAM и типу платы. Здесь + * определяются массивы, а не только extern; не дублировать подключение. */ #if BALSAM == 166 //------------------------------------------------------------- int def_cal[][8] = { -// Ñèëîâîé UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2 - 4936, 4877, 4972, 4857, 1960, 1920, 2610, 2570, // Áîðò 0 - 4876, 5005, 4876, 4847, 1950, 1965, 2600, 2615, // Áîðò 1 +// Силовой UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2 + 4936, 4877, 4972, 4857, 1960, 1920, 2610, 2570, // Борт 0 + 4876, 5005, 4876, 4847, 1950, 1965, 2600, 2615, // Борт 1 -// ÓÌÏ UA UC IA IC 20mA O 4mA O 20mA I 4mA I - 3820, 3790, 3505, 3380, 1718, 673, 854, 14, // Áîðò 0 - 3835, 3785, 3522, 3332, 1697, 653, 860, 17, // Áîðò 1 +// УМП UA UC IA IC 20mA O 4mA O 20mA I 4mA I + 3820, 3790, 3505, 3380, 1718, 673, 854, 14, // Борт 0 + 3835, 3785, 3522, 3332, 1697, 653, 860, 17, // Борт 1 -// ÂÝÏ 380Ô1 380Ô2 300 1 300 2 400 1 400 2 +// ВЭП 380Ф1 380Ф2 300 1 300 2 400 1 400 2 1281, 1272, 0, 0, 2049, 2050, 2749, 2750 }; #endif //--------------------------------------------------------------------- #if BALSAM == 165 //------------------------------------------------------------- int def_cal[][8] = { -// Ñèëîâîé UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2 - 5130, 4960, 4925, 5070, 1881, 1881, 2506, 2516, // Áîðò 0 - 5020, 5040, 4950, 5030, 1871, 1879, 2507, 2514, // Áîðò 1 +// Силовой UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2 + 5130, 4960, 4925, 5070, 1881, 1881, 2506, 2516, // Борт 0 + 5020, 5040, 4950, 5030, 1871, 1879, 2507, 2514, // Борт 1 -// ÓÌÏ UA UC IA IC 20mA O 4mA O 20mA I 4mA I - 3890, 3865, 5100, 4850, 1730, 675, 854, 14, // Áîðò 0 - 3845, 3800, 3250, 3100, 1044, 0, 860, 17, // Áîðò 1 +// УМП UA UC IA IC 20mA O 4mA O 20mA I 4mA I + 3890, 3865, 5100, 4850, 1730, 675, 854, 14, // Борт 0 + 3845, 3800, 3250, 3100, 1044, 0, 860, 17, // Борт 1 -// ÂÝÏ 380Ô1 380Ô2 300 1 300 2 400 1 400 2 +// ВЭП 380Ф1 380Ф2 300 1 300 2 400 1 400 2 1289, 1280, 0, 0, 2073, 2071, 2773, 2771 }; #endif //--------------------------------------------------------------------- #if BALSAM == 164 //------------------------------------------------------------- int def_cal[][8] = { -// Ñèëîâîé UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2 - 7573, 7573, 7573, 7573, 1979, 1888, 2592, 2513, // Áîðò 0 - 7573, 7573, 7573, 7573, 1970, 1907, 2584, 2558, // Áîðò 1 +// Силовой UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2 + 7573, 7573, 7573, 7573, 1979, 1888, 2592, 2513, // Борт 0 + 7573, 7573, 7573, 7573, 1970, 1907, 2584, 2558, // Борт 1 -// ÓÌÏ UA UC IA IC 20mA O 4mA O 20mA I 4mA I - 3920, 3905, 3300, 3220, 1015, 0, 854, 14, // Áîðò 0 - 3835, 3785, 5100, 4600, 1750, 680, 860, 17, // Áîðò 1 +// УМП UA UC IA IC 20mA O 4mA O 20mA I 4mA I + 3920, 3905, 3300, 3220, 1015, 0, 854, 14, // Борт 0 + 3835, 3785, 5100, 4600, 1750, 680, 860, 17, // Борт 1 -// ÂÝÏ 380Ô1 380Ô2 300 1 300 2 400 1 400 2 +// ВЭП 380Ф1 380Ф2 300 1 300 2 400 1 400 2 1266, 1267, 0, 0, 2063, 2040, 2678, 2655 }; #endif //--------------------------------------------------------------------- @@ -51,15 +51,15 @@ #if PXXXXX == 1 //------------------------------------------------------------- int def_cal[][6] = { -// Ñèëîâîé UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2 - 0400, 0400, 0400, 0400, 1950, 1950, 2600, 2600, // Áîðò 0 - 0400, 0400, 0400, 0400, 1950, 1950, 2600, 2600, // Áîðò 1 +// Силовой UA1 UB1 UA2 UB2 300 1 300 2 400 1 400 2 + 0400, 0400, 0400, 0400, 1950, 1950, 2600, 2600, // Борт 0 + 0400, 0400, 0400, 0400, 1950, 1950, 2600, 2600, // Борт 1 -// ÓÌÏ UA UC IA IC 20mA 4mA - 0400, 0400, 4800, 4800, 0, 0, 0, 0, // Áîðò 0 - 0400, 0400, 4800, 4800, 0, 0, 0, 0, // Áîðò 1 +// УМП UA UC IA IC 20mA 4mA + 0400, 0400, 4800, 4800, 0, 0, 0, 0, // Борт 0 + 0400, 0400, 4800, 4800, 0, 0, 0, 0, // Борт 1 -// ÂÝÏ 380Ô1 380Ô2 300 1 300 2 400 1 400 2 +// ВЭП 380Ф1 380Ф2 300 1 300 2 400 1 400 2 1270, 1270, 0, 0, 1950, 1950, 2600, 2600 }; #endif //--------------------------------------------------------------------- */ diff --git a/Source/Internal/Include/can_telemetry_impl.h b/Source/Internal/Include/can_telemetry_impl.h new file mode 100644 index 0000000..69b187e --- /dev/null +++ b/Source/Internal/Include/can_telemetry_impl.h @@ -0,0 +1,123 @@ +#ifndef CAN_TELEMETRY_IMPL_H /* Реализация включается только в ecan.c после аппаратных типов и переменных штатного передатчика. */ +#define CAN_TELEMETRY_IMPL_H /* Не допускает повторного определения состояния и функций в одной единице трансляции. */ +#define CAN_HEARTBEAT_ADDR 0x0100U /* Как в варианте 167, отдельный адрес heartbeat находится вне R0–R127 и служебной области логгера 0x1000. */ +#define CAN_HEARTBEAT_TICKS ((Uint32)READY_FREQ) /* READY_FREQ задаёт частоту Timer1 в герцах; это ровно одна секунда его тактов. */ +#define CAN_REFRESH_TICKS ((Uint32)READY_FREQ * 13UL / 10UL) /* Тринадцать десятых секунды дают период повторения данных 1,3 с независимо от числа циклов main. */ +#define CAN_SCAN_TICKS ((Uint32)READY_FREQ * CANPOWSE / 1000UL) /* Существующие CANPOWSE=20 мс ограничивают задержку обнаружения обновлений, но не скорость выдачи уже готовой очереди. */ +#define CAN_ACK_TICKS ((Uint32)READY_FREQ / 10UL) /* Программная страховка через 100 мс отменяет зависший TX, если аппаратный timeout IRQ не был обработан. */ +static Uint32 can_last_hi[ANSWER_LEN], can_last_lo[ANSWER_LEN], can_last_at[ANSWER_LEN]; /* Последний подтверждённый пакет и время ACK хранятся отдельно для каждого начального адреса R0–R127. */ +static unsigned int can_valid[8], can_cursor[2], can_stream; /* Восемь 16-битных масок покрывают 128 адресов; два курсора и очередность обеспечивают справедливость потоков. */ +static Uint32 can_tx_at, can_failed_at, can_heartbeat_at, can_scan_at; /* Беззнаковые отметки Timer1 поддерживают вычитание через переполнение 32-битного счётчика. */ +static unsigned int can_backoff, can_started, can_heartbeat_count, can_heartbeat_due, can_scan_due; /* Отделяет секундную паузу после ошибки, старт часов, heartbeat и незавершённое сканирование масок. */ +static int can_pending_addr; /* Значение -1 обозначает heartbeat, который не должен индексировать кэш технологических регистров. */ +static volatile unsigned int can_tx_failed; /* Timeout ISR отмечает ошибку текущего mailbox до обработки ACK в основном цикле. */ +static Uint32 CAN_millis(void) /* Возвращает согласованный счётчик Timer1; при READY_FREQ=1000 один такт соответствует миллисекунде. */ +{ /* Чтение 32 бит защищается отдельно на 16-битном C28x без ожидания аппаратуры. */ + unsigned int saved = __disable_interrupts(); /* Сохраняет исходное состояние IRQ, включая вызовы из уже защищённой отправки. */ + Uint32 now = CpuTimer1.InterruptCount; /* Счётчик обновляют оба существующих обработчика Timer1 для пульта и измерительной платы. */ + __restore_interrupts(saved); /* Немедленно возвращает прежнюю маску прерываний. */ + return now; /* Наружу передаётся один целостный снимок времени. */ +} /* Длительные расчёты масок выполняются с разрешёнными прерываниями. */ +static void CAN_telemetry_init(void) /* Сбрасывает программное состояние при каждом InitCan, в том числе после запуска с грязной RAM. */ +{ /* Крупные массивы не очищаются, потому что их элементы недоступны без valid-бита. */ + unsigned int i; /* Перебирает восемь масок достоверности кэша. */ + for (i = 0U; i < 8U; ++i) can_valid[i] = 0U; /* Первый пакет каждого разрешённого адреса обязательно передаётся после запуска. */ + can_cursor[0] = can_cursor[1] = can_stream = 0U; /* Обе маски начинают обход с R0; далее потоки чередуются после реально поставленного кадра. */ + can_backoff = can_started = can_heartbeat_count = can_heartbeat_due = 0U; /* Новые часы и секундный heartbeat начинают отсчёт при первом обслуживании main. */ + can_scan_due = 1U; /* Первый снимок данных выдаётся сразу, без ожидания периода 1,3 с. */ + can_pending_addr = -1; can_tx_failed = 0U; wait = 0; /* Исключает подтверждение кадра и ошибку из предыдущего запуска программы. */ +} /* Сброс не меняет аппаратные CAN ID, маски регистров и настройки EEPROM. */ +static int CAN_tx_ready(Uint32 now) /* Обслуживает завершение штатного mailbox 0; вызывающий код уже запретил IRQ на короткое время. */ +{ /* Возвращает готовность без ожидания ACK, CANAA или освобождения шины в цикле. */ + if ((ECanaRegs.CANTRS.all | ECanaRegs.CANTRR.all) & 1UL) { /* Бит 0 относится только к штатному TX; служебный mailbox 2 не перезаписывается. */ + if (wait && !can_tx_failed && (ECanaRegs.CANTRS.all & 1UL) && now - can_tx_at >= CAN_ACK_TICKS) { /* Программный timeout страхует потерянное аппаратное прерывание спустя 100 мс. */ + can_tx_failed = 1U; ++CanTimeOutErrorTR; /* Отмечает ошибку ровно один раз, пока этот запрос ещё ожидает завершения отмены. */ + EALLOW; ECanaRegs.CANTOC.all &= ~1UL; EDIS; /* Снимает источник аппаратного timeout только для mailbox 0, сохраняя остальные биты контроля. */ + ECanaRegs.CANTRR.all = 1UL; /* Запрашивает аппаратную отмену без блокирующего ожидания CANAA. */ + } /* Данные занятого mailbox остаются неизменными до аппаратного освобождения. */ + return 0; /* Текущий адрес и признак готовности сканирования сохраняются для повторного обслуживания. */ + } /* Только свободный mailbox позволяет обработать завершение предыдущей передачи. */ + if (wait) { /* ACK или ошибка относятся ровно к одному ранее запущенному кадру. */ + if ((ECanaRegs.CANTA.all & 1UL) && !can_tx_failed) { /* Только успешный ACK позволяет подавлять повтор неизменившихся данных. */ + if (can_pending_addr >= 0) { /* Heartbeat не занимает ограниченный технологический кэш. */ + can_last_hi[can_pending_addr] = ECanaMboxes.MBOX0.MDH.all; /* Запоминает действительно доставленные адрес и первое слово из неизменявшегося mailbox. */ + can_last_lo[can_pending_addr] = ECanaMboxes.MBOX0.MDL.all; /* Сохраняет второе и третье слова того же подтверждённого кадра. */ + can_last_at[can_pending_addr] = now; /* Отсчитывает повтор через 1,3 с от последнего подтверждения, а не от неудачной попытки. */ + can_valid[can_pending_addr >> 4] |= 1U << (can_pending_addr & 15); /* Устанавливает один бит достоверности начального адреса пакета. */ + } /* Перекрывающиеся пакеты разных масок имеют независимые начальные адреса. */ + } else { /* Отмена, ошибка или свободный TX без CANAA не подтверждают доставку текущих данных. */ + can_failed_at = now; can_backoff = 1U; /* Ограничивает новые попытки одной секундой при отсутствии получателя и CAN ACK. */ + } /* Старый подтверждённый кэш сохраняется, поэтому неудачная передача не теряет обновление. */ + wait = 0; can_tx_failed = 0U; can_pending_addr = -1; /* Завершение обрабатывается один раз даже без отдельного CANAA после отмены. */ + } /* Проверяет паузу после ошибки до подготовки следующего кадра. */ + if (can_backoff && now - can_failed_at < CAN_HEARTBEAT_TICKS) return 0; /* Во время секундной паузы данные и heartbeat остаются ожидающими. */ + can_backoff = 0U; /* Снятие паузы не требует изменения таймеров технологических данных. */ + return 1; /* Mailbox свободен и может принять один новый актуальный кадр. */ +} /* Чужие mailbox, аппаратный CAN ID и получаемые команды не меняются. */ +int CAN_send(int Port, int data[], int Addr) /* Возвращает 0 при занятости, 1 после запуска TX и 2 при неизменном пакете до срока повторения. */ +{ /* Снимок данных и запуск mailbox защищаются одним коротким запретом IRQ. */ + Uint32 hiword, loword, now; /* Ровно два 32-битных поля соответствуют восьми октетам существующего формата BALZAM. */ + unsigned int saved = __disable_interrupts(); /* Исключает разрыв трёхсловного снимка и гонку запуска с timeout ISR. */ + (void)Port; now = CAN_millis(); /* Как прежний передатчик, использует eCAN-A; время берётся из общего Timer1. */ + if (!CAN_tx_ready(now)) { __restore_interrupts(saved); return 0; } /* При занятости ничего не перезаписывает и не подтверждает данные программно. */ + if (Addr == CAN_HEARTBEAT_ADDR) { /* Отдельный пакет состояния узла не обращается к data=NULL или к R256. */ + hiword = 0xE0000000UL | ((Uint32)CAN_HEARTBEAT_ADDR << 16) | can_heartbeat_count; /* Сохраняет маркер BALZAM и передаёт циклический 16-битный счётчик секунд. */ + loword = ((Uint32)(unsigned int)Mode << 16) | (unsigned int)Desk; /* Два следующих слова сообщают аппаратный Mode и тип платы Desk. */ + can_pending_addr = -1; /* Успешный heartbeat не подтверждает ни один технологический пакет. */ + } else { /* Первый снимок, изменение любого слова либо истечение периода вызывают одинаковую отправку данных. */ + if (Addr < 0 || Addr >= ANSWER_LEN) { __restore_interrupts(saved); return 2; } /* Не допускает чтения за картой R0–R127 и позволяет планировщику пропустить неверный адрес. */ + hiword = 0xE0000000UL | ((Uint32)Addr << 16) | ((Uint32)data[Addr] & 0xFFFFUL); /* Первый регистр занимает младшие шестнадцать бит старшей половины CAN-данных. */ + loword = Addr + 1 < ANSWER_LEN ? ((Uint32)data[Addr + 1] & 0xFFFFUL) << 16 : 0UL; /* Отсутствующее второе слово у конца карты заменяется нулём. */ + if (Addr + 2 < ANSWER_LEN) loword |= (Uint32)data[Addr + 2] & 0xFFFFUL; /* Третье слово дополняется только в пределах реального массива регистров. */ + if ((can_valid[Addr >> 4] & (1U << (Addr & 15))) && can_last_hi[Addr] == hiword && can_last_lo[Addr] == loword && now - can_last_at[Addr] < CAN_REFRESH_TICKS) { /* Совпадение всех слов подавляет передачу только до индивидуального срока 1,3 с. */ + __restore_interrupts(saved); return 2; /* Не сдвигает время подтверждения: неизменные данные всё равно повторятся по таймеру. */ + } /* Изменение данных не ждёт окончания периода повторения. */ + can_pending_addr = Addr; /* Подготовленное состояние попадёт в кэш только после успешного аппаратного ACK. */ + } /* Для heartbeat и данных используется один и тот же безопасный жизненный цикл TX. */ + ECanaRegs.CANTA.all = 1UL; ECanaRegs.CANAA.all = 1UL; /* Очищает старые ACK и отмену mailbox 0 записью единиц в соответствующие биты eCAN. */ + ECanaMboxes.MBOX0.MDH.all = hiword; ECanaMboxes.MBOX0.MDL.all = loword; /* Записывает замороженный трёхсловный снимок без последующей подмены во время ожидания ACK. */ + EALLOW; ECanaRegs.CANTOC.all &= ~1UL; ECanaRegs.CANTSC = 0UL; ECanaRegs.CANTOC.all |= 1UL; EDIS; /* Перезапускает аппаратный timeout только для нового штатного запроса TX. */ + can_tx_at = now; can_tx_failed = 0U; wait = 1; /* Сохраняет момент запуска и принадлежность будущего ACK до разрешения прерываний. */ + ECanaRegs.CANTRS.all = 1UL; /* Однократно запускает аппаратную передачу в штатном mailbox 0. */ + led1_toggle(); __restore_interrupts(saved); /* Сохраняет индикацию передачи и возвращает исходную маску IRQ без ожидания шины. */ + return 1; /* Подтверждает только постановку кадра, оставляя окончательную доставку аппаратному ACK. */ +} /* Формат CAN ID, порядок слов и служебный mailbox логгера остаются прежними. */ +void CAN_heartbeat_service(void) /* Обслуживает независимый секундный heartbeat и завершение ранее запущенного TX. */ +{ /* Вызывается из main и не зависит от Cancount, масок данных или признака CanGO. */ + Uint32 now = CAN_millis(), elapsed, seconds; /* Время Timer1 учитывает задержки main без накопления дрейфа секундной сетки. */ + unsigned int saved = __disable_interrupts(); /* Короткая обработка ACK синхронизируется с timeout ISR. */ + CAN_tx_ready(now); __restore_interrupts(saved); /* Сохраняет успешное завершение данных даже тогда, когда новых пакетов пока нет. */ + if (!can_started) { can_started = 1U; can_heartbeat_at = can_scan_at = now; } /* Первый heartbeat появляется спустя полную секунду от начала обслуживания текущего запуска. */ + elapsed = now - can_heartbeat_at; /* Беззнаковое вычитание корректно при переполнении 32-битного счётчика. */ + if (elapsed >= CAN_HEARTBEAT_TICKS) { /* Формирует новую отметку на каждой секундной границе Timer1. */ + seconds = elapsed / CAN_HEARTBEAT_TICKS; can_heartbeat_at += seconds * CAN_HEARTBEAT_TICKS; /* После паузы main оставляет последнее значение без очереди устаревших кадров. */ + can_heartbeat_count = (unsigned int)((can_heartbeat_count + seconds) & 0xFFFFUL); can_heartbeat_due = 1U; /* Счётчик heartbeat циклически проходит диапазон 0..65535 секунд. */ + } /* Занятый передатчик не теряет ожидающий heartbeat. */ + if (can_heartbeat_due && CAN_send(0, 0, CAN_HEARTBEAT_ADDR) == 1) can_heartbeat_due = 0U; /* Приоритетно ставит один актуальный heartbeat после освобождения mailbox. */ +} /* Следующий повтор heartbeat планируется секундной сеткой, а не длительностью обхода масок. */ +void CAN_telemetry_service(void) /* Передаёт изменившиеся данные и повторяет каждый подтверждённый пакет через 1,3 с. */ +{ /* Фоновое обслуживание не ждёт CAN ACK и выдаёт готовую очередь по мере освобождения mailbox. */ + Uint32 now; unsigned int attempt, stream, pass, address, cursor; int result; /* Локальные счётчики ограничивают обход двумя потоками и конечной картой из 128 регистров. */ + CAN_heartbeat_service(); now = CAN_millis(); /* Секундный heartbeat получает приоритет перед обычными данными независимо от настройки потоков. */ + if (now - can_scan_at >= CAN_SCAN_TICKS) { can_scan_at += (now - can_scan_at) / CAN_SCAN_TICKS * CAN_SCAN_TICKS; can_scan_due = 1U; } /* Сохраняет сетку обнаружения изменений с интервалом 20 мс без накопления дрейфа после задержек main. */ + if (!can_scan_due) return; /* При неизменных данных main не повторяет полный обход масок на каждой итерации. */ + for (attempt = 0U; attempt < 2U; ++attempt) { /* После успешной постановки чередует потоки, исключая голодание медленной маски. */ + stream = (can_stream + attempt) & 1U; cursor = can_cursor[stream]; /* Начинает следующий поиск после последнего принятого кадра данного потока. */ + if (!Cancount[stream]) continue; /* Ноль сохраняет штатное отключение соответствующего потока; ненулевой период заменяется общим повтором 1,3 с. */ + for (pass = 0U; pass < 2U; ++pass) { /* Два конечных прохода реализуют циклический обход без зависания на пустой маске. */ + for (address = 0U; address < ANSWER_LEN;) { /* Формирует те же трёхсловные группы от первого разрешённого адреса маски. */ + if (!(Maska[stream][address >> 4] & (1U << (address & 15)))) { ++address; continue; } /* Пропускает запрещённые регистры и гарантированно продвигает поиск. */ + if ((pass == 0U && address >= cursor) || (pass == 1U && address < cursor)) { /* Сначала рассматривает хвост карты после курсора, затем оставшееся начало. */ + result = CAN_send(0, modbus, address); /* Сравнивает полный снимок с подтверждённым кэшем и индивидуальным временем повтора. */ + if (result != 2) { /* Только неизменный пакет до срока допускает переход к следующему кандидату в этом же вызове. */ + if (result == 1) { can_cursor[stream] = address + 3U < ANSWER_LEN ? address + 3U : 0U; can_stream = stream ^ 1U; } /* Продвигает курсор лишь после постановки кадра и отдаёт следующий свободный слот другому потоку. */ + return; /* При занятости сохраняет адрес; при постановке продолжит готовую очередь следующей итерацией main после ACK. */ + } /* Пропущенные неизменные пакеты не занимают физическую шину. */ + } /* Завершает проверку одного допустимого начального адреса. */ + address += 3U; /* Как прежний протокол, один кадр покрывает три последовательных регистра независимо от разреженности маски. */ + } /* Максимальный адрес ограничен размером реальной технологической карты. */ + } /* После обхода обеих частей все пакеты потока рассмотрены ровно один раз. */ + } /* Ни один разрешённый пакет не требует немедленной передачи. */ + can_scan_due = 0U; /* Следующее плановое сканирование произойдёт через 20 мс; выдача готовой очереди этим ожиданием не задерживается. */ +} /* Период 1,3 с относится к каждому пакету, а не к одному кадру всей маски за один период. */ +#endif /* Закрывает единственную реализацию фоновой телеметрии текущей прошивки 166. */ diff --git a/Source/Internal/Include/cntrl_adr.h b/Source/Internal/Include/cntrl_adr.h index af5fb23..945ee39 100644 --- a/Source/Internal/Include/cntrl_adr.h +++ b/Source/Internal/Include/cntrl_adr.h @@ -1,5 +1,5 @@ -/* Ñîáñòâåííûé, îáùèé è ñïåöèàëüíûå àäðåñà ïîñëåäîâàòåëüíîãî îáìåíà. - * main çàäà¸ò àäðåñà ÷åðåç set_cntrl_addr äî íà÷àëà îáìåíà. +/* Собственный, общий и специальные адреса последовательного обмена. + * main задаёт адреса через set_cntrl_addr до начала обмена. */ #ifndef _CNTRL_ADR #define _CNTRL_ADR @@ -8,22 +8,22 @@ extern "C" { #endif -/** àäðåñ êîíòðîëëåðà äëà ïîñûëêè âñåì ÀÈÍàì */ +/** адрес контроллера дла посылки всем АИНам */ extern int ADDR_FOR_ALL; -/** àäðåñ êîíòðîëëåðà äëà ïîñûëêè îòâåòà */ +/** адрес контроллера дла посылки ответа */ extern const int ADDR_ANSWER; -/** àäðåñà òåðìèíàëà äëà ïîñûëêè îòâåòà */ +/** адреса терминала дла посылки ответа */ extern const int ADDR_TERMINAL; -/* Àäðåñ êîíòðîëëåðà */ +/* Адрес контроллера */ extern int CNTRL_ADDR; -/* Óíèâåðñàëüíûé àäðåñ êîíòðîëëåðà */ +/* Универсальный адрес контроллера */ extern const int CNTRL_ADDR_UNIVERSAL; -/** Óñòàíîâêà àäðåñà êîíòðîëëåðà äëà ïðîøèâêè */ +/** Установка адреса контроллера дла прошивки */ void set_cntrl_addr (int cntrl_addr,int cntrl_addr_for_all); diff --git a/Source/Internal/Include/crc16.h b/Source/Internal/Include/crc16.h index 8885beb..b06e4a1 100644 --- a/Source/Internal/Include/crc16.h +++ b/Source/Internal/Include/crc16.h @@ -1,5 +1,5 @@ -/* Èíòåðôåéñû CRC. Ðàçëè÷àòü áóôåð êàäðà è ìàññèâ ñëîâ EEPROM; - * ðåçóëüòàò çàâèñèò îò ïîðÿäêà îáðàáîòêè áàéòîâ. +/* Интерфейсы CRC. Различать буфер кадра и массив слов EEPROM; + * результат зависит от порядка обработки байтов. */ typedef unsigned short WORD; typedef unsigned char byte; diff --git a/Source/Internal/Include/ecan.h b/Source/Internal/Include/ecan.h index bf17d0a..ab0a61d 100644 --- a/Source/Internal/Include/ecan.h +++ b/Source/Internal/Include/ecan.h @@ -1,9 +1,11 @@ -/* Òåëåìåòðèÿ eCAN è ôîíîâàÿ âûäà÷à îòâåòîâ ëîããåðà. - * UMP_CAN_service âûçûâàåòñÿ èç main, íå èç ïðè¸ìíîãî IRQ. +/* Телеметрия eCAN и фоновая выдача ответов логгера. + * UMP_CAN_service вызывается из main, не из приёмного IRQ. */ void InitCan(int Port, int DevNum); -void CAN_send(int Port, int data[], int Addr); +int CAN_send(int Port, int data[], int Addr); /* 0: занят, 1: кадр поставлен, 2: подтверждённые данные не изменились и 1,3 с ещё не прошли. */ +void CAN_heartbeat_service(void); /* Планирует отдельный heartbeat по Timer1 с периодом одна секунда. */ +void CAN_telemetry_service(void); /* В main обслуживает heartbeat, изменения данных и повтор каждого разрешённого пакета через 1,3 с. */ extern int CAN_input_data[]; -/* Íåáëîêèðóþùàÿ ïåðåäà÷à îòâåòîâ ëîããåðà îòäåëüíûì CAN mailbox. */ +/* Неблокирующая передача ответов логгера отдельным CAN mailbox. */ void UMP_CAN_service(void); diff --git a/Source/Internal/Include/filter_bat2.h b/Source/Internal/Include/filter_bat2.h index 50f6879..c58a892 100644 --- a/Source/Internal/Include/filter_bat2.h +++ b/Source/Internal/Include/filter_bat2.h @@ -1,5 +1,5 @@ -/* Êîýôôèöèåíòû è èçìåíÿåìàÿ èñòîðèÿ ôèëüòðà. Êàæäûé íåçàâèñèìûé - * êàíàë äîëæåí èìåòü îòäåëüíûé ýêçåìïëÿð FILTERBAT. +/* Коэффициенты и изменяемая история фильтра. Каждый независимый + * канал должен иметь отдельный экземпляр FILTERBAT. */ #ifndef _FILTER_BAT2 #define _FILTER_BAT2 diff --git a/Source/Internal/Include/firmware_info.h b/Source/Internal/Include/firmware_info.h new file mode 100644 index 0000000..53879d2 --- /dev/null +++ b/Source/Internal/Include/firmware_info.h @@ -0,0 +1,10 @@ +#ifndef BALSAM_FIRMWARE_INFO_H /* Исключает повторное объявление адаптера паспорта при совместном подключении RS и CAN. */ +#define BALSAM_FIRMWARE_INFO_H /* Обозначает единственный интерфейс firmware-info v1 приложения 166. */ +#include "firmware_info_static.h" /* Использует тот же статический 12-словный контракт общей библиотеки, который подключён в 167. */ +#define FIRMWARE_INFO_ADDRESS 0x1200U /* Адрес firmware-info v1 из протокола 167 и SetGUI; не пересекается с логгером 0x1000..0x117B. */ +#define FIRMWARE_INFO_END (FIRMWARE_INFO_ADDRESS + FIRMWARE_INFO_STATIC_COUNT) /* Исключающая верхняя граница 0x120C охватывает ровно двенадцать 16-битных регистров. */ +static unsigned int firmware_info_range(unsigned int address, unsigned int count) /* Проверяет только чтение внутри паспорта без переполнения 16-битной суммы адреса и длины. */ +{ /* Вычитание выполняется после проверки адреса, поэтому не переполняется на C28x. */ + return address >= FIRMWARE_INFO_ADDRESS && address < FIRMWARE_INFO_END && count > 0U && count <= FIRMWARE_INFO_END - address; /* Разрешает полное и частичное чтение, запрещая нулевую длину и пересечение границы паспорта. */ +} /* Не меняет правила остальных технологических и служебных адресов. */ +#endif /* Завершает адаптер, не добавляя изменяемое состояние или параметры EEPROM. */ diff --git a/Source/Internal/Include/kanal.h b/Source/Internal/Include/kanal.h index 94917d8..807e2de 100644 --- a/Source/Internal/Include/kanal.h +++ b/Source/Internal/Include/kanal.h @@ -1,4 +1,4 @@ -/* Èíòåðôåéñ êàíàëà èíäèêàöèè. Îí íå ôîðìèðóåò START_DPTB - * è íå äîëæåí èñïîëüçîâàòüñÿ âìåñòî ôóíêöèé óïðàâëåíèÿ íàãðóçêîé. +/* Интерфейс канала индикации. Он не формирует START_DPTB + * и не должен использоваться вместо функций управления нагрузкой. */ void kanal_Send(int adr, long dat, int dot); diff --git a/Source/Internal/Include/log_to_mem.h b/Source/Internal/Include/log_to_mem.h index 57c36c4..209baf0 100644 --- a/Source/Internal/Include/log_to_mem.h +++ b/Source/Internal/Include/log_to_mem.h @@ -1,5 +1,5 @@ -/* Êîíòðàêò ëîããåðà ñ SetGUI: ðàçìåð çàïèñè, âåðñèÿ è àäðåñà. - * ×òåíèå öåëîãî áëîêà çàùèùàåòñÿ îò IRQ íà ñòîðîíå RS/CAN îáðàáîò÷èêà. +/* Контракт логгера с SetGUI: размер записи, версия и адреса. + * Чтение целого блока защищается от IRQ на стороне RS/CAN обработчика. */ #ifndef _LOG_TO_MEM #define _LOG_TO_MEM @@ -8,11 +8,11 @@ extern "C" { #endif -/* Îïðåäåëåíèa äëa ðàáîòû ëîããåðà */ +/* Определениa длa работы логгера */ #define LOG_PAGE_START 0x0200000 #define LOG_PAGE_LEN 0xFA00 -extern int no_write, never_write; // Ôëàãè, ÷òîáû íå ïèñàòü (åñëè ÷òî) +extern int no_write, never_write; // Флаги, чтобы не писать (если что) typedef struct { @@ -25,22 +25,25 @@ typedef struct extern LOG Log; -/* Çàïèñü ñëîâa â ïàìàòü, ãäå ëîãè ëåæàò */ +/* Запись словa в памать, где логи лежат */ #define Log_to_mem(x) *(int *)(Log.Adres++) = x -/* Ïðîâåðêà ãðàíèöû ïàìàòè äëà ëîãîâ */ +/* Проверка границы памати дла логов */ #define Test_mem_limit(x) if(Log.Adres > (Log.Finis - (x))) Log.Adres = Log.Start -/* Î÷èñòêà ïàìàòè (îáíóëåíèå) */ +/* Очистка памати (обнуление) */ void clear_mem(); -/* Ëîããåð ÓÌÏ: îòäåëüíîå àäðåñíîå ïðîñòðàíñòâî Modbus, áåç èçìåíåíèÿ - * 128 òåõíîëîãè÷åñêèõ ðåãèñòðîâ. Äâà áàíêà ïî 800 çàïèñåé: - * òåêóùèé êîëüöåâîé æóðíàë è çàôèêñèðîâàííûé ôðàãìåíò îòêëþ÷åíèÿ. */ +/* Логгер УМП: отдельное адресное пространство Modbus, без изменения + * 128 технологических регистров. Два банка по 800 записей: + * текущий кольцевой журнал и зафиксированный фрагмент отключения. */ #define UMP_LOG_BASE 0x1000U #define UMP_LOG_DATA 0x1010U -#define UMP_LOG_WORDS 40U +/* Формат v4 совпадает с 167: 12 слов по 16 бит содержат выбранные сигналы и нулевой резерв для парной передачи CAN. */ +#define UMP_LOG_WORDS 12U #define UMP_LOG_CAPACITY 800U +/* Онлайн-окно вмещает 120 слов полезных данных: при формате v4 это десять полных записей. */ +#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/Include/measure.h b/Source/Internal/Include/measure.h index f81b792..89a5647 100644 --- a/Source/Internal/Include/measure.h +++ b/Source/Internal/Include/measure.h @@ -1,5 +1,5 @@ -/* ×àñòîòû è ñîñòîÿíèÿ èçìåðåíèé. READY â 166 — ñ÷¸ò÷èê äî íóëÿ. - * READY_FREQ çàäà¸ò òàéìåð ÑÈÔÓ, DAC_FREQ — ðàñ÷¸ò ÖÀÏ. +/* Частоты и состояния измерений. READY в 166 — счётчик до нуля. + * READY_FREQ задаёт таймер СИФУ, DAC_FREQ — расчёт ЦАП. */ #ifndef _MEASURE #define _MEASURE @@ -65,14 +65,14 @@ typedef union #define NOER 0xE000//C #define EROR 0x01FF -#define READY_FREQ (500.0 * 2)// Ãö -#define BLINK_FREQ 2 // Ãö +#define READY_FREQ (500.0 * 2)// Гц +#define BLINK_FREQ 2 // Гц #define BLINK_TIME (READY_FREQ / BLINK_FREQ) #define CANPOWSE 20 -#define ADC_FREQ 3750 //3885.0//777//2000//20000 //777 //3885 // Ãö (777*5) -#define DAC_FREQ 200//5 // Ãö +#define ADC_FREQ 3750 //3885.0//777//2000//20000 //777 //3885 // Гц (777*5) +#define DAC_FREQ 200//5 // Гц #define LOAD_TIME 30//15 // sec @@ -87,23 +87,23 @@ extern unsigned int Caliber_time; #define ZERO 27 -#define Cooling 5 // (°Ñ) Ãèñòåðåçèñ ïî ñíàòèþ ïåðåãðåâà +#define Cooling 5 // (°С) Гистерезис по снатию перегрева #define COSPi6 0.86602540378443864676372317075294 #define RADIX2 1.4142135623730950488016887242097 -#define POWER_380 0 // ïèòàíèå 380 -#define POWER_38O 1 // ïèòàíèå 380 +#define POWER_380 0 // питание 380В +#define POWER_38O 1 // питание 380В -#define CURRENT 2 // òîê -#define VOLTAGE 3 // íàïðàæåíèå +#define CURRENT 2 // ток +#define VOLTAGE 3 // напражение -#define POWER_31 4 // ïèòàíèå 31 -#define POWER_27 5 // ïèòàíèå 24 -#define POWER_24 6 // ïèòàíèå 24 -#define POWER_15 7 // ïèòàíèå 15 -#define TERMO_AD 8 // òåðìîäàò÷èê ìåëêîñõåìà +#define POWER_31 4 // питание 31В +#define POWER_27 5 // питание 24В +#define POWER_24 6 // питание 24В +#define POWER_15 7 // питание 15В +#define TERMO_AD 8 // термодатчик мелкосхема extern int TPL_CANS,tpl_cans; diff --git a/Source/Internal/Include/message.h b/Source/Internal/Include/message.h index 2ddb361..da1f013 100644 --- a/Source/Internal/Include/message.h +++ b/Source/Internal/Include/message.h @@ -1,5 +1,5 @@ -/* Òåõíîëîãè÷åñêèå ðåãèñòðû è Modbus. ANSWER_LEN îãðàíè÷èâàåò - * ìàññèâ modbus; àäðåñîì ëîããåðà 0x1000 èíäåêñèðîâàòü åãî íåëüçÿ. +/* Технологические регистры и Modbus. ANSWER_LEN ограничивает + * массив modbus; адресом логгера 0x1000 индексировать его нельзя. */ #ifndef MESSAGE_H #define MESSAGE_H @@ -14,8 +14,8 @@ typedef unsigned char CHAR; typedef struct { - unsigned char Address; // Àäðåñ êîíòðîëëåðà - unsigned char Number; // Íîìåð êîìàíäû + unsigned char Address; // Адрес контроллера + unsigned char Number; // Номер команды BAITE byte0; BAITE byte1; diff --git a/Source/Internal/Include/package.h b/Source/Internal/Include/package.h index dd97020..00171ac 100644 --- a/Source/Internal/Include/package.h +++ b/Source/Internal/Include/package.h @@ -1,10 +1,16 @@ -/* Ìàêðîñû îáðàùàþòñÿ ê îáùåé êàðòå modbus, íå ê ëîêàëüíûì äàííûì. - * START/STOP ÷èòàþòñÿ ÷åðåç volatile. Âõîäÿùàÿ çàïèñü ñëîâà 127 - * äîëæíà ïðîéòè UMP_commands_write äëÿ ôèêñàöèè ôðîíòà. +/* Макросы обращаются к общей карте modbus, не к локальным данным. + * START/STOP читаются через volatile. Входящая запись слова 127 + * должна пройти UMP_commands_write для фиксации фронта. */ #ifndef PACKAGE #define PACKAGE +/* Задаёт числовой код прямого порядка индикаторов, чтобы сравнение OBOROT в препроцессоре не заменяло неопределённое имя нулём. */ +#define STRAIGHT 0 +/* Отличающийся код обратного порядка выбирает ветку перестановки двух показаний в pulto.c. */ +#define REVERSE 1 + +/* Сохраняет выбранное в обеих ветках исполнение 165 с прямым порядком индикаторов; перенос функций не меняет аппаратные калибровки. */ #define BALSAM 165 #if BALSAM == 166 @@ -84,13 +90,13 @@ #define bSecretBt Buttons.bit.bit1 #define bTermoCal Buttons.bit.bit2 -#define Cancount (modbus+0x60) // ïàóçà ìåæäó I ïîñûëêàìè CAN -#define Bright (modbus+0x62) // àðêîñòü ñèãíàëüíûõ ëàìïî÷åê -#define Brightness modbus[0x62] // àðêîñòü ñèãíàëüíûõ ëàìïî÷åê +#define Cancount (modbus+0x60) // пауза между I посылками CAN +#define Bright (modbus+0x62) // аркость сигнальных лампочек +#define Brightness modbus[0x62] // аркость сигнальных лампочек -/* Íå âðåìà! -#define DAC_go modbus[0x64] // íà÷àëî çàðàäà -#define DAC_stop modbus[0x65] // êîíåö çàðàäà +/* Не врема! +#define DAC_go modbus[0x64] // начало зарада +#define DAC_stop modbus[0x65] // конец зарада */ #define m_FAST 0 @@ -135,7 +141,7 @@ #define LastMode Modbus[126].all -/* Ñëîâî ìåíÿåòñÿ èç CAN/RS; ÷òåíèå êîìàíäû íå äîëæíî êåøèðîâàòüñÿ. */ +/* Слово меняется из CAN/RS; чтение команды не должно кешироваться. */ #define Commands (((volatile WORDE *)modbus)[127].all) #define cTestLamp Modbus[127].bit.bit0 #define cDefParam Modbus[127].bit.bit1 diff --git a/Source/Internal/Include/peripher.h b/Source/Internal/Include/peripher.h index b482fd8..771694e 100644 --- a/Source/Internal/Include/peripher.h +++ b/Source/Internal/Include/peripher.h @@ -1,6 +1,6 @@ -/* Ôèçè÷åñêèå GPIO ñ ó÷¸òîì ðåæèìà è ïîëÿðíîñòè. set îçíà÷àåò - * àêòèâèðîâàòü ôóíêöèþ, íå âñåãäà âûñòàâèòü 1. START/STOP íàãðóçêè - * àêòèâíû åäèíèöåé, RES_OUT_2 íóë¸ì. Äèñêðåòàìè âëàäååò àâòîìàò ÑÈÔÓ. +/* Физические GPIO с учётом режима и полярности. set означает + * активировать функцию, не всегда выставить 1. START/STOP нагрузки + * активны единицей, RES_OUT_2 нулём. Дискретами владеет автомат СИФУ. */ #include "DSP2833x_Device.h" // DSP281x Headerfile Include File diff --git a/Source/Internal/Include/pulto.h b/Source/Internal/Include/pulto.h index f3f1bb9..b384b14 100644 --- a/Source/Internal/Include/pulto.h +++ b/Source/Internal/Include/pulto.h @@ -1,5 +1,5 @@ -/* Ñîñòîÿíèÿ ïóëüòà dsk_EPLT. Îáðàáîò÷èê òàéìåðà íàãðóçêè - * îïðåäåë¸í îòäåëüíî â measure.c. +/* Состояния пульта dsk_EPLT. Обработчик таймера нагрузки + * определён отдельно в measure.c. */ //void what_is(void); diff --git a/Source/Internal/Include/spise2p.h b/Source/Internal/Include/spise2p.h index 0f84d10..85a996d 100644 --- a/Source/Internal/Include/spise2p.h +++ b/Source/Internal/Include/spise2p.h @@ -1,11 +1,11 @@ -/* Àâòîìàò SPI EEPROM ïðîäâèãàåò òàéìåð 2. Ñèíõðîííîå îæèäàíèå - * òðåáóåò ðàçðåø¸ííûõ IRQ. PAGE_LEN/WORD_LEN çàäàþò àäðåñàöèþ ñòðàíèö. +/* Автомат SPI EEPROM продвигает таймер 2. Синхронное ожидание + * требует разрешённых IRQ. PAGE_LEN/WORD_LEN задают адресацию страниц. */ #ifndef __SPISE2P_H__ #define __SPISE2P_H__ -// ¨ìêîñòü ïàìàòè â áàéòàõ +// Ёмкость памати в байтах #define SEEPROM_LEN 0x10000 #define NULL 0 @@ -97,25 +97,25 @@ void spiSe2pRead(SPISE2P_DRV *se2p, SE2P_DATA *data); #define WORD_LEN 1 #endif -/* Óñòàíîâêà äðàéâåðà ñåðèàëüíîé EEPROM. ** -** Èíèöèàëèçàöèà SPI è ïðî÷. Òàêæå íàñòðîéêà òàéìåðà. ** -** Äðàéâåð ðàáîòàåò íà ïðåðûâàíèàõ îò òàéìåðà 2! */ +/* Установка драйвера сериальной EEPROM. ** +** Инициализациа SPI и проч. Также настройка таймера. ** +** Драйвер работает на прерываниах от таймера 2! */ void InitSeeprom(void); -/* Çàïèñü áëîêà â SEEPROM. Ïàðàìåòðû òàêîâû: ** -** adres - àäðåñ â åïðîìêå, êóäà ïèñàòü. ** -** adres = 0..0x8000, åñëè äëèíà ñëîâà 8 áèò ** -** adres = 0..0x4000, åñëè äëèíà ñëîâà 16 áèò ** -** buf - óêàçàòåëü íà ïàìàòü, îòêóäà ïèñàòü. ** -** size - äëèíà áëîêà â áàéòàõ. Ïî-ëþáîìó â áàéòàõ! */ +/* Запись блока в SEEPROM. Параметры таковы: ** +** adres - адрес в епромке, куда писать. ** +** adres = 0..0x8000, если длина слова 8 бит ** +** adres = 0..0x4000, если длина слова 16 бит ** +** buf - указатель на памать, откуда писать. ** +** size - длина блока в байтах. По-любому в байтах! */ void Seeprom_write(unsigned int adres, unsigned int buf[], unsigned int size); -/* ×òåíèå áëîêà èç SEEPROM. Ïàðàìåòðû òàêîâû: ** -** adres - àäðåñ â åïðîìêå, îòêóäà ÷èòàòü. ** -** adres = 0..0x8000, åñëè äëèíà ñëîâà 8 áèò ** -** adres = 0..0x4000, åñëè äëèíà ñëîâà 16 áèò ** -** buf - óêàçàòåëü íà ïàìàòü, êóäà ÷èòàòü. ** -** size - äëèíà áëîêà â áàéòàõ. Ïî-ëþáîìó â áàéòàõ! */ +/* Чтение блока из SEEPROM. Параметры таковы: ** +** adres - адрес в епромке, откуда читать. ** +** adres = 0..0x8000, если длина слова 8 бит ** +** adres = 0..0x4000, если длина слова 16 бит ** +** buf - указатель на памать, куда читать. ** +** size - длина блока в байтах. По-любому в байтах! */ void Seeprom_read(unsigned int adres, unsigned int buf[], unsigned int size); #endif diff --git a/Source/Internal/Include/tools.h b/Source/Internal/Include/tools.h index bdb03f9..3087bc9 100644 --- a/Source/Internal/Include/tools.h +++ b/Source/Internal/Include/tools.h @@ -1,5 +1,5 @@ -/* Èíèöèàëèçàöèÿ ïàìÿòè è çàäåðæêè. pause_us íå èñïîëüçîâàòü - * äëÿ äëèòåëüíîñòè äèñêðåòîâ; èõ îòñ÷èòûâàåò àïïàðàòíûé òàéìåð. +/* Инициализация памяти и задержки. pause_us не использовать + * для длительности дискретов; их отсчитывает аппаратный таймер. */ #ifndef TOOLS_H #define TOOLS_H diff --git a/Source/Internal/Include/ump_can_protocol.h b/Source/Internal/Include/ump_can_protocol.h index e374045..1e0e507 100644 --- a/Source/Internal/Include/ump_can_protocol.h +++ b/Source/Internal/Include/ump_can_protocol.h @@ -1,28 +1,34 @@ -/* Ñëóæåáíûé CAN-ïðîòîêîë ëîããåðà ÓÌÏ. Íå èñïîëüçóåò àäðåñà 0..127 - * òåõíîëîãè÷åñêîãî îáìåíà. Ôîðìàò ïîëåçíûõ äàííûõ ñîâìåñòèì ñ ïîðÿäêîì - * ñëîâ ñòàðîãî CAN: MDL (ñëîâà 1,2), çàòåì MDH (ìàðêåð, ñëîâî 0). - * Çàïðîñ: ìàðêåð 0x1F00, ñëîâî 0 = token:8 | function:8, - * ñëîâà 1,2 = àäðåñ ðàñøèðåíèÿ è ÷èñëî ñëîâ/çàïèñûâàåìîå çíà÷åíèå. - * Îòâåòû: ìàðêåð 0x1F00 + íîìåð ôðàãìåíòà, ñëîâî 0 = token:8 | error:8, - * ñëîâà 1,2 = äâà ñëîâà åäèíîãî çàôèêñèðîâàííîãî ñíèìêà. - * Áèòû ìàñêè çàïèñè â çàãîëîâêå çàïðîñà ðàâíû íóëþ: ñòàðàÿ ïëàòà - * èãíîðèðóåò çàïðîñ, íå èçìåíÿÿ òåõíîëîãè÷åñêèå ðåãèñòðû. */ +/* Служебный CAN-протокол логгера УМП. Не использует адреса 0..127 + * технологического обмена. Формат полезных данных совместим с порядком + * слов старого CAN: MDL (слова 1,2), затем MDH (маркер, слово 0). + * Запрос: маркер 0x1F00, слово 0 = token:8 | function:8, + * слова 1,2 = адрес расширения и число слов/записываемое значение. + * Ответы: маркер 0x1F00 + номер фрагмента, слово 0 = token:8 | error:8, + * слова 1,2 = два слова единого зафиксированного снимка. + * Биты маски записи в заголовке запроса равны нулю: старая плата + * игнорирует запрос, не изменяя технологические регистры. */ #ifndef UMP_CAN_PROTOCOL_H #define UMP_CAN_PROTOCOL_H #include "log_to_mem.h" +#include "firmware_info.h" /* Использует то же окно firmware-info v1, что FC03, сохраняя остальной служебный CAN-протокол 166. */ #define UMP_CAN_MARKER 0x1F00U #define UMP_CAN_MAX_WORDS 124U -/* Âûçûâàþùèé êîä çàùèùàåò âåñü ñíèìîê îò IRQ. Ôóíêöèÿ íå æä¸ò CAN è - * íå ïèøåò çà ïðåäåëàìè reply[124]. Îøèáêè âîçâðàùàþòñÿ îòäåëüíûì êàäðîì. */ +/* Вызывающий код защищает весь снимок от IRQ. Функция не ждёт CAN и + * не пишет за пределами reply[124]. Ошибки возвращаются отдельным кадром. */ static unsigned int ump_can_prepare(unsigned int function, unsigned int address, unsigned int value, unsigned int *reply, unsigned int *error) { unsigned int i; *error = 0; if (function == 3) { + if (firmware_info_range(address, value)) { /* Признаёт только чтение внутри нового двенадцатисловного паспорта. */ + for (i = 0; i < value; ++i) reply[i] = firmware_info_static_read(address - FIRMWARE_INFO_ADDRESS + i); /* Общий статический упаковщик выдаёт те же слова, что RS, без чтения архива логгера. */ + return value; /* Передаёт паспорт существующему механизму фрагментов CAN без изменения mailbox, ID и повторов. */ + } /* Все остальные запросы продолжают проходить прежнюю проверку окон логгера v4. */ if (!((address == UMP_LOG_BASE && value == 16) || - (address == UMP_LOG_DATA && (value == 40 || value == 80 || value == 120)) || + /* Разрешает от одной до десяти целых 12-словных записей v4 в пределах 120 слов полезного окна CAN. */ + (address == UMP_LOG_DATA && value >= UMP_LOG_WORDS && value <= 120U && value % UMP_LOG_WORDS == 0U) || (address == UMP_LOG_LIVE && value == 124))) *error = 2; else { for (i = 0; i < value; i++) reply[i] = ump_log_read(address+i); @@ -32,7 +38,7 @@ static unsigned int ump_can_prepare(unsigned int function, unsigned int address, if (address < UMP_LOG_BASE || address > UMP_LOG_BASE+3) *error = 2; else if (!ump_log_write(address, value)) *error = 3; } else *error = 1; - /* Äëÿ çàïèñè âîçâðàùàåì ýõî àäðåñà è çíà÷åíèÿ, äëÿ îøèáêè — å¸ êîíòåêñò. */ + /* Для записи возвращаем эхо адреса и значения, для ошибки — её контекст. */ reply[0] = address; reply[1] = value; return 2; } diff --git a/Source/Internal/Include/ump_control_impl.h b/Source/Internal/Include/ump_control_impl.h index de544fe..d837910 100644 --- a/Source/Internal/Include/ump_control_impl.h +++ b/Source/Internal/Include/ump_control_impl.h @@ -1,18 +1,18 @@ -/* Ïîäêëþ÷àåòñÿ òîëüêî èç DAC.c; â host-òåñòå — ñ ïîäìåíîé GPIO/IRQ. */ +/* Подключается только из DAC.c; в host-тесте — с подменой GPIO/IRQ. */ #ifndef UMP_CONTROL_IMPL_H #define UMP_CONTROL_IMPL_H -/* Àïïàðàòíàÿ îá¸ðòêà àâòîìàòà. Õðàíèì å¸ â ñóùåñòâóþùåì DAC.c, ÷òîáû - * ñòàðûé ïðîåêò CCS è íîâûé CCS12 ñîáèðàëè îäèíàêîâûé íàáîð èñõîäíèêîâ. - * Âñå âõîäû íèæå ñîõðàíÿþò ïðåæíþþ ìàñêó IRQ; íåëüçÿ ïðîñòî äåëàòü EINT - * ïðè âûõîäå, ïîñêîëüêó âûçîâ âîçìîæåí èç óæå çàùèù¸ííîãî îáðàáîò÷èêà. */ +/* Аппаратная обёртка автомата. Храним её в существующем 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(); @@ -22,8 +22,8 @@ static void UMP_apply_outputs(unsigned int previous_output, unsigned int previou if (ump_pulse.relay) set_RES_OUT_2(); else clear_RES_OUT_2(); } - /* Ñòàðîå èìÿ îñòàâëåíî äëÿ ïðîòîêîëà ëîããåðà. Ýòî òåïåðü îòðàæåíèå - * òàéìåðà àâòîìàòà, à íå ïåðåìåííàÿ, êîòîðóþ îäíîâðåìåííî ïðàâèò main. */ + /* Старое имя оставлено для протокола логгера. Это теперь отражение + * таймера автомата, а не переменная, которую одновременно правит main. */ IMPowse = ump_pulse.remaining; } @@ -34,8 +34,8 @@ void UMP_pulse_init(void) 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); @@ -47,9 +47,9 @@ void UMP_commands_write(unsigned int commands) unsigned int output = ump_pulse.output, relay = ump_pulse.relay; Commands = commands; if (Desk == dsk_LOAD && ump_pulse_enabled) { - /* Âûïîëíÿåì ôðîíò â ìîìåíò ïðèíÿòèÿ ñëîâà. Íåò î÷åðåäè, êîòîðóþ - * main äîëæåí îïðîñèòü ïîñëå äëèòåëüíîãî îáðàùåíèÿ ê EEPROM. - * Çäåñü òîëüêî íåñêîëüêî îïåðàöèé ñ ïàìÿòüþ/GPIO, áåç îæèäàíèé. */ + /* Выполняем фронт в момент принятия слова. Нет очереди, которую + * main должен опросить после длительного обращения к EEPROM. + * Здесь только несколько операций с памятью/GPIO, без ожиданий. */ ump_pulse_accept(&ump_pulse, commands, (unsigned int)READY_FREQ); UMP_apply_outputs(output, relay); } @@ -70,11 +70,11 @@ void UMP_pulse_tick(void) void UMP_reset_parameter_commands(void) { unsigned int saved = __disable_interrupts(); - /* EEPROM ñîäåðæèò ïàðàìåòðû, íî íå ÿâëÿåòñÿ èñòî÷íèêîì êîìàíä ïóñêà. - * Ñîõðàíÿåì ïîñëåäíèå ïðèíÿòûå START/STOP è èñòîðèþ ôðîíòîâ àâòîìàòà. - * Íåëüçÿ îáíóëèòü èõ ïðè Load/Default: òàéìåð ÖÀÏ ÷èòàåò òîò æå óðîâåíü, - * à ñëåäóþùèé ïîâòîð ïàêåòà ñ åäèíèöåé íå äîëæåí ñòàòü ëîæíûì ôðîíòîì. - * Äðóãèå ðåæèìû ïëàòû ñîõðàíÿþò ïðåæíåå ïîâåäåíèå ïîëíîãî ñáðîñà. */ + /* EEPROM содержит параметры, но не является источником команд пуска. + * Сохраняем последние принятые START/STOP и историю фронтов автомата. + * Нельзя обнулить их при Load/Default: таймер ЦАП читает тот же уровень, + * а следующий повтор пакета с единицей не должен стать ложным фронтом. + * Другие режимы платы сохраняют прежнее поведение полного сброса. */ if (Desk == dsk_LOAD) Commands &= UMP_START_MASK | UMP_STOP_MASK; else Commands = 0; __restore_interrupts(saved); diff --git a/Source/Internal/Include/ump_pulse.h b/Source/Internal/Include/ump_pulse.h index 408446f..0599fe5 100644 --- a/Source/Internal/Include/ump_pulse.h +++ b/Source/Internal/Include/ump_pulse.h @@ -1,8 +1,8 @@ -/* Óïðàâëåíèå èìïóëüñàìè ÑÈÔÓ. ×èñòûé àâòîìàò áåç äîñòóïà ê GPIO. - * Îäèí è òîò æå êîä èñïîëüçóåòñÿ ïðîøèâêîé è host-òåñòîì. - * ÂÀÆÍÎ: âûçûâàþùàÿ ñòîðîíà ñåðèàëèçóåò init/accept/tick çàïðåòîì IRQ. - * volatile îáåñïå÷èâàåò îáðàùåíèÿ ê îáùåìó ñîñòîÿíèþ, íî íå çàìåíÿåò - * êðèòè÷åñêóþ ñåêöèþ: îáíîâëåíèå íåñêîëüêèõ ïîëåé íå ÿâëÿåòñÿ àòîìàðíûì. +/* Управление импульсами СИФУ. Чистый автомат без доступа к GPIO. + * Один и тот же код используется прошивкой и host-тестом. + * ВАЖНО: вызывающая сторона сериализует init/accept/tick запретом IRQ. + * volatile обеспечивает обращения к общему состоянию, но не заменяет + * критическую секцию: обновление нескольких полей не является атомарным. */ #ifndef UMP_PULSE_H #define UMP_PULSE_H @@ -21,10 +21,10 @@ typedef struct { static void ump_pulse_init(volatile UMP_PULSE_STATE *s, unsigned int commands) { - /* Óæå àêòèâíàÿ êîìàíäà ïðè îêîí÷àíèè çàãðóçêè íå ÿâëÿåòñÿ íîâûì ïóñêîì. - * Ñíèìàåì ôèçè÷åñêèå âûõîäû îòäåëüíî â àïïàðàòíîé îá¸ðòêå. - * Åñëè íà÷àëüíîå ñëîâî íóëåâîå, ïåðâàÿ ñâåæàÿ åäèíèöà áóäåò ïðèíÿòà: - * áîëüøå íå íóæåí ñëó÷àéíûé ïðîõîä main, óñïåâøèé ïðî÷èòàòü íîëü. */ + /* Уже активная команда при окончании загрузки не является новым пуском. + * Снимаем физические выходы отдельно в аппаратной обёртке. + * Если начальное слово нулевое, первая свежая единица будет принята: + * больше не нужен случайный проход main, успевший прочитать ноль. */ s->previous = commands; s->remaining = 0; s->output = UMP_PULSE_NONE; @@ -35,23 +35,23 @@ 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 çàìå÷àåòñÿ. - * Ïîâòîðíûå ïàêåòû ñ óäåðæèâàåìîé åäèíèöåé íå ïðîäëåâàþò èìïóëüñ. */ + /* История относится к каждому принятому слову CAN/RS, а не к редким + * снимкам main. Поэтому даже 1->0->1 между проходами main замечается. + * Повторные пакеты с удерживаемой единицей не продлевают импульс. */ s->previous = commands; if (commands & UMP_STOP_MASK) { - /* STOP èìååò ïðèîðèòåò äàæå ïðè îäíîâðåìåííîì ôðîíòå START. - * Åãî óäåðæàíèå çàïðåùàåò íîâûé START. Çàïðåù¸ííûé ïóñê íå ñòàâèì - * â î÷åðåäü: ñíÿòèå STOP íå äîëæíî íåîæèäàííî çàïóñêàòü ÑÈÔÓ. */ + /* 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 ïðîäëåâàåò ñóùåñòâóþùèé èìïóëüñ, - * êàê ðàíüøå; îòäåëüíûé ýëåêòðè÷åñêèé ôðîíò çäåñü íå îáåùàåòñÿ. */ + /* Новый START после снятия команды STOP переключает выходы. + * Новый фронт во время START продлевает существующий импульс, + * как раньше; отдельный электрический фронт здесь не обещается. */ s->output = UMP_PULSE_START; s->remaining = ticks; s->relay = 1; @@ -60,9 +60,9 @@ static void ump_pulse_accept(volatile UMP_PULSE_STATE *s, static void ump_pulse_tick(volatile UMP_PULSE_STATE *s) { - /* Åäèíñòâåííûé âëàäåëåö îòñ÷¸òà — òàéìåð 1 êÃö. main íå ó÷àñòâóåò - * â çàâåðøåíèè èìïóëüñà, ïîýòîìó EEPROM íå ðàñòÿãèâàåò åãî. - * RES_OUT_2 ñîõðàíÿåò ïîñëåäíåå ñîñòîÿíèå ïîñëå êîíöà èìïóëüñà. */ + /* Единственный владелец отсчёта — таймер 1 кГц. main не участвует + * в завершении импульса, поэтому EEPROM не растягивает его. + * RES_OUT_2 сохраняет последнее состояние после конца импульса. */ if (s->remaining && --s->remaining == 0) s->output = UMP_PULSE_NONE; } diff --git a/Source/Internal/RS485.c b/Source/Internal/RS485.c index b91e8ac..72696fa 100644 --- a/Source/Internal/RS485.c +++ b/Source/Internal/RS485.c @@ -1,8 +1,8 @@ -/* Íèçêîóðîâíåâûé UART äâóõ ïîðòîâ. RX ISR ñîáèðàåò RS_Header, - * TX ISR ïðîäîëæàåò ïåðåäà÷ó. RS_DataReady ïåðåäà¸ò ãîòîâûé êàäð - * â main äëÿ ïðîâåðêè CRC; ïðè¸ì áàéòîâ åù¸ íå îçíà÷àåò èñïîëíåíèÿ. - * RS_Send ñîäåðæèò îæèäàíèÿ UART è íå îòíîñèòñÿ ê áûñòðîìó ïóòè ÑÈÔÓ. - * Ðàçìåðû áóôåðîâ íóæíî ïîíèìàòü ñ ó÷¸òîì 16-áèòíîé ABI C2000. +/* Низкоуровневый UART двух портов. RX ISR собирает RS_Header, + * TX ISR продолжает передачу. RS_DataReady передаёт готовый кадр + * в main для проверки CRC; приём байтов ещё не означает исполнения. + * RS_Send содержит ожидания UART и не относится к быстрому пути СИФУ. + * Размеры буферов нужно понимать с учётом 16-битной ABI C2000. */ //#include "big_dsp_module.h" @@ -28,7 +28,7 @@ static char size_cmd15=1; void RS_RX_Handler(RS_DATA *rs_arr); void RS_TX_Handler(RS_DATA *rs_arr); -/** Îáðàáîò÷èê ïðåðûâàíèé UART - ïðèíàòî */ +/** Обработчик прерываний UART - принато */ interrupt void RSA_RX_Handler(void) { // Set interrupt priority: @@ -101,7 +101,7 @@ interrupt void RSB_TX_Handler(void) PieCtrlRegs.PIEIER9.all = TempPIEIER; } -/** Îáðàáîò÷èê ïðåðûâàíèé UART - ïðèíàòî */ +/** Обработчик прерываний UART - принато */ void RS_RX_Handler(RS_DATA *rs_arr) { char Rc; @@ -109,16 +109,16 @@ void RS_RX_Handler(RS_DATA *rs_arr) // led1_on(); - for(;;) // 'goto' ýòî íå îïåðàòîð àçûêà Ñ + for(;;) // 'goto' это не оператор азыка С { if(!rs_arr->SciRegs->SCIRXST.bit.RXRDY) // Receiver ready flag { PieCtrlRegs.PIEACK.bit.ACK9 |= 1; rs_arr->SciRegs->SCIFFRX.bit.RXFFINTCLR=1; // Clear INT flag - return; // êñòàòè ýòî åäèíñòâåííûé âûõîä èç ïðåðûâàíèà + return; // кстати это единственный выход из прерываниа } - Rc = rs_arr->SciRegs->SCIRXBUF.bit.RXDT; // ×èòàåì ñèìâîë â ëþáîì ñëó÷àå + Rc = rs_arr->SciRegs->SCIRXBUF.bit.RXDT; // Читаем символ в любом случае if(rs_arr->SciRegs->SCIRXST.bit.RXERROR) // Receiver error flag { @@ -128,110 +128,110 @@ void RS_RX_Handler(RS_DATA *rs_arr) continue; } - if(rs_arr->RS_DataReady) continue; // Íå çàáðàëè äàííûå + if(rs_arr->RS_DataReady) continue; // Не забрали данные - if (rs_arr->RS_Flag9bit==1) // äëà RS485???????? + if (rs_arr->RS_Flag9bit==1) // дла RS485???????? { - // Èíèöèàëèçèðóåì ïåðåìåííûå è ôëàãè - rs_arr->RS_FlagBegin = true; // Æäåì çàãîëîâîê + // Инициализируем переменные и флаги + rs_arr->RS_FlagBegin = true; // Ждем заголовок rs_arr->RS_RecvLen = 0; rs_arr->RS_FlagSkiping = false; rs_arr->RS_HeaderCnt = 0; rs_arr->RS_Cmd = 0; } - if(rs_arr->RS_FlagSkiping) continue; // Íå íàì + if(rs_arr->RS_FlagSkiping) continue; // Не нам - if (rs_arr->RS_FlagBegin) // Çàãîëîâîê + if (rs_arr->RS_FlagBegin) // Заголовок { - if (rs_arr->RS_HeaderCnt==0) // Àäðåñ êîíòðîëëåðà èëè ñòàíäàðòíàà êîìàíäà + if (rs_arr->RS_HeaderCnt==0) // Адрес контроллера или стандартнаа команда { if( (Rc == CNTRL_ADDR_UNIVERSAL) || (Rc == CNTRL_ADDR && CNTRL_ADDR!=0) || ((Rc == rs_arr->addr_answer) && rs_arr->flag_LEADING) || ((Rc == ADDR_FOR_ALL && ADDR_FOR_ALL!=0) && !rs_arr->flag_LEADING)) { - rs_arr->addr_recive=Rc; // çàïîìíèëè àäðåñ ïî êîòîðîìó íàñ çàïðîñèëè - rs_arr->RS_Header[rs_arr->RS_HeaderCnt++] = Rc; // Ïåðâûé áàéò - RS_SetBitMode(rs_arr,8); // ïåðåñòðîèëèñü â 8-áèò ðåæèì + rs_arr->addr_recive=Rc; // запомнили адрес по которому нас запросили + rs_arr->RS_Header[rs_arr->RS_HeaderCnt++] = Rc; // Первый байт + RS_SetBitMode(rs_arr,8); // перестроились в 8-бит режим } else { - rs_arr->RS_FlagSkiping = true; // Íå íàøåìó êîíòðîëëåðó - rs_arr->RS_FlagBegin = false; // îñòàëèñü â 9-áèò ðåæèìå + rs_arr->RS_FlagSkiping = true; // Не нашему контроллеру + rs_arr->RS_FlagBegin = false; // остались в 9-бит режиме // led1_off(); } } else { - rs_arr->RS_Header[rs_arr->RS_HeaderCnt++] = Rc; // Âòîðîé áàéò è ò.ä. + rs_arr->RS_Header[rs_arr->RS_HeaderCnt++] = Rc; // Второй байт и т.д. if (rs_arr->RS_HeaderCnt == 7 && rs_arr->RS_Cmd==CMD_MODBUS_16 && !rs_arr->flag_LEADING) { RS_Len[CMD_MODBUS_16] = (10+Rc); } - // åñëè âòîðîé áàéò - ýòî êîìàíäà + // если второй байт - это команда if (rs_arr->RS_HeaderCnt == 2) { rs_arr->RS_Cmd = Rc; - // Ïðîâåðêà äëèíû ïîñûëêè - // CMD_LOAD - ìëàäøàà íà äàííûé ìîìåíò - // CMD_STD_ANS - ñòàðøàà íà äàííûé ìîìåíò + // Проверка длины посылки + // CMD_LOAD - младшаа на данный момент + // CMD_STD_ANS - старшаа на данный момент if ((rs_arr->RS_Cmd < CMD_MODBUS_3) || (rs_arr->RS_Cmd > CMD_STD_ANS) || (RS_Len[rs_arr->RS_Cmd]<3) || ((rs_arr->RS_Cmd == CMD_LOAD)&&(rs_arr->RS_PrevCmd != CMD_INITLOAD)) ) { - RS_SetBitMode(rs_arr,9); // Ïîëó÷èëè âñå ïåðåñòðîèëèñü â 9-áèò äëà RS485? - rs_arr->RS_HeaderCnt = 0; // Ïîòîìó ÷òî êîìàíäà íå òà + RS_SetBitMode(rs_arr,9); // Получили все перестроились в 9-бит дла RS485? + rs_arr->RS_HeaderCnt = 0; // Потому что команда не та rs_arr->RS_FlagBegin = true; rs_arr->RS_FlagSkiping = false; rs_arr->RS_Cmd=0; // led1_off(); continue; } - if (rs_arr->RS_Cmd == CMD_LOAD) // Äëà ýòîé êîìàíäû çàãîëîâîê î÷åíü êîðîòêèé - rs_arr->RS_FlagBegin = false;// äàëüøå èäóò äàííûå + if (rs_arr->RS_Cmd == CMD_LOAD) // Дла этой команды заголовок очень короткий + rs_arr->RS_FlagBegin = false;// дальше идут данные } if( (rs_arr->RS_HeaderCnt >= RS_Len[rs_arr->RS_Cmd]) || (rs_arr->RS_HeaderCnt >= sizeof(rs_arr->RS_Header))) - { // Ïîëó÷èëè çàãîëîâîê - RS_SetBitMode(rs_arr,9); // Ïîëó÷èëè âñå ïåðåñòðîèëèñü â 9-áèò äëà RS485? + { // Получили заголовок + RS_SetBitMode(rs_arr,9); // Получили все перестроились в 9-бит дла RS485? rs_arr->RS_FlagBegin = false; rs_arr->RS_FlagSkiping = true; rs_arr->RS_DataReady = true; rs_arr->RS_Cmd=0; // led1_off(); } } } - else // Ïîòîê äàííûõ + else // Поток данных { if(rs_arr->pRS_RecvPtr<(unsigned int *)Rec_Bloc_Begin || rs_arr->pRS_RecvPtr>(unsigned int *)Rec_Bloc_End) { - rs_arr->pRS_RecvPtr = (unsigned int *)Rec_Bloc_Begin; // Íà ïðîãðàììó íàäåéñà, à ñàì íå ïëîøàé - rs_arr->pRecvPtr = (unsigned int *)Rec_Bloc_Begin; // Íà ïðîãðàììó íàäåéñà, à ñàì íå ïëîøàé + rs_arr->pRS_RecvPtr = (unsigned int *)Rec_Bloc_Begin; // На программу надейса, а сам не плошай + rs_arr->pRecvPtr = (unsigned int *)Rec_Bloc_Begin; // На программу надейса, а сам не плошай } - if(rs_arr->RS_PrevCmd != CMD_INITLOAD) continue; // Ìû çäåñü îêàçàëèñü ïî êàêîé-òî ÷óäîâèùíîé îøèáêå + if(rs_arr->RS_PrevCmd != CMD_INITLOAD) continue; // Мы здесь оказались по какой-то чудовищной ошибке - if(rs_arr->RS_DataReady) // Åñëè äàííûå â îñíîâíîì öèêëå íå çàáðàíû, - { // òî ïðîïóñêàåì ñëåäóþùóþ ïîñûëêó - rs_arr->RS_FlagSkiping = true; // Èãíîðèðóåì äî ñëåäóþùåãî çàãîëîâêà + if(rs_arr->RS_DataReady) // Если данные в основном цикле не забраны, + { // то пропускаем следующую посылку + rs_arr->RS_FlagSkiping = true; // Игнорируем до следующего заголовка // led1_off(); continue; } RS_BytePtr = rs_arr->RS_RecvLen++ % 2; - if(RS_BytePtr) *rs_arr->pRS_RecvPtr++ |= Rc; // Ïîëó÷èëè ñëîâî + if(RS_BytePtr) *rs_arr->pRS_RecvPtr++ |= Rc; // Получили слово else *rs_arr->pRS_RecvPtr = Rc<<8; - if(rs_arr->RS_Length <= rs_arr->RS_RecvLen) // Êîíåö ïîñûëêè + if(rs_arr->RS_Length <= rs_arr->RS_RecvLen) // Конец посылки { rs_arr->RS_PrevCmd = rs_arr->RS_Header[1] = CMD_LOAD; - RS_SetBitMode(rs_arr,9); // Ïîëó÷èëè âñå äàííûå ïåðåñòðîèëèñü â 9-áèò äëà RS485? - rs_arr->RS_FlagSkiping = true; // Èãíîðèðóåì äî ñëåäóþùåãî çàãîëîâêà - rs_arr->RS_DataReady = true; // Ôëàã â îñíîâíîé öèêë - äàííûå ïîëó÷åíû + RS_SetBitMode(rs_arr,9); // Получили все данные перестроились в 9-бит дла RS485? + rs_arr->RS_FlagSkiping = true; // Игнорируем до следующего заголовка + rs_arr->RS_DataReady = true; // Флаг в основной цикл - данные получены // led1_off(); } } } } -/** Îáðàáîò÷èê ïðåðûâàíèé UART - ïîñëàíî */ +/** Обработчик прерываний UART - послано */ void RS_TX_Handler(RS_DATA *rs_arr) { char RS_BytePtr; @@ -241,19 +241,19 @@ void RS_TX_Handler(RS_DATA *rs_arr) { if(++rs_arr->RS_SendLen >= rs_arr->RS_SLength) { - enableUARTInt(rs_arr); /* Çàïðåùàåì ïðåðûâàíèà ïî ïåðåäà÷å */ + enableUARTInt(rs_arr); /* Запрещаем прерываниа по передаче */ } SCI_send(rs_arr,*(rs_arr->pRS_SendPtr++)); if(rs_arr->RS_SendLen >= rs_arr->RS_SLength) { RS_Wait4OK(rs_arr); -// for (i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){} /* Ïàóçà äëà PC */ +// for (i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){} /* Пауза дла PC */ - RS_SetBitMode(rs_arr,9); /* Ïåðåäàëè âñå ïåðåñòðîèëèñü â 9-áèò äëà RS485?*/ - RS_Line_to_receive(rs_arr); /* ðåæèì ïðèåìà RS485 */ + RS_SetBitMode(rs_arr,9); /* Передали все перестроились в 9-бит дла RS485?*/ + RS_Line_to_receive(rs_arr); /* режим приема RS485 */ - rs_arr->flag_TIMEOUT_to_Send=false; /* ñáðîñèëè ôëàã îæèäàíèà òàéìàóòà */ + rs_arr->flag_TIMEOUT_to_Send=false; /* сбросили флаг ожиданиа таймаута */ } } else /* BM_PACKED */ @@ -262,7 +262,7 @@ void RS_TX_Handler(RS_DATA *rs_arr) RS_BytePtr = (rs_arr->RS_SendLen++) % 2; if(rs_arr->RS_SendLen >= rs_arr->RS_SLength) { - enableUARTInt(rs_arr); /* Çàïðåùàåì ïðåðûâàíèà ïî ïåðåäà÷å */ + enableUARTInt(rs_arr); /* Запрещаем прерываниа по передаче */ } if(RS_BytePtr) SCI_send(rs_arr, LOBYTE( *(rs_arr->pRS_SendPtr++) )); else SCI_send(rs_arr, HIBYTE( *rs_arr->pRS_SendPtr )); @@ -270,9 +270,9 @@ void RS_TX_Handler(RS_DATA *rs_arr) if(rs_arr->RS_SendLen >= rs_arr->RS_SLength) { RS_Wait4OK(rs_arr); -// for (i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){} /* Ïàóçà äëà PC */ -// RS_SetBitMode(rs_arr,9); /* Ïåðåäàëè âñå ïåðåñòðîèëèñü â 9-áèò äëà RS485?*/ -// RS_Line_to_receive(); /* ðåæèì ïðèåìà RS485 */ +// for (i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){} /* Пауза дла PC */ +// RS_SetBitMode(rs_arr,9); /* Передали все перестроились в 9-бит дла RS485?*/ +// RS_Line_to_receive(); /* режим приема RS485 */ } } @@ -281,7 +281,7 @@ void RS_TX_Handler(RS_DATA *rs_arr) // rs_arr->SciRegs->SCIFFTX.bit.TXINTCLR=1; // Clear INT flag } -/** Èíèöèàëèçàöèà ìàññèâà äëèí êîìàíä */ +/** Инициализациа массива длин команд */ void setup_arr_cmd_length() { int i; @@ -307,89 +307,89 @@ void setup_arr_cmd_length() RS_Len[CMD_EXTEND] = 18; } -/** Íàñòðîéêà ðåæèìà ïðèåìà/ïåðåäà÷è */ +/** Настройка режима приема/передачи */ void RS_SetBitMode(RS_DATA *rs_arr,int n) { if(n == 8) { - RS_SetLineMode(rs_arr,8,'N',1); /* ðåæèì ëèíèè */ + RS_SetLineMode(rs_arr,8,'N',1); /* режим линии */ rs_arr->RS_Flag9bit=0; } if(n == 9) { - RS_SetLineMode(rs_arr,8,'N',1); /* ðåæèì ëèíèè */ + RS_SetLineMode(rs_arr,8,'N',1); /* режим линии */ rs_arr->RS_Flag9bit=1; } } -/** Ïîñûëêà áëîêà áàéòîâ. - Ïîñûëàåò ìàññèâà 32-áèòíûõ öåëûõ ÷èñåë ñòàðøèå áèòû äîëæíû áûòü 0. - @precondition Ðàáîòà ô-öèè çàâèñèò îò ìàêðî RS_TRANSMIT_INTR - @param buf àäðåñ ìàññèâà - @param len êîëè÷åñòâî áàéò +/** Посылка блока байтов. + Посылает массива 32-битных целых чисел старшие биты должны быть 0. + @precondition Работа ф-ции зависит от макро RS_TRANSMIT_INTR + @param buf адрес массива + @param len количество байт @see RS_BSend, RS_TRANSMIT_INTR */ -/* Ïåðåäà÷ó ïðîäîëæàåò TX ISR. Çäåñü åñòü ñòàðûå ïðîãðàììíûå ïàóçû - * è îæèäàíèÿ UART: íå âûçûâàòü èç CAN ISR èëè ñåêöèè àâòîìàòà ÑÈÔÓ. +/* Передачу продолжает TX ISR. Здесь есть старые программные паузы + * и ожидания UART: не вызывать из CAN ISR или секции автомата СИФУ. */ int RS_Send(RS_DATA *rs_arr,unsigned int *pBuf,unsigned long len) { unsigned int i; - for (i=0; i <= 30000; i++){} /* Ïàóçà äëà PC */ + for (i=0; i <= 30000; i++){} /* Пауза дла PC */ - RS_Line_to_send(rs_arr); /* ðåæèì ïåðåäà÷è RS485 */ + RS_Line_to_send(rs_arr); /* режим передачи RS485 */ - for (i=0; i <= 10000; i++){} /* Ïàóçà äëà PC */ + for (i=0; i <= 10000; i++){} /* Пауза дла PC */ - rs_arr->RS_SLength = len; /* Íàñòðàèâàåì ïåðåìåííûå */ + rs_arr->RS_SLength = len; /* Настраиваем переменные */ rs_arr->pRS_SendPtr = pBuf + 1; rs_arr->RS_SendBlockMode = BM_CHAR32; - RS_Wait4OK(rs_arr); /* Äîæèäàåìñà óõîäà */ - RS_SetBitMode(rs_arr,8); /* Îñòàëüíûå â 8-áèò ðåæèìå */ + RS_Wait4OK(rs_arr); /* Дожидаемса ухода */ + RS_SetBitMode(rs_arr,8); /* Остальные в 8-бит режиме */ - rs_arr->RS_SendLen = 1; /* Äâà áàéòà óæå ïåðåäàëè */ + rs_arr->RS_SendLen = 1; /* Два байта уже передали */ if(len > 1) { - enableUARTIntW(rs_arr); /* Ðàçðåøàåì ïðåðûâàíèà ïî ïåðåäà÷å */ - SCI_send(rs_arr, *pBuf); // Ïåðåäàåì âòîðîé áàéò ïî ïðåðûâàíèþ + enableUARTIntW(rs_arr); /* Разрешаем прерываниа по передаче */ + SCI_send(rs_arr, *pBuf); // Передаем второй байт по прерыванию } else { - SCI_send(rs_arr, *pBuf); // Ïåðåäàåì âòîðîé áàéò ïî ïðåðûâàíèþ - RS_Wait4OK(rs_arr); /* Äîæèäàåìñà óõîäà áåç ïðåðûâàíèà */ - for (i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){} /* Ïàóçà äëà PC */ - RS_SetBitMode(rs_arr,9); /* Îáðàòíî â 9-áèò ðåæèì */ - RS_Line_to_receive(rs_arr); /* ðåæèì ïðèåìà RS485 */ + SCI_send(rs_arr, *pBuf); // Передаем второй байт по прерыванию + RS_Wait4OK(rs_arr); /* Дожидаемса ухода без прерываниа */ + for (i=0; i <= TIME_WAIT_RS_BYTE_OUT; i++){} /* Пауза дла PC */ + RS_SetBitMode(rs_arr,9); /* Обратно в 9-бит режим */ + RS_Line_to_receive(rs_arr); /* режим приема RS485 */ } return 0; } -// Ïîñûëêà áëîêà óïàêîâàííûõ áàéòîâ +// Посылка блока упакованных байтов int RS_BSend(RS_DATA *rs_arr,unsigned int *pBuf, unsigned long len) { - RS_Line_to_send(rs_arr); // ðåæèì ïåðåäà÷è RS485 + RS_Line_to_send(rs_arr); // режим передачи RS485 - rs_arr->RS_SLength = len; // Íàñòðàèâàåì ïåðåìåííûå + rs_arr->RS_SLength = len; // Настраиваем переменные rs_arr->pRS_SendPtr = pBuf; rs_arr->RS_SendBlockMode = BM_PACKED; - RS_Wait4OK(rs_arr); // Îæèäàåì î÷èñòêè è óõîäà ïîñëåäíåãî áàéòà - RS_SetBitMode(rs_arr,8); /* Îñòàëüíûå â 8-áèò ðåæèìå */ + RS_Wait4OK(rs_arr); // Ожидаем очистки и ухода последнего байта + RS_SetBitMode(rs_arr,8); /* Остальные в 8-бит режиме */ - rs_arr->RS_SendLen = 1; // Îäèí áàéò óæå ïåðåäàëè + rs_arr->RS_SendLen = 1; // Один байт уже передали - enableUARTIntW(rs_arr); /* Ðàçðåøàåì ïðåðûâàíèà ïî ïåðåäà÷å */ + enableUARTIntW(rs_arr); /* Разрешаем прерываниа по передаче */ - SCI_send(rs_arr,HIBYTE(*pBuf));// Ïåðåäàåì ïåðâûé áàéò + SCI_send(rs_arr,HIBYTE(*pBuf));// Передаем первый байт return 0; } -/** Óñòàíàâëèâàåò ñêîðîñòü îáìåíà. - @param speed ñêîðîñòü RS â áîä */ -/** Óñòàíàâëèâàåò ñêîðîñòü îáìåíà. - @param speed ñêîðîñòü RS â áîä */ +/** Устанавливает скорость обмена. + @param speed скорость RS в бод */ +/** Устанавливает скорость обмена. + @param speed скорость RS в бод */ void RS_SetLineSpeed(RS_DATA *rs_arr,unsigned long speed) { long SciBaud; @@ -403,7 +403,7 @@ void RS_SetLineSpeed(RS_DATA *rs_arr,unsigned long speed) } -/** Èíèöèàëèçàöèà ïîñëåäîâàòåëüíîãî ïîðòà */ +/** Инициализациа последовательного порта */ void create_uart_vars(char size_cmd15_set) { size_cmd15=size_cmd15_set; @@ -413,7 +413,7 @@ void create_uart_vars(char size_cmd15_set) -/** Èíèöèàëèçàöèà ïîñëåäîâàòåëüíîãî ïîðòà */ +/** Инициализациа последовательного порта */ void setup_uart(char commnumber, unsigned long speed_baud) { @@ -478,14 +478,14 @@ void setup_uart(char commnumber, unsigned long speed_baud) SciRegs->SCICTL1.bit.RXENA=1; SciRegs->SCIFFTX.bit.SCIFFENA=0; // fifo off - SciRegs->SCIFFRX.bit.RXFFIL=1; // Äëèíà íàèìåíüøåé êîìàíäû + SciRegs->SCIFFRX.bit.RXFFIL=1; // Длина наименьшей команды setup_arr_cmd_length(); - RS_SetLineSpeed(rs_arr,speed_baud); // ñêîðîñòü ëèíèè - RS_Line_to_receive(rs_arr); // ðåæèì ïðèåìà RS485 - enableUARTInt(rs_arr); // ðàçðåøåíèå ïðåðûâàíèé UART + RS_SetLineSpeed(rs_arr,speed_baud); // скорость линии + RS_Line_to_receive(rs_arr); // режим приема RS485 + enableUARTInt(rs_arr); // разрешение прерываний UART RS_SetBitMode(rs_arr,9); - rs_arr->RS_PrevCmd = 0; // íå áûëî íèêàêèõ êîìàíä + rs_arr->RS_PrevCmd = 0; // не было никаких команд rs_arr->flag_TIMEOUT_to_Send = 0; rs_arr->flag_LEADING = 0; @@ -493,10 +493,10 @@ void setup_uart(char commnumber, unsigned long speed_baud) SciRegs->SCICTL1.bit.SWRESET=1; // Relinquish SCI from Reset } -/** Íàñòðîéêà ðåæèìà ëèíèè. - @param bit êîëè÷åñòâî áèò äàííûõ - @param parity ðåæèì ÷åòíîñòè (N,O,E,M,S) - @param stop êîëè÷åñòâî ñòîïîâûõ áèò */ +/** Настройка режима линии. + @param bit количество бит данных + @param parity режим четности (N,O,E,M,S) + @param stop количество стоповых бит */ void RS_SetLineMode(RS_DATA *rs_arr, int bit, char parity, int stop) { volatile struct SCI_REGS *SciRegs; @@ -539,7 +539,7 @@ void clear_timer_rs_live(RS_DATA *rs_arr) rs_arr->time_wait_rs_out=0; } -/* ïðîâåðêà íà æèâó÷åñòü RS */ +/* проверка на живучесть RS */ void test_rs_live(RS_DATA *rs_arr) { /* if (rs_arr->time_wait_rs_out < RS_TIME_OUT) @@ -547,6 +547,6 @@ void test_rs_live(RS_DATA *rs_arr) else { rs_arr->time_wait_rs_out=0; - RS_Line_to_receive(rs_arr); // ðåæèì ïðèåìà RS485 + RS_Line_to_receive(rs_arr); // режим приема RS485 RS_SetBitMode(rs_arr,9); }*/ } diff --git a/Source/Internal/bios.c b/Source/Internal/bios.c index f16d6ad..cda2da7 100644 --- a/Source/Internal/bios.c +++ b/Source/Internal/bios.c @@ -1,8 +1,8 @@ -/* Ñëóæåáíûå êîìàíäû äîñòóïà ê ïàìÿòè è çàãðóçêè. get_command - * ïðîâåðÿåò çàâåðø¸ííûé RS-êàäð è CRC ïåðåä äèñïåò÷åðèçàöèåé â main. - * Ïðîèçâîëüíàÿ çàïèñü ïàìÿòè ñåðâèñíîé êîìàíäîé íå ïðîõîäèò - * àâòîìàò ôðîíòîâ ÑÈÔÓ. Ôîðìàò CMD_* ñîãëàñîâàí ñ çàãðóç÷èêîì ÏÊ; - * íåëüçÿ ïåðåíóìåðîâûâàòü êîìàíäû ïðè ðàñøèðåíèè ïðîòîêîëà. +/* Служебные команды доступа к памяти и загрузки. get_command + * проверяет завершённый RS-кадр и CRC перед диспетчеризацией в main. + * Произвольная запись памяти сервисной командой не проходит + * автомат фронтов СИФУ. Формат CMD_* согласован с загрузчиком ПК; + * нельзя перенумеровывать команды при расширении протокола. */ #include "DSP2833x_Device.h" // DSP2833x Headerfile Include File #include "RS485.h" @@ -14,14 +14,14 @@ //#include "spartan_tools.h" //#include "big_dsp_module.h" -int flag_DEBUG = false; /* Ôëàã îòëàäî÷íîãî ðåæèìà */ +int flag_DEBUG = false; /* Флаг отладочного режима */ //static unsigned int *RecvPtr; -//static int BS_LoadOK = false; /** Ôëàã óñïåøíîñòè ïðèåìà áëîêà */ +//static int BS_LoadOK = false; /** Флаг успешности приема блока */ /**********************************************************/ -/* Ïðîòîòèïû ôóíêöèé, èñïîëüçóåìûõ è îïðåäåëåííûõ â ôàéëå */ +/* Прототипы функций, используемых и определенных в файле */ /**********************************************************/ //static int _getbyte(int *addr, int offs); @@ -36,60 +36,60 @@ void write_memory(unsigned long addr, unsigned int data) } -/** Âîçâðàùàåò íîìåð êîììàíäû, åñëè åñòü èëè -1 åñëè òðàíçàêöèé íå áûëî */ +/** Возвращает номер комманды, если есть или -1 если транзакций не было */ int get_command(RS_DATA *rs_arr) { int cmd; unsigned int crc, rcrc; - if(rs_arr->RS_DataReady) // Äàííûå ïî RS ïðèøëè + if(rs_arr->RS_DataReady) // Данные по RS пришли { rs_arr->RS_DataReady = false; - cmd = rs_arr->RS_Header[1]; // Ïðî÷èòàëè íîìåð êîìàíäû + cmd = rs_arr->RS_Header[1]; // Прочитали номер команды - // Ïðîâåðàåì äëèíó êîìàíäû äëà ñ÷èòûâàíèà CRC + // Провераем длину команды дла считываниа CRC if((RS_Len[cmd]<3) || (RS_Len[cmd]>MAX_RECEIVE_LENGTH)) { - RS_Line_to_receive(rs_arr); // ðåæèì ïðèåìà RS485 + RS_Line_to_receive(rs_arr); // режим приема RS485 RS_SetBitMode(rs_arr,9); return -1; } - if(cmd == CMD_LOAD) // Åñëè êîìàíäà çàãðóçêè + if(cmd == CMD_LOAD) // Если команда загрузки { rs_arr->RS_PrevCmd = cmd; - return cmd; // Íåò ïðîâåðêè crc + return cmd; // Нет проверки crc } - else // Âñå îñòàëüíûå êîìàíäû + else // Все остальные команды { - // Ñ÷èòûâàåì crc èç ïîñûëêè + // Считываем crc из посылки crc = (rs_arr->RS_Header[RS_Len[cmd]-1] << 8) | (rs_arr->RS_Header[RS_Len[cmd]-2]) ; } - // Ðàññ÷èòûâàåì crc èç ïîñûëêè + // Рассчитываем crc из посылки rcrc = 0xffff; rcrc = get_crc_16( rcrc, rs_arr->RS_Header, (RS_Len[cmd]-2) ); - if(crc == rcrc) // Ïðîâåðàåì crc + if(crc == rcrc) // Провераем crc { rs_arr->RS_PrevCmd = cmd; return cmd; } else { - RS_Line_to_receive(rs_arr); // ðåæèì ïðèåìà RS485 + RS_Line_to_receive(rs_arr); // режим приема RS485 RS_SetBitMode(rs_arr,9); } } return -1; } -/** Ñòàíäàðòíûé îòâåò, áåç ïàðàìåòðîâ */ +/** Стандартный ответ, без параметров */ void Answer(RS_DATA *rs_arr,int n) { int crc; - flag_DEBUG = true; // Ôëàã îòëàäî÷íîãî ðåæèìà + flag_DEBUG = true; // Флаг отладочного режима rs_arr->buffer[0] = rs_arr->addr_recive; //CNTRL_ADDR; rs_arr->buffer[1] = n; @@ -105,7 +105,7 @@ void Answer(RS_DATA *rs_arr,int n) RS_Send(rs_arr,rs_arr->buffer, 6); } -/* Âíóòðåííàà ô-öèà */ +/* Внутреннаа ф-циа */ static char _getbyte(unsigned int *addr, int32 offs) { unsigned int *address; @@ -118,7 +118,7 @@ static char _getbyte(unsigned int *addr, int32 offs) } -/* íà÷àëüíûå óñòàíîâêè (íå ðàáîòàåò)*/ +/* начальные установки (не работает)*/ void init(RS_DATA *rs_arr) { /* @@ -141,13 +141,13 @@ void init(RS_DATA *rs_arr) */ } -/**@name Êîììàíäû -* Êîììàíäû, âûçûâàåìûå ÷åðåç ïîñëåäîâàòåëüíûé êàíàë +/**@name Комманды +* Комманды, вызываемые через последовательный канал */ //@{ -/** Èíèöèèðîâàòü çàãðóçêó áëîêà. - Íàñòðàèâàåò ïðèåì áëîêà äàííûõ */ +/** Инициировать загрузку блока. + Настраивает прием блока данных */ void initload(RS_DATA *rs_arr) { unsigned long Address; @@ -171,8 +171,8 @@ void initload(RS_DATA *rs_arr) Answer(rs_arr,CMD_INITLOAD); } -/** Çàãðóçêà áëîêà. - Âûçûâàåòñà ïîñëå çàãðóçêè áëîêà ÷åðåç RS */ +/** Загрузка блока. + Вызываетса после загрузки блока через RS */ void load(RS_DATA *rs_arr) { unsigned int rcrc, crc; @@ -197,27 +197,27 @@ void load(RS_DATA *rs_arr) else { rs_arr->BS_LoadOK = false; - RS_Line_to_receive(rs_arr); // ðåæèì ïðèåìà RS485 + RS_Line_to_receive(rs_arr); // режим приема RS485 RS_SetBitMode(rs_arr,9); } } -/** Âûïîëíèòü ïðîãðàììó â ôîðìàòå Serial Boot. - @precondition Äîëæíà áûòü ïðîèçâåäåíà çàãðóçêà áëîêà - Àäðåñ ïðîãðàììû áåðåòñà èç çàãîëîâêà è - ñðàâíèâàåòñà ñ ïåðåìåííîé RecvPtr, çàïîëíàåìîé â ô-öèè load +/** Выполнить программу в формате Serial Boot. + @precondition Должна быть произведена загрузка блока + Адрес программы беретса из заголовка и + сравниваетса с переменной RecvPtr, заполнаемой в ф-ции load @see load */ void run (RS_DATA *rs_arr) { return; } -/** Ïðî÷èòàòü à÷åéêó ïàìàòè */ +/** Прочитать ачейку памати */ void peek(RS_DATA *rs_arr) { unsigned long Address; unsigned int Data, crc; - flag_DEBUG = true; // Ôëàã îòëàäî÷íîãî ðåæèìà + flag_DEBUG = true; // Флаг отладочного режима Address = rs_arr->RS_Header[5] & 0xFF; Address = (Address<<8) | (rs_arr->RS_Header[4] & 0xFF); @@ -250,7 +250,7 @@ void peek(RS_DATA *rs_arr) } -/** Çàïèñàòü â à÷åéêó ïàìàòè */ +/** Записать в ачейку памати */ void poke(RS_DATA *rs_arr) { unsigned long Address; @@ -272,12 +272,12 @@ void poke(RS_DATA *rs_arr) Answer(rs_arr,CMD_POKE); } -/** Ïåðåäàòü áëîê ïàìàòè */ +/** Передать блок памати */ void upload(RS_DATA *rs_arr) { int32 Address, Length, crc; - no_write = 1; // Ôëàã îòëàäî÷íîãî ðåæèìà + no_write = 1; // Флаг отладочного режима // stopp=1; Address = rs_arr->RS_Header[5] & 0xFF; @@ -297,10 +297,10 @@ void upload(RS_DATA *rs_arr) crc = get_crc_16( crc, rs_arr->buffer, 2); crc = get_crc_16b( crc, (unsigned int *)Address, Length); - RS_Send(rs_arr,rs_arr->buffer, 1); // <=2 áàéò ïî ôëàãó + RS_Send(rs_arr,rs_arr->buffer, 1); // <=2 байт по флагу rs_arr->buffer[0] = CMD_UPLOAD; - RS_Send(rs_arr,rs_arr->buffer, 1); // <=2 áàéò ïî ôëàãó + RS_Send(rs_arr,rs_arr->buffer, 1); // <=2 байт по флагу RS_Wait4OK(rs_arr); RS_BSend(rs_arr,(unsigned int*)Address, Length); @@ -314,21 +314,21 @@ void upload(RS_DATA *rs_arr) } -/** Ïðîøèòü XILINX. - @precondition Äîëæíà áûòü ïðîèçâåäåíà çàãðóçêà áëîêà - Àäðåñ è äëèíà ïðîøèâêè áåðåòñà èç çàãîëîâêà è - ñðàâíèâàåòñà ñ ïåðåìåííûìè RecvPtr è Length, çàïîëíàåìûìè â ô-öèè load, - òàê æå ñìîòðèò ìàãè÷åñêîå ñëîâî â íà÷àëå ïðîøèâêè +/** Прошить XILINX. + @precondition Должна быть произведена загрузка блока + Адрес и длина прошивки беретса из заголовка и + сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load, + так же смотрит магическое слово в начале прошивки @see load */ void xflash(RS_DATA *rs_arr) { return; } -/** Ïðîøèòü TMS. - @precondition Äîëæíà áûòü ïðîèçâåäåíà çàãðóçêà áëîêà - Àäðåñ è äëèíà ïðîøèâêè áåðåòñà èç çàãîëîâêà è - ñðàâíèâàåòñà ñ ïåðåìåííûìè RecvPtr è Length, çàïîëíàåìûìè â ô-öèè load +/** Прошить TMS. + @precondition Должна быть произведена загрузка блока + Адрес и длина прошивки беретса из заголовка и + сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load @see load */ void tflash(RS_DATA *rs_arr) { @@ -337,7 +337,7 @@ void tflash(RS_DATA *rs_arr) /* if(!rs_arr->BS_LoadOK) { - RS_Line_to_receive(rs_arr); // ðåæèì ïðèåìà RS485 + RS_Line_to_receive(rs_arr); // режим приема RS485 RS_SetBitMode(rs_arr,9); return; } @@ -362,7 +362,7 @@ void tflash(RS_DATA *rs_arr) if( (Address2 < 0x100000) || (Address2 > 0x180000) || ((Address2+LengthW) > 0x180000) ) { - RS_Line_to_receive(rs_arr); // ðåæèì ïðèåìà RS485 + RS_Line_to_receive(rs_arr); // режим приема RS485 RS_SetBitMode(rs_arr,9); return; } @@ -374,10 +374,10 @@ void tflash(RS_DATA *rs_arr) return; } -/** Ïðîøèòü TMS. - @precondition Äîëæíà áûòü ïðîèçâåäåíà çàãðóçêà áëîêà - Àäðåñ è äëèíà ïðîøèâêè áåðåòñà èç çàãîëîâêà è - ñðàâíèâàåòñà ñ ïåðåìåííûìè RecvPtr è Length, çàïîëíàåìûìè â ô-öèè load +/** Прошить TMS. + @precondition Должна быть произведена загрузка блока + Адрес и длина прошивки беретса из заголовка и + сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load @see load */ void extendbios(RS_DATA *rs_arr) { @@ -403,10 +403,10 @@ void extendbios(RS_DATA *rs_arr) switch ( code ) { - // Ïðîøèâàåì EPROM Èç RAM + // Прошиваем EPROM Из RAM case 4: Seeprom_write(Address1,(unsigned int*)Address2,Length); break; - // ×èòàåì èç EPROM â RAM + // Читаем из EPROM в RAM case 5: Seeprom_read(Address1,(unsigned int*)Address2,Length); break; diff --git a/Source/Internal/cntrl_adr.c b/Source/Internal/cntrl_adr.c index 1328ae0..5f1e704 100644 --- a/Source/Internal/cntrl_adr.c +++ b/Source/Internal/cntrl_adr.c @@ -1,7 +1,7 @@ -/* Àäðåñàöèÿ ïîñëåäîâàòåëüíîãî ïðîòîêîëà. set_cntrl_addr çàäà¸ò - * ñîáñòâåííûé è îáùèé àäðåñ. CAN ID âû÷èñëÿåòñÿ îòäåëüíî èç Mode. - * Îáùèé RS-àäðåñ íå çàìåíÿåò ñîáñòâåííûé âî âñåõ îòâåòàõ: äëÿ - * ëîããåðà SetGUI èñïîëüçîâàòü ñîáñòâåííûé àäðåñ ïëàòû (îáû÷íî 5/6). +/* Адресация последовательного протокола. set_cntrl_addr задаёт + * собственный и общий адрес. CAN ID вычисляется отдельно из Mode. + * Общий RS-адрес не заменяет собственный во всех ответах: для + * логгера SetGUI использовать собственный адрес платы (обычно 5/6). */ #include "cntrl_adr.h" @@ -11,28 +11,27 @@ #define ADDR_UNIVERSAL_DEF 10 -/** Óñòàíîâêà àäðåñà êîíòðîëëåðà äëà ïîñûëêè âñåì ÀÈÍàì */ +/** Установка адреса контроллера дла посылки всем АИНам */ int ADDR_FOR_ALL = ADDR_FOR_ALL_DEF; -/** Óñòàíîâêà àäðåñà êîíòðîëëåðà äëà ïîñûëêè îòâåòà */ +/** Установка адреса контроллера дла посылки ответа */ const int ADDR_ANSWER = ADDR_ANSWER_DEF; -/** Óñòàíîâêà àäðåñà òåðìèíàëà äëà ïîñûëêè îòâåòà */ +/** Установка адреса терминала дла посылки ответа */ const int ADDR_TERMINAL = ADDR_TERMINAL_DEF; -/* Óíèâåðñàëüíûé àäðåñ êîíòðîëëåðà */ +/* Универсальный адрес контроллера */ const int CNTRL_ADDR_UNIVERSAL=ADDR_UNIVERSAL_DEF; -/* Àäðåñ êîíòðîëëåðà */ +/* Адрес контроллера */ int CNTRL_ADDR=1; int cntr_addr_c; int cntr_addr_c_all; -/** Óñòàíîâêà àäðåñà êîíòðîëëåðà äëà ïðîøèâêè */ +/** Установка адреса контроллера дла прошивки */ void set_cntrl_addr (int cntrl_addr,int cntrl_addr_for_all) { CNTRL_ADDR = cntrl_addr; ADDR_FOR_ALL = cntrl_addr_for_all; } - diff --git a/Source/Internal/crc16.c b/Source/Internal/crc16.c index 0e32263..0b7e077 100644 --- a/Source/Internal/crc16.c +++ b/Source/Internal/crc16.c @@ -1,8 +1,8 @@ -/* CRC êàäðîâ îáìåíà è ïàðàìåòðîâ EEPROM. get_crc_16 ðàáîòàåò - * ñ ïðåäñòàâëåíèåì áóôåðà ïðîòîêîëà, get_crc16 îáðàáàòûâàåò îáà - * áàéòà êàæäîãî ñëîâà ïàðàìåòðîâ. Ïîðÿäîê áàéòîâ ñóùåñòâåíåí. - * Íåëüçÿ çàìåíÿòü ýòè ôóíêöèè ðåàëèçàöèåé äëÿ ÏÊ áåç ïðîâåðêè - * ïðåäñòàâëåíèÿ äàííûõ è îñîáåííîñòåé 16-áèòíîé ABI C2000. +/* CRC кадров обмена и параметров EEPROM. get_crc_16 работает + * с представлением буфера протокола, get_crc16 обрабатывает оба + * байта каждого слова параметров. Порядок байтов существенен. + * Нельзя заменять эти функции реализацией для ПК без проверки + * представления данных и особенностей 16-битной ABI C2000. */ #include "crc16.h" #define MAKE_TABS 0 /* Builds tables below */ diff --git a/Source/Internal/ecan.c b/Source/Internal/ecan.c index bae99d6..f7fc4b3 100644 --- a/Source/Internal/ecan.c +++ b/Source/Internal/ecan.c @@ -49,6 +49,8 @@ static unsigned int ump_can_length, ump_can_index, ump_can_reply_tag; static unsigned int ump_can_waiting; static unsigned long ump_can_sent_at; +#include "can_telemetry_impl.h" /* Определяет heartbeat, подтверждённый кэш и повтор данных через 1,3 с после объявления состояния штатного TX. */ + void InitCan(int Port, int DevNum) { struct ECAN_REGS ECanShadow; @@ -59,6 +61,7 @@ void InitCan(int Port, int DevNum) long id = 0x80BA0000; + CAN_telemetry_init(); /* Сбрасывает кэш, очередь и секундный heartbeat до разрешения аппаратных прерываний. */ DevNum--; if(DevNum<0)DevNum=0; if(DevNum>15)DevNum=15; @@ -138,8 +141,7 @@ void InitCan(int Port, int DevNum) ECanMOTORegs->MOTO0 = 550000; ECanMOTORegs->MOTO1 = 550000; - /* До первой передачи отключает тайм-ауты всех mailbox; по SPRUI07, 13.8.18.3, сброс TOC снимает TOS и MTOF. */ - ECanRegs->CANTOC.all = 0; + ECanRegs->CANTOC.all = 0; // До первой передачи отключает контроль mailbox: по SPRUI07, 13.8.18.3, сброс TOC снимает TOS и MTOF без записи в CANTOS. ECanRegs->CANTSC = 0; // clear time-out counter ECanShadow.CANGIM.all = 0; @@ -172,49 +174,7 @@ void InitCan(int Port, int DevNum) /* При занятом MBOX0 возвращается без ожидания ACK в цикле. * Это отличается от блокирующих UART/EEPROM операций main. */ -void CAN_send(int Port, int data[], int Addr) -{ - unsigned long hiword,loword; - volatile struct ECAN_REGS * ECanRegs; - volatile struct ECAN_MBOXES * ECanMboxes; - - ECanRegs = &ECanaRegs; - ECanMboxes = &ECanaMboxes; - - /* Не меняет данные mailbox 0, пока передача либо её аппаратная отмена ещё выполняется; бит 0 соответствует штатному TX. */ - if ((ECanRegs->CANTRS.all | ECanRegs->CANTRR.all) & 1UL) - return; /* Сохраняет текущий кадр до завершения CANTRS/CANTRR, не ожидая аппаратного ответа в главном цикле. */ - - if(wait) - if(!(ECanRegs->CANTA.all & 1)) - if(!(ECanRegs->CANAA.all & 1)) - return; - - ECanRegs->CANTA.all = 1; - ECanRegs->CANAA.all = 1; - - hiword= ((((Uint32) Addr ) & 0xffff)<<16)| 0xE0000000 | - ((((Uint32)data[Addr ]) & 0xffff) ); - loword= ((((Uint32)data[Addr+1]) & 0xffff)<<16)| - ((((Uint32)data[Addr+2]) & 0xffff) ); - - ECanMboxes->MBOX0.MDH.all = hiword; - ECanMboxes->MBOX0.MDL.all = loword; - - EALLOW; - /* Отключает старый контроль mailbox 0 перед перезапуском счётчика; остальные mailbox используют собственный контроль. */ - ECanRegs->CANTOC.all = 0; - /* Записывает ECanRegs->CANTSC значением 0; E CAN Regs CANTSC. */ - ECanRegs->CANTSC = 0; // clear time-out counter - /* Заново разрешает тайм-аут штатного TX с порогом MOTO0, установленным в InitCan, только для следующего кадра. */ - ECanRegs->CANTOC.all = 1UL; - EDIS; - - ECanRegs->CANTRS.all = 1; // запустить передачу - - wait=1; - led1_toggle(); -} +/* CAN_send определён общим для этой единицы трансляции блоком can_telemetry_impl.h выше. */ void Handlai(volatile struct ECAN_MBOXES * ECanMboxes) @@ -305,10 +265,11 @@ interrupt void CANa_reset_err(void) if (ECanaRegs.CANTOS.all & 1UL) { /* Обрабатывает только штатный передатчик; служебный mailbox 2 контролируется отдельно в UMP_CAN_service. */ EALLOW; /* Разрешает изменение управляющего регистра eCAN перед снятием источника прерывания. */ - ECanaRegs.CANTOC.all = 0; /* Сброс TOC снимает TOS и MTOF согласно SPRUI07, 13.8.18.3; одной отмены TX недостаточно. */ + ECanaRegs.CANTOC.all &= ~1UL; /* Снимает timeout только mailbox 0, сохраняя контроль служебных передач. */ /* Сброс TOC снимает TOS и MTOF согласно SPRUI07, 13.8.18.3; одной отмены TX недостаточно. */ EDIS; /* Восстанавливает защиту регистров до выхода из ветви обработки тайм-аута. */ if (ECanaRegs.CANTRS.all & 1UL) /* Передача могла завершиться между чтением TOS и снятием контроля. */ ECanaRegs.CANTRR.all = 1UL; /* Запрашивает отмену только ещё занятого mailbox 0, не задерживая прерывание ожиданием CANAA. */ + can_tx_failed = 1U; /* Не допускает записи повреждённого или отменённого кадра в подтверждённый кэш телеметрии. */ CanTimeOutErrorTR++; /* Считает обнаруженный тайм-аут один раз, исключая фантомные повторные входы PIE. */ } /* Следующая штатная передача сама заново включит TOC после сброса временного счётчика. */ diff --git a/Source/Internal/filter_bat2.c b/Source/Internal/filter_bat2.c index b462f22..9d54ecd 100644 --- a/Source/Internal/filter_bat2.c +++ b/Source/Internal/filter_bat2.c @@ -1,7 +1,7 @@ -/* Ðåêóðñèâíûé ôèëüòð. FILTERBAT õðàíèò êîýôôèöèåíòû è èñòîðèþ - * äâóõ âõîäîâ/âûõîäîâ; êàæäûé âûçîâ èçìåíÿåò ïåðåäàííûé ýêçåìïëÿð. - * Íåçàâèñèìûì êàíàëàì íóæíû îòäåëüíûå ñîñòîÿíèÿ. Ñèíõðîíèçàöèè - * çäåñü íåò: ñìåíó êîýôôèöèåíòîâ ñîãëàñîâûâàåò âûçûâàþùèé êîä. +/* Рекурсивный фильтр. FILTERBAT хранит коэффициенты и историю + * двух входов/выходов; каждый вызов изменяет переданный экземпляр. + * Независимым каналам нужны отдельные состояния. Синхронизации + * здесь нет: смену коэффициентов согласовывает вызывающий код. */ #include "filter_bat2.h" diff --git a/Source/Internal/log_to_mem.c b/Source/Internal/log_to_mem.c index aa3870b..06161e6 100644 --- a/Source/Internal/log_to_mem.c +++ b/Source/Internal/log_to_mem.c @@ -1,8 +1,8 @@ -/* Ðåãèñòðàòîð ÓÌÏ âî âíåøíåé ïàìÿòè .logg: äâà áàíêà ïî 800 çàïèñåé - * èç 40 ñëîâ äëÿ SetGUI. Àðõèâ îòêëþ÷åíèÿ íå ìåøàåò äàëüíåéøåé çàïèñè. - * Ïèñàòåëè èç main/CAN/òàéìåðà çàùèùàþòñÿ êîðîòêèìè ñåêöèÿìè IRQ - * ñ âîññòàíîâëåíèåì ïðåæíåé ìàñêè. Àðõèâ íå ýíåðãîíåçàâèñèìûé. - * clear_mem âûïîëíÿåòñÿ ïðè çàïóñêå äî âêëþ÷åíèÿ ïðåðûâàíèé. +/* Регистратор УМП во внешней памяти .logg: два банка по 800 записей + * из 12 слов формата v4 для SetGUI. Архив отключения не мешает дальнейшей записи. + * Писатели из main/CAN/таймера защищаются короткими секциями IRQ + * с восстановлением прежней маски. Архив не энергонезависимый. + * clear_mem выполняется при запуске до включения прерываний. */ #include "DSP2833x_Device.h" #include "filter_bat2.h" @@ -16,7 +16,7 @@ #include "log_to_mem.h" int no_write = 0, - never_write = 0; // Ôëàãè, ÷òîáû íå ïèñàòü (åñëè ÷òî) + never_write = 0; // Изначально разрешает запись; установленный флаг прекращает сохранение снимков до следующего запуска регистратора. #pragma DATA_SECTION(logs_block,".logg"); unsigned int logs_block[0xFA00]; @@ -24,7 +24,7 @@ unsigned int logs_block[0xFA00]; LOG Log; unsigned int flog=0; -// Î÷èùåíèå ïàìàòè, ãäå ëîãè ëåæàò +// Очищение памати, где логи лежат void clear_mem() { unsigned long i; @@ -37,27 +37,27 @@ void clear_mem() for (i=Log.Start; i= UMP_LOG_CAPACITY/2) ump_count = UMP_LOG_CAPACITY/2-1; ump_post_dropped = 0; ump_post = 1000; reason |= 0x100; } - /* Ïîñëåäíåå ìåñòî îñòàâëÿåì äëÿ ñíèìêà êîíöà ïîñòèíòåðâàëà. Ïðè - * ïåðåïîëíåíèè ÷åñòíî îòìå÷àåì óñå÷åíèå áèòîì 0x200 â êîíå÷íîé çàïèñè. */ + /* Последнее место оставляем для снимка конца постинтервала. При + * переполнении честно отмечаем усечение битом 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]; + /* Выбирает слот банка по числу 16-битных слов записи; ёмкость 800 записей сохранена для исполнения 166. */ + record = logs_block + ((unsigned long)ump_bank * UMP_LOG_CAPACITY + ump_next) * UMP_LOG_WORDS; + /* Слова 0/1 передают 32-битное время в миллисекундах младшей половиной вперёд, как в формате v4 исполнения 167. */ + record[0] = (unsigned int)ump_time; record[1] = (unsigned int)(ump_time >> 16); + /* Слово 2 содержит событие, а маска 0xC0 оставляет в слове 3 только назначенные протоколом биты 7/6 пуска и сброса УМП. */ + record[2] = reason; record[3] = commands & 0xC0U; + /* Слова 4/5 сохраняют фактические логические входы и выходы нагрузки для дискретных дорожек SetGUI. */ + record[4] = ump_inputs(); record[5] = ump_outputs(); + /* Слово 6 содержит расчётное задание тока регистра 0x1C в единицах 0,1 мА; физическое измерение тока здесь не выполняется. */ + record[6] = modbus[0x1C]; + /* Слова 7/8 содержат штатные фиксированные уставки разгона 166: начальные 6 мА и конечные 16 мА. */ + record[7] = 6; record[8] = 16; + /* Слова 9/10 передают последние ЗПТ1/ЗПТ2 в вольтах из CAN-индексов 305/8, соответствующих регистрам ПМ67 306/9. */ + record[9] = ump_pm67_voltage[0]; record[10] = ump_pm67_voltage[1]; + /* Нулевое слово 11 дополняет запись до чётной длины: служебный CAN передаёт данные парами 16-битных слов. */ + record[11] = 0; + /* Обновляет полные команды и фактические дискреты для обнаружения следующих событий, сохраняя алгоритм триггера 166. */ + ump_prev_commands = commands; ump_prev_inputs = record[4]; ump_prev_outputs = record[5]; ump_next++; if (ump_next == UMP_LOG_CAPACITY) ump_next = 0; if (ump_count < UMP_LOG_CAPACITY) ump_count++; ump_sequence++; } -/* Çàâåðø¸ííûé áàíê áîëüøå íå èçìåíÿåòñÿ äî ñëåäóþùåãî îòêëþ÷åíèÿ. - * Íîìåð ïîêîëåíèÿ ïîçâîëÿåò GUI îáíàðóæèòü çàìåíó àðõèâà âî âðåìÿ ÷òåíèÿ. */ +/* Завершённый банк больше не изменяется до следующего отключения. + * Номер поколения позволяет GUI обнаружить замену архива во время чтения. */ static void ump_freeze(void) { ump_archive_bank = ump_bank; @@ -152,8 +152,8 @@ void ump_log_tick(void) __restore_interrupts(saved); } -/* Äîïîëíèòåëüíûé ñíèìîê òîëüêî ïðè èçìåíåíèè êîìàíä, âõîäîâ èëè âûõîäîâ. - * Ýòî íå çàìåíÿåò ïåðèîäè÷åñêóþ çàïèñü àíàëîãîâûõ âåëè÷èí â òàéìåðå. */ +/* Дополнительный снимок только при изменении команд, входов или выходов. + * Это не заменяет периодическую запись аналоговых величин в таймере. */ void ump_log_io(void) { unsigned int saved; @@ -164,17 +164,34 @@ void ump_log_io(void) __restore_interrupts(saved); } -/* Âûçûâàåòñÿ ïîñëå ïðèìåíåíèÿ ñëîâ ïðèíÿòîãî CAN-êàäðà: ñíèìîê ñîäåðæèò - * íîâûå êîìàíäû, à òàêæå èñõîäíûé àäðåñ/ìàñêó è âñå òðè ñëîâà êàäðà. */ +/* Обновляет напряжения из принятых слов 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; + /* Хранит прежнюю маску IRQ, индекс слова, текущий CAN-адрес, маску разрешения и три принятых 16-битных значения. */ + unsigned int saved, word_index, address, mask, can_words[3]; + /* Напряжения и журнал принадлежат плате нагрузки; другие аппаратные режимы их не обновляют. */ + if (Desk != dsk_LOAD) return; + /* Исключает смешивание обновления напряжений с периодическим снимком таймера и восстанавливает прежние IRQ в конце. */ 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++; + /* Располагает три принятых слова в том же порядке, в котором заголовок задаёт их последовательные адреса. */ + can_words[0] = a; can_words[1] = b; can_words[2] = c; + /* Младшие 13 бит заголовка задают нулевой индекс первого регистра CAN; верхние три бита являются масками слов. */ + address = header & 0x1FFFU; + /* Старший бит 0x8000 разрешает первое слово, далее используются биты 0x4000 и 0x2000. */ + mask = 0x8000U; + /* Продвигает адрес и маску для всех трёх позиций, включая пропущенные слова, чтобы не перепутать регистры ПМ67. */ + for (word_index = 0; word_index < 3; word_index++, address++, mask >>= 1) { + /* Не использует содержимое позиции, если соответствующий бит заголовка не подтверждает её передачу. */ + if (!(header & mask)) continue; + /* Индекс 305 соответствует регистру 306 ПМ67: суммарное напряжение ЗПТ1 передаётся в целых вольтах. */ + if (address == 305U) ump_pm67_voltage[0] = can_words[word_index]; + /* Индекс 8 соответствует регистру 9 ПМ67: суммарное напряжение ЗПТ2 передаётся в целых вольтах. */ + if (address == 8U) ump_pm67_voltage[1] = can_words[word_index]; + } /* Завершает разбор трёх слов CAN после обновления только подтверждённых напряжений. */ + /* Сохраняет компактный снимок только при активной записи и готовности 166, которые проверяет ump_capture. */ ump_capture(2); + /* Возвращает исходную маску IRQ, в том числе при вызове из обработчика CAN. */ __restore_interrupts(saved); } @@ -185,8 +202,8 @@ void ump_log_rs(void) __restore_interrupts(saved); } -/* Óïðàâëåíèå æóðíàëîì îòäåëåíî îò òåõíîëîãè÷åñêèõ êîìàíä: íà÷àëî çàïèñè - * ÍÅ çàïóñêàåò ÓÌÏ. Âûáîð àðõèâà íå îñòàíàâëèâàåò òåêóùóþ çàïèñü. */ +/* Управление журналом отделено от технологических команд: начало записи + * НЕ запускает УМП. Выбор архива не останавливает текущую запись. */ int ump_log_write(unsigned int address, unsigned int value) { unsigned int saved, valid = 1; @@ -211,8 +228,8 @@ int ump_log_write(unsigned int address, unsigned int value) return valid; } -/* Ïðåîáðàçîâàíèå õðîíîëîãè÷åñêîãî èíäåêñà â ôèçè÷åñêóþ ïîçèöèþ êîëüöà. - * Äëÿ àðõèâà ñîõðàíåíû ñîáñòâåííûå count/next, íåçàâèñèìûå îò æèâîãî áàíêà. */ +/* Преобразование хронологического индекса в физическую позицию кольца. + * Для архива сохранены собственные 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; @@ -225,16 +242,17 @@ static unsigned int ump_word(unsigned int archived, unsigned int record, unsigne return logs_block[((unsigned long)bank * UMP_LOG_CAPACITY + slot) * UMP_LOG_WORDS + word]; } -/* Âåñü Modbus-áëîê ÷èòàåòñÿ âûçûâàþùèì êîäîì ïîä îäíîé áëîêèðîâêîé IRQ. - * Ïîýòîìó timestamp/äàííûå è çàãîëîâîê îíëàéí-áëîêà îòíîñÿòñÿ ê îäíîìó - * ñîñòîÿíèþ êîëüöà, äàæå åñëè â ýòîò ìîìåíò ïðèõîäèò íîâàÿ CAN-êîìàíäà. */ +/* Весь 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; + /* Версия 4 сообщает SetGUI о 12-словной записи, исключая её ошибочный разбор как прежних 40 слов v2. */ + case UMP_LOG_BASE+1: return 4; 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; @@ -254,10 +272,11 @@ unsigned int ump_log_read(unsigned int address) 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; + /* Ограничивает число целых записей ёмкостью 120-словного окна: формат v4 позволяет передать до десяти снимков. */ + 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/Source/Internal/main.c b/Source/Internal/main.c index 1e9c576..4c5ad16 100644 --- a/Source/Internal/main.c +++ b/Source/Internal/main.c @@ -1,8 +1,8 @@ -/* Èíèöèàëèçàöèÿ è ôîíîâûé öèêë ïëàòû. Ïîñëå íàñòðîéêè GPIO, îáìåíà, - * ïàðàìåòðîâ è ÖÀÏ UMP_pulse_init ðàçðåøàåò ñâåæèå êîìàíäû ÑÈÔÓ. - *  main îñòàþòñÿ òåëåìåòðèÿ, EEPROM è ðàçáîð ãîòîâûõ RS-ïàêåòîâ. - * CAN-ïóñê è îêîí÷àíèå èìïóëüñà ðàáîòàþò â IRQ, íå îæèäàÿ main. - * RS-êîìàíäà åù¸ äîëæíà ïðîéòè ïðîâåðêó CRC â get_command èç main. +/* Инициализация и фоновый цикл платы. После настройки GPIO, обмена, + * параметров и ЦАП UMP_pulse_init разрешает свежие команды СИФУ. + * В main остаются телеметрия, EEPROM и разбор готовых RS-пакетов. + * CAN-пуск и окончание импульса работают в IRQ, не ожидая main. + * RS-команда ещё должна пройти проверку CRC в get_command из main. */ #include "DSP2833x_Device.h" // DSP2833x Headerfile Include File @@ -43,8 +43,7 @@ void timer_Init() void main() { - int i,j,mask; - static unsigned int cancount[2], cancell[2]; + int i,j; /* Счётчики остались для прежних операций main; выбор CAN-пакетов перенесён в независимый сервис. */ RS_DATA * rs; int presbyt=0; @@ -100,7 +99,7 @@ void main() if(Desk==dsk_LOAD) Setup_DAC_time(); - /* Çàâåðøåíà íà÷àëüíàÿ íàñòðîéêà: òîëüêî òåïåðü ðàçðåøàåì äèñêðåòû. */ + /* Завершена начальная настройка: только теперь разрешаем дискреты. */ UMP_pulse_init(); LastMode = Mode; @@ -110,32 +109,9 @@ void main() while(1) { - /* ×òåíèå ëîããåðà ïî CAN íå áëîêèðóåò öèêë óïðàâëåíèÿ. */ + /* Чтение логгера по CAN не блокирует цикл управления. */ UMP_CAN_service(); - if(CanGO) - { - CanGO=0; - for(i=0;i<2;i++) - if(Cancount[i]) - if(++cancount[i] >= Cancount[i]) - { - cancount[i] = 0; - while(1) - { - if(cancell[i] >= 0x80) cancell[i]=0; - mask = Maska[i][cancell[i]/16] >> (cancell[i]%16); - if(!mask) cancell[i] = (cancell[i] + 0x10) & 0xFFF0; - else - { - while(!(mask & 1)) - { - cancell[i]++; mask >>= 1; - } - break; - } } - CAN_send(0,modbus,cancell[i]); - cancell[i]+=3; - } } + CAN_telemetry_service(); /* Обслуживает heartbeat 1 Гц, изменения масок данных и индивидуальные повторы 1,3 с без ожидания CAN ACK. */ if(cDefParam) { @@ -169,10 +145,10 @@ void main() presbyt = bTermoCal; } - /* START/STOP èñïîëíÿþòñÿ ïðè ïðè¸ìå CAN/RS, ñíèìàþòñÿ òàéìåðîì. - * Çäåñü áîëüøå íåò îïðîñà óðîâíÿ: main ìîæåò îæèäàòü EEPROM. */ + /* START/STOP исполняются при приёме CAN/RS, снимаются таймером. + * Здесь больше нет опроса уровня: main может ожидать EEPROM. */ - /* Ñíèìîê ïîñëå îáíîâëåíèÿ âõîäîâ è ôîðìèðîâàíèÿ ïóñêîâûõ âûõîäîâ. */ + /* Снимок после обновления входов и формирования пусковых выходов. */ ump_log_io(); for(i=0;i<2;i++) @@ -188,16 +164,16 @@ void main() led2_toggle(); switch(j) { - case CMD_INIT: init(rs); break; // íà÷àëüíûå óñòàíîâêè - case CMD_INITLOAD: initload(rs); break; // íàñòðîéêà çàãðóçêè - case CMD_RUN: run(rs); break; // çàãðóçèòü áëîê - case CMD_LOAD: load(rs); break; // çàãðóçèòü áëîê - case CMD_PEEK: peek(rs); break; // ïðî÷èòàòü à÷åéêó ïàìàòè - case CMD_POKE: poke(rs); break; // çàïèñàòü â à÷åéêó ïàìàòè - case CMD_UPLOAD: upload(rs); break; // ïåðåäàòü áëîê ïàìàòè - case CMD_EXTEND: extendbios(rs); break; // ðàñøèðåííûå êîìàíäû äëà áèîñà + case CMD_INIT: init(rs); break; // начальные установки + case CMD_INITLOAD: initload(rs); break; // настройка загрузки + case CMD_RUN: run(rs); break; // загрузить блок + case CMD_LOAD: load(rs); break; // загрузить блок + case CMD_PEEK: peek(rs); break; // прочитать ачейку памати + case CMD_POKE: poke(rs); break; // записать в ачейку памати + case CMD_UPLOAD: upload(rs); break; // передать блок памати + case CMD_EXTEND: extendbios(rs); break; // расширенные команды дла биоса - case CMD_TFLASH: tflash(rs); break; // ïðîøèòü TMS + case CMD_TFLASH: tflash(rs); break; // прошить TMS case CMD_MODBUS_3: ReceiveCommandModbus3(rs); break; case CMD_MODBUS_6: ReceiveCommandModbus6(rs); break; diff --git a/Source/Internal/measure.c b/Source/Internal/measure.c index 4909173..3592222 100644 --- a/Source/Internal/measure.c +++ b/Source/Internal/measure.c @@ -1,8 +1,8 @@ -/* Èçìåðåíèÿ, äèàãíîñòèêà è ïåðèîäè÷åñêîå îáñëóæèâàíèå. ADC ISR - * ïîñòàâëÿåò âûáîðêè; òàéìåð 1 îáñëóæèâàåò èíäèêàöèþ è òåëåìåòðèþ. - * Äëÿ dsk_LOAD îí ñíà÷àëà çàâåðøàåò èìïóëüñ ÑÈÔÓ, çàòåì âûçûâàåò - * ðàñ÷¸ò ÖÀÏ è ñíèìîê ëîããåðà. ×àñòîòû íàõîäÿòñÿ â measure.h; - * ïðè èõ èçìåíåíèè òðåáóåòñÿ ïåðåñ÷èòàòü çàâèñèìûå èíòåðâàëû. +/* Измерения, диагностика и периодическое обслуживание. ADC ISR + * поставляет выборки; таймер 1 обслуживает индикацию и телеметрию. + * Для dsk_LOAD он сначала завершает импульс СИФУ, затем вызывает + * расчёт ЦАП и снимок логгера. Частоты находятся в measure.h; + * при их изменении требуется пересчитать зависимые интервалы. */ #include "DSP2833x_Device.h" // DSP2833x Headerfile Include File #include "DSP2833x_SWPrioritizedIsrLevels.h" @@ -20,13 +20,13 @@ #include "message.h" #include "log_to_mem.h" -#include // Ýòî ÷òîáû ìåðèòü àìïëèòóäó! sqrt áåç ýòîãî áóäåò êðèâ!!! +#include // Это чтобы мерить амплитуду! sqrt без этого будет крив!!! unsigned int CanPowse=CANPOWSE,CanGO=0; unsigned int Maska[2][8]; -int TPL_CANS=0; // Êîëè÷åñòâî òåìïåðàòóðíûõ êàíàëîâ +int TPL_CANS=0; // Количество температурных каналов int tpl_cans=0; int cal_addr=0; @@ -53,23 +53,23 @@ int Curr_Edge; float powK[] = { - 0.127, // ïèòàíèå 380 - 0.127, // ïèòàíèå 380 + 0.127, // питание 380В + 0.127, // питание 380В - 1.000, // òîê - 1.000, // íàïðàæåíèå + 1.000, // ток + 1.000, // напражение - 0.0076, // ïèòàíèå 31 - 0.0076, // ïèòàíèå 24 - 0.0076, // ïèòàíèå 24 - 0.0076, // ïèòàíèå 15 - 1.0000, // òåðìîäàò÷èê ìåëêîñõåìà + 0.0076, // питание 31В + 0.0076, // питание 24В + 0.0076, // питание 24В + 0.0076, // питание 15В + 1.0000, // термодатчик мелкосхема }; FILTERBAT def_FILTERBAT = DEF_FILTERBAT; -FILTERBAT adc_filter[20+4]; // ìàêñ.TPL*2 + 4 êàëèáð -FILTERBAT out_filter[20+4]; // ìàêñ.TPL*2 + 4 íàïðàæ -FILTERBAT zer_filter[4]; // 4 íàïðàæ +FILTERBAT adc_filter[20+4]; // макс.TPL*2 + 4 калибр +FILTERBAT out_filter[20+4]; // макс.TPL*2 + 4 напраж +FILTERBAT zer_filter[4]; // 4 напраж long sens_count[24+4]; @@ -79,7 +79,7 @@ float K_T1,K_T2; interrupt void cpu_timer1_isr_SENS(void); /********************************************************************/ -/* Ðàñ÷åò ìîäóëà òîêà èç ïîêàçàíèé äâóõ ôàç */ +/* Расчет модула тока из показаний двух фаз */ /********************************************************************/ float im_calc(float ia,float ib) { @@ -115,8 +115,8 @@ interrupt void cpu_timer1_isr_SENS(void) int TST; -#define err_lamp work_lamp // ýòî äëà øêàïà, -#define alm_lamp heat_lamp // ÷òîá áûëî ïîíàòíåå +#define err_lamp work_lamp // это дла шкапа, +#define alm_lamp heat_lamp // чтоб было понатнее EALLOW; CpuTimer1.InterruptCount++; @@ -140,10 +140,10 @@ interrupt void cpu_timer1_isr_SENS(void) if(Desk==dsk_LOAD) { - /* Ñíÿòü èñò¸êøèé èìïóëüñ äî ðàñ÷¸òà ÖÀÏ, íåçàâèñèìî îò main. */ + /* Снять истёкший импульс до расчёта ЦАП, независимо от main. */ UMP_pulse_tick(); Load_runner(); - /* Áàçà âðåìåíè 1 ìñ; ñíèìîê ñîäåðæèò ðåçóëüòàò òåêóùåãî øàãà ÖÀÏ. */ + /* База времени 1 мс; снимок содержит результат текущего шага ЦАП. */ ump_log_tick(); return; } @@ -156,9 +156,9 @@ interrupt void cpu_timer1_isr_SENS(void) ((Desk==dsk_COMM) && heat_lamp) ) set_RES_OUT_1(); else clear_RES_OUT_1(); - if(work_lamp) set_LED_OUT_1(); // Îíà æå err_lamp äëà øêàïà + if(work_lamp) set_LED_OUT_1(); // Она же err_lamp дла шкапа else clear_LED_OUT_1(); - if(heat_lamp) set_LED_OUT_2(); // Îíà æå alm_lamp äëà øêàïà + if(heat_lamp) set_LED_OUT_2(); // Она же alm_lamp дла шкапа else clear_LED_OUT_2(); } @@ -360,37 +360,37 @@ void Init_packMask() switch(Desk) { case dsk_EPLT: - Maska[m_SLOW][0]|= 0x000F; // Ïîëó÷åííîå - Maska[m_SLOW][6]|= 0x01FC; // ßðêîñòü ëàìï è îäèíî÷åñòâî + Maska[m_FAST][0]|= 0x000F; // Включает R0–R3 в быструю обратную связь VPU для ПМ67; четыре младших бита маски исключают ожидание медленного обхода параметров. + Maska[m_SLOW][6]|= 0x01FC; // Яркость ламп и одиночество break; default: for(i=0;itpl_cans) return; -// Kun èìåííî ÷òîá ñêîìïåíñèðîâàòü íå÷åòíîñòü +// Kun именно чтоб скомпенсировать нечетность if(kun&1) Numb = (Numb-K300_2)*K_T2+ZERO; else Numb = (Numb-K300_1)*K_T1+ZERO; } @@ -706,7 +706,7 @@ sens_data[chan+8] = adc_table_tpl[chan]; error.all = 0; no_ignor = !sens_error[chan].bit.Ignor; -// Îáðûâ èëè íåèñïðàâíîñòü +// Обрыв или неисправность if(Temper==-20 || Temper==200) { error.bit.Tear = 1; @@ -714,7 +714,7 @@ sens_data[chan+8] = adc_table_tpl[chan]; } else -// Ïåðåãðåâ +// Перегрев if(((Temper>sens_hi_edge[chan]-Cooling) && (sens_error[chan].bit.Hyper)) || (Temper>sens_hi_edge[chan]) ) { @@ -724,7 +724,7 @@ sens_data[chan+8] = adc_table_tpl[chan]; } else -// Ïðåäóïðåæäåíèå ïî òåìïåðàòóðå +// Предупреждение по температуре if(Temper>sens_lo_edge[chan]) { error.bit.Over = 1; @@ -796,7 +796,7 @@ void Power_count(int chan) error.bit.Stop = 1; } } -/* Ïîâûøåííîå íàïðàæåíèå +/* Повышенное напражение if(Power > sens_hi_edge[chan]) { error.bit.Hyper = 1; @@ -812,4 +812,3 @@ void Power_count(int chan) if(!WAKE) reset_errs(chan,error); } - diff --git a/Source/Internal/message.c b/Source/Internal/message.c index 7662a0a..1b18f61 100644 --- a/Source/Internal/message.c +++ b/Source/Internal/message.c @@ -1,8 +1,8 @@ -/* Ïàðàìåòðû è îáðàáîò÷èêè Modbus ïîñëå ïðîâåðêè CRC. Ìàññèâ modbus - * ñîäåðæèò îáû÷íûå àäðåñà 0..127, îáëàñòü 0x1000 îáñëóæèâàåò ëîããåð. - * EEPROM õðàíèò ïàðàìåòðû, íî íå ÿâëÿåòñÿ èñòî÷íèêîì START/STOP: - * ïðè çàãðóçêå ñîõðàíÿåòñÿ ïîñëåäíÿÿ æèâàÿ êîìàíäà íàãðóçêè. - * Ôóíêöèè âûçûâàþòñÿ èç main; EEPROM áëîêèðóåò ýòîò êîíòåêñò. +/* Параметры и обработчики Modbus после проверки CRC. Массив modbus + * содержит обычные адреса 0..127, область 0x1000 обслуживает логгер. + * EEPROM хранит параметры, но не является источником START/STOP: + * при загрузке сохраняется последняя живая команда нагрузки. + * Функции вызываются из main; EEPROM блокирует этот контекст. */ #include "DSP2833x_Device.h" // DSP2833x Headerfile Include File #include "package.h" @@ -21,9 +21,12 @@ #include "ecan.h" #include "pulto.h" #include "spise2p.h" +#include "include/balsam167_eeprom_block.h" /* Использует общий с 167 контракт FC03: окно 0x8000..0xBFFF, до 120 слов AT25256B за запрос. */ #include "caliber.h" #include "log_to_mem.h" +#include "firmware_info.h" /* Подключает адрес и границы неизменяемого паспорта 0x1200, совместимого с проверкой прошивки в 167. */ +#include "../src/firmware_info_static.c" /* Собирает общие 12 слов firmware-info через include-путь firmware-info/include; как в 167, копии упаковщика в проекте нет. */ #include "DAC.h" int modbus[ANSWER_LEN+1]; @@ -47,7 +50,7 @@ void Default_params() for(i=0;iRS_Header[2] << 8) | rs_arr->RS_Header[3]; -// ïîëó÷èëè êîëè÷åñòâî ñëîâ äàííûõ +// получили количество слов данных Length_MB = (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5]; + if (Address_MB >= BALSAM167_EEPROM_RTU_BASE) { /* Выделяет только верхнее окно EEPROM; старые регистры, логгер и паспорт обрабатываются прежним кодом ниже. */ + if (!balsam167_eeprom_block_valid_profile(CMD_MODBUS_3, Address_MB, Length_MB, 0U)) { /* Профиль 0 сохраняет контракт 167 для 32 КиБ: запрещает пустой блок, более 120 слов, M95 и выход за конец окна. */ + modbus_exception(rs_arr, CMD_MODBUS_3, 2U); /* Возвращает Illegal Data Address с CRC до любого обращения к SPI при неверном диапазоне. */ + return; /* Не допускает перехода ошибочного запроса EEPROM к backend логгера или обычным регистрам. */ + } /* Валидатор проверяет конец через вычитание, поэтому переполнение 16-битного адреса не разрешает чтение. */ + Seeprom_read(Address_MB - BALSAM167_EEPROM_RTU_BASE, &rs_arr->buffer[3], Length_MB * 2U); /* Как в 167, SPI получает адрес в 16-битных словах и длину в октетах; IRQ остаются разрешены для автомата Timer2. */ + for (i = Length_MB; i > 0U; --i) { /* Разворачивает прочитанные слова с конца в том же UART-буфере без нового массива и перезаписи ещё не обработанных слов. */ + value = rs_arr->buffer[i + 2U]; /* Временное слово сохраняет оба SPI-октета до расширения одного элемента C28x в два октета RTU. */ + rs_arr->buffer[i * 2U + 2U] = value & 0xFFU; /* Записывает младший октет слова после старшего, как требует физический дамп EEPROM в SETGUI. */ + rs_arr->buffer[i * 2U + 1U] = (value >> 8) & 0xFFU; /* Маска 0xFF выделяет восемь бит линии из 16-битного unsigned int C28x. */ + } /* Обратный обход корректен и для одного слова, и для максимального блока из 120 слов. */ + rs_arr->buffer[0] = CNTRL_ADDR; /* Отвечает собственным адресом платы, сохраняя поддержку общего адреса 16 существующим приёмником. */ + rs_arr->buffer[1] = CMD_MODBUS_3; /* Возвращает стандартную команду FC03 без введения отдельной команды BIOS или записи памяти. */ + rs_arr->buffer[2] = Length_MB * 2U; /* Число полезных октетов находится в диапазоне 2..240 и помещается в одном октете RTU. */ + crc = get_crc_16(0xFFFFU, rs_arr->buffer, Length_MB * 2U + 3U); /* Проверяет адрес, команду, длину и весь блок тем же Modbus CRC16, что остальные ответы прошивки. */ + rs_arr->buffer[Length_MB * 2U + 3U] = LOBYTE(crc); /* Передаёт младший октет CRC первым в соответствии с Modbus RTU. */ + rs_arr->buffer[Length_MB * 2U + 4U] = HIBYTE(crc); /* Завершает кадр старшим октетом CRC без устаревшего нулевого хвоста. */ + rs_arr->flag_TIMEOUT_to_Send = true; /* Использует штатное управление таймаутом UART при отправке готового ответа из main. */ + RS_Send(rs_arr, rs_arr->buffer, Length_MB * 2U + 5U); /* Отправляет ровно 5 служебных октетов плюс данные, максимум 245 элементов из существующего буфера на 400. */ + return; /* Завершает только новый маршрут EEPROM, сохраняя прежние форматы остальных ответов FC03. */ + } /* Новый маршрут не меняет PEEK, запись EEPROM, адреса параметров или драйвер SPI. */ if (!Length_MB || Length_MB > 125 || !((Address_MB < ANSWER_LEN && Length_MB <= ANSWER_LEN-Address_MB) || (Address_MB >= UMP_LOG_BASE && Address_MB <= UMP_LOG_BASE+15 && Length_MB <= UMP_LOG_BASE+16-Address_MB) || (Address_MB >= UMP_LOG_DATA && Address_MB < UMP_LOG_DATA+120 && Length_MB <= UMP_LOG_DATA+120-Address_MB) || - (Address_MB == UMP_LOG_LIVE && Length_MB == 124))) { + (Address_MB == UMP_LOG_LIVE && Length_MB == 124) || /* Сохраняет точное прежнее 124-словное онлайн-окно логгера. */ + firmware_info_range(Address_MB, Length_MB))) { /* Дополнительно разрешает только полное или частичное чтение двенадцати регистров паспорта. */ modbus_exception(rs_arr, CMD_MODBUS_3, 2); return; } ///////////////////////////////////////////////// - // Îòñûëêà - /* Ïîñ÷èòàëè êîíòðîëüíóþ ñóììó ïåðåä ñàìîé ïîñûëêîé */ + // Отсылка + /* Посчитали контрольную сумму перед самой посылкой */ rs_arr->buffer[0] = CNTRL_ADDR; rs_arr->buffer[1] = CMD_MODBUS_3; rs_arr->buffer[2] = Length_MB*2; - /* Çàùèùàåì öåëîñòíîñòü îäíîãî ñíèìêà/áëîêà; ïåðåäà÷à UART èä¸ò óæå - * ñ ðàçðåø¸ííûìè ïðåðûâàíèÿìè è íå çàäåðæèâàåò èçìåðåíèå/óïðàâëåíèå. */ - if (Address_MB >= UMP_LOG_BASE) saved = __disable_interrupts(); + /* Защищаем целостность одного снимка/блока; передача UART идёт уже + * с разрешёнными прерываниями и не задерживает измерение/управление. */ + if (Address_MB >= UMP_LOG_BASE && Address_MB < FIRMWARE_INFO_ADDRESS) saved = __disable_interrupts(); /* Неизменяемый паспорт не требует блокировки IRQ; целостность прежних снимков логгера сохраняется. */ for (i=0;i= UMP_LOG_BASE ? ump_log_read(Address_MB+i) : modbus[Address_MB+i]; + if (Address_MB >= FIRMWARE_INFO_ADDRESS) value = firmware_info_static_read(Address_MB - FIRMWARE_INFO_ADDRESS + i); /* После проверки диапазона читает только соответствующее слово статического паспорта, без обращения к логгеру. */ + else value = Address_MB >= UMP_LOG_BASE ? ump_log_read(Address_MB+i) : (unsigned int)modbus[Address_MB+i]; /* Сохраняет прежнюю маршрутизацию и беззнаковое представление 16-битных слов технологической карты и логгера v4. */ rs_arr->buffer[3+i*2] = (value >> 8) & 0xFF; rs_arr->buffer[3+i*2+1] = value & 0xFF; } - if (Address_MB >= UMP_LOG_BASE) __restore_interrupts(saved); + if (Address_MB >= UMP_LOG_BASE && Address_MB < FIRMWARE_INFO_ADDRESS) __restore_interrupts(saved); /* Возвращает сохранённую маску только для действительно защищённого снимка логгера. */ crc = 0xffff; crc = get_crc_16(crc, rs_arr->buffer, Length_MB*2+3); @@ -258,9 +284,9 @@ void ReceiveCommandModbus3(RS_DATA *rs_arr) rs_arr->buffer[Length_MB*2+8] = 0; rs_arr->flag_TIMEOUT_to_Send=true; - /* Ðàñøèðåíèå ëîããåðà îòâå÷àåò òî÷íûì êàäðîì Modbus áåç õâîñòîâûõ - * íóëåé: îíè èíà÷å ïîïàëè áû â íà÷àëî îòâåòà ñëåäóþùåãî áëîêà GUI. - * Èñòîðè÷åñêèé ôîðìàò òåõíîëîãè÷åñêèõ ðåãèñòðîâ îñòàâëåí ïðåæíèì. */ + /* Расширение логгера отвечает точным кадром Modbus без хвостовых + * нулей: они иначе попали бы в начало ответа следующего блока GUI. + * Исторический формат технологических регистров оставлен прежним. */ RS_Send(rs_arr, rs_arr->buffer, Length_MB*2+(Address_MB >= UMP_LOG_BASE ? 5 : 8)); return; @@ -271,26 +297,27 @@ void ReceiveCommandModbus6(RS_DATA *rs_arr) unsigned int Address_MB, Data_MB, i; ///////////////////////////////////////////////// - // Îòñûëêà - /* Îòïðàâëàåì íàçàä òî æå ñàìîå */ + // Отсылка + /* Отправлаем назад то же самое */ for (i=0;i<8;i++) rs_arr->buffer[i] = rs_arr->RS_Header[i]; -// ïîëó÷èëè íà÷àëüíûé àäðåñ çàïèñè +// получили начальный адрес записи Address_MB = (rs_arr->RS_Header[2] << 8) | rs_arr->RS_Header[3]; -// ïîëó÷èëè ñëîâî äàííûõ +// получили слово данных Data_MB = (rs_arr->RS_Header[4] << 8) | rs_arr->RS_Header[5]; + if (Address_MB >= FIRMWARE_INFO_ADDRESS && Address_MB < FIRMWARE_INFO_END) { modbus_exception(rs_arr, CMD_MODBUS_6, 2); return; } /* Как в контракте 167, запись в паспорт запрещена с Illegal Data Address и не достигает параметров или логгера. */ if (Address_MB >= UMP_LOG_BASE) { if (!ump_log_write(Address_MB, Data_MB)) { modbus_exception(rs_arr, CMD_MODBUS_6, 3); return; } } else if (Address_MB < ANSWER_LEN) { - /* RS è CAN èñïîëüçóþò îäíó èñòîðèþ ôðîíòîâ. ×åðåäîâàíèå êàíàëîâ - * íå ñîçäà¸ò äâóõ íåçàâèñèìûõ ïîâòîðíûõ çàïóñêîâ. */ + /* RS и CAN используют одну историю фронтов. Чередование каналов + * не создаёт двух независимых повторных запусков. */ if (Address_MB == 127) { UMP_commands_write(Data_MB); ump_log_rs(); diff --git a/Source/Internal/peripher.c b/Source/Internal/peripher.c index 885ffb2..d99e024 100644 --- a/Source/Internal/peripher.c +++ b/Source/Internal/peripher.c @@ -51,10 +51,10 @@ void get_Mode() { EALLOW; - GpioCtrlRegs.GPAMUX1.all &= 0xFF000000; // Обнуляет двухбитовые поля MUX для GPIO0–11 по карте регистров TMS320F28335, выбирая обычный GPIO и сохраняя назначение GPIO12–15. - GpioCtrlRegs.GPAMUX2.all &= 0xFF00003F; // Выбирает обычный GPIO для выводов 19–27: маска сохраняет поля GPIO16–18 и GPIO28–31 в двухбитовой таблице MUX. - GpioCtrlRegs.GPBMUX1.all &= 0xFFFFFFC0; // Обнуляет младшие шесть битов MUX, переводя GPIO32–34 в режим обычных входов или выходов без изменения остальных выводов банка. - GpioCtrlRegs.GPBMUX2.all &= 0x000FF000; // Сохраняет поля GPIO54–57 и переводит GPIO48–53 и GPIO58–63 в обычный GPIO согласно двухбитовой раскладке GPBMUX2. + GpioCtrlRegs.GPAMUX1.all &= 0xFF000000; // 00—11 + GpioCtrlRegs.GPAMUX2.all &= 0xFF00003F; // 19—27 + GpioCtrlRegs.GPBMUX1.all &= 0xFFFFFFC0; // 32—34 + GpioCtrlRegs.GPBMUX2.all &= 0x000FF000; // 48—53, 58—63 GpioCtrlRegs.GPADIR.bit.GPIO20 = 0; GpioCtrlRegs.GPADIR.bit.GPIO21 = 0; @@ -205,15 +205,14 @@ void get_Buttons() if(Desk==dsk_EPLT) { - /* Сохраняет TESTLAMP до достижения порога фильтра: 1000 означает число опросов главного цикла, а bTestLamp удерживает прежний режим при кратком провале GPIO26, чтобы рабочие маски не прерывали тест индикации. */ - bTestLamp = er_anal(GpioDataRegs.GPADAT.bit.GPIO26, &INcount0, 1000, bTestLamp); + /* Таймер пульта включает местный тест после непрерывного удержания TESTLAMP в течение 2 с; число проходов main не влияет на задержку. */ if(GpioDataRegs.GPADAT.bit.GPIO27) butt +=0x0001; if(GpioDataRegs.GPADAT.bit.GPIO24) butt +=0x0002; if(GpioDataRegs.GPBDAT.bit.GPIO53) butt +=0x0004; if(GpioDataRegs.GPBDAT.bit.GPIO50) butt +=0x0008; - if(GpioDataRegs.GPADAT.bit.GPIO26) butt +=0x0010; + if(GpioDataRegs.GPADAT.bit.GPIO26) butt +=0x0010; // Передаёт исходное состояние TESTLAMP в бите 4 слова Inputs (0x10), по которому основной контроллер вызывает сброс ошибок при коротком нажатии. if(GpioDataRegs.GPADAT.bit.GPIO23) butt +=0x0020; if(GpioDataRegs.GPBDAT.bit.GPIO52) butt +=0x0040; if(GpioDataRegs.GPADAT.bit.GPIO4 ) butt +=0x0080; @@ -224,7 +223,7 @@ void get_Buttons() if(GpioDataRegs.GPADAT.bit.GPIO5 ) butt +=0x0800; if(GpioDataRegs.GPBDAT.bit.GPIO48) butt +=0x1000; - if(GpioDataRegs.GPADAT.bit.GPIO10) butt +=0x2000; // Публикует активный секретный вход GPIO10 в бите 13 слова Inputs; маска 0x2000 задаёт назначенную ему позицию протокола. + if(GpioDataRegs.GPADAT.bit.GPIO10) butt +=0x2000; // Секретный вход Inputs.all = butt; } diff --git a/Source/Internal/pulto.c b/Source/Internal/pulto.c index 8790b7f..48b5202 100644 --- a/Source/Internal/pulto.c +++ b/Source/Internal/pulto.c @@ -43,11 +43,11 @@ interrupt void cpu_timer1_isr_PULT(void) static int cownt=0,count_bright; unsigned int light=0, i; unsigned int Alone = 20*READY_FREQ; + static unsigned int test_lamp_hold_ticks = 0; // Считает длительность непрерывного нажатия GPIO26 в тиках READY_FREQ; насыщение на пороге исключает переполнение при долгом удержании. EALLOW; CpuTimer1.InterruptCount++; - /* Оставляет только ранее разрешённые источники по таблице приоритетов TI MINT13 и сбрасывает M_INT13 — бит 12 регистра IER, запрещая повторный Timer1 и перемешивание стробов DATA/CLOCK; исходную маску восстановит IRET. */ - IER &= (MINT13 & ~M_INT13); + IER &= (MINT13 & ~M_INT13); // Сохраняет только ранее разрешённые источники по таблице TI и запрещает повторный Timer1, чтобы передача DATA/CLOCK завершилась без вложенного вызова. EINT; EDIS; // This is needed to disable write to EALLOW protected registers @@ -61,8 +61,8 @@ interrupt void cpu_timer1_isr_PULT(void) toggle_ONLINE(); - toggle_RES_OUT_1(); // Переключает резервный выход RES_OUT_1 в каждом такте пульта, сохраняя существующую выдачу признака активности обработчика. - toggle_RES_OUT_2(); // Переключает второй резервный выход RES_OUT_2 синхронно с тактом пульта, сохраняя существующее поведение этого режима платы. + toggle_RES_OUT_1(); // Формирует на резервном выходе 1 меандр с частотой READY_FREQ/2 (500 Гц) для контроля работы таймера пульта. + toggle_RES_OUT_2(); // Дублирует переключения таймера на резервном выходе 2 с частотой READY_FREQ/2 (500 Гц) для контроля активности пульта. if(++Lonely > Alone) Lonely = Alone; @@ -75,6 +75,14 @@ interrupt void cpu_timer1_isr_PULT(void) if(++cownt>2) cownt=0; + if(GpioDataRegs.GPADAT.bit.GPIO26) // Единица GPIO26 означает нажатие TESTLAMP, как и бит 4 Inputs; таймер измеряет удержание независимо от загрузки main. + { // Накапливает время текущего нажатия перед включением местного теста ламп. + if(test_lamp_hold_ticks < 2U * (unsigned int)READY_FREQ) // Две секунды при частоте READY_FREQ Гц соответствуют 2000 тикам текущего таймера 1000 Гц. + test_lamp_hold_ticks++; // Добавляет один период таймера (1 мс); после достижения порога счётчик сохраняет значение до отпускания. + } // Завершает обработку удерживаемой кнопки. + else test_lamp_hold_ticks = 0; // При отпускании обнуляет время, чтобы отдельные короткие нажатия не складывались в длинное. + bTestLamp = (test_lamp_hold_ticks >= 2U * (unsigned int)READY_FREQ); // Включает местный тест после 2 с удержания и выключает при отпускании; короткое нажатие остаётся сигналом сброса для основного контроллера. + if(cTestLamp|bTestLamp) { what_is(); diff --git a/Source/Internal/spise2p.c b/Source/Internal/spise2p.c index 8020cda..8c9f370 100644 --- a/Source/Internal/spise2p.c +++ b/Source/Internal/spise2p.c @@ -1,8 +1,8 @@ -/* SPI EEPROM. Seeprom_read/write ðàçáèâàþò çàïðîñ íà ñòðàíèöû - * è ñèíõðîííî æäóò spiSe2pFree. SPI-àâòîìàò ïðîäâèãàåò òàéìåð 2 - * êàæäûå 100 ìêñ. Ïðè çàïðåòå ýòîãî IRQ îæèäàíèå íå çàâåðøèòñÿ. - * Òàéì-àóò â ñòàðîì äðàéâåðå îòñóòñòâóåò. Äèñêðåòû ÑÈÔÓ òåïåðü - * íå çàâèñÿò îò òîãî, çàâåðøèëîñü ëè ýòî îæèäàíèå â main. +/* SPI EEPROM. Seeprom_read/write разбивают запрос на страницы + * и синхронно ждут spiSe2pFree. SPI-автомат продвигает таймер 2 + * каждые 100 мкс. При запрете этого IRQ ожидание не завершится. + * Тайм-аут в старом драйвере отсутствует. Дискреты СИФУ теперь + * не зависят от того, завершилось ли это ожидание в main. */ #include "DSP2833x_Device.h" // DSP2833x Headerfile Include File @@ -25,8 +25,8 @@ int ccc=0; /******* SPI bus Serial EEPROM driver Initialization routine ********/ /********************************************************************/ -/* Áëîêèðóåò main äî çàâåðøåíèÿ ñòðàíèö. Çàïðåò IRQ îñòàíîâèò - * SPI-àâòîìàò. CAN è òàéìåð ÑÈÔÓ äîëæíû ïðåðûâàòü ýòî îæèäàíèå. +/* Блокирует main до завершения страниц. Запрет IRQ остановит + * SPI-автомат. CAN и таймер СИФУ должны прерывать это ожидание. */ void Seeprom_write( unsigned int adres, unsigned int buf[], @@ -59,8 +59,8 @@ void Seeprom_write( unsigned int adres, CpuTimer2Regs.TCR.all = 0x4010; // Use write-only instruction to set TSS bit = 1 } -/* ×òåíèå òàêæå ñèíõðîííîå äëÿ main, òàéì-àóò íå ðåàëèçîâàí. - * Ïðè çàâèñàíèè ïðîâåðèòü step/SPI è ðàáîòó òàéìåðà 2. +/* Чтение также синхронное для main, тайм-аут не реализован. + * При зависании проверить step/SPI и работу таймера 2. */ void Seeprom_read( unsigned int adres, unsigned int buf[], diff --git a/Source/Internal/tools.c b/Source/Internal/tools.c index 71f9ac6..97e1cfb 100644 --- a/Source/Internal/tools.c +++ b/Source/Internal/tools.c @@ -1,7 +1,7 @@ -/* Âíåøíÿÿ ïàìÿòü è ïðîãðàììíûå çàäåðæêè. init_zone7 ãîòîâèò XINTF - * äî ïåðâîãî îáðàùåíèÿ ê .logg; âðåìåíà øèíû çàâèñÿò îò ÷àñòîòû DSP - * è àïïàðàòíîé ïàìÿòè. pause_us çàíèìàåò CPU öèêëîì è èñïîëüçóåòñÿ - * ïðè èíèöèàëèçàöèè. Äëèòåëüíîñòü ÑÈÔÓ äîëæíà çàäàâàòüñÿ òàéìåðîì. +/* Внешняя память и программные задержки. init_zone7 готовит XINTF + * до первого обращения к .logg; времена шины зависят от частоты DSP + * и аппаратной памяти. pause_us занимает CPU циклом и используется + * при инициализации. Длительность СИФУ должна задаваться таймером. */ #include "DSP2833x_Device.h" // DSP281x Headerfile Include File diff --git a/UKSSTMS320F28335/.cproject b/UKSSTMS320F28335/.cproject index 605f09e..e06ac12 100644 --- a/UKSSTMS320F28335/.cproject +++ b/UKSSTMS320F28335/.cproject @@ -13,7 +13,7 @@ - + - @@ -207,7 +210,7 @@ - +