/* Подключается только из DAC.c; в host-тесте — с подменой GPIO/IRQ. */ #ifndef UMP_CONTROL_IMPL_H #define UMP_CONTROL_IMPL_H /* Аппаратная обёртка автомата. Храним её в существующем 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(); if (ump_pulse.output == UMP_PULSE_STOP) set_STOP_DPTB(); } if (previous_relay != ump_pulse.relay) { if (ump_pulse.relay) set_RES_OUT_2(); else clear_RES_OUT_2(); } /* Старое имя оставлено для протокола логгера. Это теперь отражение * таймера автомата, а не переменная, которую одновременно правит main. */ IMPowse = ump_pulse.remaining; } void UMP_pulse_init(void) { unsigned int saved = __disable_interrupts(); if (Desk == dsk_LOAD) { 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); } void UMP_commands_write(unsigned int commands) { unsigned int saved = __disable_interrupts(); unsigned int output = ump_pulse.output, relay = ump_pulse.relay; Commands = commands; if (Desk == dsk_LOAD && ump_pulse_enabled) { /* Выполняем фронт в момент принятия слова. Нет очереди, которую * main должен опросить после длительного обращения к EEPROM. * Здесь только несколько операций с памятью/GPIO, без ожиданий. */ ump_pulse_accept(&ump_pulse, commands, (unsigned int)READY_FREQ); UMP_apply_outputs(output, relay); } __restore_interrupts(saved); } void UMP_pulse_tick(void) { unsigned int saved = __disable_interrupts(); unsigned int output = ump_pulse.output, relay = ump_pulse.relay; if (Desk == dsk_LOAD && ump_pulse_enabled) { ump_pulse_tick(&ump_pulse); UMP_apply_outputs(output, relay); } __restore_interrupts(saved); } void UMP_reset_parameter_commands(void) { unsigned int saved = __disable_interrupts(); /* EEPROM содержит параметры, но не является источником команд пуска. * Сохраняем последние принятые START/STOP и историю фронтов автомата. * Нельзя обнулить их при Load/Default: таймер ЦАП читает тот же уровень, * а следующий повтор пакета с единицей не должен стать ложным фронтом. * Другие режимы платы сохраняют прежнее поведение полного сброса. */ if (Desk == dsk_LOAD) Commands &= UMP_START_MASK | UMP_STOP_MASK; else Commands = 0; __restore_interrupts(saved); } #endif