DLL分频模块:由于该系统的需要 , FPGA的工作时钟不止一个 , 有的由输入提供 , 有的必须由本地晶振产生再经FPGA分频后得到 。同时 , 随MPDU一起输出的6.25MHz时钟也要由本地时钟分频得到 。尽量利用FPGA的DLL资源(Delay-Locked Loop)来分频 , 这样可以提高时钟质量 。
双口RAM:发来的每一帧不一定能及时处理(有可能这一帧还没处理完 , 后面又来了很多帧) , 而且接收和发送时钟频率还不一样 。双口RAM就是起到数据缓存的作用 。这里收发两个双口RAM都是4bit 16K , 即每个存储单元为4bit , 存储深度是16K 。每个RAM都是单向的 , 一端只负责收 , 另一端只负责发 , 收发时钟独立 。实现上Xilinx ISE开发工具提供了RAM的IP Core , 使用的是FPGA内的Block RAM资源 。
Length存储器:每一帧的数据长度不是一定的 , 而是有一个范围 , 所以要用一个存储器把双口RAM里每一帧的长度(这里指Nibble数 , 每4bit称为一个Nibble)都存起来 。这样一方面在读数时能与读计数器有个比较 , 知道什么时候这一帧读完了;另一方面也是MPUD帧格式本身的需要 , MPDU帧头部分要加上12bit Length来表示帧长 。
写控制状态机:写控制状态机由4个状态组成 , 分别为空闲状态(Idle)、判决状态(Decision)、写状态(Write)、结束状态(End) 。
Idle状态:把所有计数器、寄存器清零 , 等待着数据帧的到来 。
Decision状态:假如数据使能信号出现高电平 , 就跳到该状态 , 完成的功能就是根据帧头的Preamble来决定这一帧是接收还是丢弃 。Preamble由15个1010和一个1011组成 , 假如连续收到8个或8个以上1010 , 然后再收到一个1011 , 那么就可以认为这一帧有效 , 否则就认为这一帧已经出现了严重的误码 , 或是使能信号置高是由于外界干扰而出现的假象 , 所以将这一帧丢弃 , 重新回到Idle状态 。
Write状态:在该状态下主要完成3件事 。将数据并行写入双口RAM;启动Write计数器 , 记录这一帧共有多少Nibble;然后把Write计数器的值存入Length存储器 。
End状态:这个状态一方面完成全部使能信号的归零 , 另一方面假如由于前面的处理使得数据和使能信号发生了错位 , 在这个状态就可以调整 。
读控制状态机:根据需要 , 笔者设计的读控制状态机分别由搜索状态(Search)、Length发送状态(Tran_Length)、读状态(Read)、结束状态(End)4个状态组成 。图5给出了状态转移图 。
Search状态:每15个时钟周期就检测一下双口RAM中有没有完整的帧 。之所以要15个时钟周期才检测一次 , 而不时时刻刻都在检测 , 是因为笔者要求每个MPDU之间的间隔至少为15个时钟周期 。假如有一个或一个以上完整的帧 , 而且基带部分已经预备好 , 那么就跳到下一个状态 。
Tran_Length状态:这个状态下 , 12位寄存器里的值(表示的是该帧的Nibble数)转换成Byte数 , 再串行移位发送出去 。
Read状态:这里开辟了一个控制计数器 , 从00到11以4个时钟为周期循环计数 , 每个周期内都把双口RAM里的一个Nibble装载到4位寄存器内 , 然后再串行移位输出 , 这样就完成了数据的并/串转换 。同时启动Read计数器 , 计数的值与12位寄存器里的值比较 , 假如相等说明该帧已经发送完毕了 , 就停止读数 。
End状态:跟写数时一样 , 这个状态主要完成使能信号归零和错位调整 。
帧计数器:用来记录双口RAM里完整的帧的数量 , 只有当它的值大于或等于1时才能读数 , 这样才不至于读空 。接收模块
接收是发送的逆过程 , 在实现上与发送模块有很大的相似性 , 本文不再赘述 。
推荐阅读
- 芦笋为什么是苦的 芦笋苦是因为什么
- 汽车绞牙是什么
- 1024是什么
- 谈基于802.11无线网络的发展方向
- 龙利鱼和巴沙鱼是一种鱼吗
- 公寓是商品房的一种吗
- 预防大白菜干烧心
- 怎么写小说
- 什么方法是目前普遍采用的一种放松技术
- 苍蝇是蛆变的吗