0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何实现一种基于ZYNQ的简单FSK基带发射器?

OpenFPGA 来源:OpenFPGA 2023-09-04 09:03 次阅读

绪论

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

c86058c0-4aba-11ee-97a6-92fbcf53809c.png

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

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

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

数字调制

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

c87ff0ea-4aba-11ee-97a6-92fbcf53809c.png

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

Vivado 中的逻辑设计

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

c89a8b26-4aba-11ee-97a6-92fbcf53809c.png

代码如下:

`timescale1ns/1ps

modulesin_lut(
inputclk,
inputrst,
input[8:0]sel,
output[15:0]DAC_code
);

reg[15:0]DAC_code;

always@(posedgeclk)
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@(posedgeclk)
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 控制器。

`timescale1ns/1ps

modulesin_axis(
inputclk,
inputreset,
input[31:0]s_axis_tdata,
input[3:0]s_axis_tkeep,
inputs_axis_tlast,
outputregs_axis_tready,
inputs_axis_tvalid,
outputreg[31:0]m_axis_tdata,
outputreg[3:0]m_axis_tkeep,
outputregm_axis_tlast,
inputm_axis_tready,
outputregm_axis_tvalid,
output[2:0]state_reg
);

sin_smsin_sm_i(
.clk(clk),
.rst(reset),
.tdata_slave(tdata_slave),
.tdata_master(tdata_master),
.tx_pkt_done(tx_pkt_done)
);


regtlast;
reg[2:0]state_reg;

wiretx_pkt_done;
wire[31:0]tdata_master;
reg[31:0]tdata_slave;


parameterinit=3'd0;
parameterSetSlaveTready=3'd1;
parameterCheckSlaveTvalid=3'd2;
parameterProcessTdata=3'd3;
parameterCheckTlast=3'd4;

always@(posedgeclk)
begin
//Defaultoutputs
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 传输(源文件也附在下面):

intmain()
{
init_platform();

XAxiDma_Config*CfgPtr;//DMAconfigurationpointer
intStatus,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
", DMA_DEV_ID);
        return XST_FAILURE;
    }

    Status = XAxiDma_CfgInitialize(&AxiDma, CfgPtr);
    if (Status != XST_SUCCESS) {
        xil_printf("Initialization failed %d
", 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...
");
 return XST_FAILURE;
    }

    cleanup_platform();
    return 0;
}
c8dd4ae2-4aba-11ee-97a6-92fbcf53809c.png

测试设备

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

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

c9412b52-4aba-11ee-97a6-92fbcf53809c.png

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

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

c962228a-4aba-11ee-97a6-92fbcf53809c.png

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







审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 发射器
    +关注

    关注

    6

    文章

    842

    浏览量

    53390
  • FSK
    FSK
    +关注

    关注

    14

    文章

    114

    浏览量

    58338
  • SDR
    SDR
    +关注

    关注

    7

    文章

    233

    浏览量

    50413
  • 基带
    +关注

    关注

    4

    文章

    159

    浏览量

    30825
  • 数字调制
    +关注

    关注

    0

    文章

    46

    浏览量

    13003
  • Zynq
    +关注

    关注

    9

    文章

    608

    浏览量

    47122
  • Zynq芯片
    +关注

    关注

    0

    文章

    3

    浏览量

    1712

原文标题:ZYNQ上的简单 FSK 基带发射器

文章出处:【微信号:Open_FPGA,微信公众号:OpenFPGA】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    简单的低功耗红外发射器电路

    该红外发射器电路是简单的低功耗红外发射器,可用于许多远程控制应用。正如我们所看到的,许多遥控器使用红外波进行控制。该电路能够以1kHz的频率传输甚至十米的红外波,并且可以根据您的要
    的头像 发表于 07-04 18:23 2083次阅读
    <b class='flag-5'>一</b>个<b class='flag-5'>简单</b>的低功耗红外<b class='flag-5'>发射器</b>电路

    WE800 FM/FSK l~0.1 GHz发射器

    ; WE800是款完全集成的单片FM/FSK发射器芯片,工作频率为0.1~1 GHz,包括ISM频段(902~928 MHz)。它适用于模拟/数字900 MHz无绳电话、无线遥控、报警和安防系统以及无线工业
    发表于 08-16 23:05

    RF2513 FM/FSK 915/868/433 MHz发射器

    ;nbsp; RF2513是个使用低成本频率合成器的单片FM/FSK发射器。它适合美国915 MHz ISM频带和欧洲433 MHz或868 MHz ISM频带应用。  主要技术特点
    发表于 08-28 11:25

    TH72011 FSK发射器芯片

    TH72011 FSK发射器芯片【产品名称】 TH72011 FSK发射器芯片 【产品类别】  集成电路 【市 场 价
    发表于 01-21 16:34

    如何去实现一种基带解调的设计?

    AD6654是什么?如何去实现一种基带解调的设计?AD6654在数字电视基带解调设计中有什么
    发表于 06-07 06:16

    构建个77.5 KHz的简单发射器

    描述DCF77实验发射机构建个 77.5 KHz 的简单发射器,以便能够设置时间 DCF77 时钟,这些时钟不能正确接收来自德国发射器的信
    发表于 09-06 07:19

    UHFFM/FSK无线电收发电路设计?

     介绍了一种采用CMX017/018单片UHFFM/FSK发射芯片和接收芯片的无线电收发电路。     关键词:UHF,FM/FSK,无线电
    发表于 05-10 13:34 2219次阅读
    UHFFM/<b class='flag-5'>FSK</b>无线电收发电路设计?

    红外发射器,红外发射器是什么意思

    红外发射器,红外发射器是什么意思 红外线属于一种电磁射线,其特性等同于无线电或X射线。人眼可见的光波是380nm-780nm,发射波长为780nm-1mm的长射
    发表于 02-27 17:35 6730次阅读

    MAX7049 ASK/FSK UHF发射器

    MAX7049高性能,单芯片,超低功耗ASK / FSK UHF发射器在工业,科学,医疗(ISM)频段在288MHz至945MHz的载波频率经营
    发表于 07-08 11:26 2245次阅读
    MAX7049 ASK/<b class='flag-5'>FSK</b> UHF<b class='flag-5'>发射器</b>

    一种基于FPGA的ZigBee物理层发射机的数字基带实现方案_陈

    一种基于FPGA的ZigBee物理层发射机的数字基带实现方案_陈迪平
    发表于 03-14 16:54 6次下载

    nRF904 FSK 915 MHz发射器

    关键词:FSK , nRF904 , 发射器 nRF904是个符合北美FCC CFR47 Part 15标准的单片发射器芯片。它适合报警
    发表于 08-27 15:12 397次阅读

    IoTEE项目正在推出一种接收发射器设备,以实现太空物联网

    我们知道,当前的网络无法应对物联网以及它所带来连网设备的指数级增长。虽然低功耗广域网(LPWAN)技术对于应对未来需求至关重要,但专家们越来越多地将卫星视为一种补充解决方案,尤其是对于人口稀少地区。IoTEE项目正在推出一种接收
    发表于 10-29 15:00 1313次阅读

    ADF7901:高性能ISM波段00K/FSK发射器IC数据表

    ADF7901:高性能ISM波段00K/FSK发射器IC数据表
    发表于 04-27 21:39 3次下载
    ADF7901:高性能ISM波段00K/<b class='flag-5'>FSK</b><b class='flag-5'>发射器</b>IC数据表

    ADF7010:高性能ISM磁带Ask/FSK/GFSK发射器IC过时的数据Sheet

    ADF7010:高性能ISM磁带Ask/FSK/GFSK发射器IC过时的数据Sheet
    发表于 04-29 09:31 2次下载
    ADF7010:高性能ISM磁带Ask/<b class='flag-5'>FSK</b>/GFSK<b class='flag-5'>发射器</b>IC过时的数据Sheet

    简单的FM跟踪发射器电路

    这是简单的 FM 跟踪发射器电路项目,此 FM 跟踪的电流消耗为 3.7mA,因此 1.5V 纽扣电池将持续段时间。
    发表于 07-10 10:51 1700次阅读
    <b class='flag-5'>一</b>个<b class='flag-5'>简单</b>的FM跟踪<b class='flag-5'>发射器</b>电路