А если мы хотим сгенерировать частоту 1 МГц?
Нужно вводить большие задержки или указывать другую тактовую частоту.
В каких пределах можно задать тактовую частоту?
Внутри каждой стейт-машины стоит 24-битный делитель, который разделён на две части:
16 бит — целая часть (от 1 до 65535).
8 бит — дробная часть (шагами по 1/256).
На самом деле физически невозможно разделить один такт системной шины на «четвертинки». Делитель хитрит: он использует джиттер (дрожание фазы).
Если вы задали делитель 1.5, PIO будет чередовать такты: один такт он «спит» 1 системный цикл, а следующий — 2 системных цикла. В среднем за большой промежуток времени получится ровно 1.5, и частота будет соответствовать заданной.
Например, для качественного звука нужна частота дискретизации 44100 Гц.
С учетом всех тактов PIO, вам может понадобиться частота шины PIO, например, 11.2896 МГц.
125 МГц / 11,2896 МГц = 11,0721372
Благодаря 8-битной дробной части, можно установить ближайшее значение (например, 11 + 18/256 = 11,0703125)
125 МГц / 11,0703125 = 11,2915 МГц
и ошибка в частоте звука будет ничтожной (11,2915*100/11,2896 = 100,017%).
Поскольку дробный делитель работает через чередование длительности тактов, на высоких частотах это может создать «некрасивый» сигнал - импульсы меандра будут иметь разную длину (один чуть короче, другой чуть длиннее).
Максимальный коэффициент деления 16-битного делителя - 65536.
При системной частоте 125 МГц минимальная частота PIO составит: 125000000 / 65536 = 1907,35 Гц.
Задавая тактовую частоту PIO, число должно быть целым: В Python пишите 125_000_000 или 125000000.
Вернёмся к генерации частоты в 1 МГц.
Код:
# код CircuitPython
# генератор меандра 1 MГц на пине 15
# с использованием PIO
import board
import rp2pio
import adafruit_pioasm
# 1 такт на включение + 31 такт задержки
# 1 такт на выключение + 31 такт задержки
# Итого 64 такта на полный цикл
pio_code = """
.program square_wave
.wrap_target
set pins, 1 [31]
set pins, 0 [31]
.wrap
"""
assembled = adafruit_pioasm.assemble(pio_code)
# Настройка: 1000000 Гц * 64 такта = 64 000 000 Гц
sm = rp2pio.StateMachine(
assembled,
frequency=64_000_000,
first_set_pin=board.GP15,
set_pin_count=1
)
print("Генератор 1 МГц запущен на GP15")
while True:
pass
.
Вложение:
code08.rar [545 байт]
4 скачивания
.
Разберём особенности кода.
У нас одна команда стейт-машины занимает 16 бит, хотя ассемблерных команд для неё всего девять: JMP, WAIT, IN, OUT, PUSH, PULL, MOV, IRQ и SET.
Остальные биты тоже значащие:
3 бита: Код самой операции,
5 бит: Поле Delay/Side-set,
8 бит: Специфические данные операции (куда записать, что сравнить).
Мы можем использовать поле Delay/Side-set для задержки или для управления дополнительными пинами.
Всего 5 бит позволяют задать число от 0 до 31.
Существует три основных сценария настройки:
- Только Delay (5:0): Все 5 бит используются для задержки. Вы можете ждать от 0 до 31 такта после выполнения команды.
- Только Side-set (0:5): Все 5 бит управляют дополнительными пинами (до 5 штук). Задержки нет (0 тактов).
- Смешанный режим (например, 3:2): 3 бита под задержку (0–7 тактов) и 2 бита под управление двумя Side-set пинами.
У нас используется только задержка - к каждому такту установки/сброса добавляем задержки на 31 такт.
Выбираем тактовую частоту PIO 64 МГц и задержку в 64 такта (1+31+1+31)
64 МГц / 64 = 1 МГц.
Вложение:
06 частота.png [ 1.75 МБ | 172 просмотра ]
.
Вложение:
07 форма.png [ 338.8 КБ | 172 просмотра ]