Я продолжаю изучать FPGA китайской компании GOWIN и делаю проекты для FPGA платы Марсоход3GW. В этой статье пойдет речь об АЦП. На нашей плате установлена микросхема АЦП ADC1175. Она даёт нам 8ми битные выборки на частоте до 20МГц. Первый эксперимент, который я сделаю - выведу данные из АЦП просто на 8 светодиодов платы. Сделать это в программе Verilog HDL очень просто. Для этого нужно на АЦП подать тактовую частоту pll_out_clk взятую, например из rPLL, и этим же сигналом тактовой частоты защелкивать входные данные в регистре adc_data. Ну а выход регистра потом подать на светодиоды:
...
wire pll_out_clk;
wire pll_locked;
Gowin_rPLL rpll(
.clkin( CLK ),
.clkout( pll_out_clk ),
. lock( pll_locked )
);
//pass clk to external ADC chip
assign ADC_CLK = pll_out_clk;
//capture ADC data
reg [7:0]adc_data;
always @(posedge pll_out_clk)
adc_data <= ADC_D;
//show ADC data on LEDs
assign LED = adc_data;
...
Чтобы испытать этот проект можно ко входу АЦП на плате Марсоход3GW подключить среднюю точку переменного резистора. Ну а два других вывода переменного резистора подключить к +5В и к Земле соответственно. Вот как на этотом фрагменте схема платы Марсоход3GW я добавил синим цветом:
Получается делитель напряжения и вот это напряжение на средней точке и можно измерить с помощью нашего АЦП. На представленном выше видео показано, как я вращаю ручку переменного резистора и как от этого действия меняется двоичное число на 8ми светодиодах платы. Понятно, что это очень примитивный проект, но он дает отправную точку для следующих, более сложных проектов.
Далее я собираюсь оцифрованные данные передавать через последовательный порт в компьютер. А на компьютере напишу программу на питоне и она будет мне отображать осцилограммы из полученных данных.
Как вы знаете, на нашей плате стоит двухканальная микросхема FTDI FT2232H. Первый канал используется для JTAG загрузки проектов в SRAM ПЛИС, а вот второй канал свободен для обмена данными между платой и ПК. Максимальная скорость последовательной передачи для FT2232H это 12МГц. Вообще-то есть ещё режим передачи FIFO, но это мы пока не рассматриваем.
Я решил в rPLL создать такую частоту 12МГц и подаю её на сдвиговый регистр, в который буду загружать данные из АЦП. Причем я подумал, что если я сделаю три стоп бита, то получится, что на один передаваемый байт уходит старт бит, байт 8 бит и три стопа - всего 12 бит. Значит поток байт в ПК будет 1 мегабайт в секунду. Один миллион отсчетов АЦП в секунду. Ровное число.
...
//Max serial baud for FTDI 2232H is 12Mbit, get it from PLL
wire pll_out_clk;
wire pll_locked;
Gowin_rPLL rpll(
.clkin( CLK ),
.clkout( pll_out_clk ), //12MHz
.lock( pll_locked )
);
//count serial bits: 1 start, 8 data, 3 stop bits -> 12 bits per serial byte
reg [3:0]cnt_div12;
always @(posedge pll_out_clk)
if(cnt_div12==11)
cnt_div12<=0;
else
cnt_div12<=cnt_div12+1;
//pass clk to external ADC chip
assign ADC_CLK = pll_out_clk;
//capture ADC data
reg [7:0]adc_data;
always @(posedge pll_out_clk)
adc_data <= ADC_D;
//show ADC data on LEDs
assign LED = adc_data;
reg [11:0]serial_out_reg;
always @(posedge pll_out_clk)
if(cnt_div12==0)
serial_out_reg <= { 3'b111, adc_data, 1'b0 }; //load
else
serial_out_reg <= { 1'b1, serial_out_reg[11:1] }; //shift out, LSB first
//Serial_TX
assign FTB1 = serial_out_reg[0];
...
С этой задачей всё решено. Теперь второй вопрос - программа на Питоне. Я не буду приводить её исходный код, скажу только, что программа базируется на питоновских библиотеках pyserial и matplotlib. Если у вас их нет, то для этого проекта их нужно поставить.
Программа на Питоне принимает в командной строке параметр имя последовательного порта, его можно посмотреть в менеджере устройств Windows.
Программа отображает график из 1000 выборок АЦП. Получается своего рода осцилограмма:
В качестве исходного сигнала я взял просто свой смартфон и установил на него первую попавшуюся программу генератора аудио сигналов. Она может выдавать синусоиду или пилу или меандр. Можно выдавать сумму двух или трёх синусоид. Частоты всех сигналов можно менять прямо из программы на смартфоне.
Аудио выход смартфона я подключаю через разделительный конденсатор к центральной точке делителя напряжения использовавшегося в предыдущем проекте по вот такой схеме:
Вот смотрите, как это работает:
Кажется получилось неплохо.
Напоминаю, что исходные тексты проектов можно взять из нашего репозитория на github: https://github.com/marsohod4you/Marsohod3GW
Рассмотренные в этой статье проекты находятся в папках _adc_led и _adc_serial_python.
Подробнее...