Задать вопрос
seeklay1337
@seeklay1337

Как посчитать частоту внешнего сигнала в тактах на RP2040?

Код MicroPython

import rp2
from machine import Pin
import time

PIN_NUM = 6
INITIAL = 0xFFFFFFFF  # стартовое значение для счетчика

@rp2.asm_pio()
def freq_counter():
    pull()                  # берём INITIAL из TX-FIFO
    mov(y, osr)            # заполняем У чтобы не дергать фифо каждый раз
    wrap_target() # переходим в основной цикл 
    mov(x, y) # заполняем Х для вычитания из него кол-ва тактов прошедших за момент низкого уровня
    wait(1, pin, 0)         # ждём первого фронта
    wait(0, pin, 0)         # ждём первого спада
    label("count_loop")
    jmp(pin, "done")        # если фронт — выходим
    jmp(x_dec, "count_loop") # иначе декремент X, и назад (считаем сколько тактов сигнал был в 0)
    label("done")
    mov(isr, x)             # сохраняем остаток в ISR
    push()                  # отправляем в RX-FIFO
    wrap()

sm = rp2.StateMachine(
    0, freq_counter,
    freq=100_000_000,       # скорость ПИО = 100 МГц
    in_base=Pin(PIN_NUM),
    jmp_pin=Pin(PIN_NUM)
)
sm.put(INITIAL)         # даём INITIAL
sm.active(1)

while True:
    while not sm.rx_fifo(): # ждём, когда PIO пульнет результат
        pass
    ticks = INITIAL - sm.get()        # читаем число тактов
    freq = 100_000_000 // ticks if ticks else 0
    print(f"Частота: {freq / 1000000:.3f} МГц, Такты: {ticks}")
    time.sleep(0.2)


При этом, скорее всего, часть тактов занимаемых инструкциям подсчета не учитывается.
Как учесть эту погрешность, т.к сейчас при стабильном клоке в 1мгц на входе частота подсчитывается под 3мгц.
Если на входе 8 МГц, то вообще не удаётся считать — вывода нет, хотя запас должен быть, и даже большой: ведь частота дискретизируемого сигнала как минимум в 5 раз меньше частоты дискретизации, чего должно хватать.
  • Вопрос задан
  • 41 просмотр
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 1
15432
@15432
Системный программист ^_^
Рекомендую не выставлять делитель для PIO, а менять системную частоту. По умолчанию система работает на 125 МГц, с этой же частотой будет работать и PIO, если ничего не менять. При необходимости RP2040 гонится где-то до 360 МГц, но больше 200 МГц я б не рекомендовал ставить. RP2350 уже получше гонится, мой текущий проект на 600 МГц бегает.

Ваш подсчет не очень корректный, поскольку замеряет длительность клока "в нуле". Из-за согласования уровней и передачи сигнала, может оказаться, что "в нуле" сигнал проводит больше времени, чем "в единице", поэтому надёжнее делать замер между двумя фронтами.

Также замер будет не сильно точный из-за плавающей частоты PIO (125 системных МГц не делится нацело на 100 МГц, которые вы поставили для PIO, если питоновский API вообще задаёт дробную часть делителя, надо уточнить). Рекомендую не задавать конкретную частоту вовсе и исходить из clk_sys при расчетах.

Тем не менее, в цикле у вас две инструкции, при 100 МГц, выполнение каждой из них занимает один такт, но замеряете вы полупериод, поэтому надо 100_000_000 / (4 * ticks) считать. (Насчитывает вдвое меньше 100мгц поскольку две инструкции, и ещё вдвое меньше потому что полупериод)

Ещё из рекомендаций - можно включить autopull / autopush и вместо pull / mov делать out y, 32 и in x, 32. Сейчас вы не столкнулись с ограничением в 32 опкода, но в дальнейшем это может вызвать проблемы

Почему на 8 МГц не хватает - тут не слишком ясно, осциллографом бы посмотреть. Возможно генератор сигнала даёт такой логический уровень, который rp2040 не воспринимает как логическую единицу, должно работать. Но можете попробовать включить на входе pull_up (мне помогало хватать и 1.8в уровни), отключить или добавить логические драйверы (set_drive_strength на 2ma или 12ma), тоже влияет. Ну или добавить перед RPi транслятор логических уровней (рублей 50 на Али восьмиканальный level shifter от texas)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

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