introducción
Dado que algunos requisitos requieren generar una onda sinusoidal, la función sin() en la aplicación C se usa para calcular el valor de amplitud del círculo unitario y luego convertir ese valor de amplitud al código DAC apropiado para el AD9717 (convirtiendo cada valor de ángulo a radianes por supuesto).
Al poder generar ondas sinusoidales simples usando un DAC, la siguiente idea es usar modulación de frecuencia en SDR (Software Defined Radio).
La mayoría de los diseños de SDR tienen 3 frecuencias operativas internas diferentes: una frecuencia de banda base baja para procesar los datos del ADC/DAC; una o más frecuencias intermedias a las que se eleva el flujo de datos de banda base final como paso intermedio; y finalmente la entrada de RF /salida la frecuencia de salida de la antena. Obviamente, el lugar más fácil para comenzar es la banda base, ya que es la frecuencia más baja y es donde el flujo de datos analógicos real se combina/extrae de los bits de datos digitales individuales. Para reducirlo aún más, los puntos exactos en los que los bits digitales de 1 y 0 se relacionan con alguna forma de onda analógica relevante se denominan mapeador de símbolos, que es el componente básico de SDR mencionado anteriormente.
Por lo tanto, este proyecto será un mapeador de símbolos de banda base muy simplificado para el extremo de transmisión de la cadena (digital a analógica) del esquema de modulación digital FSK.
modulación digital
La manipulación por desplazamiento de frecuencia (FSK) es un tipo de modulación digital que cambia la frecuencia para representar diferentes bits/símbolos en un flujo de datos. En su forma más básica, se usa una frecuencia para representar un 1 binario y otra frecuencia para representar un 0 binario. Esta forma de FSK se llama FSK binaria o 2-FSK.
Como se puede ver en lo anterior, un bit 1 está representado por aproximadamente el doble de la frecuencia de un bit 0. Para ZYNQ+SDR, esto significa que debe poder generar dos frecuencias diferentes con fases continuas. En otras palabras: la sincronización es importante aquí para garantizar que la fase de una frecuencia ocurra exactamente donde se detuvo la fase de la última frecuencia. Cada bit también completa un ciclo completo de cada frecuencia.
Diseño lógico en Vivado.
Dado que en esta demostración solo el lado del transmisor es de interés, para manejar la contrapresión que la lógica del mapeador de símbolos puede imponer en el flujo de datos de la memoria DDR en la lectura del MM2S, se coloca una LUT sin con el mapeador de símbolos FSK en los datos de AXIS FIFO y entre la IP del controlador DAC. De esta manera, FIFO puede completar la transferencia MM2S desde la memoria y AXI DMA no se bloqueará en tdata mientras la lógica del asignador de símbolos genera el valor de frecuencia correspondiente durante un ciclo por bit.
El código se muestra a continuación:
`timescale 1ns / 1ps
module sin_lut(
input clk,
input rst,
input [8:0] sel,
output [15:0] DAC_code
);
reg [15:0] DAC_code;
always @ (posedge clk)
begin
if (rst == 1'b0)
begin
end
else
begin
case (sel)
9'd0 : DAC_code = 16'h0000;
9'd1 : DAC_code = 16'h01C8;
9'd2 : DAC_code = 16'h0390;
9'd3 : DAC_code = 16'h0558;
9'd4 : DAC_code = 16'h0724;
9'd5 : DAC_code = 16'h08EC;
9'd6 : DAC_code = 16'h0AB0;
9'd7 : DAC_code = 16'h0C78;
9'd8 : DAC_code = 16'h0E3C;
9'd9 : DAC_code = 16'h1004;
9'd10 : DAC_code = 16'h11C4;
9'd11 : DAC_code = 16'h1388;
9'd12 : DAC_code = 16'h1548;
9'd13 : DAC_code = 16'h1708;
9'd14 : DAC_code = 16'h18C4;
9'd15 : DAC_code = 16'h1A7C;
9'd16 : DAC_code = 16'h1C38;
9'd17 : DAC_code = 16'h1DEC;
9'd18 : DAC_code = 16'h1FA0;
9'd19 : DAC_code = 16'h2154;
9'd20 : DAC_code = 16'h2304;
9'd21 : DAC_code = 16'h24B0;
9'd22 : DAC_code = 16'h2658;
9'd23 : DAC_code = 16'h2800;
9'd24 : DAC_code = 16'h29A4;
9'd25 : DAC_code = 16'h2B44;
9'd26 : DAC_code = 16'h2CE0;
9'd27 : DAC_code = 16'h2E78;
9'd28 : DAC_code = 16'h3010;
9'd29 : DAC_code = 16'h31A0;
9'd30 : DAC_code = 16'h3330;
9'd31 : DAC_code = 16'h34B8;
9'd32 : DAC_code = 16'h3640;
9'd33 : DAC_code = 16'h37C0;
9'd34 : DAC_code = 16'h3940;
9'd35 : DAC_code = 16'h3AB8;
9'd36 : DAC_code = 16'h3C2C;
9'd37 : DAC_code = 16'h3D9C;
9'd38 : DAC_code = 16'h3F08;
9'd39 : DAC_code = 16'h406C;
9'd40 : DAC_code = 16'h41D0;
9'd41 : DAC_code = 16'h432C;
9'd42 : DAC_code = 16'h4480;
9'd43 : DAC_code = 16'h45D0;
9'd44 : DAC_code = 16'h471C;
9'd45 : DAC_code = 16'h4864;
9'd46 : DAC_code = 16'h49A4;
9'd47 : DAC_code = 16'h4AE0;
9'd48 : DAC_code = 16'h4C14;
9'd49 : DAC_code = 16'h4D44;
9'd50 : DAC_code = 16'h4E6C;
9'd51 : DAC_code = 16'h4F90;
9'd52 : DAC_code = 16'h50AC;
9'd53 : DAC_code = 16'h51C4;
9'd54 : DAC_code = 16'h52D4;
9'd55 : DAC_code = 16'h53DC;
9'd56 : DAC_code = 16'h54E0;
9'd57 : DAC_code = 16'h55DC;
9'd58 : DAC_code = 16'h56D4;
9'd59 : DAC_code = 16'h57C0;
9'd60 : DAC_code = 16'h58A8;
9'd61 : DAC_code = 16'h598C;
9'd62 : DAC_code = 16'h5A64;
9'd63 : DAC_code = 16'h5B38;
9'd64 : DAC_code = 16'h5C04;
9'd65 : DAC_code = 16'h5CC8;
9'd66 : DAC_code = 16'h5D88;
9'd67 : DAC_code = 16'h5E3C;
9'd68 : DAC_code = 16'h5EEC;
9'd69 : DAC_code = 16'h5F94;
9'd70 : DAC_code = 16'h6034;
9'd71 : DAC_code = 16'h60CC;
9'd72 : DAC_code = 16'h6160;
9'd73 : DAC_code = 16'h61E8;
9'd74 : DAC_code = 16'h6268;
9'd75 : DAC_code = 16'h62E4;
9'd76 : DAC_code = 16'h6358;
9'd77 : DAC_code = 16'h63C0;
9'd78 : DAC_code = 16'h6424;
9'd79 : DAC_code = 16'h6480;
9'd80 : DAC_code = 16'h64D4;
9'd81 : DAC_code = 16'h6520;
9'd82 : DAC_code = 16'h6564;
9'd83 : DAC_code = 16'h659C;
9'd84 : DAC_code = 16'h65D0;
9'd85 : DAC_code = 16'h65FC;
9'd86 : DAC_code = 16'h6620;
9'd87 : DAC_code = 16'h663C;
9'd88 : DAC_code = 16'h6650;
9'd89 : DAC_code = 16'h665C;
9'd90 : DAC_code = 16'h6660;
9'd91 : DAC_code = 16'h665C;
9'd92 : DAC_code = 16'h6650;
9'd93 : DAC_code = 16'h663C;
9'd94 : DAC_code = 16'h6620;
9'd95 : DAC_code = 16'h65FC;
9'd96 : DAC_code = 16'h65D0;
9'd97 : DAC_code = 16'h659C;
9'd98 : DAC_code = 16'h6564;
9'd99 : DAC_code = 16'h6520;
9'd100 : DAC_code = 16'h64D4;
9'd101 : DAC_code = 16'h6480;
9'd102 : DAC_code = 16'h6424;
9'd103 : DAC_code = 16'h63C0;
9'd104 : DAC_code = 16'h6358;
9'd105 : DAC_code = 16'h62E4;
9'd106 : DAC_code = 16'h6268;
9'd107 : DAC_code = 16'h61E8;
9'd108 : DAC_code = 16'h6160;
9'd109 : DAC_code = 16'h60CC;
9'd110 : DAC_code = 16'h6034;
9'd111 : DAC_code = 16'h5F94;
9'd112 : DAC_code = 16'h5EEC;
9'd113 : DAC_code = 16'h5E3C;
9'd114 : DAC_code = 16'h5D88;
9'd115 : DAC_code = 16'h5CC8;
9'd116 : DAC_code = 16'h5C04;
9'd117 : DAC_code = 16'h5B38;
9'd118 : DAC_code = 16'h5A64;
9'd119 : DAC_code = 16'h598C;
9'd120 : DAC_code = 16'h58A8;
9'd121 : DAC_code = 16'h57C0;
9'd122 : DAC_code = 16'h56D4;
9'd123 : DAC_code = 16'h55DC;
9'd124 : DAC_code = 16'h54E0;
9'd125 : DAC_code = 16'h53DC;
9'd126 : DAC_code = 16'h52D4;
9'd127 : DAC_code = 16'h51C4;
9'd128 : DAC_code = 16'h50AC;
9'd129 : DAC_code = 16'h4F90;
9'd130 : DAC_code = 16'h4E6C;
9'd131 : DAC_code = 16'h4D44;
9'd132 : DAC_code = 16'h4C14;
9'd133 : DAC_code = 16'h4AE0;
9'd134 : DAC_code = 16'h49A4;
9'd135 : DAC_code = 16'h4864;
9'd136 : DAC_code = 16'h471C;
9'd137 : DAC_code = 16'h45D0;
9'd138 : DAC_code = 16'h4480;
9'd139 : DAC_code = 16'h432C;
9'd140 : DAC_code = 16'h41D0;
9'd141 : DAC_code = 16'h406C;
9'd142 : DAC_code = 16'h3F08;
9'd143 : DAC_code = 16'h3D9C;
9'd144 : DAC_code = 16'h3C2C;
9'd145 : DAC_code = 16'h3AB8;
9'd146 : DAC_code = 16'h3940;
9'd147 : DAC_code = 16'h37C0;
9'd148 : DAC_code = 16'h3640;
9'd149 : DAC_code = 16'h34B8;
9'd150 : DAC_code = 16'h3330;
9'd151 : DAC_code = 16'h31A0;
9'd152 : DAC_code = 16'h3010;
9'd153 : DAC_code = 16'h2E78;
9'd154 : DAC_code = 16'h2CE0;
9'd155 : DAC_code = 16'h2B44;
9'd156 : DAC_code = 16'h29A4;
9'd157 : DAC_code = 16'h2800;
9'd158 : DAC_code = 16'h2658;
9'd159 : DAC_code = 16'h24B0;
9'd160 : DAC_code = 16'h2304;
9'd161 : DAC_code = 16'h2154;
9'd162 : DAC_code = 16'h1FA0;
9'd163 : DAC_code = 16'h1DEC;
9'd164 : DAC_code = 16'h1C38;
9'd165 : DAC_code = 16'h1A7C;
9'd166 : DAC_code = 16'h18C4;
9'd167 : DAC_code = 16'h1708;
9'd168 : DAC_code = 16'h1548;
9'd169 : DAC_code = 16'h1388;
9'd170 : DAC_code = 16'h11C4;
9'd171 : DAC_code = 16'h1004;
9'd172 : DAC_code = 16'h0E3C;
9'd173 : DAC_code = 16'h0C78;
9'd174 : DAC_code = 16'h0AB0;
9'd175 : DAC_code = 16'h08EC;
9'd176 : DAC_code = 16'h0724;
9'd177 : DAC_code = 16'h0558;
9'd178 : DAC_code = 16'h0390;
9'd179 : DAC_code = 16'h01C8;
9'd180 : DAC_code = 16'h0000;
9'd181 : DAC_code = 16'hFE37;
9'd182 : DAC_code = 16'hFC6F;
9'd183 : DAC_code = 16'hFAA7;
9'd184 : DAC_code = 16'hF8DB;
9'd185 : DAC_code = 16'hF713;
9'd186 : DAC_code = 16'hF54F;
9'd187 : DAC_code = 16'hF387;
9'd188 : DAC_code = 16'hF1C3;
9'd189 : DAC_code = 16'hEFFB;
9'd190 : DAC_code = 16'hEE3B;
9'd191 : DAC_code = 16'hEC77;
9'd192 : DAC_code = 16'hEAB7;
9'd193 : DAC_code = 16'hE8F7;
9'd194 : DAC_code = 16'hE73B;
9'd195 : DAC_code = 16'hE583;
9'd196 : DAC_code = 16'hE3C7;
9'd197 : DAC_code = 16'hE213;
9'd198 : DAC_code = 16'hE05F;
9'd199 : DAC_code = 16'hDEAB;
9'd200 : DAC_code = 16'hDCFB;
9'd201 : DAC_code = 16'hDB4F;
9'd202 : DAC_code = 16'hD9A7;
9'd203 : DAC_code = 16'hD7FF;
9'd204 : DAC_code = 16'hD65B;
9'd205 : DAC_code = 16'hD4BB;
9'd206 : DAC_code = 16'hD31F;
9'd207 : DAC_code = 16'hD187;
9'd208 : DAC_code = 16'hCFEF;
9'd209 : DAC_code = 16'hCE5F;
9'd210 : DAC_code = 16'hCCCF;
9'd211 : DAC_code = 16'hCB47;
9'd212 : DAC_code = 16'hC9BF;
9'd213 : DAC_code = 16'hC83F;
9'd214 : DAC_code = 16'hC6BF;
9'd215 : DAC_code = 16'hC547;
9'd216 : DAC_code = 16'hC3D3;
9'd217 : DAC_code = 16'hC263;
9'd218 : DAC_code = 16'hC0F7;
9'd219 : DAC_code = 16'hBF93;
9'd220 : DAC_code = 16'hBE2F;
9'd221 : DAC_code = 16'hBCD3;
9'd222 : DAC_code = 16'hBB7F;
9'd223 : DAC_code = 16'hBA2F;
9'd224 : DAC_code = 16'hB8E3;
9'd225 : DAC_code = 16'hB79B;
9'd226 : DAC_code = 16'hB65B;
9'd227 : DAC_code = 16'hB51F;
9'd228 : DAC_code = 16'hB3EB;
9'd229 : DAC_code = 16'hB2BB;
9'd230 : DAC_code = 16'hB193;
9'd231 : DAC_code = 16'hB06F;
9'd232 : DAC_code = 16'hAF53;
9'd233 : DAC_code = 16'hAE3B;
9'd234 : DAC_code = 16'hAD2B;
9'd235 : DAC_code = 16'hAC23;
9'd236 : DAC_code = 16'hAB1F;
9'd237 : DAC_code = 16'hAA23;
9'd238 : DAC_code = 16'hA92B;
9'd239 : DAC_code = 16'hA83F;
9'd240 : DAC_code = 16'hA757;
9'd241 : DAC_code = 16'hA673;
9'd242 : DAC_code = 16'hA59B;
9'd243 : DAC_code = 16'hA4C7;
9'd244 : DAC_code = 16'hA3FB;
9'd245 : DAC_code = 16'hA337;
9'd246 : DAC_code = 16'hA277;
9'd247 : DAC_code = 16'hA1C3;
9'd248 : DAC_code = 16'hA113;
9'd249 : DAC_code = 16'hA06B;
9'd250 : DAC_code = 16'h9FCB;
9'd251 : DAC_code = 16'h9F33;
9'd252 : DAC_code = 16'h9E9F;
9'd253 : DAC_code = 16'h9E17;
9'd254 : DAC_code = 16'h9D97;
9'd255 : DAC_code = 16'h9D1B;
9'd256 : DAC_code = 16'h9CA7;
9'd257 : DAC_code = 16'h9C3F;
9'd258 : DAC_code = 16'h9BDB;
9'd259 : DAC_code = 16'h9B7F;
9'd260 : DAC_code = 16'h9B2B;
9'd261 : DAC_code = 16'h9ADF;
9'd262 : DAC_code = 16'h9A9B;
9'd263 : DAC_code = 16'h9A63;
9'd264 : DAC_code = 16'h9A2F;
9'd265 : DAC_code = 16'h9A03;
9'd266 : DAC_code = 16'h99DF;
9'd267 : DAC_code = 16'h99C3;
9'd268 : DAC_code = 16'h99AF;
9'd269 : DAC_code = 16'h99A3;
9'd270 : DAC_code = 16'h999F;
9'd271 : DAC_code = 16'h99A3;
9'd272 : DAC_code = 16'h99AF;
9'd273 : DAC_code = 16'h99C3;
9'd274 : DAC_code = 16'h99DF;
9'd275 : DAC_code = 16'h9A03;
9'd276 : DAC_code = 16'h9A2F;
9'd277 : DAC_code = 16'h9A63;
9'd278 : DAC_code = 16'h9A9B;
9'd279 : DAC_code = 16'h9ADF;
9'd280 : DAC_code = 16'h9B2B;
9'd281 : DAC_code = 16'h9B7F;
9'd282 : DAC_code = 16'h9BDB;
9'd283 : DAC_code = 16'h9C3F;
9'd284 : DAC_code = 16'h9CA7;
9'd285 : DAC_code = 16'h9D1B;
9'd286 : DAC_code = 16'h9D97;
9'd287 : DAC_code = 16'h9E17;
9'd288 : DAC_code = 16'h9E9F;
9'd289 : DAC_code = 16'h9F33;
9'd290 : DAC_code = 16'h9FCB;
9'd291 : DAC_code = 16'hA06B;
9'd292 : DAC_code = 16'hA113;
9'd293 : DAC_code = 16'hA1C3;
9'd294 : DAC_code = 16'hA277;
9'd295 : DAC_code = 16'hA337;
9'd296 : DAC_code = 16'hA3FB;
9'd297 : DAC_code = 16'hA4C7;
9'd298 : DAC_code = 16'hA59B;
9'd299 : DAC_code = 16'hA673;
9'd300 : DAC_code = 16'hA757;
9'd301 : DAC_code = 16'hA83F;
9'd302 : DAC_code = 16'hA92B;
9'd303 : DAC_code = 16'hAA23;
9'd304 : DAC_code = 16'hAB1F;
9'd305 : DAC_code = 16'hAC23;
9'd306 : DAC_code = 16'hAD2B;
9'd307 : DAC_code = 16'hAE3B;
9'd308 : DAC_code = 16'hAF53;
9'd309 : DAC_code = 16'hB06F;
9'd310 : DAC_code = 16'hB193;
9'd311 : DAC_code = 16'hB2BB;
9'd312 : DAC_code = 16'hB3EB;
9'd313 : DAC_code = 16'hB51F;
9'd314 : DAC_code = 16'hB65B;
9'd315 : DAC_code = 16'hB79B;
9'd316 : DAC_code = 16'hB8E3;
9'd317 : DAC_code = 16'hBA2F;
9'd318 : DAC_code = 16'hBB7F;
9'd319 : DAC_code = 16'hBCD3;
9'd320 : DAC_code = 16'hBE2F;
9'd321 : DAC_code = 16'hBF93;
9'd322 : DAC_code = 16'hC0F7;
9'd323 : DAC_code = 16'hC263;
9'd324 : DAC_code = 16'hC3D3;
9'd325 : DAC_code = 16'hC547;
9'd326 : DAC_code = 16'hC6BF;
9'd327 : DAC_code = 16'hC83F;
9'd328 : DAC_code = 16'hC9BF;
9'd329 : DAC_code = 16'hCB47;
9'd330 : DAC_code = 16'hCCCF;
9'd331 : DAC_code = 16'hCE5F;
9'd332 : DAC_code = 16'hCFEF;
9'd333 : DAC_code = 16'hD187;
9'd334 : DAC_code = 16'hD31F;
9'd335 : DAC_code = 16'hD4BB;
9'd336 : DAC_code = 16'hD65B;
9'd337 : DAC_code = 16'hD7FF;
9'd338 : DAC_code = 16'hD9A7;
9'd339 : DAC_code = 16'hDB4F;
9'd340 : DAC_code = 16'hDCFB;
9'd341 : DAC_code = 16'hDEAB;
9'd342 : DAC_code = 16'hE05F;
9'd343 : DAC_code = 16'hE213;
9'd344 : DAC_code = 16'hE3C7;
9'd345 : DAC_code = 16'hE583;
9'd346 : DAC_code = 16'hE73B;
9'd347 : DAC_code = 16'hE8F7;
9'd348 : DAC_code = 16'hEAB7;
9'd349 : DAC_code = 16'hEC77;
9'd350 : DAC_code = 16'hEE3B;
9'd351 : DAC_code = 16'hEFFB;
9'd352 : DAC_code = 16'hF1C3;
9'd353 : DAC_code = 16'hF387;
9'd354 : DAC_code = 16'hF54F;
9'd355 : DAC_code = 16'hF713;
9'd356 : DAC_code = 16'hF8DB;
9'd357 : DAC_code = 16'hFAA7;
9'd358 : DAC_code = 16'hFC6F;
9'd359 : DAC_code = 16'hFE37;
9'd360 : DAC_code = 16'h0000;
default : DAC_code = 16'h0000;
endcase
end
end
endmodule
Dado que los valores seleccionados en la declaración de caso de sin LUT son para cada 360 grados del círculo unitario de la onda sinusoidal, la velocidad a la que el contador aumenta de 0 a 360 finalmente establece la frecuencia de la onda sinusoidal de salida.
Se requieren tres contadores en la lógica encima de sin LUT: uno para contar los grados que la sin LUT selecciona de 0 a 359, uno para contar el retraso entre incrementos de frecuencia 0 y otro para contar el retraso de frecuencia entre incrementos de 0. Frecuencia 1.
always @ (posedge clk)
begin
if (rst == 1'b0)
begin
degree_cntr <= 9'd0;
degree_cntr_done <= 1'b0;
end
else if (incr_degree_cntr == 1'b1)
begin
if (degree_cntr < unit_circle_deg)
begin
degree_cntr <= degree_cntr + 1;
degree_cntr_done <= 1'b0;
end
else
begin
degree_cntr <= 9'd0;
degree_cntr_done <= 1'b1;
end
end
else
begin
degree_cntr <= degree_cntr;
end
end
always @ (posedge clk)
begin
if (rst == 1'b0)
begin
incr_degree_cntr = 1'b0;
period_cntr <= 3'd0;
end
else
begin
if (period_cntr == period)
begin
incr_degree_cntr = 1'b1;
period_cntr <= 3'd0;
end
else
begin
incr_degree_cntr = 1'b0;
period_cntr <= period_cntr + 1;
end
end
end
always @ (posedge clk)
begin
if (rst == 1'b0)
begin
tdata_sel_cntr <= 5'd0;
end
else
begin
if (degree_cntr_done == 1'b1)
begin
tdata_sel_cntr <= tdata_sel_cntr + 1;
end
else
begin
tdata_sel_cntr <= tdata_sel_cntr;
end
end
end
También se necesita un conversor paralelo a serie para obtener los datos de 32 bits a través de la interfaz AXI Stream del paquete de datos enviado desde el DDR a través de la transmisión MM2S y serializarlo. Se puede realizar un ciclo de la frecuencia respectiva del bit. salida a través de la transmisión MM2S. DAC una vez. Aquí es donde entran en juego las limitaciones del 2-FSK: sólo se puede transmitir un bit a la vez.
always @ (tdata_sel_cntr)
begin
case (tdata_sel_cntr)
32'd0 :
begin
current_tx_bit <= tdata[0];
tx_pkt_done <= 1'b0;
end
32'd1 :
begin
current_tx_bit <= tdata[1];
tx_pkt_done <= 1'b0;
end
32'd2 :
begin
current_tx_bit <= tdata[2];
tx_pkt_done <= 1'b0;
end
32'd3 :
begin
current_tx_bit <= tdata[3];
tx_pkt_done <= 1'b0;
end
32'd4 :
begin
current_tx_bit <= tdata[4];
tx_pkt_done <= 1'b0;
end
32'd5 :
begin
current_tx_bit <= tdata[5];
tx_pkt_done <= 1'b0;
end
32'd6 :
begin
current_tx_bit <= tdata[6];
tx_pkt_done <= 1'b0;
end
32'd7 :
begin
current_tx_bit <= tdata[7];
tx_pkt_done <= 1'b0;
end
32'd8 :
begin
current_tx_bit <= tdata[8];
tx_pkt_done <= 1'b0;
end
32'd9 :
begin
current_tx_bit <= tdata[9];
tx_pkt_done <= 1'b0;
end
32'd10 :
begin
current_tx_bit <= tdata[10];
tx_pkt_done <= 1'b0;
end
32'd11 :
begin
current_tx_bit <= tdata[11];
tx_pkt_done <= 1'b0;
end
32'd12 :
begin
current_tx_bit <= tdata[12];
tx_pkt_done <= 1'b0;
end
32'd13 :
begin
current_tx_bit <= tdata[13];
tx_pkt_done <= 1'b0;
end
32'd14 :
begin
current_tx_bit <= tdata[14];
tx_pkt_done <= 1'b0;
end
32'd15 :
begin
current_tx_bit <= tdata[15];
tx_pkt_done <= 1'b0;
end
32'd16 :
begin
current_tx_bit <= tdata[16];
tx_pkt_done <= 1'b0;
end
32'd17 :
begin
current_tx_bit <= tdata[17];
tx_pkt_done <= 1'b0;
end
32'd18 :
begin
current_tx_bit <= tdata[18];
tx_pkt_done <= 1'b0;
end
32'd19 :
begin
current_tx_bit <= tdata[19];
tx_pkt_done <= 1'b0;
end
32'd20 :
begin
current_tx_bit <= tdata[20];
tx_pkt_done <= 1'b0;
end
32'd21 :
begin
current_tx_bit <= tdata[21];
tx_pkt_done <= 1'b0;
end
32'd22 :
begin
current_tx_bit <= tdata[22];
tx_pkt_done <= 1'b0;
end
32'd23 :
begin
current_tx_bit <= tdata[23];
tx_pkt_done <= 1'b0;
end
32'd24 :
begin
current_tx_bit <= tdata[24];
tx_pkt_done <= 1'b0;
end
32'd25 :
begin
current_tx_bit <= tdata[25];
tx_pkt_done <= 1'b0;
end
32'd26 :
begin
current_tx_bit <= tdata[26];
tx_pkt_done <= 1'b0;
end
32'd27 :
begin
current_tx_bit <= tdata[27];
tx_pkt_done <= 1'b0;
end
32'd28 :
begin
current_tx_bit <= tdata[28];
tx_pkt_done <= 1'b0;
end
32'd29 :
begin
current_tx_bit <= tdata[29];
tx_pkt_done <= 1'b0;
end
32'd30 :
begin
current_tx_bit <= tdata[30];
tx_pkt_done <= 1'b0;
end
32'd31 :
begin
current_tx_bit <= tdata[31];
tx_pkt_done <= 1'b1;
end
default :
begin
current_tx_bit <= 1'b0;
tx_pkt_done <= 1'b0;
end
endcase
end
always @ (posedge clk)
begin
if (current_tx_bit == 1'b1)
period <= T1_period;
else
period <= T0_period;
end
Al final, la interfaz AXI Stream solo necesita seguir la lógica anterior, utilizando la interfaz esclava para recibir datos del AXIS FIFO y la interfaz maestra para enviar los datos al controlador DAC.
`timescale 1ns / 1ps
module sin_axis(
input clk,
input reset,
input [31:0] s_axis_tdata,
input [3:0] s_axis_tkeep,
input s_axis_tlast,
output reg s_axis_tready,
input s_axis_tvalid,
output reg [31:0] m_axis_tdata,
output reg [3:0] m_axis_tkeep,
output reg m_axis_tlast,
input m_axis_tready,
output reg m_axis_tvalid,
output [2:0] state_reg
);
sin_sm sin_sm_i(
.clk(clk),
.rst(reset),
.tdata_slave(tdata_slave),
.tdata_master(tdata_master),
.tx_pkt_done(tx_pkt_done)
);
reg tlast;
reg [2:0] state_reg;
wire tx_pkt_done;
wire [31:0] tdata_master;
reg [31:0] tdata_slave;
parameter init = 3'd0;
parameter SetSlaveTready = 3'd1;
parameter CheckSlaveTvalid = 3'd2;
parameter ProcessTdata = 3'd3;
parameter CheckTlast = 3'd4;
always @ (posedge clk)
begin
// Default outputs
m_axis_tvalid <= 1'b0;
if (reset == 1'b0)
begin
tlast <= 1'b0;
tdata_slave[31:0] <= 32'd0;
s_axis_tready <= 1'b0;
m_axis_tdata[31:0] <= 32'd0;
m_axis_tkeep <= 4'h0;
m_axis_tlast <= 1'b0;
state_reg <= init;
end
else
begin
case(state_reg)
init : // 0
begin
tlast <= 1'b0;
tdata_slave[31:0] <= 32'd0;
s_axis_tready <= 1'b0;
m_axis_tdata[31:0] <= 32'd0;
m_axis_tkeep <= 4'h0;
m_axis_tlast <= 1'b0;
state_reg <= SetSlaveTready;
end
SetSlaveTready : // 1
begin
s_axis_tready <= 1'b1;
state_reg <= CheckSlaveTvalid;
end
CheckSlaveTvalid : // 2
begin
if (s_axis_tkeep == 4'hf && s_axis_tvalid == 1'b1)
begin
s_axis_tready <= 1'b0;
tlast <= s_axis_tlast;
tdata_slave[31:0] <= s_axis_tdata[31:0];
state_reg <= ProcessTdata;
end
else
begin
tdata_slave[31:0] <= 32'd0;
state_reg <= CheckSlaveTvalid;
end
end
ProcessTdata : // 3
begin
m_axis_tkeep <= 4'hf;
m_axis_tlast <= tlast;
m_axis_tvalid <= 1'b1;
m_axis_tdata[31:0] <= tdata_master[31:0];
if (m_axis_tready == 1'b1 && tx_pkt_done == 1'b1)
begin
state_reg <= CheckTlast;
end
else
begin
state_reg <= ProcessTdata;
end
end
CheckTlast : // 4
begin
if (m_axis_tlast == 1'b1)
begin
state_reg <= init;
end
else if (m_axis_tready == 1'b1)
begin
state_reg <= SetSlaveTready;
end
else
begin
state_reg <= CheckTlast;
end
end
endcase
end
end
endmodule
Vea el código completo al final.
software vitis
Dado que toda la lógica para generar la onda sinusoidal se maneja en HDL en Verilog, lo único que queda en el código C es controlar la transmisión MM2S (el archivo fuente también se adjunta a continuación):
int main()
{
init_platform();
XAxiDma_Config *CfgPtr; //DMA configuration pointer
int Status, Index;
u8 *TxBufferPtr;
TxBufferPtr = (u8 *)TX_BUFFER_BASE;
for(Index = 0; Index < MAX_PKT_LEN; Index ++){
TxBufferPtr[Index] = 0x00;
}
CfgPtr = XAxiDma_LookupConfig(DMA_DEV_ID);
if (!CfgPtr) {
xil_printf("No config found for %d\r\n", DMA_DEV_ID);
return XST_FAILURE;
}
Status = XAxiDma_CfgInitialize(&AxiDma, CfgPtr);
if (Status != XST_SUCCESS) {
xil_printf("Initialization failed %d\r\n", Status);
return XST_FAILURE;
}
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);
TxBufferPtr[0] = 0xef;
Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, MAX_PKT_LEN);
XAxiDma_Reset(&AxiDma);
Status = XAxiDma_MM2Stransfer(&AxiDma,(UINTPTR) TxBufferPtr, MAX_PKT_LEN);
if (Status != XST_SUCCESS){
xil_printf("XAXIDMA_DMA_TO_DEVICE transfer failed...\r\n");
return XST_FAILURE;
}
cleanup_platform();
return 0;
}
Equipo de prueba
Para verificar la salida analógica, conecte su canal 1 al canal 1 del osciloscopio e inicie WaveForms en la PC host para verlo.
Luego, se inició la depuración de la aplicación C en Vitis y se estableció un punto de interrupción antes de que comenzara la transferencia MM2S:
Dado que el DAC está configurado en modo de ganancia baja, el valor máximo de salida es de aproximadamente 1,0 V. En la pestaña Alcance de WaveForms, configure el disparador de nivel para flancos ascendentes por encima de 100 mV y haga clic en Ejecutar.
Obtenga una salida clara de dos valores de frecuencia diferentes 1 y 0:
Como mencioné anteriormente, esta es solo una versión muy simplificada del mapeador de símbolos para superar las dificultades de comenzar con el diseño SDR de una manera más práctica y práctica. Dos contadores de períodos con diferentes frecuencias son un buen punto de partida para ver el resultado.
código
❝https://github.com/Digilent/vivado-boards
❞
❝https://github.com/suisuisi/FPGATechnologyGroup/tree/main/simple_2_fsk
❞