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

Почему программа PIO на RP2040 не загружается: не хватает места?

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

Блок PIO в RP2040 — четыре автомата и общая память программ на 32 команды. Блоков два, PIO0 и PIO1, и каждый со своей памятью. Если несколько библиотек — например, для WS2812, I2S и UART — грузят свои программы в один блок, место заканчивается быстро. Общее устройство — на странице PIO RP2040.

Сколько места

РесурсRP2040
Блоков PIO2
Автоматов в блоке4
Память команд блока32 команды, общая для 4 автоматов
Всего команд64 (наш расчёт: 2 × 32)
Поле адреса JMP5 бит — адреса 0–31

Как загружать без ошибок

// Pick a PIO block that still has room (pico-sdk 2.3.1, hardware/pio.h)
PIO pio = pio0;
if (!pio_can_add_program(pio, &uart_tx_program)) pio = pio1;
int offset = pio_add_program(pio, &uart_tx_program);
if (offset < 0) { /* no room in either block */ }

Программа с директивой .origin загружается только по указанному адресу — обычно 0. Две такие программы в один блок не поместятся, даже если команд в них немного; их разносят по разным блокам. Перемещаемые программы (origin = −1) SDK кладёт в любое свободное место. Ненужную программу освобождают функцией pio_remove_program.

Как сделать программу короче

Что такое программируемый ввод-вывод в целом, описано в термине «PIO», а отличия следующего поколения — на странице RP2350.

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

Можно ли запустить одну программу на нескольких автоматах?

Да, и памяти это не прибавит: программу загружают один раз, а несколько автоматов того же блока запускают с одного смещения, каждый со своей конфигурацией выводов и делителя. Так даташит предлагает делать, например, несколько передатчиков UART.

Как сэкономить команды в программе PIO?

Использовать .wrap вместо JMP в начало цикла, задержки [n] вместо пустых команд, side-set вместо отдельных SET для тактового вывода и autopull или autopush вместо явных PULL и PUSH. Каждый из этих приёмов по даташиту RP2040 убирает по команде из цикла.

Почему программа с .origin 0 не загружается, хотя свободных команд хватает?

Директива .origin требует загрузки строго по указанному адресу, обычно 0, а он уже занят другой программой. По даташиту RP2040 так делают программы с переходами по данным, у которых адрес перехода хранится в нескольких битах. Такую программу загружают первой или переносят в другой блок PIO.

Источники

  1. Raspberry Pi Ltd. RP2040 Datasheet (build 2025-02-20) — разд. 3.1: два блока PIO по четыре автомата; разд. 3.2: четыре автомата исполняют программы из общей памяти команд, система имеет к ней доступ только на запись, в примере — 32 слота на экземпляр PIO; разд. 3.3.1: директива .origin задаёт смещение загрузки — обычно 0 для программ, которые используют переходы по данным с абсолютным адресом в нескольких битах; разд. 3.4.2: поле адреса JMP — 5 бит; разд. 3.5.4: autopush и autopull избавляют от отдельных PUSH и PULL; разд. 3.5.2: .wrap и .wrap_target — переход в начало цикла без команды JMP
  2. Raspberry Pi Ltd. pico-sdk 2.3.1, src/rp2_common/hardware_pio/include/hardware/pio.h — pio_program_t.origin — требуемое смещение или −1 для перемещаемой программы; pio_can_add_program(pio, program) и pio_can_add_program_at_offset(); pio_add_program() возвращает смещение загрузки или отрицательное значение при ошибке (−1, PICO_ERROR_GENERIC); pio_remove_program() освобождает место; PIO_INSTRUCTION_COUNT — размер памяти команд

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