差别
这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 | 前一修订版 | ||
vga显示模块 [2017/07/03 15:25] anran 创建 |
vga显示模块 [2017/09/06 11:08] (当前版本) anran [硬件说明] |
||
---|---|---|---|
行 1: | 行 1: | ||
- | ======基于STEP FPGA的PCF8591的ADC(I2C)功能驱动====== | + | ======基于STEP FPGA的8色VGA功能驱动====== |
- | 本节将和大家一起使用FPGA驱动底板上的PCF8591的ADC采样(I2C)功能。 | + | 本节将和大家一起使用FPGA驱动底板上的8色VGA接口实现8色彩条显示功能。 |
====硬件说明==== | ====硬件说明==== | ||
------- | ------- | ||
- | PCF8591是集成了4路ADC和1路DAC的芯片,使用I2C总线通信。 | + | VGA(video graphics array)即视频图形阵列,是IBM在1987年随PS/2一起推出的使用模拟信号的一种视频传输标准。VGA接口分公口和母口,如下图: |
\\ | \\ | ||
- | I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件,然后主机接收从器件发送的数据,最后由主机终止接收过程。这里不做过多的讲解,硬件连接如下: | + | {{ :vga接口.jpg?400 |}} |
- | {{ :i2c总线框架.jpg?800 |}} | + | |
\\ | \\ | ||
- | 本设计的硬件连接如下 | + | VGA接口引脚定义如下: |
- | {{ :pcf8591硬件连接.jpg?1000 |}} | + | |
\\ | \\ | ||
- | 本设计中FPGA作为I2C主设备,PCF8591作为I2C从设备,从设备的地址由固定地址和可编程地址组成,我们的外设底板已将可编程地址A0、A1、A2接地,所以7位地址为7'h48,加上最低位的读写控制,所以给PCF8591写数据时的寻址地址为8'h90,对PCF8591读数据时的寻址地址为8'h91。如下 | + | {{ :vga接口定义.jpg?800 |}} |
- | {{ :pcf8591_i2c地址.jpg?800 |}} | + | |
\\ | \\ | ||
- | PCF8591集成了很多功能,当需要不同的功能时要对PCF8591做相应的配置,配置数据存储在名为CONTROL BYTE的寄存器中,下图展示了寄存器中部分bit的功能,详细请参考PCF8591的datasheet,本设计中我们只使用通道1的ADC功能,配置数据为8'h01。 | + | 一个标准的VGA接口应该有以下端口: |
- | {{ :pcf8591_控制字.jpg?800 |}} | + | |
\\ | \\ | ||
- | 本设计中我们需要两次通信, | + | * 红绿蓝三色信号(R\G\B) |
- | * 第一次为配置数据,具体为:开始--写寻址--读响应--写配置数据--读响应--结束 | + | * 行场同步信号(HS\VS) |
- | * 第二次为读ADC数据,具体为:开始--读寻址--读响应--[读ADC数据--写响应--]循环读 | + | * 以及很多的地屏蔽; |
- | 第二次的时序如下图: | + | 三色信号都是模拟信号,行场同步信号都是数字信号; |
- | {{ :pcf8591_adc时序.jpg?1000 |}} | + | |
\\ | \\ | ||
- | 通过上面的介绍大家应该对如何驱动PCF8591进行ADC采样有了整体的概念,还有一些细节就是I2C通信的时序明细,如下图 | + | 对于VGA的接口模拟电压,为0~0.714V,0代表无色,0.714代表满色,FPGA输出3.3V,所以还必须要经过DAC的转换。现今有两种比较成熟的方法:电阻分压方式和DAC转换方式。 |
- | {{ :pcf8591_时序控制.jpg?800 |}} | + | \\ |
- | {{ :pcf8591_时序控制2.jpg?800 |}} | + | 我们的底板上就是采用的电阻分压的方式,因VGA显示器端有75欧的下拉电阻,为了得到0.714V的电压我们给RGB信号线上串入270欧的电阻,3.3V*75/(270+75)=0.717V。如下 |
+ | \\ | ||
+ | {{ :vga接口电路.png?800 |}} | ||
+ | \\ | ||
+ | VGA驱动显示器用的是扫描的方式,逐行扫描the HS (Horizontal Synchronization)逐行扫描是扫描从屏幕的左上角一点开始,由左向右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间CRT(阴极射线显像管)对电子束进行消隐,每行结束时,用行同步信号进行同步;当扫描完所有行之后形成一帧,用场同步信号进行同步,并使扫描回到屏幕左上方,同时进行场消隐,开始下一帧。VGA一直在扫描,每一场的扫描包括了若干行扫描,依次循环; | ||
+ | \\ | ||
+ | VGA显示时序如下: | ||
+ | {{ :vga时序.png?800 |}} | ||
+ | \\ | ||
+ | VGA显示区域和消隐区域: | ||
+ | {{ :vga显示区域.png?800 |}} | ||
+ | \\ | ||
+ | 常见的VGA显示模式: | ||
+ | {{ :常见的vga显示模式.png?800 |}} | ||
====Verilog代码==== | ====Verilog代码==== | ||
行 36: | 行 44: | ||
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< | // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< | ||
// -------------------------------------------------------------------- | // -------------------------------------------------------------------- | ||
- | // Module: ADC_I2C | + | // Module: Param_define |
// | // | ||
// Author: Step | // Author: Step | ||
// | // | ||
- | // Description: ADC_I2C | + | // Description: Param_define |
// | // | ||
// Web: www.stepfpga.com | // Web: www.stepfpga.com | ||
行 50: | 行 58: | ||
// V1.1 |2016/10/30 |Initial ver | // V1.1 |2016/10/30 |Initial ver | ||
// -------------------------------------------------------------------- | // -------------------------------------------------------------------- | ||
- | module ADC_I2C | + | `timescale 1ns / 1ns |
+ | |||
+ | //VGA显示器驱动只需要5个信号即可(行同步、场同步、红色、绿色、蓝色信号) | ||
+ | //红绿蓝三色信号为模拟信号,输入电压范围为0.0V~0.7V | ||
+ | //VGA时序中行同步和场同步都分为四个阶段(同步脉冲、后廊、有效线数、前廊) | ||
+ | //VGA显示有很多模式,每种模式都是有固定的时钟和时序参数,需要根据要求控制 | ||
+ | |||
+ | `ifdef VGA_800X600_60Hz //不同VGA显示模式相应的参数 | ||
+ | //--------------------------------------------------------------------------- | ||
+ | //-- Horizonal timing information | ||
+ | `define HSYNC_A 16'd128 // 128 | ||
+ | `define HSYNC_B 16'd216 // 128 + 88 | ||
+ | `define HSYNC_C 16'd1016 // 128 + 88 + 800 | ||
+ | `define HSYNC_D 16'd1056 // 128 + 88 + 800 + 40 //行同步脉冲+后廊+有效线数+前廊 | ||
+ | //-- Vertical timing information | ||
+ | `define VSYNC_O 16'd4 // 4 | ||
+ | `define VSYNC_P 16'd27 // 4 + 23 | ||
+ | `define VSYNC_Q 16'd627 // 4 + 23 + 600 | ||
+ | `define VSYNC_R 16'd628 // 4 + 23 + 600 + 1 //场同步脉冲+后廊+有效线数+前廊 | ||
+ | //--------------------------------------------------------------------------- | ||
+ | `endif | ||
+ | |||
+ | `ifdef VGA_640X480_85Hz //不同VGA显示模式相应的参数 | ||
+ | //--------------------------------------------------------------------------- | ||
+ | //-- Horizonal timing information | ||
+ | `define HSYNC_A 16'd48 // 48 | ||
+ | `define HSYNC_B 16'd160 // 48 + 112 | ||
+ | `define HSYNC_C 16'd800 // 48 + 112 + 640 | ||
+ | `define HSYNC_D 16'd832 // 48 + 112 + 640 + 32 //行同步脉冲+后廊+有效线数+前廊 | ||
+ | //-- Vertical timing information | ||
+ | `define VSYNC_O 16'd3 // 3 | ||
+ | `define VSYNC_P 16'd28 // 3 + 25 | ||
+ | `define VSYNC_Q 16'd508 // 3 + 25 + 480 | ||
+ | `define VSYNC_R 16'd509 // 3 + 25 + 480 + 1 //场同步脉冲+后廊+有效线数+前廊 | ||
+ | //--------------------------------------------------------------------------- | ||
+ | `endif | ||
+ | </code> | ||
+ | |||
+ | <code verilog> | ||
+ | // -------------------------------------------------------------------- | ||
+ | // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< | ||
+ | // -------------------------------------------------------------------- | ||
+ | // Module: Vga_Module | ||
+ | // | ||
+ | // Author: Step | ||
+ | // | ||
+ | // Description: Vga_Module | ||
+ | // | ||
+ | // Web: www.stepfpga.com | ||
+ | // | ||
+ | // -------------------------------------------------------------------- | ||
+ | // Code Revision History : | ||
+ | // -------------------------------------------------------------------- | ||
+ | // Version: |Mod. Date: |Changes Made: | ||
+ | // V1.1 |2016/10/30 |Initial ver | ||
+ | // -------------------------------------------------------------------- | ||
+ | `define VGA_800X600_60Hz //定义使用的VGA显示模式 | ||
+ | |||
+ | `ifdef VGA_800X600_60Hz //根据VGA显示模式的定义调用相应的参数 | ||
+ | `include "Param_define.v" //调用Param_define.v文件中的全局定义 | ||
+ | `endif | ||
+ | |||
+ | module Vga_Module | ||
( | ( | ||
- | input clk_in, //系统时钟 | + | input clk_in, //40MHz系统时钟 |
- | input rst_n_in, //系统复位,低有效 | + | input rst_n_in, //系统复位,低有效 |
- | output scl_out, //I2C总线SCL | + | output reg sync_v, //VGA场同步sync_v |
- | inout sda_out, //I2C总线SDA | + | output reg sync_h, //VGA行同步sync_h |
- | output reg adc_done, //ADC采样完成标志 | + | output reg [2:0] vga_data //VGA数据MSB~LSB = {R,G,B} |
- | output reg [7:0] adc_data //ADC采样数据 | + | |
); | ); | ||
- | |||
- | parameter CNT_NUM = 15; | ||
- | |||
- | localparam IDLE = 3'd0; | ||
- | localparam MAIN = 3'd1; | ||
- | localparam START = 3'd2; | ||
- | localparam WRITE = 3'd3; | ||
- | localparam READ = 3'd4; | ||
- | localparam STOP = 3'd5; | ||
- | |||
- | //根据PCF8591的datasheet,I2C的频率最高为100KHz, | ||
- | //我们准备使用4个节拍完成1bit数据的传输,所以需要400KHz的时钟触发完成该设计 | ||
- | //使用计数器分频产生400KHz时钟信号clk_400khz | ||
- | reg clk_400khz; | ||
- | reg [9:0] cnt_400khz; | ||
- | always@(posedge clk_in or negedge rst_n_in) begin | ||
- | if(!rst_n_in) begin | ||
- | cnt_400khz <= 10'd0; | ||
- | clk_400khz <= 1'b0; | ||
- | end else if(cnt_400khz >= CNT_NUM-1) begin | ||
- | cnt_400khz <= 10'd0; | ||
- | clk_400khz <= ~clk_400khz; | ||
- | end else begin | ||
- | cnt_400khz <= cnt_400khz + 1'b1; | ||
- | end | ||
- | end | ||
- | |||
- | reg [7:0] adc_data_r; | ||
- | reg scl_out_r; | ||
- | reg sda_out_r; | ||
- | reg [2:0] cnt; | ||
- | reg [3:0] cnt_main; | ||
- | reg [7:0] data_wr; | ||
- | reg [2:0] cnt_start; | ||
- | reg [2:0] cnt_write; | ||
- | reg [4:0] cnt_read; | ||
- | reg [2:0] cnt_stop; | ||
- | reg [2:0] state; | ||
- | always@(posedge clk_400khz or negedge rst_n_in) begin | + | reg [15:0] x_cnt; |
- | if(!rst_n_in) begin //如果按键复位,将相关数据初始化 | + | reg [15:0] y_cnt; |
- | scl_out_r <= 1'd1; | + | reg vga_valid; |
- | sda_out_r <= 1'd1; | + | |
- | cnt <= 1'b0; | + | |
- | cnt_main <= 4'd0; | + | |
- | cnt_start <= 3'd0; | + | |
- | cnt_write <= 3'd0; | + | |
- | cnt_read <= 5'd0; | + | |
- | cnt_stop <= 1'd0; | + | |
- | adc_done <= 1'b0; | + | |
- | adc_data <= 1'b0; | + | |
- | state <= IDLE; | + | |
- | end else begin | + | |
- | case(state) | + | |
- | IDLE:begin //软件自复位,主要用于程序跑飞后的处理 | + | |
- | scl_out_r <= 1'd1; | + | |
- | sda_out_r <= 1'd1; | + | |
- | cnt <= 1'b0; | + | |
- | cnt_main <= 4'd0; | + | |
- | cnt_start <= 3'd0; | + | |
- | cnt_write <= 3'd0; | + | |
- | cnt_read <= 5'd0; | + | |
- | cnt_stop <= 1'd0; | + | |
- | adc_done <= 1'b0; | + | |
- | state <= MAIN; | + | |
- | end | + | |
- | MAIN:begin | + | |
- | if(cnt_main >= 4'd6) cnt_main <= 4'd6; //对MAIN中的子状态执行控制cnt_main | + | |
- | else cnt_main <= cnt_main + 1'b1; | + | |
- | case(cnt_main) | + | |
- | 4'd0: begin state <= START; end //I2C通信时序中的START | + | |
- | 4'd1: begin data_wr <= 8'h90; state <= WRITE; end //A0,A1,A2都接了GND,写地址为8'h90 | + | |
- | 4'd2: begin data_wr <= 8'h00; state <= WRITE; end //control byte为8'h00,采用4通道ADC中的通道0 | + | |
- | 4'd3: begin state <= STOP; end //I2C通信时序中的START | + | |
- | 4'd4: begin state <= START; end //I2C通信时序中的STOP | + | |
- | 4'd5: begin data_wr <= 8'h91; state <= WRITE; end //A0 A1 A2都接了GND,读地址为8'h91 | + | |
- | 4'd6: begin state <= READ; adc_done <= 1'b0; end //读取ADC的采样数据 | + | |
- | 4'd7: begin state <= STOP; adc_done <= 1'b1; end //I2C通信时序中的STOP,读取完成标志 | + | |
- | 4'd8: begin state <= MAIN; end //预留状态,不执行 | + | |
- | default: state <= IDLE; //如果程序失控,进入IDLE自复位状态 | + | |
- | endcase | + | |
- | end | + | |
- | START:begin //I2C通信时序中的起始START | + | |
- | if(cnt_start >= 3'd5) cnt_start <= 1'b0; //对START中的子状态执行控制cnt_start | + | |
- | else cnt_start <= cnt_start + 1'b1; | + | |
- | case(cnt_start) | + | |
- | 3'd0: begin sda_out_r <= 1'b1; scl_out_r <= 1'b1; end //将SCL和SDA拉高,保持4.7us以上 | + | |
- | 3'd1: begin sda_out_r <= 1'b1; scl_out_r <= 1'b1; end //clk_400khz每个周期2.5us,需要两个周期 | + | |
- | 3'd2: begin sda_out_r <= 1'b0; end //SDA拉低到SCL拉低,保持4.0us以上 | + | |
- | 3'd3: begin sda_out_r <= 1'b0; end //clk_400khz每个周期2.5us,需要两个周期 | + | |
- | 3'd4: begin scl_out_r <= 1'b0; end //SCL拉低,保持4.7us以上 | + | |
- | 3'd5: begin scl_out_r <= 1'b0; state <= MAIN; end //clk_400khz每个周期2.5us,需要两个周期,返回MAIN | + | |
- | default: state <= IDLE; //如果程序失控,进入IDLE自复位状态 | + | |
- | endcase | + | |
- | end | + | |
- | WRITE:begin //I2C通信时序中的写操作WRITE和相应判断操作ACK | + | |
- | if(cnt <= 3'd6) begin //共需要发送8bit的数据,这里控制循环的次数 | + | |
- | if(cnt_write >= 3'd3) begin cnt_write <= 1'b0; cnt <= cnt + 1'b1; end | + | |
- | else begin cnt_write <= cnt_write + 1'b1; cnt <= cnt; end | + | |
- | end else begin | + | |
- | if(cnt_write >= 3'd7) begin cnt_write <= 1'b0; cnt <= 1'b0; end //两个变量都恢复初值 | + | |
- | else begin cnt_write <= cnt_write + 1'b1; cnt <= cnt; end | + | |
- | end | + | |
- | case(cnt_write) | + | |
- | //按照I2C的时序传输数据 | + | |
- | 3'd0: begin scl_out_r <= 1'b0; sda_out_r <= data_wr[7-cnt]; end //SCL拉低,并控制SDA输出对应的位 | + | |
- | 3'd1: begin scl_out_r <= 1'b1; end //SCL拉高,保持4.0us以上 | + | |
- | 3'd2: begin scl_out_r <= 1'b1; end //clk_400khz每个周期2.5us,需要两个周期 | + | |
- | 3'd3: begin scl_out_r <= 1'b0; end //SCL拉低,准备发送下1bit的数据 | + | |
- | //获取从设备的响应信号并判断 | + | |
- | 3'd4: begin sda_out_r <= 1'bz; end //释放SDA线,准备接收从设备的响应信号 | + | |
- | 3'd5: begin scl_out_r <= 1'b1; end //SCL拉高,保持4.0us以上 | + | |
- | 3'd6: begin if(sda_out) state <= IDLE; else state <= state; end //获取从设备的响应信号并判断 | + | |
- | 3'd7: begin scl_out_r <= 1'b0; state <= MAIN; end //SCL拉低,返回MAIN状态 | + | |
- | default: state <= IDLE; //如果程序失控,进入IDLE自复位状态 | + | |
- | endcase | + | |
- | end | + | |
- | READ:begin //I2C通信时序中的读操作READ和返回ACK的操作 | + | |
- | if(cnt <= 3'd6) begin //共需要接收8bit的数据,这里控制循环的次数 | + | |
- | if(cnt_read >= 3'd3) begin cnt_read <= 1'b0; cnt <= cnt + 1'b1; end | + | |
- | else begin cnt_read <= cnt_read + 1'b1; cnt <= cnt; end | + | |
- | end else begin | + | |
- | if(cnt_read >= 3'd7) begin cnt_read <= 1'b0; cnt <= 1'b0; end //两个变量都恢复初值 | + | |
- | else begin cnt_read <= cnt_read + 1'b1; cnt <= cnt; end | + | |
- | end | + | |
- | case(cnt_read) | + | |
- | //按照I2C的时序接收数据 | + | |
- | 3'd0: begin scl_out_r <= 1'b0; sda_out_r <= 1'bz; end //SCL拉低,释放SDA线,准备接收从设备数据 | + | |
- | 3'd1: begin scl_out_r <= 1'b1; end //SCL拉高,保持4.0us以上 | + | |
- | 3'd2: begin adc_data_r[7-cnt] <= sda_out; end //读取从设备返回的数据 | + | |
- | 3'd3: begin scl_out_r <= 1'b0; end //SCL拉低,准备接收下1bit的数据 | + | |
- | //向从设备发送响应信号 | + | |
- | 3'd4: begin sda_out_r <= 1'b0; adc_done <= 1'b1; adc_data <= adc_data_r; end //发送响应信号,将前面接收的数据锁存 | + | |
- | 3'd5: begin scl_out_r <= 1'b1; end //SCL拉高,保持4.0us以上 | + | |
- | 3'd6: begin scl_out_r <= 1'b1; adc_done <= 1'b0; end //SCL拉高,保持4.0us以上 | + | |
- | 3'd7: begin scl_out_r <= 1'b0; state <= MAIN; end //SCL拉低,返回MAIN状态 | + | |
- | default: state <= IDLE; //如果程序失控,进入IDLE自复位状态 | + | |
- | endcase | + | |
- | end | + | |
- | STOP:begin //I2C通信时序中的结束STOP | + | |
- | if(cnt_stop >= 3'd5) cnt_stop <= 1'b0; //对STOP中的子状态执行控制cnt_stop | + | |
- | else cnt_stop <= cnt_stop + 1'b1; | + | |
- | case(cnt_stop) | + | |
- | 3'd0: begin sda_out_r <= 1'b0; end //SDA拉低,准备STOP | + | |
- | 3'd1: begin sda_out_r <= 1'b0; end //SDA拉低,准备STOP | + | |
- | 3'd2: begin scl_out_r <= 1'b1; end //SCL提前SDA拉高4.0us | + | |
- | 3'd3: begin scl_out_r <= 1'b1; end //SCL提前SDA拉高4.0us | + | |
- | 3'd4: begin sda_out_r <= 1'b1; end //SDA拉高 | + | |
- | 3'd5: begin sda_out_r <= 1'b1; state <= MAIN; end //完成STOP操作,返回MAIN状态 | + | |
- | default: state <= IDLE; //如果程序失控,进入IDLE自复位状态 | + | |
- | endcase | + | |
- | end | + | |
- | default:; | + | |
- | endcase | + | |
- | end | + | |
- | end | + | |
- | assign scl_out = scl_out_r; //对SCL端口赋值 | + | //对时钟计数标识VGA一次行扫描需要的时间 |
- | assign sda_out = sda_out_r; //对SDA端口赋值 | + | always @ (posedge clk_in or negedge rst_n_in) |
+ | if(!rst_n_in) x_cnt <= 16'd0; //复位时初始值 | ||
+ | else if(x_cnt >= `HSYNC_D) x_cnt <= 16'd0; //一次行扫描需要1056个时钟(128+88+800+40) | ||
+ | else x_cnt <= x_cnt + 1'b1; | ||
- | endmodule | + | //对行扫描计数标识VGA一次场扫描需要的时间 |
- | </code> | + | always @ (posedge clk_in or negedge rst_n_in) |
+ | if(!rst_n_in) y_cnt <= 16'd0; //复位时初始值 | ||
+ | else if(x_cnt == `HSYNC_D) begin //每次行扫描时 | ||
+ | if(y_cnt >= `VSYNC_R) y_cnt <= 16'd0; //每次场扫描包含628次行扫描 | ||
+ | else y_cnt <= y_cnt + 1'b1; | ||
+ | end else y_cnt <= y_cnt; //在每次行扫描过程中场扫描计数器保持不变 | ||
+ | //按照显示模式的参数产生行同步扫描的脉冲 | ||
+ | always @ (posedge clk_in or negedge rst_n_in) | ||
+ | if(!rst_n_in) sync_h <= 1'b1; | ||
+ | else if(x_cnt < `HSYNC_A) sync_h <= 1'b0; | ||
+ | else sync_h <= 1'b1; | ||
+ | //按照显示模式的参数产生场同步扫描的脉冲 | ||
+ | always @ (posedge clk_in or negedge rst_n_in) | ||
+ | if(!rst_n_in) sync_v <= 1'b1; | ||
+ | else if(y_cnt < `VSYNC_O) sync_v <= 1'b0; | ||
+ | else sync_v <= 1'b1; | ||
+ | |||
+ | //根据行场同步信号的有效线数确定有效显示区域 | ||
+ | always @ (posedge clk_in or negedge rst_n_in) | ||
+ | if(!rst_n_in) | ||
+ | vga_valid <= 1'b0; | ||
+ | else if((x_cnt > `HSYNC_B) && (x_cnt <`HSYNC_C) && (y_cnt > `VSYNC_P) && (y_cnt < `VSYNC_Q)) | ||
+ | vga_valid <= 1'b1; //有效显示区域中vga_valid标志为1 | ||
+ | else | ||
+ | vga_valid <= 1'b0; | ||
+ | |||
+ | //在VGA有效显示区域不同的段显示不同的颜色 | ||
+ | always @ (posedge clk_in or negedge rst_n_in) | ||
+ | begin | ||
+ | if(!rst_n_in) vga_data = 3'b111; | ||
+ | else if(vga_valid)begin //在有效显示区域内 | ||
+ | if((x_cnt > `HSYNC_B) && (x_cnt <= `HSYNC_B + 10'd100)) | ||
+ | vga_data = 3'b100; //红色 | ||
+ | else if((x_cnt > `HSYNC_B + 10'd100) && (x_cnt <= `HSYNC_B + 10'd200)) | ||
+ | vga_data = 3'b010; //绿色 | ||
+ | else if((x_cnt > `HSYNC_B + 10'd200) && (x_cnt <= `HSYNC_B + 10'd300)) | ||
+ | vga_data = 3'b001; //蓝色 | ||
+ | else if((x_cnt > `HSYNC_B + 10'd300) && (x_cnt <= `HSYNC_B + 10'd400)) | ||
+ | vga_data = 3'b110; //黄色 | ||
+ | else if((x_cnt > `HSYNC_B + 10'd400) && (x_cnt <= `HSYNC_B + 10'd500)) | ||
+ | vga_data = 3'b101; //紫色 | ||
+ | else if((x_cnt > `HSYNC_B + 10'd500) && (x_cnt <= `HSYNC_B + 10'd600)) | ||
+ | vga_data = 3'b011; //青色 | ||
+ | else if((x_cnt > `HSYNC_B + 10'd600) && (x_cnt <= `HSYNC_B + 10'd700)) | ||
+ | vga_data = 3'b111; //白色 | ||
+ | else if((x_cnt > `HSYNC_B + 10'd700) && (x_cnt <= `HSYNC_B + 10'd800)) | ||
+ | vga_data = 3'b000; //黑色 | ||
+ | else | ||
+ | vga_data = 3'b111; //白色 | ||
+ | end else | ||
+ | vga_data = 3'b111; //白色 | ||
+ | end | ||
+ | |||
+ | endmodule | ||
+ | </code> | ||
====小结==== | ====小结==== | ||
------ | ------ | ||
- | 本节主要为大家讲解了使用I2C驱动PCF8591的ADC功能的原理及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。 | + | 本节主要为大家讲解了VGA显示的原理、时序及软件设计,需要大家掌握的同时自己创建工程,通过整个设计流程,生成FPGA配置文件加载测试。 |
\\ | \\ | ||
如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。 | 如果你对Diamond软件的使用不了解,请参考这里:[[lattice_diamond的使用|Diamond的使用]]。 | ||
行 232: | 行 206: | ||
------ | ------ | ||
\\ | \\ | ||
- | 使用[[STEP-MXO2第二代]]的PCF8591的ADC驱动程序: 后续会有下载连接 待更新 | + | 使用[[STEP-MXO2第二代]]的VGA显示驱动程序: 后续会有下载连接 待更新 |
\\ | \\ | ||
- | 使用[[STEP-MAX10]]的PCF8591的ADC驱动程序: 后续会有下载连接 待更新 | + | 使用[[STEP-MAX10]]的VGA显示驱动程序: 后续会有下载连接 待更新 |
\\ | \\ |