ZYNQ上的简单 FSK 基带发射器

绪论

由于某种需求需要生成正弦波,因此使用 C 应用程序中的sin()函数来计算单位圆的幅度值,然后将该幅度值转换为 AD9717 的适当 DAC 代码(当然将每个角度值转换为弧度)。

ZYNQ上的简单 FSK 基带发射器_第1张图片

能够使用DAC生成简单的正弦波,下一个想法就是在 SDR(软件定义无线电)中使用频率调制。

大多数 SDR 设计都有 3 个不同的内部运行频率:一个低基带频率,用于处理来自 ADC/DAC 的数据;一个或多个中间频率,最终基带数据流作为中间步骤提升到该频率;以及最终的 RF 将输入/输出天线的输出频率。显然,最简单的起点是基带,因为它是最低频率,并且是实际模拟数据流从各个数字数据位组合在一起/提取的地方。为了进一步缩小范围,1 和 0 的数字位与某些相关模拟波形相关的确切点被称为符号映射器,它是前面提到的 SDR 基本构建块。

因此,本项目将是一个非常简化的基带符号映射器,用于 FSK 数字调制方案的链(数字到模拟)的发送端。

数字调制

频移键控 (FSK) 是一种数字调制,通过更改频率来表示数据流中的不同位/符号。在其最基本的形式中,一个频率用于表示二进制 1,另一个频率用于表示二进制 0。这种形式的 FSK 被称为二进制 FSK 或 2-FSK。

ZYNQ上的简单 FSK 基带发射器_第2张图片

从上面可以看出,1比特由大约是表示0比特的频率的两倍的频率来表示。对于 ZYNQ+SDR 来说,这意味着它需要能够分别以连续相位输出两个不同的频率。换句话说:定时在这里很重要,可以确保一个频率的相位恰好在最后一个频率的相位停止的地方出现。每个频率的一个完整周期也是每一位完成的。

Vivado 中的逻辑设计

由于本演示中只关注发送器端,为了处理符号映射器逻辑可能在 MM2S 读取中对来自 DDR 内存的数据流施加的背压,将带有 FSK 符号映射器的 sin LUT 放置在 AXIS 数据 FIFO 和 DAC 控制器 IP 之间。这样,FIFO 可以完成从内存的 MM2S 传输,当符号映射器逻辑每比特输出一个周期的相应频率值时,AXI DMA 不会被锁定tdata。

ZYNQ上的简单 FSK 基带发射器_第3张图片

代码如下:

`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

由于 sin LUT 的 case 语句中的选择值是正弦波单位圆的每个 360 度值,因此计数器从 0 到 360 递增的速度最终设置了输出正弦波的频率。

sin LUT 上方的逻辑中需要三个计数器:一个计数器用于对 sin LUT 选择从 0 到 359 的度数进行计数,一个计数器用于计算频率 0 的增量之间的延迟,以及一个计数器用于计算频率 0 的增量之间的延迟。频率 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

还需要一个并行到串行转换器,通过 MM2S 传输从 DDR 发出的数据包的 AXI Stream 接口获取 32 位数据,并将其串行化,可以通过 MM2S 传输输出该位各自频率的一个周期。 DAC一次。这就是 2-FSK 的局限性暴露出来的地方:一次只能传输一位。

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

最后,AXI Stream 接口只需要围绕上述逻辑,使用从接口接收来自 AXIS FIFO 的数据,并使用主接口将数据输出到 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

完整的代码见最后。

Vitis 软件

由于生成正弦波的所有逻辑都是在 Verilog 的 HDL 中处理的,因此 C 代码中唯一剩下的就是控制 MM2S 传输(源文件也附在下面):

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;
}
ZYNQ上的简单 FSK 基带发射器_第4张图片

测试设备

为了验证模拟输出,将其通道 1 连接到示波器通道 1,并在主机 PC 上启动 WaveForms 来查看它。

然后,在 Vitis 中启动 C 应用程序的调试,并在 MM2S 传输开始之前设置了断点:

ZYNQ上的简单 FSK 基带发射器_第5张图片

由于将DAC设置为低增益模式,因此峰值输出值约为 1.0v。在 WaveForms 的 Scope 选项卡中,为超过 100mV 的上升沿设置电平触发器,然后单击Run 。

得到 1 和 0 两个不同频率值的清晰输出:

ZYNQ上的简单 FSK 基带发射器_第6张图片

正如我上面提到的,这只是符号映射器的一个非常简化的版本,目的是为了以更实用、更实际的方式克服 SDR 设计入门的困难。两个不同频率的周期计数器是查看输出结果的良好起点。

代码

https://github.com/Digilent/vivado-boards

https://github.com/suisuisi/FPGATechnologyGroup/tree/main/simple_2_fsk

你可能感兴趣的:(fpga开发)