Захват данных от АЦП с использованием NIOS II


В статье я расскажу о том, как захватывать данные от АЦП, установленного на отладочной плате DE0-nano. Данные при этом можно обрабатывать при помощи софтового процессора NIOS, и выводить их на VGA монитор.

Данная статья является продолжением предыдущей: Формирование VGA изображения с использованием NIOS II.
Вывод изображения там уже реализован, остается добавить в имеющуюся SOPC узлы для захвата сигнала с параллельной шины. У Altera имеется пример использования АЦП совместно с Nios (специально для DE0-nano): пример. В этом примере выход АЦП просто отражается в адресное пространство системы. Намного интереснее для захвата данных использовать DMA, для того чтобы данные от АЦП аппаратно записывались в SDRAM.
Таким образом, в систему из предыдущей статьи нужно добавить:
  • модуль соединения системы с шиной АЦП
  • модуль FIFO, для согласования различных тактовых частот АЦП и системы
  • модуль DMA

Частота тактирования (дискретизации) АЦП выбрана достаточно низкой — 50 кГц. Это связано с тем, оцифровывать я собирался звук, формируемый звуковой платой компьютера.
Потоковые данные в систему можно передавать по специальной шине Nios — Avalon Streaming Interface.
Для того, чтобы вывести шину наружу из системы, требуется специальный модуль. Я взял готовый отсюда. Модуль по ссылке предназначен для подключения к шине модуля FFT, так что мне пришлось его переделать.
У меня в проекте файлы этого модуля хранятся в папке «fft_wrapper», которая расположена в папке проекта. За счет этого, SOPC Builder автоматически обнаруживает пользовательский модуль, который появляется в меню выбора модулей.
Модуль состоит из двух частей — описания компонента на Verilog (в данном случае в нем просто указывается, что выходные порты соединены с входными) и TCL-файла, в котором указываются параметры модуля, которые использует SOPC Builder при встраивании модуля в систему.
Мой модуль выводит из системы 32-битную шину Avalon-ST с поддержкой пакетной передачи (подробнее о шине — ниже). 32 бита были выбраны про запас (для экспериментов с FFT). Модуль в системе у меня называется fft_avalon_wraper2 (знаю, что в названии ошибка, но исправлять там нужно достаточно много).
  • data_format_adapter — нужен для согласования модуля fft_avalon_wraper2 с FIFO.
    Настройки:

    Стоит заметить, что шины в системе делятся на символы («Symbols»). В настройках модуля fft_avalon_wraper2 указано, что шина 32-битная, длина символа — 8 бит, и за 1 такт передается 4 символа. Это должно учитываться в настойках всех остальных модулей, и поэтому в настойках модуля data_format_adapter — указано «Data symbols per beat: 4».
    Empty — специальные сигнальные линии, характерные для Avalon-ST. В этом проекте они не нужны, и в модуле fft_avalon_wraper2 их нет. FIFO требует этих линий, и модуль data_format_adapter добавляет их.
  • FIFO — в проекте dc_fifo_ext — Avalon-ST Dual Clock FIFO. Настройки оставлены без изменений.
  • DMA — в проекте sgdma_fft — Scatter-Gather DMA Controller. Такой же DMA, как и используется для вывода изображения на монитор. Соединен напрямую с контроллером SDRAM.
    Настройки:

В настройках Nios II нужно указать Nios II/s. По каким-то причинам при использовании Nios II/f DMA захвата данных работал ужасно — данные захватывались лишь частично.

Настройки источников тактирования:
-clk_50M — external — 50MHz (тактирование PLL)
-alt_pll_sys — pll.c0 — 100MHz (тактирование системы)
-alt_pll_sdram — pll.c1 — 100MHz (тактирование SDRAM)
-alt_pll_pclk — pll.c3 — 25MHz (тактирование видеосистемы)
-ext_clk — external — 0.05MHz (тактирование модулей, отвечающих за захват данных)

Вид всей системы SOPC:


Так видеосистема и система захвата данных от АЦП работают одновременно, то нужно настроить арбитраж.
Для этого нужно включить отображение уровней арбитража: view — show arbitration shares.
Вид соединений модулей после этого (числа уже отредактированы):

Числа указывают, сколько передач данных будет выполнено для одного модуля, после чего произойдет переключение к следующему.

Вид выводов шины в Quartus:

Слева — входы шины, справа — выходы.
-eop_to_the_fft_avalon_wraper2 — линия сигнала «конец пакета» (end of packet).
-fft_data_to_the_fft_avalon_wraper2 — шина данных.
-sop_to_the_fft_avalon_wraper2 — линия сигнала «начало пакета» (start of packet).
-valid_to_the_fft_avalon_wraper2 — линия сигнала «готовность» (от источника сигнала).
-ready_from_the_fft_avalon_wraper2 — линия сигнала «готовность» (от приемника сигнала — fft_avalon_wraper2).

Как я упоминал выше, в использованной шине используется пакетная передача данных. В момент начала передачи данных источник сигнала должен на время одного такта установить на линии sop единичный уровень. В момент конца передачи данных источник сигнала должен на время одного такта установить на линии eop единичный уровень. На время передачи данных на линии valid должен быть единичный уровень. Приемник сигнала (fft_avalon_wraper2 — «sink») указывает о готовности принимать данные установкой единичного уровня на линии ready.

Таким образом, чтобы передать данные от АЦП в систему, нужен специальный модуль, который в нужный момент сформирует сигналы sop, eop, valid. Мне пришлось написать такой модуль самому. У меня он называется «FFT_CTRL».
Запуск формирования этих импульсов начинается после подачи короткого импульса на вход «start» модуля.
Именно этот модуль определяет размер пакета, то есть число захватываемых выборок данных. Модуль настроен на 512 выборок. Также перед запуском передачи пакета модуль ожидает готовности приемника.

Вид всей схемы в Quartus:


АЦП, установленный на плате, имеет последовательный выход, так что для получения данных от АЦП используется модуль «ADC_CTRL». Это частично доработанный модуль из примеров, прилагаемых к DE0-nano. Модуль тактируется частотой 2 МГц (битрейт), также на модуль подается частота 50 кГц — частота выборок.
Для формирования этих тактовых частот в схему добавлен второй PLL.

Программная часть.
Так как в системе для захвата данных от АЦП используется DMA, то для захвата данных достаточно подготовить DMA, оправить стартовый импульс на модуль «FFT_CTRL», дождаться, когда DMA закончит захват данных.
Пример кода, производящего захват данных:
void start_adc_capture(void)//rx_buf - pointer to write data
{
	int i;
	alt_u8 status = 0;

	rx_ptr = &data_buf[0];
	// Construct descriptors in the same input and output memory.
	alt_avalon_sgdma_construct_stream_to_mem_desc(&desc1,&desc_stop,rx_ptr,0,0);


	for (i=0;i<FTT_LENGTH;i++){data_buf[i] = 0;}//очистка буфера перед началом передачи (для тестирования)

	alt_avalon_sgdma_do_async_transfer(receive_DMA, &desc1);//запуск передачи (DMA готов принимать данные)

	//запуск передачи пакета
	IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 128);
	asm("nop");
	asm("nop");
	asm("nop");
	asm("nop");
	asm("nop");
	asm("nop");
	asm("nop");
	asm("nop");
	IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 0);


	//ожидание конца передачи
	while (IORD(SGDMA_FFT_BASE,0)!=14) {};
	tx_byte = desc1.actual_bytes_transferred;//число переданных байт
}

После того, как данные захвачены, их можно вывести на монитор или программно обработать.

Пример захвата синусоидального сигнала, формируемого аудиокартой:

Так как аудиокарта выдает переменное напряжение, то перед тем, как подавать его на АЦП, его приходится смещать, используя резисторный делитель и конденсатор.
Вид конструкции:


Следует заметить, что частота захвата данных системой определяется тактовой частотой ext_clk, которая в данном проекте равна 50кГц. Я проверял работу получившейся системы на частоте 10МГц, при этом в качестве источника сигнала использовался DDC генератор (модуль NCO в Quartus). Все работало стабильно.

Ссылка на проект.
  • +7
  • 21 июля 2014, 23:37
  • citizen

Комментарии (9)

RSS свернуть / развернуть
Вопрос: нужно ли писать статью про работу с аппаратным FFT модулем?
0
Пиши)))
+1
Пишите конечно, пригодится;)
+1
Однозначно пригодится.
0
Привет!
Объясните пожалуйста, для чего нужен fft_avalon_wraper2? Почему нельзя проэкспортить непосредственно вход data_format_adapter, к которому, собственно, подключен выход wraper-а.

Спасибо!
NJ
0
Почему нельзя проэкспортить непосредственно вход data_format_adapter
Я не знаю, как это сделать.
0
Мое предложение может быть принципиально не правильным, но я имел в виду вот это:


Если там кликнуть, то вход будет экспортирован из ниоса. К нему можно будет подключить сигналы от FFT_CTRL и ADC_CTRL.
0
Это вроде бы можно сделать только в Qsys, а я использую SOPC Builder.
0
Тогда все ясно. Дело в том, что в ряде опубликованных проектов используется wrapper вроде вашего в том или ином виде. По неопытности, я искал в этом какой-то смысл. Учитывая, что все эти проекты сделаны именно в SOPC Builder-е, теперь понятно.

Спасибо!
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.