Перейти к содержанию

Как запустить несколько автоматов PIO RP2040 синхронно?

Обновлено Редакция GAW

Синхронные автоматы нужны, когда несколько сигналов должны идти с точным сдвигом друг относительно друга: параллельная шина из нескольких программ, многоканальный ШИМ с заданными фазами, захват данных и тактов разными автоматами. Каждый автомат тактируется своим делителем, и если включать их по очереди, фазы получатся случайными.

Что синхронизирует автоматы

МеханизмГдеЧто делает
Одинаковый делительSMx_CLKDIVодинаковая частота исполнения команд
CLKDIV_RESTARTCTRL, биты 11:8сброс фазы делителей выбранных автоматов в 0
SM_ENABLECTRL, биты 3:0включение автоматов одной записью
SM_RESTARTCTRL, биты 7:4сброс внутреннего состояния, кроме PC, OSR, X, Y

Делитель — дробное число в формате 16.8, и при дробном коэффициенте у каждого автомата есть своё дрожание. Если перезапустить делители с одинаковым коэффициентом одновременно, по даташиту и это дрожание у них совпадает, и автоматы идут строго такт в такт («Джиттер»). Коэффициент для нужной частоты считает калькулятор PIO RP2040.

// Start SM0..SM2 of PIO0 in lockstep (pico-sdk 2.3.1, hardware/pio.h)
for (uint sm = 0; sm < 3; sm++) {
    pio_sm_init(pio0, sm, offset[sm], &cfg[sm]);   // same clkdiv in every cfg
}
pio_enable_sm_mask_in_sync(pio0, 0x7);   // SM_ENABLE + CLKDIV_RESTART in one write

Все три автомата должны быть одного блока: регистр CTRL у PIO0 и PIO1 свой. Если программы разные и не помещаются в 32 команды блока, смотрите ответ «Почему программа PIO не загружается». Основы PIO — на странице PIO RP2040, выводы микросхемы — на странице RP2040.

Похожие вопросы

Синхронны ли автоматы из разных блоков PIO0 и PIO1?

Регистр CTRL у каждого блока свой, поэтому одной записью включить автоматы обоих блоков нельзя. Внутри одного блока синхронный запуск гарантирован механизмом CLKDIV_RESTART; для автоматов разных блоков точное совпадение фаз нужно проверять отдельно.

Можно ли сменить делитель на ходу и не потерять синхронность?

Да: по описанию регистра CTRL биты CLKDIV_RESTART можно записывать, пока автоматы работают, и это предназначено как раз для повторной синхронизации делителей после смены коэффициента SMx_CLKDIV.

Сбрасывает ли перезапуск программу автомата?

CLKDIV_RESTART трогает только делитель. Состояние автомата сбрасывают биты SM_RESTART, но и они не трогают счётчик команд, регистр OSR и регистры X и Y, поэтому начальную точку программы задают отдельно, например командой перехода через pio_sm_exec.

Источники

  1. Raspberry Pi Ltd. RP2040 Datasheet (build 2025-02-20) — разд. 3.7, табл. 368, регистр CTRL: биты 11:8 CLKDIV_RESTART — перезапуск делителя автомата с начальной фазы 0; делители работают свободно, их выход, включая дробное дрожание, определяется только коэффициентом SMx_CLKDIV, поэтому одновременно перезапущенные делители с одинаковым коэффициентом идут строго синхронно; установка и сброс SM_ENABLE не останавливает делитель, синхронность сохраняется; CLKDIV_RESTART можно писать на ходу после смены коэффициента; биты 7:4 SM_RESTART — сброс внутреннего состояния автомата (счётчики сдвига, ISR, счётчик задержки, ожидание IRQ), счётчик команд, OSR и X/Y не сбрасываются; биты 3:0 SM_ENABLE; разд. 3.2: делитель — число 16.8 с дробной частью
  2. Raspberry Pi Ltd. pico-sdk 2.3.1, src/rp2_common/hardware_pio/include/hardware/pio.h — pio_sm_clkdiv_restart(pio, sm) — сброс целой и дробной фаз делителя, вызывается в pio_sm_init(); pio_clkdiv_restart_sm_mask(pio, mask) — одновременный перезапуск делителей нескольких автоматов, при одинаковых делителях они идут детерминированно синхронно; pio_set_sm_mask_enabled(pio, mask, enabled); для синхронного включения рекомендуется pio_enable_sm_mask_in_sync()

Нашли ошибку?