Я всё-таки буду делать проект в режиме блога. Если кто только учится, то, возможно, это поможет двинуться дальше, а тот, кто ещё не знает ничего о STM32L, может быть, заинтересуется и увлечётся. Если кто-то проходил этот этап тысячу раз, то, надеюсь, тоже поучаствует, поделится опытом и поможет мне избежать pitfalls, которые гарантированны в процессе при создании проекта.
Итак, синхронизация готова. Теперь на неё надо накладывать обработку. Ресурсов у нас не так уж и много. Например, имея 32 mHz CPU при частоте передатчика Tx = 6 kHz у нас на всё про всё есть 5333 цикла. Если за один период мы хотим обработать 16 отсчётов, то на один отсчёт у нас остаётся всего 333 цикла. Не особенно разбежишься, но мы не обрабатываем каждый отсчёт в отдельности. Мы накапливаем 16 отсчётов на одном периоде, а затем выполняем функцию синхронного детектирования.
То, что у меня получилось, я изобразил на графике снизу.
Сигнал Tx выводится наружу для питания катушки. Точка отсчёта фазы Tx_ph0 находится посередине импульса. Ширина и частота следования импульсов может изменятся независимо. При настройке частота выводится на дисплей в кГц, а длина импульса в наносекундах.
Начальная фаза Rx сдвинута относительно Tx на величину Ph для компенсации сдвига н аредусилителе и на др. элементах. Величина Ph меняется о 0 до 360 (считая от Tx_ph0) и отражается на дисплее в градусах. При изменении частоты следования Tx импульсов абсолютная величина в счётчиках корректируется так, чтобы Ph не изменялось.
На рисунке восклицательными знаками показаны моменты синхронизации счётчиков.
АЦП начинает генерацию отсчётов по фронту счётчика S. Сам АЦП засинхронизирован отдельным генератором частотой порядка 16 мГц. По окончании генерации отсчёт копируется в память с помощью DMA. После этого контроллер DMA генерирует прерывание, в котором а) отсчёт копируется по в массив по индексу Sidx для обработки б) Индекс Sidx шнкрементируется.
Обратите внимание, что счётчик отсчётов S, который инициализирует работу АЦП, засинхронизирован по фронту Rx. Это важно, т.к. этот фронт генерирует прерывание RXint (само прерывание начинается с небольшой задержкой порядка 2 мкс), внутри которого происходит обработка отсчётов. Отсчёт, который попал на начало этого прерывания, становится первым в группе (имеется в виду отсчёт, который генерируется АЦП в данный момент). Если граница отсчётов будет "гулять" относительно начала RXint, то сигнал на выходе синхронного детектора будет "скакать". Я проверил по осциллографу, что начало прерывания находится примерно в середине между моментами обновления отсчёчтов.
Понятно, что обработку надо закончить до начала поступления нового запроса на прерывание RXint. программа обработки получилась довольно короткой.
Код:
!<--- момент перезагрузки счётчика Tx
!
! !<--- Tx_ph0 (отсчёт фазы Tx) !<----
!_____!_____ _____!_____
Tx: __| ! |___________________________________________________| ! |___________
!<-- Wtx -->! ! ! !
! !<---------------------------- Ptx ---------------------------->! !
! ! ! ! ! !
! !<- Ph -->!<--- Rx_ph0 = Tx_ph0 + Ph (отсчёт фазы Rx) ! !<----
__! ! !_______________________________________________! ! !_____
Rx: |_______________| |_______________|
! !
_ _ _ _ !_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ !_ _
S: _| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_
! !
DMAint |___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|_
Sidx C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1
! _________________________________________________ ! _______
RXint: __________________| |_____________|
!<------------------ обработка ------------------>!
-------- N -1 --->!<---------------------- N ----------------------->!<- N+1
Кстати, немного о настройке. Чтобы "увидеть" все интересующие меня сигналы, я вывожу их на внешние порты. К сожалению, в этом конкретном устройстве практически все порты заняты дебильным дисплеем на 6 знакомест. В будущем надо будет его выкинуть и подключить что-то более разумное. Заодно, освободить массу портов. К счастью, он не запаян.
P.S. Теперь паяем...