Джи́ттер — фазовое дрожание цифрового сигнала данных нежелательные фазовые или частотные отклонения передаваемого сигнала. Большое его значение сильно искажает принимаемый сигнал, а точнее уменьшает соотношение сигнал-шум. И с увеличением частоты влияние джиттера становится всё более заметным.
Если кратко, джиттер это когда переход между логическими состояниями тактового сигнала происходит через рваные промежутки времени, хоть и сохраняет при этом частоту.
Это приводит к тому, что выборки из АЦП происходят раньше или позже необходимого времени, и чем этот разброс больше, тем хуже.
Джиттер измеряется в пикосекундах (плохие значения) и фемтосекундах (хорошие значения).
В текущей реализации трансивера основным источником джиттера являются:
1. низкое качество кварцевого генератора
2. отсутствие синхронизатора тактового сигнала вроде микросхемы MC10EL32 или подобной, вот тут замечательная статья http://www.russianelectronics.ru/leader-r/review/2190/doc/48469/
3. использование FPGA в процессе передачи тактового сигнала — идеально, когда АЦП подключен к генератору напрямую.
4. использование PLL блоков в FPGA — в микросхемах семейства Cyclone IV джиттер может доходить до 600пикосекунд!
В этой статье опишем как побороть проблему 3 и 4 (первые 2 потребуют нового генератора на 48мгц, которого у меня нет, либо нового АЦП под мой генератор в 96мгц). А также опишем общие понятия, как перестроить систему под любую тактовую частоту.
Подаём на АПЦ сигнал напрямую с генератора, его частота не должна превышать максимальную частоту АЦП. Для меня это будут 50мгц генератор от FPGA и 65msps АЦП.
Далее в Quartus удаляем выходы ADC_CLK / DAC_CLK, они нам больше не нужны.
Сейчас тактование всей логики FPGA происходит через PLL модуль, который снижает частоту с 50мгц до 48мгц, будем использовать 50мгц напрямую, т.к. частота смесителей, NCO генератора и CIC фильтров должна соответствовать АЦП.
Перестраиваем NCO на новую частоту.
Рассчитываем коэффициенты децимации CIC фильтра, наша задача получить максимально приближенную к 48кгц частоту дискретизации на выходе к STM32. Для этого я подготовил XLS файл (лежит в папке со схемой в прошивке).
Обновляем параметры CIC фильтра RX и TX части.
Рассчитываем новый CIC компенсатор в MatLab.
Устанавливаем название, коэффициент децимации (для RX) или интерполяции (для TX), указываем параметры нашего CIC фильтра и границу среза.
Устанавливаем разрядность входных и выходных данных.
Собираем код в последовательной архитектуре (можно попробовать параллельную, но это увеличит количество блоков, используемых в FPGA).
В окне Matlab будет указано, во сколько раз частота подаваемая на модуль, должна превышать частоту входного аудио-сигнала.
Поводим эту операцию и для TX и для RX компенсатора.
Переносим файлы в папку проекта, в Quartus нажимаем по ним правой кнопкой и выбираем Create Symbol Files for Current File.
ВАЖНО! удаляем из схемы проекта старые компенсатора и добавляем новые, просто заменить файлы не достаточно, т.к. сохранятся коэффициенты.
Подстраиваем частоту PLL под наш аудио-поток.
Собираем программу и прошиваем FPGA.
Правим значение тактового генератора в STM32 прошивке (файл fpga.h), это значение используется для расчёта фразы частоты, передаваемой в NCO.
Компилируем, прошиваемся, наслаждаемся более чистым сигналом!
Дважды переустанавливал матлаб, не вылечился ( Попытаю удачи с более ранней версией, когда скачается.
Версия 2017 года оказалась более восприимчивой к лечению. Но, видимо, все это пока что зря, т.к. мой-то генератор на 122.88, а АЦП 65, так что буду ждать введения Вами в схему генератора на 96МГц.
Пока меня останавливает сложность реализации делителя, я рассчитывал на PLL в FPGA, Но у него такой бешенный джиттер, что от этой идеи я отказался.
Думаю в сторону микросхемы https://ru.mouser.com/datasheet/2/308/MC10EL32-D-109777.pdf — даже в даташитах к АЦП она и его брат на делитель 4 участвуют. Схему подключения можно взять с даташита AD9226.
Соответственно делим и стабилизируем им частоту на 2, а дальше всё как в статье.
Также, возможно начну свои разработки с более дешевого триггера 74HC574D, самый быстрый из того что смог найти у себя в городе.
А для Вашей реализации схемы обязательны подтягивающие резисторы в ПЛИС на линиях АЦП?
нет, я думаю они совершенно не критичны.
Что-то я, видимо, упускаю при портировании с vet6 на zet6 — кодек инициализируется и активируется, интерфейс отрисовывается, тач работает, но ни водопада, ни спектра, ни звука. Кубовые проекты сверяю до каждого значения, в fpga.h GPIOC на свой меняю (к слову, может быть лучше было бы поставить дефайн вместо прямого определения?), но эффект нулевой. Заметил, что Вы добавили тестирование шины данных с ПЛИС, завтра посмотрю, что выдается.
Обратите внимание на смещения << в FPGA_writePacket (fpga.c) и FPGA_readPacket. Например в bitRead(packet, 2) << 6 & FPGA_OUT_D2_Pin, 6ка значит 6й вывод, т.е. я читаю напрямую из регистра, а не по именам пинов, если ножки другие то надо менять эти значения. Ну и тестирование да, тоже скажет какая нога не отвечает на пару приём-передача.
И обратите внимание, что в последней версии прошивки, обмен по шине STM32-FPGA тактируется с помощью PLL на 48кгц от FPGA, а не по таймеру
Переназначил ноги ПЛИС, перестал компилироваться проект (что-то про старые и новые значения было), сделал очистку, теперь не формируется sof файл 🙂
Если пишет что-то про honor location — помогает удаление папок db и incremental_db и потом переоткрыть проект
Оказывается, квартус вылечился не до конца ) Поправил лицензию, файлы стали формироваться. Правда, особого эффекта это не оказало, хоть тест шины ПЛИС и выдает ОК, ни звука, ни спектра нет. Завтра скачаю текущий архив с проектом и буду с ним разбираться.
Я для отладки использую UART и вывожу через него данные.
Например в файле stm32f4xx_it.c функция TIM6_DAC_IRQHandler — по таймеру раз в секунду можно вывести отладку.
Думаю стоит вывести следующие значения:
1. FPGA_Audio_Buffer_Q[0] и FPGA_Audio_Buffer_I[0] — посмотреть что в аудио-буффере прилетающим из FPGA
2. FPGA_Audio_Buffer_Index — двигается ли индекс по буферу FPGA
3. FPGA_Audio_Buffer_Q_tmp[0] и FPGA_Audio_Buffer_I_tmp[0] — кеширующий буфер
4. Processor_AudioBuffer_A[0] и Processor_AudioBuffer_B[0] — буфер обработчика звука
5. Processor_AudioBuffer_ReadyBuffer — активный буффер обработчика, должен периодически меняться
6. CODEC_Audio_Buffer_RX[0] — буффер аудио-кодека
7. WM8731_DMA_state — состояние DMA аудио-кодека (полупустой или полный, должен периодически меняться)
8. FFTInput_A[0] и FFTInput_B[0] — буфер водопада
9. FFTInputBufferInProgress — текущий буфер водопада
если вообще ничего и по нулям:
1. вывести FPGA_samples — сколько раз в секунду запустилась шина получения аудио с FPGA, Должно быть около 48000
2. запускается ли функция FPGA_fpgadata_getiq (в ней что-нить в UART вывести)
3. запускается ли FPGA_fpgadata_iqclock (аналогично)
а уже FPGA_fpgadata_iqclock дёргает прерывание EXTI15_10_IRQHandler — если оно не вызывается то нет клока от FPGA на 48кгц
Довел проект до состояния отображаемого водопада. Правда, картинка неправильная, жаль, прикрепить нельзя.
Тест шины ОК, FPGA_samples 48к с небольшим, все остальное, что было закомментировано в TIM6_DAC_IRQHandler по нулям, кроме WM8731_DMA_state, всегда 1. Если нажать TUNE, AUDIOPROC_TXA_samples и AUDIOPROC_TXB_samples примерно по 750. FPGA_Audio_Buffer_Q[0] и FPGA_Audio_Buffer_I[0] по нулям.
processRxAudio в TIM5_IRQHandler вызывается, но из-за того, что Processor_NeedBuffer, видимо, постоянно false, сразу происходит выход.
Думаю с DMA аудио-кодека какие-то проблемы