Фазовая модуляция радиосигнала в ПЛИС



    Так иногда бывает, что занимаешься одной технической проблемой, но, по мере погружения в задачу и во время поиска ее решения, появляются «побочные продукты». Так случилось и в этот раз. Я исследовал различные методы измерения временных интервалов с помощью ПЛИС. В одном из предложенных методов измерений был использован динамический сдвиг фазы тактовой частоты с PLL. Позже пришла идея: используя свойства PLL можно попробовать сделать в ПЛИС простейший радиопередатчик с фазовой модуляцией.

    И кое-что получилось!

    Пожалуй нужно немного рассказать, что такое PLL. PLL (Phase Locked Loop) — это устройство фазовой автоподстройки частоты генератора. Выглядит примерно вот так:



    Здесь есть ГУН — Генератор, Управляемый Напряжением. Он выдает желаемую частоту, которая через обратную связь идет на фазовый детектор. Фазовый детектор определяет разность фаз между опорной частотой F0 и получившейся частотой F1, разность фаз — это сигнал ошибки, который отфильтровывается и воздействует на ГУН, заставляя его колебаться чуть быстрее или чуть медленнее. Так, на выходе ФАПЧ получается частота, синхронная с опорной.

    В микросхемах ПЛИС, например, от компании Интел (эх… когда-то была Альтера) серии MAX10 есть встроенный PLL, который выглядит вот так:



    Кажется, что это что-то гораздо более сложное, чем то, что изображено выше. Но нет, если присмотреться внимательно, то видны общие черты: ГУН, Генератор Управляемый Напряжением — это VCO, Voltage Controlled Oscilator. PFD — это фазовый детектор, LF — Loop Filter, фильтр фазовой ошибки.

    Кроме всего прочего, PLL внутри ПЛИС имеет набор счетчиков делителей. Например, делитель частоты M в цепи обратной связи позволяет получить на выходе PLL частоту в несколько раз выше, чем опорная. Так же имеются выходные счетчики C0-C4, которые позволяют на пяти выходах PLL получить сетку частот с разными делителями.

    Есть внутри PLL еще компоненты, которые почему-то обычно не изображаются на структурных схемах в документации Altera/Intel — это схемы управляющие перезагрузкой и перенастройкой PLL. Логические схемы в ПЛИС могут на лету перезагружать коэффициенты счетчиков делителей в PLL и еще они позволяют сдвигать фазу выходных частот PLL. Конечно, перезагрузить на лету параметры PLL — это не очень простая операция, которая к тому же занимает определенное время. А вот сдвигать фазу выходной частоты PLL можно довольно просто и быстро. Причем, разрешающая способность по фазе напрямую зависит от частоты Fvco. Сдвигать фронт тактовой частоты можно на 1/8 периода Fvco. Например, входная частота на PLL Fin=100МГц, а делитель M в цепи обратной связи к фазовому детектору равен 13-ти. Тогда Fvco=1300МГц, а разрешение по фазе для выходной частоты PLL Fout=100МГц будет составлять всего 3,46 градуса.

    Для разработки проекта для ПЛИС Altera/Intel используется среда САПР Quartus Prime и в ней есть средства настройки экземпляров PLL: Megawizard Plug-In Manager. С его помощью можно устанавливать нужные свойства PLL:



    Здесь как раз и видно какие получаются Fvco и разрешение по фазе для выходных частот.

    Для управления фазой выходных частот у компонента PLL есть дополнительные сигналы: SCANCLK, PHASESTEP, PHASEUPDOWN, PHASECOUNTERSELECT, PHASEDONE.

    В документации Altera/Intel написано, как управлять этими сигналами, чтобы получить единичный сдвиг фазы на избранной выходной частоте.



    Получается так: сигнал PHASEUPDOWN определяет в какую сторону нужно двигать фазу. PHASECOUNTERSELECT определяет сигнал какой именно тактовой частоты PLL будет сдвинут (например, если нужно сдвинуть частоту c1, то PHASECOUNTERSELECT=3'b011 — это есть в документации). Цикл сдвига фазы начинается с установки сигнала PHASESTEP и заканчивается, когда PLL выставит в ноль PHASEDONE. Если нужно сдвинуть фазу значительно, то придется выполнить несколько таких циклов. Все это при желании можно даже просимулировать в ModelSim, как это делается я писал вот здесь.

    Теперь, дальше — интереснее. Плавно перехожу к моему «радиопередатчику»:



    Я использую плату Марсоход3bis на чипе ПЛИС Altera/Intel MAX10. Плата имеет встроенный программатор на базе двухканального чипа FTDI. Причем один канал FT2232HL используется под JTAG (загрузка ПЛИС, отладка в SignalTap), а второй канал используется для передачи данных в плату, как последовательный порт.

    К плате, прямо к двум цифровым пинам-выходам подключены два куска провода по 0,75 метра. Это антенна, «полуволновый вибратор». Без выходного аналогового фильтра на излучаемый диапазон, конечно, не хорошо, но сама антенна уже какой-то фильтр, да и мощность передатчика невелика…

    Проект написан на языке Verilog HDL — всего-то пара десятков строк кода:

    module top(
    	input wire CLK100MHZ,
    	input wire key0,
    	input wire key1,
    	input wire FTDI_BD0, //serial RX line 
    	output wire [19:0]io
    );
    
    wire wc0;
    wire wc1;
    wire wlocked;
    wire wpdone;
    wire up_down; 
    reg pstep;
    wire scanclk; assign scanclk = wc0;
    	
    reg [7:0]cnt8;
    always @( posedge scanclk )
    	cnt8 <= cnt8 + 8'h01;
    
    mypll mypll_ (
    	.areset( ~key0 ),
    	.inclk0(CLK100MHZ),
    	.phasecounterselect( 3'b011 ),
    	.phasestep( pstep ),
    	.phaseupdown( up_down ),
    	.scanclk(scanclk),
    	.c0(wc0),
    	.c1(wc1),
    	.locked(wlocked),
    	.phasedone( wpdone )
    	);
    
    wire [7:0]w_rx_byte;
    wire w_byte_ready;
    reg [1:0]byte_rdy;
    always @( posedge wc0 )
    	byte_rdy <= {byte_rdy[0],w_byte_ready};
    	
    serial receiver(
    	.reset( ~wlocked ),
    	.clk100( wc0 ),	//100MHz
    	.rx( FTDI_BD0 ),
    	.sbyte( 8'h00 ),
    	.send( 1'b0 ),
    	.rx_byte( w_rx_byte ),
    	.rbyte_ready( w_byte_ready ),
    	.tx(),
    	.busy(), 
    	.rb()
    	);
    
    reg  [7:0]current_pll_phase = 0;
    wire [7:0]signal; assign signal = w_rx_byte[7:0];
    assign up_down = signal>current_pll_phase;
    
    reg [3:0]state = 0;
    always @( negedge scanclk )
    begin
    	case(state)
    	0: begin 
    			//wait recv byte
    			if( byte_rdy ) state <= 1;
    		end
    	1: begin 
    			//do we really need to change phase?
    			if( current_pll_phase==signal ) state <= 0;
    			else state <= 2;
    		end	
    	2: begin 
    			//wait phase done
    			if( ~wpdone ) state <= 3;
    	        end
    	3: begin 
    			state <= 4;
    		end
    	4: begin 
    			state <= 1;
    		end
    	endcase
    	
    	if( pstep && (~wpdone) )
    		if( up_down )
    			current_pll_phase <= current_pll_phase + 6'h1;
    		else
    			current_pll_phase <= current_pll_phase - 6'h1;
    			
    	if( ~wpdone )
    		pstep <= 1'b0;
    	else
    	if( state==2 )
    		pstep <= 1'b1;
    end
    
    assign io[17:0] = 0;
    assign io[18] =  wc1;
    assign io[19] = ~wc1;
    
    endmodule

    Весь проект для САПР Intel Quartus Prime можно взять на GitHub: github.com/marsohod4you/Fpga-PM-Radio.

    В проекте есть PLL с двумя выходами c0 и c1, на каждом из них 100МГц. Выход c0 используется для тактирования всей схемы, а вот выход c1 — это и есть несущая 100МГц, частота моего «радиопередатчика» (FM-диапазон). Ее я и собираюсь модулировать по фазе.

    Я собираюсь посылать сырой аудиофайл с компьютера в плату через последовательный порт. При формате данных 8 бит на одну аудиовыборку, моно, 22050Гц, наиболее удобна скорость последовательного порта 230400 бод. В самом деле, каждый байт при последовательной передаче имеет старт бит и один или два стоп бита. Если два стоп бита, то получается 11 передаваемых бит на байт данных. Значит 230400/11=20945 выборок в секунду. Это конечно не идеал, не 22050, но чуть-чуть похоже. Ну получится у меня звук немного ниже, чем нужно, мне для моих экспериментов не важно… Итак в проекте есть приемник последовательных данных.

    Полученный из последовательного порта байт w_rx_byte внутри ПЛИС сравнивается с внутренней переменной (регистром) current_pll_phase. Разница меж ними — это и есть количество шагов по сдвигу фазы, которые нужно сделать в одну или другую сторону. Таким образом выполняется фазовая модуляция на выходе c1 у PLL.

    Теперь второй вопрос. Предположим, что передатчик с фазовой модуляцией работает, а чем слушать?

    Я исхожу из того, что ФМ и ЧМ непосредственно связаны друг с другом интегральным/дифференциальным законом. Мгновенная частота радиосигнала — это производная от его фазы. Производная синуса — это косинус. Вряд ли слушатель радиопередачи отличит их на слух (шутка). В общем, я решил попробовать передавать аудио файл моим «радиопередатчиком» с фазовой модуляцией, а слушать мою «радиопередачу» обычным FM-приемником. Я использую мобильный телефон с гарнитурой в качестве FM приемника.

    Вот как это выглядит:


    Удивительно, но передаваемая мной музыка устойчиво слышна в FM радиоприемнике мобильного телефона на расстоянии до 10-15 метров.

    PS: В России 7 мая отмечается День радио. В 1895 году выдающийся русский физик и изобретатель Александр Попов в Санкт-Петербургском университете продемонстрировал созданную им первую в мире искровую беспроводную приемо-передающую радиосистему. В России этот факт был принят за точку отсчета начала радиосвязи.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 8

      0
      > один канал FT2232HL используется под JTAG (загрузка ПЛИС, отладка в SignalTap)
        –9
        Если не секрет, для чего??
        Смысл, делать это?
        Все технологии тут отработаны, все работает.
        Фазовой подстройке частоты, сто лет в обед.
          0

          У такого PLL можно ли вращать фазу на несколько оборотов?
          т.е. на 360*N где N например может достигать до +-100?
          например:
          когда из езернета приходят пакеты со звуком,
          а т.к. у посылающей стороны тактовая чууууточку иная,
          то со временем станет накапливатся или опустошаться буфер,
          например 1 выборка за пару секунд при 96кГц дискретизации.


          А выдавать сигнал нужно с синхронной тактовой I2S например.
          Вот и хотелось бы иметь возможность чуууток ускорять или тормозить тактовую на выходе I2S.

            +1

            А это уже ASRC, это несколько другая задача, которую не стоит решать только фазовым вращением.

            +1
            Оффтоп, но не смог удержаться.
            Case лучше без default не оставлять.
            А еще иногда кодирование состояний степенями двойки (1 2 4 ...) экономит логику.
              0
              Да, это называется One-Hot State Machine.
            • НЛО прилетело и опубликовало эту надпись здесь
                0
                Мгновенная частота радиосигнала — это производная от его полной фазы.
                Представьте, импульсную последовательность, а потом, что сдвигаете фазу одного из импульсов. Тогда получится, что между этим импульсом и предыдущим уже другой временной промежуток:
                ____#____#____#____#____#__.__#____#____#____#
                сдвиг фазы порождает мгновенное изменение периода, следовательно и частоты сигнала.

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

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое