Files
Balsam_167/Source/Internal/Include/ump_pulse.h
T
Andrey 31f92e89d9 Обновить сборку прошивки 166, TESTLAMP и кодировку исходников
Перенести настройки выпуска в JSON, добавить переносимый сценарий сборки и проверки BIN. Обновить конфигурации CCS, исходники в UTF-8, обработку TESTLAMP, образы прошивки и регрессионные проверки.
2026-10-17 14:36:59 +03:00

70 lines
3.6 KiB
C

/* Управление импульсами СИФУ. Чистый автомат без доступа к GPIO.
* Один и тот же код используется прошивкой и host-тестом.
* ВАЖНО: вызывающая сторона сериализует init/accept/tick запретом IRQ.
* volatile обеспечивает обращения к общему состоянию, но не заменяет
* критическую секцию: обновление нескольких полей не является атомарным.
*/
#ifndef UMP_PULSE_H
#define UMP_PULSE_H
#define UMP_START_MASK 0x0080U
#define UMP_STOP_MASK 0x0040U
#define UMP_PULSE_NONE 0U
#define UMP_PULSE_START 1U
#define UMP_PULSE_STOP 2U
typedef struct {
unsigned int previous;
unsigned int remaining;
unsigned int output;
unsigned int relay;
} UMP_PULSE_STATE;
static void ump_pulse_init(volatile UMP_PULSE_STATE *s, unsigned int commands)
{
/* Уже активная команда при окончании загрузки не является новым пуском.
* Снимаем физические выходы отдельно в аппаратной обёртке.
* Если начальное слово нулевое, первая свежая единица будет принята:
* больше не нужен случайный проход main, успевший прочитать ноль. */
s->previous = commands;
s->remaining = 0;
s->output = UMP_PULSE_NONE;
s->relay = 0;
}
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 замечается.
* Повторные пакеты с удерживаемой единицей не продлевают импульс. */
s->previous = commands;
if (commands & UMP_STOP_MASK) {
/* 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 продлевает существующий импульс,
* как раньше; отдельный электрический фронт здесь не обещается. */
s->output = UMP_PULSE_START;
s->remaining = ticks;
s->relay = 1;
}
}
static void ump_pulse_tick(volatile UMP_PULSE_STATE *s)
{
/* Единственный владелец отсчёта — таймер 1 кГц. main не участвует
* в завершении импульса, поэтому EEPROM не растягивает его.
* RES_OUT_2 сохраняет последнее состояние после конца импульса. */
if (s->remaining && --s->remaining == 0)
s->output = UMP_PULSE_NONE;
}
#endif