Фронты START/STOP обрабатываются при принятии командного слова CAN/RS, а окончание импульса обслуживается таймером. STOP имеет приоритет, перекрытие выходов исключено, сохранена защита от самопуска при включении. Загрузка параметров больше не подменяет живые команды нагрузки. Добавлены подробные русские комментарии во все собственные C-модули и основные заголовки, описание поведения и host-тест автомата. Обновлены файлы прошивки. Полная сборка TI 22.6.1.LTS и тесты пройдены; проверка на физической плате не выполнялась.
11 KiB
Слабые места обработки START/STOP
Исторический анализ до переноса обработки в приём команды и таймер. Текущее поведение, исправления и оставшиеся ограничения описаны в SIFU_START_STOP.md.
Дата: 22.09.2026. Проверен код проекта 166 после переноса исправления
из коммита 799e6ba проекта 167. Документ описывает результаты просмотра
кода; сценарии на устройстве не воспроизводились. Предлагаемые ниже
изменения не внесены.
Что исправлено переносом
В Source/Internal/main.c:166 команды копируются в локальные
umpstart и umpstop. Проверка фронта и сохранение предыдущего состояния
используют одну копию каждой команды за проход основного цикла.
Раньше команда читалась дважды. При обновлении из CAN-прерывания между
проверкой и сохранением состояния переход 0 → 1 мог быть пропущен:
проверка видела 0, а предыдущее состояние уже сохранялось как 1.
Перенос устраняет эту ошибку на уровне алгоритма, но не обеспечивает
накопление событий и не решает остальные вопросы доступа из прерываний.
1. Команда может целиком пройти между опросами
Код: Source/Internal/main.c:166, Source/Internal/ecan.c:211.
CAN-приём записывает текущее значение в modbus. Основной цикл проверяет
только последнее состояние. Если до следующего опроса придут включение
и выключение команды (0 → 1 → 0), цикл увидит 0 и не выдаст импульс.
Локальная копия этот случай не закрывает.
Когда существенно: если отправитель не гарантирует достаточное время удержания команды или основной цикл задерживается.
Возможное исправление: фиксировать фронт при приёме команды и хранить событие до обработки. Передача и сброс такого события должны быть согласованы с прерыванием. Если важен каждый повторный фронт, одного флага недостаточно: нужен счётчик либо очередь. Альтернатива — протокол с подтверждением обработки.
2. START и STOP могут быть активны одновременно
Код: Source/Internal/main.c:169–183.
Для START и STOP используются два независимых if. Каждый включает
свой выход, не снимая противоположный. Оба выхода сбрасываются только
после обнуления общего IMPowse.
Возможны два сценария:
- Одновременно обнаружены оба фронта: включаются оба выхода. Значение
RES_OUT_2в итоге соответствует STOP, поскольку его обработка идёт второй. - STOP приходит во время активного START: включается STOP, START остаётся включённым, общий таймер запускается заново. Импульс START удлиняется. Аналогичное перекрытие возможно при обратном порядке команд.
Возможное исправление: определить по требованиям СИФУ приоритет команд, допустимость перекрытия и поведение повторной команды. Затем реализовать переключение состояний либо отдельные таймеры. Выбирать приоритет STOP без подтверждённых требований к устройству нельзя.
3. Длительность импульса зависит от основного цикла
Код: Source/Internal/DAC.c:107, Source/Internal/main.c:183.
Счётчик IMPowse уменьшается в Load_runner(), вызываемом из обработчика
таймера (Source/Internal/measure.c:137). Однако физические выходы
сбрасываются в основном цикле, когда он обнаруживает нулевой счётчик.
Если цикл задержался, счётчик уже может быть равен нулю, а выход остаётся
активным. Перед проверкой команд выполняются, в частности, сохранение
и загрузка параметров, расчёт коэффициентов. Время их выполнения в этой
проверке не измерялось. Сброс также расположен внутри условия
Desk == dsk_LOAD; если допускается смена режима во время импульса,
нужен явный сброс при выходе из режима.
Возможное исправление: завершать импульс в обработчике таймера либо аппаратно. При этом запуск и завершение должны быть синхронизированы, чтобы обработчик не снял только что запущенный импульс.
4. Данные, общие с прерываниями, не имеют volatile
Код:
Source/Internal/message.c:21—int modbus[ANSWER_LEN+1].Source/Internal/Include/message.h:31— объявление массива.Source/Internal/Include/package.h:58—Modbusприводится кWORDE *.Source/Internal/DAC.c:21иSource/Internal/Include/DAC.h:6—IMPowse.
Команды изменяются в CAN-прерывании и читаются основным циклом.
IMPowse записывается основным циклом и уменьшается обработчиком таймера.
Обычные обращения к памяти не описывают компилятору асинхронное изменение
этих объектов. Конкретное проявление зависит от оптимизации и машинного
кода; сбой из-за этого в ходе проверки не подтверждён.
Возможное исправление: согласовать volatile в определениях,
объявлениях и указателях доступа. Изменение только массива недостаточно,
если макрос Modbus продолжит обращаться через WORDE * без volatile.
Потребуется проверить и функции, которым передаётся массив.
volatile не делает последовательность операций атомарной и не заменяет
синхронизацию. Для общего счётчика отдельно нужно проверить машинные
инструкции доступа и допустимые точки прерывания.
5. START и STOP не образуют согласованный снимок
Код: Source/Internal/main.c:166–167,
Source/Internal/Include/package.h:134.
Обе команды находятся в одном слове Commands, но читаются двумя
выражениями. Если CAN обновит слово между ними, umpstart может относиться
к старому состоянию, а umpstop — к новому. Например, при смене START на
STOP локальные копии могут содержать две единицы, хотя ни одно полученное
слово не содержало их одновременно. Фактическое число чтений памяти
зависит от сгенерированного кода.
Возможное исправление: один раз прочитать всё слово команд через
корректный volatile-доступ, затем выделить биты START и STOP из локальной
копии. Это согласует снимок, но не решает потерю коротких событий.
Дополнительное замечание только к проекту 167
В ../167/Source/Internal/DAC.c:139 обнаружена вероятная опечатка:
if(dac_stop > 16) dac_go = 16;
По соседним ограничениям ожидается присваивание dac_stop = 16.
Сейчас превышение конечного значения меняет начальное, а следующая
проверка может дополнительно изменить конечное значение.
Этот участок отсутствует в текущем коде 166 и не перенесён вместе с
799e6ba. Он не относится к изменениям рассматриваемого коммита.
Порядок дальнейших действий
- Согласовать доступ к общим данным и чтение одного слова команд.
- Определить требования к удержанию команд, повторным фронтам и одновременным START/STOP.
- По этим требованиям выбрать фиксацию событий и управление выходами.
- Проверить на стенде короткую команду, смену START на STOP, оба фронта одновременно, повторную команду до завершения импульса и задержку основного цикла. Измерить длительность и перекрытие выходных импульсов.
Успешная сборка подтверждает собираемость перенесённого исправления, но не проверяет перечисленные временные сценарии.