OFDM 802.11a的FPGA实现(二十一)发射主控模块MCU(含代码)

2024-05-24 04:20

本文主要是介绍OFDM 802.11a的FPGA实现(二十一)发射主控模块MCU(含代码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

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_redirecticon-default.png?t=N7T8https://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帧结构

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 6RATE = [1 1 0 1];case 9RATE = [1 1 1 1];case 12RATE = [0 1 0 1];case 18RATE = [0 1 1 1];case 24RATE = [1 0 0 1];case 36RATE = [1 0 1 1];case 48RATE = [0 0 0 1];case 54RATE = [0 0 1 1];otherwisedisp('tx_rate_error');
end
%保留位
R = 0;
%LENGTH字段:LSB-MSB(bit5-16)
byte_len = dec2bin(leng_num_in/8,12);
for m = 1:12LENGTH(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层发来的信息byteinput  [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)beginif(!rst_n)phy_rst_n <= 1'b1;else if(mcu_config_din_start)phy_rst_n <= 1'b0;elsephy_rst_n <= 1'b1;
end
//发完一包数据后,准备好再次向MAC层接收数据
always@(posedge clk or negedge rst_n)beginif(!rst_n)mcu_config_dout_rdy <= 1'b1;else if(tx_end)mcu_config_dout_rdy <= 1'b1;elsemcu_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)beginif(!rst_n)beginmcu_dout_scram_load <= 1'b0;mcu_dout_scram_seed <= 'd0;endelse beginmcu_dout_scram_load <= ~phy_rst_n;mcu_dout_scram_seed <= SEED;end
endendmodule

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;elsemcu_config_din_start <= 1'b0;always@(posedge clk or negedge rst_n)if(!rst_n)beginmcu_config_din <= 'd0;mcu_config_din_vld <= 1'b0;endelse if(mcu_config_din_start)beginmcu_config_din <= {LEGENTH,6'd36,3'd0};mcu_config_din_vld <= 1'b1;endelsemcu_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_redirecticon-default.png?t=N7T8https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkxNjM0NDk2Nw==&action=getalbum&album_id=3409621333838200834#wechat_redirect

 

这篇关于OFDM 802.11a的FPGA实现(二十一)发射主控模块MCU(含代码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/997359

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n