完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1 功能
使用 FPGA 驱动 TFT-LCD 彩屏 R61509V3 显示彩色图片,屏幕分辨率为240*400,刷新速度100Hz。 2 环境 硬件: [tr]项目说明[/tr]
系统框图: fpga开发板输入时钟为100MHz,通过MMCM输出30MHz时钟作为工作时钟。R61509V3驱动模块完成器件的初始化和显示。R61509V 显示模块例化ROM IP核 ,利用片内存储资源存储图片信息,并根据驱动模块的请求输出数据。80-16bit并口模块将驱动模块输出的指令按照80系统16位并口的时序输出。 3.1 .coe 文件的产生 xilinx 家的 FPGA 例化单端口 ROM 时,要指定对应的初始化文件。产生coe文件的matlab代码(源文件在相关资料里面工程目录下的matlab文件夹): clear all; close all; %lcd参数 P_lcd_X = 240; %宽 P_lcd_Y = 400; %高 %读取原图片 img_rgb = imread("./pic.jpg"); % figure;imshow(img_rgb); %根据lcd的参数剪切与压缩图片 img_rgb_size = size(img_rgb); img_rgb_cut = img_rgb(1:floor(img_rgb_size(1)/P_lcd_Y):400*floor(img_rgb_size(1)/P_lcd_Y),... floor(img_rgb_size(2)/2-(P_lcd_X/2)*(img_rgb_size(1)/P_lcd_Y)):(img_rgb_size(1)/P_lcd_Y):floor(img_rgb_size(2)/2+(P_lcd_X/2)*(img_rgb_size(1)/P_lcd_Y))-1,:); figure;imshow(img_rgb_cut); %RGB数据转为2进制 img_rgb_cut_R = img_rgb_cut(:,:,1); img_rgb_cut_G = img_rgb_cut(:,:,2); img_rgb_cut_B = img_rgb_cut(:,:,3); img_rgb_cut_bin_R = dec2bin(img_rgb_cut_R'); img_rgb_cut_bin_G = dec2bin(img_rgb_cut_G'); img_rgb_cut_bin_B = dec2bin(img_rgb_cut_B'); img_rgb_cut_bin_R = img_rgb_cut_bin_R(:,1:5); img_rgb_cut_bin_G = img_rgb_cut_bin_G(:,1:6); img_rgb_cut_bin_B = img_rgb_cut_bin_B(:,1:5); %写到.coe文件,用来初始化rom if(0) coef_bin = [img_rgb_cut_bin_R img_rgb_cut_bin_G img_rgb_cut_bin_B]; fid = fopen('.coepic1.coe','w'); fprintf(fid,'MEMORY_INITIALIZATION_RADIX=2;n'); fprintf(fid,'MEMORY_INITIALIZATION_VECTOR=n'); for i = 1:1:length(coef_bin) fprintf(fid,'%s',coef_bin(i,:)); if i==length(coef_bin) fprintf(fid,';'); else fprintf(fid,',n'); end end fclose(fid); end 首先导入需要转换的图片,然后根据 LCD 的尺寸剪切与压缩图片,然后分别将范围为 0~255 的 RGB 数据转换为 8 位二进制数,最后根据 RGB565 的格式取 R 分量的高 5 位、 G 分量的高 6 位与B分量的高 5 位组合成对应像素点的数据,240*400 像素点对应 coe 文件初始化向量的长度位 96000。在本示例中,原图片,剪切后的图片,生成的 .coe 文件为:
3.2.1 顶层模块 顶层模块对应的 RTL 原理图为: 时钟管理器模块(mmcm_100M) 通过例化 MMCM 来实现。由后面 3.2.4 80-16bit并口模块 的说明可知本设计最大工作时钟受限于 写入低电平脉冲宽度(一个时钟周期,min(PWLW)=30ns),取工作时钟为 30MHz。 R61509V3 驱动模块(R61509V3_driver) 在上电后首先完成 R61509V3 的配置,配置完成后根据设置的刷新频率,输出对应像素点的坐标并且根据对应的 RGB 数据输入刷新屏幕。本模块只是输出80并口的 数据,数据类型,读写类型,触发信号。80并口的时序转换由“80-16bit并口模块”完成。 80-16bit并口模块(lcd_80_16b_dri) 根据用户接口输入的数据类型按照 80系统16位并口 的时序输出。 图片显示模块(pic_disp_rom) 例化rom IP核存储图片的 RGB 数据,根据输入的坐标将对应的数据输出。 顶层模块的代码如下: `timescale 1ns / 1ps // // Company: // Engineer: w0shishabi // // Create Date: 2021/02/09 19:54:44 // Design Name: // Module Name: top // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module top( input I_sys_clk , input I_reset_n , output O_lcd_cs , output O_lcd_rs , output O_lcd_wr , output O_lcd_rd , output O_lcd_reset_n , inout [15:0] IO_lcd_data ); //wire define wire W_reset_n ; wire W_mmcm_locked ; wire W_clk_100M ; wire W_clk_30M ; wire [15:0] W_data_w ; wire W_datah_instl ; wire W_rh_wl ; wire W_80_exec ; wire W_80_done ; wire W_lcd_init_done ; wire [15:0] W_rgb_data ; wire [7:0] W_pixel_xpos ; wire [8:0] W_pixel_ypos ; wire W_pos_en ; //main assign W_reset_n = I_reset_n && W_mmcm_locked; mmcm_100M mmcm_100M_u ( // Clock out ports .clk_out100M(W_clk_100M ), // output clk_out100M .clk_out30M (W_clk_30M ), // output clk_out20M // Status and control signals .reset (~I_reset_n ), // input reset .locked (W_mmcm_locked), // output locked // Clock in ports .clk_in1 (I_sys_clk ));// input clk_in1 pic_disp_rom pic_disp_rom_u( .I_sys_clk (W_clk_30M ), .I_reset_n (W_reset_n ), .I_pos_x (W_pixel_xpos), .I_pos_y (W_pixel_ypos), .I_pos_en (W_pos_en ), .O_data (W_rgb_data ) ); R61509V3_driver R61509V3_driver_u( .I_sys_clk (W_clk_30M ), .I_reset_n (W_reset_n ), .I_rgb_data (W_rgb_data ), .O_pixel_xpos (W_pixel_xpos ), .O_pixel_ypos (W_pixel_ypos ), .O_pos_en (W_pos_en ), .O_data_w (W_data_w ), .O_datah_instl (W_datah_instl ), .O_rh_wl (W_rh_wl ), .O_80_exec (W_80_exec ), .I_80_done (W_80_done ), .O_lcd_init_done(W_lcd_init_done) ); lcd_80_16b_dri lcd_80_16b_dri_u( .I_sys_clk (W_clk_30M ), .I_reset_n (W_reset_n ), .I_data_w (W_data_w ), .O_data_r ( ), .I_datah_instl (W_datah_instl), .I_rh_wl (W_rh_wl ), .I_80_exec (W_80_exec ), .O_80_done (W_80_done ), .O_lcd_cs (O_lcd_cs ), .O_lcd_rs (O_lcd_rs ), .O_lcd_wr (O_lcd_wr ), .O_lcd_rd (O_lcd_rd ), .O_lcd_reset_n (O_lcd_reset_n), .IO_lcd_data (IO_lcd_data ) ); endmodule 顶层模块完成其余模块的例化,其中各模块的复位信号为 MMCM 的 locked 端口输出与系统复位的逻辑与,确保其他模块在时钟稳定后开始工作。 3.2.2 R61509V3 驱动模块 R61509V3 驱动模块的代码如下: `timescale 1ns / 1ps // // Company: // Engineer: w0shishabi // // Create Date: 2021/02/09 09:56:33 // Design Name: // Module Name: R61509V3_driver // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module R61509V3_driver( input I_sys_clk , input I_reset_n , input [15:0] I_rgb_data , output reg [7:0] O_pixel_xpos , output reg [8:0] O_pixel_ypos , output reg O_pos_en , output [15:0] O_data_w , output O_datah_instl , output O_rh_wl , output O_80_exec , input I_80_done , output O_lcd_init_done ); localparam P_60FPS_CNT = 20'd333333 ; localparam P_65FPS_CNT = 20'd307692 ; localparam P_100FPS_CNT = 20'd290912 ; localparam P_SIM_CNT = 20'd20000 ;//simulation localparam P_FPS_CNT = P_100FPS_CNT ; //reg define reg [19:0] R_clk_div_cnt ; reg [15:0] R_disp_data_w ; reg R_disp_datah_instl ; reg R_disp_rh_wl ; reg R_disp_80_exec ; reg R_disp_ena ; //wire define wire [15:0] W_init_data_w ; wire W_init_datah_instl ; wire W_init_rh_wl ; wire W_init_80_exec ; wire W_lcd_init_done ; wire W_Refresh_frame_req; //main assign O_data_w = W_lcd_init_done ? R_disp_data_w : W_init_data_w ; assign O_datah_instl = W_lcd_init_done ? R_disp_datah_instl : W_init_datah_instl; assign O_rh_wl = W_lcd_init_done ? R_disp_rh_wl : W_init_rh_wl ; assign O_80_exec = W_lcd_init_done ? R_disp_80_exec : W_init_80_exec ; assign O_lcd_init_done = W_lcd_init_done; R61509V3_config R61509V3_config_u( .I_sys_clk (I_sys_clk ), .I_reset_n (I_reset_n ), .O_data_w (W_init_data_w ), .O_datah_instl (W_init_datah_instl), .O_rh_wl (W_init_rh_wl ), .O_80_exec (W_init_80_exec ), .I_80_done (I_80_done ), .O_lcd_init_done(W_lcd_init_done ) ); always @ (posedge I_sys_clk or negedge I_reset_n) begin if(~I_reset_n) begin R_clk_div_cnt <= 20'd0; end else begin if (R_clk_div_cnt == P_FPS_CNT) R_clk_div_cnt <= 20'd0; else R_clk_div_cnt <= R_clk_div_cnt + 1'b1; end end assign W_Refresh_frame_req = (R_clk_div_cnt == P_FPS_CNT); always @ (posedge I_sys_clk or negedge I_reset_n) begin if(~I_reset_n) begin R_disp_data_w <= 1'b0; R_disp_datah_instl <= 1'b0; R_disp_rh_wl <= 1'b0; R_disp_80_exec <= 1'b0; end else begin if (W_Refresh_frame_req && W_lcd_init_done) begin {R_disp_rh_wl,R_disp_datah_instl,R_disp_data_w} <= {1'b0,1'b0,16'h0202}; R_disp_80_exec <= 1'b1; end else if (R_disp_ena && I_80_done) begin {R_disp_rh_wl,R_disp_datah_instl,R_disp_data_w} <= {1'b0,1'b1,I_rgb_data}; R_disp_80_exec <= 1'b1; end else begin {R_disp_rh_wl,R_disp_datah_instl,R_disp_data_w} <= {1'b0,1'b0,16'h0000}; R_disp_80_exec <= 1'b0; end end end always @ (posedge I_sys_clk or negedge I_reset_n) begin if(~I_reset_n) R_disp_ena <= 1'b0; else if (W_Refresh_frame_req && W_lcd_init_done) R_disp_ena <= 1'b1; else if ((O_pixel_xpos == 8'd239) && (O_pixel_ypos == 9'd399)) R_disp_ena <= 1'b0; end always @ (posedge I_sys_clk or negedge I_reset_n) begin if(~I_reset_n) begin O_pixel_xpos <= 8'd0; O_pixel_ypos <= 9'd0; O_pos_en <= 1'b0; end else begin if (W_lcd_init_done && W_Refresh_frame_req) begin O_pos_en <= 1'b1; O_pixel_xpos <= 8'd0; O_pixel_ypos <= 9'd0; end else if (W_lcd_init_done && R_disp_80_exec) begin O_pos_en <= 1'b1; O_pixel_xpos <= O_pixel_xpos + 1'b1; if (O_pixel_xpos == 8'd239 && O_pixel_ypos <= 9'd399) begin O_pixel_xpos <= 8'd0; O_pixel_ypos <= O_pixel_ypos + 1'b1; end end else begin O_pos_en <= 1'b0; O_pixel_xpos <= O_pixel_xpos; O_pixel_ypos <= O_pixel_ypos; end end end R61509V3 驱动模块 例化了 R61509V3 配置模块 完成器件的配置,根据配置完成信号(W_lcd_init_done)输出配置数据或者刷新图像数据。完成一次图片刷新需要写入一个指令(GRAM Data Read (R202h))以及240*400 = 96000 个 RGB 数据,80-16bit并口模块 完成一次数据写入需要3个时钟周期(输入30MHz),则刷新率最高为 1/[(1/30000000)∗ 3∗ 96001]≈ 104Hz 取刷新率为 100Hz,则每 290912 个时钟周期产生一个刷新请求信号。 3.2.3 R61509V3 配置模块 R61509V3 配置模块的代码如下: `timescale 1ns / 1ps // // Company: // Engineer: w0shishabi // // Create Date: 2021/02/09 18:21:11 // Design Name: // Module Name: R61509V3_config // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module R61509V3_config( input I_sys_clk , input I_reset_n , output reg [15:0] O_data_w , output reg O_datah_instl , output reg O_rh_wl , output reg O_80_exec , input I_80_done , output reg O_lcd_init_done ); localparam P_CONFIG_NUM = 82; localparam P_DELAY_1MS_CNT = 16'd30003; reg [15:0] R_delay_cnt; reg [7:0] R_config_cnt; always @ (posedge I_sys_clk or negedge I_reset_n) begin if(~I_reset_n) R_delay_cnt <= 16'd0; else if (((R_config_cnt == 7'd0)||(R_config_cnt == 7'd4)||(R_config_cnt == 7'd44)||(R_config_cnt == 7'd76)||(R_config_cnt == 7'd78)) && I_80_done) R_delay_cnt <= 16'd0; else if (R_delay_cnt < P_DELAY_1MS_CNT) R_delay_cnt <= R_delay_cnt + 1'b1; end always @ (posedge I_sys_clk or negedge I_reset_n) begin if(~I_reset_n) R_config_cnt <= 7'd0; else if (O_80_exec) R_config_cnt <= R_config_cnt + 1'b1; end always @ (posedge I_sys_clk or negedge I_reset_n) begin if(~I_reset_n) O_80_exec <= 1'b0; else if (R_delay_cnt == P_DELAY_1MS_CNT - 1'b1) O_80_exec <= 1'b1; else if (I_80_done && (R_config_cnt != 7'd0) && (R_config_cnt != 7'd4) && (R_config_cnt != 7'd44) && (R_config_cnt != 7'd76) && (R_config_cnt != 7'd78) && (R_config_cnt < P_CONFIG_NUM)) O_80_exec <= 1'b1; else O_80_exec <= 1'b0; end always @ (posedge I_sys_clk or negedge I_reset_n) begin if(~I_reset_n) O_lcd_init_done <= 1'b0; else if ((R_config_cnt == P_CONFIG_NUM) && I_80_done) O_lcd_init_done <= 1'b1; end always @ (posedge I_sys_clk or negedge I_reset_n) begin if(~I_reset_n) begin O_data_w <= 16'd0; O_datah_instl <= 1'b0; O_rh_wl <= 1'b0; end else begin case (R_config_cnt) 8'd0 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0000}; 8'd1 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0000}; 8'd2 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0000}; 8'd3 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0000}; 8'd4 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0400}; 8'd5 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h6200}; 8'd6 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0008}; 8'd7 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0808}; 8'd8 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0301}; 8'd9 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h4C06}; 8'd10 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0302}; 8'd11 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0602}; 8'd12 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0303}; 8'd13 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h050C}; 8'd14 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0304}; 8'd15 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h3300}; 8'd16 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0305}; 8'd17 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0C05}; 8'd18 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0306}; 8'd19 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h4206}; 8'd20 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0307}; 8'd21 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h060C}; 8'd22 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0308}; 8'd23 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0500}; 8'd24 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0309}; 8'd25 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0033}; 8'd26 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0010}; 8'd27 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0014}; 8'd28 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0011}; 8'd29 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0101}; 8'd30 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0012}; 8'd31 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0000}; 8'd32 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0013}; 8'd33 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0001}; 8'd34 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0100}; 8'd35 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0330}; 8'd36 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0101}; 8'd37 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0247}; 8'd38 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0103}; 8'd39 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h1000}; 8'd40 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0280}; 8'd41 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'hDE00}; 8'd42 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0102}; 8'd43 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'hD1B0}; 8'd44 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0001}; 8'd45 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0100}; 8'd46 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0002}; 8'd47 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0100}; 8'd48 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0003}; 8'd49 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h1030}; 8'd50 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0009}; 8'd51 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0001}; 8'd52 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h000C}; 8'd53 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0000}; 8'd54 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0090}; 8'd55 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h8000}; 8'd56 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h000F}; 8'd57 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0000}; 8'd58 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0210}; 8'd59 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0000}; 8'd60 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0211}; 8'd61 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h00EF}; 8'd62 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0212}; 8'd63 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0000}; 8'd64 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0213}; 8'd65 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h018F}; 8'd66 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0500}; 8'd67 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0000}; 8'd68 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0501}; 8'd69 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0000}; 8'd70 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0502}; 8'd71 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h005F}; 8'd72 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0401}; 8'd73 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0001}; 8'd74 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0404}; 8'd75 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0000}; 8'd76 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0007}; 8'd77 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0100}; 8'd78 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b0,16'h0200}; 8'd79 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0000}; 8'd80 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0201}; 8'd81 :{O_rh_wl,O_datah_instl,O_data_w} <= {1'b0,1'b1,16'h0000}; default : ; endcase end endmodule 根据【TFT-LCD学习记录1】 R61509V3 彩屏显示原理中主要指令的说明,在第1,5,45,77,79个指令之前需要延时等待,这里统一设置成延时1ms,所以写这些指令时的触发信号(O_80_exec)根据延时计数器(R_delay_cnt)的值产生,其余则根据上一个指令的完成信号(I_80_done)产生。 3.2.4 80-16bit并口模块 80-16bit并口模块的代码如下: `timescale 1ns / 1ps // // Company: // Engineer: w0shishabi // // Create Date: 2021/02/09 18:26:06 // Design Name: // Module Name: lcd_80_16b_dri // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module lcd_80_16b_dri( input I_sys_clk , input I_reset_n , input [15:0] I_data_w , output reg [15:0] O_data_r , input I_datah_instl , input I_rh_wl , input I_80_exec , output reg O_80_done , output O_lcd_cs , output reg O_lcd_rs , output reg O_lcd_wr , output reg O_lcd_rd , output O_lcd_reset_n , inout [15:0] IO_lcd_data ); //parameter define //reg define reg [15:0] R_data_out; reg R_data_dir; reg R_flag; //wire define wire [15:0] W_data_in; //main code assign O_lcd_cs = 1'b0; assign O_lcd_reset_n = 1'b1; assign IO_lcd_data = R_data_dir ? R_data_out : 1'bz; assign W_data_in = IO_lcd_data; always @ (posedge I_sys_clk or negedge I_reset_n) begin if(~I_reset_n) begin R_flag = 1'b0; end else begin if (I_80_exec) begin R_data_dir <= I_rh_wl ? 1'b0 : 1'b1; R_data_out <= I_rh_wl ? 16'bz : I_data_w; O_lcd_rs <= I_datah_instl ? 1'b1 : 1'b0; O_lcd_wr <= I_rh_wl ? 1'b1 : 1'b0; O_lcd_rd = I_rh_wl ? 1'b0 : 1'b1; R_flag <= 1'b1; end else if (R_flag == 1'b1) begin O_data_r <= I_rh_wl ? W_data_in : 1'bz; O_lcd_wr <= 1'b1; O_lcd_rd <= 1'b1; O_80_done <= 1'b1; R_flag <= 1'b0; end else begin O_80_done <= 1'b0; end end endmodule 数据/指令(I_datah_instl)以及触发信号(I_80_exec)以80系统16位并口的时序完成数据的写入或者读取。 3.2.5 图片显示模块 图片显示模块的代码如下: `timescale 1ns / 1ps // // Company: // Engineer: w0shishabi // // Create Date: 2021/02/10 22:29:39 // Design Name: // Module Name: pic_disp_rom // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module pic_disp_rom( input I_sys_clk , input I_reset_n , input [ 7:0] I_pos_x , input [ 8:0] I_pos_y , input I_pos_en , output [15:0] O_data ); localparam P_PIXEL_NUM_Y = 9'd400 ; localparam P_PIXEL_NUM_X = 8'd240 ; localparam P_PIC_POS_X = 8'd0 ; localparam P_PIC_POS_Y = 9'd0 ; localparam P_PIC_WIDTH = 8'd240 ; localparam P_PIC_HEIGTH = 9'd400 ; localparam P_PIC_TOTAL = 17'd96000 ; localparam P_COLOR_BLACK = 16'b00000_000000_00000; wire W_rom_en; reg [16:0] R_rom_addr; reg R_rom_valid; reg R_pos_en; reg [ 7:0] R_pos_x; wire [15:0] W_rom_data; wire [16:0] W_mult_addr; always @ (posedge I_sys_clk or negedge I_reset_n) begin if(~I_reset_n) begin R_pos_en <= 1'b0; R_pos_x <= 8'd0; end else begin R_pos_en <= I_pos_en; R_pos_x <= I_pos_x; end end assign O_data = R_rom_valid ? W_rom_data : P_COLOR_BLACK; assign W_rom_en = (I_pos_x >= P_PIC_POS_X) && (I_pos_x < P_PIC_POS_X + P_PIC_WIDTH) && (I_pos_y >= P_PIC_POS_Y) && (I_pos_y < P_PIC_POS_Y + P_PIC_HEIGTH) ? 1'b1 : 1'b0; always @ (posedge I_sys_clk or negedge I_reset_n) begin if(~I_reset_n) begin R_rom_addr <= 17'd0; end else begin if (R_pos_en) begin R_rom_addr <= W_mult_addr + R_pos_x; end else R_rom_addr <= R_rom_addr; end end always @ (posedge I_sys_clk or negedge I_reset_n) begin if(~I_reset_n) begin R_rom_valid <= 1'b0; end else begin R_rom_valid <= W_rom_en; end end mult_addr mult_addr_u ( .CLK(I_sys_clk), // input wire CLK .A(8'd240), // input wire [7 : 0] A .B(I_pos_y), // input wire [8 : 0] B .P(W_mult_addr) // output wire [16 : 0] P ); pic_rom pic_rom_u ( .clka(I_sys_clk), // input wire clka .ena(W_rom_en), // input wire ena .addra(R_rom_addr), // input wire [16 : 0] addra .douta(W_rom_data) // output wire [15 : 0] douta ); endmodule 4 显示效果 5 相关资料 链接:https://pan.baidu.com/s/1t66akpZ1VL5EOTJ5zQc8KA 提取码:1234 |
||
|
||
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1568 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1513 浏览 1 评论
939 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
669 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1561 浏览 2 评论
1851浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
620浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
506浏览 3评论
511浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
492浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-13 09:30 , Processed in 1.021275 second(s), Total 78, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号