赞
踩
记录FPGA(Xilinx-Ego1)学习调试时遇到的坑和Bug解决方法,以及Vivado开发FPGA的代码编写技巧,为之后复习留个底子。通篇文章均用单片机的开发思路去开发FPGA,只为帮助读者能快速上手,开发语言为最常用的Verilog。
关于如何使用Vivado创建一个工程见Ego1使用说明文档,很详细,详细见 依元素 官网:EGO1 (e-elements.com)
点击资源,然后注册邮箱,下载资料包,里面有很多例程:
源码或者现成的工程见 3c-EGo1配置实验vivado2017.2_v1.2 文件夹里的source与project文件夹
学习了基础操作后,教你怎么写代码,先对整个代码有个宏观认识:
这是一个工程的文件夹,里面只有lab5_uart.srcs文件夹里的代码是自己写或者创建的,其余是你在仿真综合时,vivado自动生成的;代码分两大部分:约束文件(.xdc)和源文件(.v)
讲解一下我对Vivado编写FPGA工程的认识:
源文件(.v)文件编写逻辑为分层(top层和模块层)编写,将你需要用到的硬件的驱动代码设计成一个模块,模块即有输入和输出,比方说我要让一个数码管按一定的频率亮,那就需要定时器,就设计一个时钟作为输入,当然,你想复位的话,还可以设计一个按键(rst)作为输入,然后输出呢就是数码管的8个段(8段LED),设计好输入输出后就是你的逻辑编写,即你什么时候让数码管亮,比如我1s让数码管亮一次,1s后再灭一次,就写相应的逻辑,当然写逻辑就要用到相关的语法,语法就去菜鸟教程看verilog语言教程就行;然后是需要即需要定义一个top层,将你所有模块的输入和输出在这个模块进行例化(相当于单片机的引脚初始化)。top层是在你设计的功能模块在2个及以上时编写,这样你看起来也比较方便,系统所有的输入输出都在top层,也方便你查看。
约束文件的作用相当于在使用单片机时对引脚进行定义,这里是将你源文件的top文件里设计的输入和输出约束到相关的引脚上,虽然像时钟,数码管这样的输入输出你看不见引脚,但你可以这样去理解,就是使用FPGA驱动硬件的逻辑就是:你设计输入和输出,然后将他们约束到相关硬件上或者引脚上,然后引脚再去接硬件。
那么我这个工程呢就是关于Ego1的循迹小车,所有硬件驱动代码都由ego1写成他具备以下功能:
基础功能:能用Ego1输出PWM波控制直流编码器电机和舵机转动,能用Ego1读取红外循迹模块的循迹反馈信号,能用Ego1的输入捕获采集编码器的信号实现电机转速测量,能用Ego1输出特定频率的方波驱动无缘蜂鸣器播放音乐,能用Ego1的数码管显示车速。
终极功能:小车上电后能在赛道上一边播放车载音乐一边进行自动循迹。
系统硬件配置设计
(根据实验的需要,论述平台的系统硬件配置,包括硬件选择、硬件配套、网络连接和参数配置等)
(1)控制器:Xilinx-Ego1(FPGA)
(2)执行元件:舵机
(3)执行元件:编码器电机
(4)执行元件:无源蜂鸣器
(5)测量元件:循迹模块(5路红外传感器)
(6)电机驱动:tb6612fng
(7)功率放大单元:L298N
(8)稳压模块:
其中舵机和电机模块的代码展示如下:(因为都是PWM,所以写在一起了)
时钟主频:clk约束到了P17,具体是50MHz还是100MHz我忘了
- `timescale 1ns / 1ps
-
- module pwm_cont(
- clk,
- sw7,
- rst_n,
- da_in,
- pwm_out,
- pwm_outz,
- hw_in,
- djfz1,
- djfz2,
- djfy1,
- djfy2,
- pwm_outy
- );
-
- input clk;
- input rst_n;
- input sw7;
- input [6:0] da_in;
-
- output reg djfz1;
- output reg djfz2;
- output reg djfy1;
- output reg djfy2;
-
- output reg pwm_out;
- output reg pwm_outz;
- output reg pwm_outy;
- input [4:0] hw_in;
- parameter s=1000_000,//20ms-----min:s4(左偏) max:s7(右偏) 中间:s1
-
- s7=190_000,//4ms----右满
- //s6=190_000,//3.5ms----270
- s5=185_000,//3ms----225
- s0=175_000,//2.5ms----右
- s1=150_000,//2ms---中间
- s2=125_000,//1.5ms----90
- s3=95_000,//1ms-----45 100_000
- s4=80_000;//0.5ms---0 左满
-
- reg [31:0] cnt_r;
- reg [31:0] cnt;
-
- reg [31:0] cnt_r1;
- reg [31:0] cnt1;
- reg biaoqian;
- reg wr_reg,wr_up,wr_down;
-
-
- always@(posedge clk or posedge rst_n) begin
- if(rst_n)
- begin
- wr_reg <= 1'b0;
- wr_up <= 1'b0;
- wr_down <= 1'b0;
- cnt_r1 <= s1;
- end
- else
- begin
- wr_reg <= sw7;
- wr_up <= sw7&(~wr_reg);//sw1上升沿检测,选择循迹模式
- wr_down <= ~sw7&wr_reg;
- if(wr_up)
- biaoqian=1;
- if(wr_down)
- biaoqian=0;
-
- if(biaoqian==1)
- begin
- djfz1=0;
- djfz2=1;
- djfy1=0;
- djfy2=1;
- case(hw_in)
- 5'b00000:
- begin
- //cnt_r1 <= s1;//中间
- biaoqian<=0;
- end
- //5'b11111: cnt_r1 <= s1;//中间
-
- 5'b11000: cnt_r1 <= s7;//右转s7满
- 5'b11110: cnt_r1 <= s7;//右转s7满
- 5'b11100: cnt_r1 <= s5;//左转
- 5'b11101: cnt_r1 <= s0;//左转
- 5'b11001: cnt_r1 <= s1;//中间
- 5'b11011: cnt_r1 <= s1;//中间
- 5'b10011: cnt_r1 <= s1;//中间
- 5'b10111: cnt_r1 <= s2;//右转
- 5'b00111: cnt_r1 <= s3;//右转
- 5'b01111: cnt_r1 <= s4;//左转s4满
- 5'b00011: cnt_r1 <= s4;//右转
-
- endcase
- end
- if(!biaoqian)
- begin
- djfz1=0;
- djfz2=0;
- djfy1=0;
- djfy2=0;
- end
- end
- end
-
- //速度选择
- always@(posedge clk or posedge rst_n)begin
- if(rst_n)
- begin
- cnt_r <= 31'd0;
- end
- else
- begin
- // case(da_in)//速度选择
- // 7'b0000001: cnt_r <= s/20;//90
- // //8'b00000011: cnt_r <= s4;//0
- // 7'b0000010: cnt_r <= s/15;//45
- // 7'b0000100: cnt_r <= s/10;//90
- // 7'b0001000: cnt_r <= s/8;//135
- // 7'b0010000: cnt_r <= s/4;//180
- // 7'b0100000: cnt_r <= s/2;//225
- // 7'b1000000: cnt_r <= s;//满速
- case(hw_in)
- 5'b11000: cnt_r <= s/8;//右转s7满
- 5'b11110: cnt_r <= s/7;//右转s7满
- 5'b11100: cnt_r <= s/7;//左转
- 5'b11101: cnt_r <= s/7;//左转
- 5'b11001: cnt_r <= s/5;//中间
- 5'b11011: cnt_r <= s/5;//中间
- 5'b11111: cnt_r <= s/5;//中间
- 5'b10011: cnt_r <= s/5;//中间
- 5'b10111: cnt_r <= s/7;//右转
- 5'b00111: cnt_r <= s/7;//右转
- 5'b01111: cnt_r <= s/7;//左转s4满
- 5'b00011: cnt_r <= s/7;//右转
- 5'b00000: cnt_r <= 0;//停止
- default: cnt_r <= s/8;//停止
- endcase
- end
- end
-
- always@(posedge clk or negedge rst_n)begin
- if(rst_n)
- begin
- cnt <= 31'd0;
- cnt1 <= 31'd0;
- end
- else if(cnt >= s)
- begin
- cnt <= 31'd0;
- cnt1 <= 31'd0;
- end
- else
- begin
- cnt <= cnt + 1'b1;
- cnt1 <= cnt1 + 1'b1;
- end
- end
-
- always@(posedge clk or negedge rst_n)begin
- if(rst_n)
- begin
- pwm_outz <= 1'b0;
- pwm_outy <= 1'b0;
- end
- else if(cnt <= cnt_r)
- begin
- pwm_outz <= 1'b1;
- pwm_outy <= 1'b1;
- if(wr_down)
- begin
- pwm_outz <= 1'b0;
- pwm_outy <= 1'b0;
- end
- end
- else
- begin
- pwm_outz <= 1'b0;
- pwm_outy <= 1'b0;
- end
- end
-
- always@(posedge clk or negedge rst_n)begin
- if(rst_n)
- begin
- //pwm_out<= s1;//中间
- pwm_out <= 1'b0;
- end
- else if(cnt1 <= cnt_r1)
- begin
- pwm_out <= 1'b1;
- end
- else
- begin
- pwm_out <= 1'b0;
- end
- end
- endmodule
代码写好了之后需要生成bit流,当然这还不够,我们需要让小车不连接电脑去跑这就需要将代码固化到Ego1里面,下面是代码固化的方法:(13条消息) vivado纯verilog代码固化程序_Kiss丶小坏-CSDN博客
简单步骤:当然你直接生成bit流之后
选择Tools——>Generate Memory Configuration File,也可以打开hardware之后右键找到。
注:这一步是产生mcs文件进行程序加载,同时也会产生prm文件(也可以不需要,例如直接在生成bit文件时,勾选bin文件,最后一步时直接加载bin文件)。详情看文档去。
配置:
如果报错就将Interface改成报错要求的值
之后是Add Configuration Memory Device。三种方法:
方法1.
方法2.
方法3.
接下来,出现如下界面,选择flash芯片。
如果报错就选择n25q64-3.3v-spi-xi_x2_x4
最后一步,在选择芯片之后会出现如下界面,也就是加载Flash,固化程序。
整个工程见如下链接:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。