Автоматы PIO в RP2040 и RP2350 работают от системной частоты clk_sys, но у каждого есть свой делитель: он не замедляет системный такт, а разрешает автомату делать шаг только в части тактов (даташит RP2040, разд. 3.5.5). Как устроены сами автоматы и их команды — в статье «PIO в RP2040».
Формула
Программа PIO выполняется с известным числом тактов: каждая команда — один такт плюс задержка в квадратных скобках, переход по .wrap тактов не тратит. Если один бит или один период сигнала занимает N тактов автомата, частота программы
Делитель D записывается в регистр SMx_CLKDIV: 16 бит целой части INT и 8 бит дробной FRAC, то есть от 1 до 65536 с шагом 1/256. Значение INT = 0 означает 65536, и FRAC тогда тоже должен быть нулём. В регистре INT стоит в битах 31…16, FRAC — в битах 15…8.
Как округляет pico-sdk
Функция sm_config_set_clkdiv() принимает делитель числом с плавающей точкой и переводит его в INT и FRAC функцией pio_calculate_clkdiv8_from_float. В pico-sdk 2.1.1 по умолчанию включено округление до ближайшей 1/256 (PICO_PIO_CLKDIV_ROUND_NEAREST): к делителю прибавляется 0,5/256, а затем дробная часть отбрасывается. Если собрать SDK с PICO_PIO_CLKDIV_ROUND_NEAREST=0, дробная часть округляется вниз — калькулятор считает оба варианта. Например, для UART 9600 бод при 125 МГц нужен делитель 1627,6042: с округлением FRAC = 155, без него — 154.
Системная частота по умолчанию в pico-sdk 2.1.1 — 125 МГц у RP2040 и 150 МГц у RP2350; с опцией PICO_USE_FASTEST_SUPPORTED_CLOCK RP2040 работает на 200 МГц. При другой частоте все делители надо пересчитать — поэтому в примерах Raspberry Pi делитель вычисляют в программе через clock_get_hz(clk_sys).
Примеры
| Программа | Тактов на бит или период | Частота | Делитель при 125 МГц |
|---|---|---|---|
| Меандр из даташита RP2040 | 4 | 12,5 МГц | 2,5 — INT 2, FRAC 128, регистр 0x00028000 |
| WS2812 из pico-examples | 10 (3 + 3 + 4) | 800 кГц | 15,625 — INT 15, FRAC 160 |
| UART из pico-examples | 8 | 115 200 бод | 135,633 — INT 135, FRAC 162 |
Для WS2812 при 150 МГц у RP2350 делитель другой — 18,75, то есть INT 18 и FRAC 192.
Дробный делитель и дрожание
По даташиту дробная часть реализована дельта-сигма-модулятором: часть периодов делителя длится n тактов системы, часть — n + 1, и только в среднем получается заданное значение. В примере даташита с делителем 2,5 такты автомата идут через 2 и 3 такта clk_sys по очереди. Поэтому края сигнала дрожат на один период clk_sys — 8 нс при 125 МГц. Для UART такое дрожание несущественно: приёмник из pico-examples считывает каждый бит в его середине, на 8 тактах автомата от края. Для тактовых сигналов, видео и других мест, где важна форма каждого периода, подбирают целый делитель — меняя число тактов на бит задержками в программе или системную частоту.
Если частота слишком высока и делитель получается меньше 1, программу нужно сократить в тактах; если слишком низка и делитель больше 65536 — добавить задержки или цикл. Аппаратный ШИМ RP2040 с делителем 8.4 считает калькулятор ШИМ RP2040, выводы платы — в статье о Raspberry Pi Pico.
Частые вопросы
Как рассчитать делитель PIO для нужной частоты?
Посчитать, сколько тактов автомата занимает один бит или период программы, с учётом задержек [n] в командах, и поделить системную частоту на произведение частоты и этого числа тактов. Например, программа WS2812 из pico-examples тратит 10 тактов на бит: 125 МГц / (800 кГц · 10) = 15,625. Делитель записывается как INT = 15 и FRAC = 0,625 · 256 = 160.
Какой делитель нужен для UART 115 200 бод на PIO?
Программы UART из pico-examples тратят 8 тактов на бит, поэтому делитель — 125 МГц / (8 · 115 200) ≈ 135,634. С шагом 1/256 pico-sdk запишет INT = 135, FRAC = 162, и скорость получится 115 200,74 бод — ошибка меньше тысячной процента.
Почему дробный делитель PIO даёт дрожание?
По даташиту RP2040 дробный делитель работает как дельта-сигма: часть периодов длится n тактов системы, часть — n + 1, и только в среднем получается нужное значение. При делителе 2,5 такты автомата идут через 2 и 3 такта clk_sys по очереди. Для UART это незаметно, а для тактового сигнала или видео лучше подобрать целый делитель.
Какой наибольший делитель у PIO?
65536: в поле INT регистра SMx_CLKDIV 16 бит, и значение 0 по даташиту означает 65536, а дробная часть тогда должна быть нулевой. При 125 МГц и одном такте на период это около 1907 Гц; для более низких частот в программу добавляют задержки или цикл со счётчиком.
Источники
- Raspberry Pi. RP2040 Datasheet (build 2025-02-20) — 3.5.5 — делитель 16 + 8 бит с дельта-сигма для дробной части, от 1 до 65536 с шагом 1/256; при дробном делителе часть периодов удлиняется с n до n + 1 тактов системы; таблица 381 (SMx_CLKDIV) — частота = clk_sys / (INT + FRAC/256), INT = 0 означает 65536, тогда и FRAC = 0; разд. 3.2 — меандр из 4 тактов с делителем 2,5 (запись 2,5 · 2^16) даёт 12,5 МГц (эталон тестов); UART на PIO — делитель на 8 скоростей передачи; WS2812 — T1 + T2 + T3 = 3 + 3 + 4 такта на бит
- Raspberry Pi. pico-sdk 2.1.1: hardware/pio.h, pico/platform.h, hardware/platform_defs.h — pio_calculate_clkdiv8_from_float: делитель от 1 до 65536; при PICO_PIO_CLKDIV_ROUND_NEAREST (по умолчанию 1) прибавляется 0,5/256, затем INT — целая часть, FRAC — дробная · 256 с отбрасыванием; sm_config_set_clkdiv_int_frac8; clk_sys по умолчанию 125 МГц у RP2040 (200 МГц с PICO_USE_FASTEST_SUPPORTED_CLOCK) и 150 МГц у RP2350; лицензия BSD-3-Clause
- Raspberry Pi. pico-examples (sdk-2.1.1): pio/ws2812, pio/uart_tx, pio/uart_rx — делитель = clock_get_hz(clk_sys) / (частота · тактов на бит); WS2812 — 10 тактов на бит, 800 кГц (второй источник тестов); UART — 8 тактов на бит
- Raspberry Pi. RP2350 Datasheet — 11.5.5 и регистр SMx_CLKDIV — тот же делитель 16.8, INT = 0 означает 65536
Встроить калькулятор на свой сайт
Скопируйте код и вставьте его в HTML страницы, статьи или вики. Виджет бесплатный, без рекламы, счётчиков и cookie. Условие одно — ссылка на GAW под рамкой остаётся на месте. Подробнее о виджетах
<iframe src="https://gaw.ru/embed/rp2040-pio/" title="Калькулятор делителя PIO RP2040 и RP2350" width="100%" height="640" style="border:1px solid #e3e5e9;border-radius:8px" loading="lazy" allow="clipboard-write"></iframe>
<p style="margin:6px 0 0;font-size:14px">Калькулятор: <a href="https://gaw.ru/tools/rp2040-pio/">Калькулятор делителя PIO RP2040 и RP2350</a> — GAW.ru</p>Автоподстройка высоты рамки
Если сайт разрешает скрипты, добавьте этот код один раз в любом месте страницы: рамка будет менять высоту вместе с результатом расчёта.
<script>window.addEventListener("message",function(e){if(e.origin!=="https://gaw.ru"||!e.data||e.data.type!=="gaw:embed-height")return;var f=document.querySelectorAll('iframe[src^="https://gaw.ru/embed/"]');for(var i=0;i<f.length;i++)if(f[i].contentWindow===e.source)f[i].style.height=e.data.height+"px"})</script>Обновлено .
Нашли ошибку в расчёте?