目录
1.前言
2.主控逻辑
3.Matlab
4.verilog
5.ModelSim
6.ModelSim仿真结构与Matlab自动化对比
完整工程链接(含verilog和Matlab代码):
https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkxNjM0NDk2Nw==&action=getalbum&album_id=3409621333838200834#wechat_redirecthttps://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkxNjM0NDk2Nw==&action=getalbum&album_id=3409621333838200834#wechat_redirect
1.前言
对于发射部分的OFDM 802.11a的FPGA实现,已经接近闻声了,现在是万事俱备只欠东风,所有功能模块已经设计完成,目前还需要一个主控模块,其作用是:
(1)与MAC通信进行数据交互;
(2)控制一包发射数据按照PPDU帧结构的顺序进行发送。
下面这两张图一直放出来,不觉得厌烦,这是协议的核心。
PPDU帧结构
PPDU帧结构
2.主控逻辑
由于最终生成的OFDM符号有着严格的格式与时序要求,并且各个功能模块的处理延迟也能保持稳定,因此主控单元MCU需要对数据流向实现控制功能。另外,每次发射处理都是由MAC层,收到物理层传输完成信号,所发起的,且需要传输大量数据,以及配置信息,所以MCU与MAC层之间的通信也采用AXI Stream协议。
当MCU收到MAC层发来的start信号后,对发射各模块硬件进行复位,并且接收参数配置信息。MAC层发来参数配置是21位信号,其中包含的是待发射PSDU帧长(LENGTH,12bits)、发射速率(RATE,6bits)和发射功率等级(TXPWR,3bits)三个发射参数。
接收到参数配置信息,送往tx_gen_pkt_sig模块,生成signal域数据帧,并以字节形式输出。不清楚的,回顾之前的文章:OFDM 802.11a的FPGA实现(十九)signal域帧生成(含代码)
复位之后,通过AXI Stream协议,向MAC层接收要发送的字节数据,并且控制训练序列开始输出。不清楚的,回顾之前的文章:OFDM 802.11a的FPGA实现(十七)PLCP的前导部分:长短训练序列组合加窗(含代码)
复位之后,加载扰码器的初始状态。不清楚的,回顾之前的文章:OFDM802.11a的FPGA实现(四)扰码
无论是signal域数据帧,还是MAC传来的待发送字节,都要送往并串转换模块,最终以bit的形式输出。MCU模块控制signal域数据帧,最先送往并串转换模块,接着MAC传来的待发送字节再送。
TxPWR为发射功率等级,输出给后面的DAC使用。
当一包数据发送完成,MCU模块接收到指令后,给MAC送去准备好信号,mcu_config_dout_rdy。
tx_mcu模块输出依次连接扰码、卷积编码、删余、一级交织、二级交织、调制映射、插入导频、ifft、DAC模块(此模块后面一章节进行设计)。如下图所示:
连接方式
DAC模块,主要是将时域的输出按照前导码、signal帧、data域的顺序进行排列,将数据速率从125M的突发形式,转换为20M的连续形式,然后送往硬件DAC输出模拟信号。这个模块后面一个章节再来讲解设计。
3.Matlab
matlab生成signal帧数据代码如下:
%% signal帧数据生成
%RATE = [R1 R2 R3 R4] 字段
tx_rate = 48 * M * code_rate / 12 /4;
switch(tx_rate)
case 6
RATE = [1 1 0 1];
case 9
RATE = [1 1 1 1];
case 12
RATE = [0 1 0 1];
case 18
RATE = [0 1 1 1];
case 24
RATE = [1 0 0 1];
case 36
RATE = [1 0 1 1];
case 48
RATE = [0 0 0 1];
case 54
RATE = [0 0 1 1];
otherwise
disp('tx_rate_error');
end
%保留位
R = 0;
%LENGTH字段:LSB-MSB(bit5-16)
byte_len = dec2bin(leng_num_in/8,12);
for m = 1:12
LENGTH(12-m+1) = str2num(byte_len(m));
end
%偶校验位
EVEN_PARITY = mod(sum([RATE,R,LENGTH]),2);
%尾bit
TAIL = [0 0 0 0 0 0];
%组帧
signal_preamble = [RATE,R,LENGTH,EVEN_PARITY,TAIL];
4.verilog
发射主控模块
`timescale 1ns / 1ps
module tx_mcu(
input clk ,
input rst_n ,
//MAC层发来参数配置,21位信号,其中包含的是待发射PSDU帧长(LENGTH,12bits)、
//发射速率(RATE,6bits)和发射功率等级(TXPWR,3bits)三个发射参数。
input [20:0] mcu_config_din ,
input mcu_config_din_vld ,
input mcu_config_din_start,
output reg mcu_config_dout_rdy ,
//MAC层发来的信息byte
input [7:0] mcu_mac_din ,
input mcu_mac_din_vld ,
output mcu_mac_dout_rdy ,
//输出信息串行bit流
input mcu_din_rdy ,
output mcu_dout ,
output mcu_dout_vld ,
output mcu_dout_sig_flag ,
output [3:0] mcu_dout_rate_con ,
//扰码器初始值配置
output reg [6:0] mcu_dout_scram_seed , //扰码器初始状态
output reg mcu_dout_scram_load ,
//物理层硬件软复位
output reg phy_rst_n ,
//输入一包数据发送完成信号
input tx_end ,
//输出发射功率等级
output [2:0] TxPWR
);
parameter SEED = 7'b1011101;
//signal
wire [ 5:0] sig_din_tx_rate ;
wire [11:0] sig_din_tx_length;
wire sig_din_vld ;
wire sig_din_rdy ;
wire [7:0] sig_dout ;
wire sig_dout_vld ;
wire sig_dout_rdy ;
wire [3:0] sig_dout_rate_con;
wire sig_dout_last ;
wire sig_dout_sig_flag;
//连接并-串
wire [7:0] P2S_din ;
wire P2S_din_vld ;
wire P2S_din_rdy ;
wire P2S_dout ;
wire P2S_dout_vld ;
wire P2S_dout_rdy ;
//MAC层发来传输信号mcu_config_din_start后,对硬件复位
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
phy_rst_n <= 1'b1;
else if(mcu_config_din_start)
phy_rst_n <= 1'b0;
else
phy_rst_n <= 1'b1;
end
//发完一包数据后,准备好再次向MAC层接收数据
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
mcu_config_dout_rdy <= 1'b1;
else if(tx_end)
mcu_config_dout_rdy <= 1'b1;
else
mcu_config_dout_rdy <= 1'b0;
end
//生成signal数据帧结构
assign sig_din_tx_rate = mcu_config_din[8:3];
assign sig_din_tx_length = mcu_config_din[20:9];
assign TxPWR = mcu_config_din[2:0];
assign sig_din_vld = mcu_config_din_vld;
//assign sig_dout_rdy = mcu_config_dout_rdy;
assign sig_din_rdy = sig_dout_sig_flag ? P2S_dout_rdy : 1'b0;
tx_gen_pkt_sig u_tx_gen_pkt_sig(
.clk (clk ),
.rst_n (rst_n ),
.sig_din_tx_rate (sig_din_tx_rate ),
.sig_din_tx_length (sig_din_tx_length ),
.sig_din_vld (sig_din_vld ),
.sig_din_rdy (sig_din_rdy ),
.sig_dout (sig_dout ),
.sig_dout_vld (sig_dout_vld ),
.sig_dout_rdy (sig_dout_rdy ),
.sig_dout_rate_con (sig_dout_rate_con ),
.sig_dout_last (sig_dout_last ),
.sig_dout_sig_flag (sig_dout_sig_flag )
);
assign mcu_dout_rate_con = sig_dout_rate_con;
assign mcu_dout_sig_flag = sig_dout_sig_flag;
assign P2S_din = sig_dout_sig_flag ?
{sig_dout[0],sig_dout[1],sig_dout[2],
sig_dout[3],sig_dout[4],sig_dout[5],
sig_dout[6],sig_dout[7]} : mcu_mac_din;
assign P2S_din_vld = sig_dout_sig_flag ? sig_dout_vld : mcu_mac_din_vld;
assign P2S_din_rdy = mcu_din_rdy;
Par2Ser #( .WIDTH (4'd8),
.LSB_FIRST (1'b1))
Par2Ser_u2(
.clk (clk ),
.rst_n (rst_n ),
.din (P2S_din ),
.din_vld (P2S_din_vld ),
.din_rdy (P2S_din_rdy ),
.dout (P2S_dout ),
.dout_vld (P2S_dout_vld ),
.dout_rdy (P2S_dout_rdy )
);
assign mcu_dout = P2S_dout;
assign mcu_dout_vld = P2S_dout_vld;
assign mcu_mac_dout_rdy = P2S_dout_rdy;
//扰码器初始值配置
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
mcu_dout_scram_load <= 1'b0;
mcu_dout_scram_seed <= 'd0;
end
else begin
mcu_dout_scram_load <= ~phy_rst_n;
mcu_dout_scram_seed <= SEED;
end
end
endmodule
5.ModelSim
等最后一个DAC模块设计完成再一起进行整个发射部分联调,现在先对MUC模块进行简单测试,粗略查看下控制时序是否正确,以及输出signal的数据是否能对应上matlab生成的。testbench测试逻辑部分如下:
always@(posedge clk or negedge rst_n)
if(!rst_n)
mcu_config_din_start <= 1'b0;
else if(mcu_config_dout_rdy)
mcu_config_din_start <= 1'b1;
else
mcu_config_din_start <= 1'b0;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
mcu_config_din <= 'd0;
mcu_config_din_vld <= 1'b0;
end
else if(mcu_config_din_start)begin
mcu_config_din <= {LEGENTH,6'd36,3'd0};
mcu_config_din_vld <= 1'b1;
end
else
mcu_config_din_vld <= 1'b0;
assign mcu_mac_din = P2S_din;
assign mcu_mac_din_vld = P2S_din_vld;
assign mcu_din_rdy = P2S_din_rdy;
assign tx_end = cnt_last;
tx_mcu u_tx_mcu(
.clk (clk ),
.rst_n (rst_n ),
.mcu_config_din (mcu_config_din ),
.mcu_config_din_vld (mcu_config_din_vld ),
.mcu_config_din_start (mcu_config_din_start ),
.mcu_config_dout_rdy (mcu_config_dout_rdy ),
.mcu_mac_din (mcu_mac_din ),
.mcu_mac_din_vld (mcu_mac_din_vld ),
.mcu_mac_dout_rdy (mcu_mac_dout_rdy ),
.mcu_din_rdy (mcu_din_rdy ),
.mcu_dout (mcu_dout ),
.mcu_dout_vld (mcu_dout_vld ),
.mcu_dout_sig_flag (mcu_dout_sig_flag ),
.mcu_dout_rate_con (mcu_dout_rate_con ),
.mcu_dout_scram_seed (mcu_dout_scram_seed ),
.mcu_dout_scram_load (mcu_dout_scram_load ),
.phy_rst_n (phy_rst_n ),
.tx_end (tx_end ),
.mcu_dout_train_rdy (mcu_dout_train_rdy ),
.TxPWR (TxPWR )
);
仿真截图
6.ModelSim仿真结构与Matlab自动化对比
%% MCU
FPGA_mcu_dout = load([PATH,'mcu_data_out.txt'])';
disp(FPGA_mcu_dout);
check_signal_preamble = signal_preamble == FPGA_mcu_dout(1:24);
disp(check_signal_preamble);
对比结果如下:
check_signal_preamble =
1×24 logical 数组
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
完整工程链接(含verilog和Matlab代码):
https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkxNjM0NDk2Nw==&action=getalbum&album_id=3409621333838200834#wechat_redirecthttps://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkxNjM0NDk2Nw==&action=getalbum&album_id=3409621333838200834#wechat_redirect