1284|2

845

帖子

3

TA的资源

版主

楼主
 

09、国产FPGA 正点原子DFPGL22G开发板测评【学习篇】SD卡读BMP图片显示实验 [复制链接]

 
本帖最后由 1nnocent 于 2023-2-20 20:39 编辑

    原本的测评计划是学习篇部分进行一个SD卡中读取图片LCD显示,但是由于安排计划时没有考虑到SD卡读取数据的速度不够快,SD卡无法及时提供LCD显示所需的数据,所以这里对测评计划做一个修改,修改后实现的效果是SD卡读取图片数据,并存到DDR中,最后从DDR中读取图片数据进行显示。

1、简介

    BMP(全称 Bitmap)是 Window 操作系统中的标准图像文件格式,文件后缀名为“.bmp”,使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此, BMP 文件所占用的空间很大,但是没有失真。 BMP 文件的图像深度可选 lbit、 4bit、 8bit、 16bit、 24bit 及 32bit。 BMP 文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。

    典型的 BMP 图像文件由四部分组成:
1、 BMP 文件头(14Byte),它包含 BMP 图像文件的类型、大小等信息;
2、 BMP 信息头(40Byte),它包含有 BMP 图像的宽、高、压缩方法,以及定义颜色等信息;
3、调色板,这个部分是可选的, 如果使用索引来表示图像,调色板就是索引与其对应颜色的映射表;
4、位图数据,即图像数据,在位深度为 24 位时直接使用 RGB 格式,而小于 24 位时使用调色板中颜色的索引值。
 

2、实验任务

    使用 ATK-DFPGL22G 开发板循环读取 SD 卡中存放的两张 BMP 格式图片,分辨率为 480*272,并将其显示在 LCD 液晶屏上。

3、硬件设计

    ATK-DFPGL22G 开发板上有一个 SD 卡插槽, 用于插入 SD 卡, 其原理图如图所示:

 

ATK-DFPGL22G 开发板上 RGB-LCD 接口部分的原理图如下图所示。FPGA 管脚输出的颜色数据位宽为 24bit, 数据格式为 RGB888,即数据高 8 位表示红色, 中间 8 位表示绿色,低 8 位表示蓝色。由于这 24 位数据不仅仅作为输出给 LCD 屏的颜色数据,同时 LCD_R7、 LCD_G7 和 LCD_B7 也用来获取 LCD 屏的 ID,因此这 24 位颜色数据对 ATK-DFPGL22G 开发板来说,是一个双向的引脚。

 

4、程序设计

    时钟模块为其它各模块提供驱动时钟; SD 卡/DDR3 参数计算模块根据 LCD ID,为 SD 卡读取图片控制模块和 DDR3 控制器模块提供参数; SD 卡读取图片控制模块控制 SD 卡控制器的读接口,以及将 SD 卡中读出的 RGB888 格式数据转换成 RGB565 格式数据,写入DDR3 控制器中;最后 LCD 顶层模块从 DDR3 控制器中读出图片数据,显示到 LCD 液晶屏上。

 

 


顶层模块(sd_bmp_lcd):顶层模块主要完成对其余各模块的例化,实现各模块之间的数据交互。

//****************************************Copyright (c)***********************************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name:           sd_bmp_lcd
// Last modified Date:  2020/11/22 15:16:38
// Last Version:        V1.0
// Descriptions:        SD卡读BMP图片LCD显示
//                      
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2020/11/22 15:16:38
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module sd_bmp_lcd(    
    input                 sys_clk      ,  //系统时钟
    input                 sys_rst_n    ,  //系统复位,低电平有效
    //SD卡接口
    input                 sd_miso      ,  //SD卡SPI串行输入数据信号
    output                sd_clk       ,  //SD卡SPI时钟信号
    output                sd_cs        ,  //SD卡SPI片选信号
    output                sd_mosi      ,  //SD卡SPI串行输出数据信号
    //DDR3接口
    input                 pad_loop_in      ,  //低位温度补偿输入
    input                 pad_loop_in_h    ,  //高位温度补偿输入
    output                pad_rstn_ch0     ,  //Memory复位
    output                pad_ddr_clk_w    ,  //Memory差分时钟正
    output                pad_ddr_clkn_w   ,  //Memory差分时钟负
    output                pad_csn_ch0      ,  //Memory片选
    output [15:0]         pad_addr_ch0     ,  //Memory地址总线
    inout  [16-1:0]       pad_dq_ch0       ,  //数据总线
    inout  [16/8-1:0]     pad_dqs_ch0      ,  //数据时钟正端
    inout  [16/8-1:0]     pad_dqsn_ch0     ,  //数据时钟负端
    output [16/8-1:0]     pad_dm_rdqs_ch0  ,  //数据Mask
    output                pad_cke_ch0      ,  //Memory差分时钟使
    output                pad_odt_ch0      ,  //On Die Terminati
    output                pad_rasn_ch0     ,  //行地址strobe
    output                pad_casn_ch0     ,  //列地址strobe
    output                pad_wen_ch0      ,  //写使能
    output [2:0]          pad_ba_ch0       ,  //Bank地址总线
    output                pad_loop_out     ,  //低位温度补偿输出
    output                pad_loop_out_h   ,   //高位温度补偿输出                                      
    //lcd接口                           
    output                lcd_hs       ,  //LCD 行同步信号
    output                lcd_vs       ,  //LCD 场同步信号
    output                lcd_de       ,  //LCD 数据输入使能
    inout       [23:0]    lcd_rgb      ,  //LCD 颜色数据
    output                lcd_bl       ,  //LCD 背光控制信号
    output                lcd_rst      ,  //LCD 复位信号
    output                lcd_pclk        //LCD 采样时钟
    );                                 
        
//parameter define    
parameter  APP_ADDR_MIN = 28'd0    ;  //ddr3读写起始地址,以一个16bit的数据为一个单位
//APP_ADDR_MAX = 'd384000;//BURST_LENGTH * 8 * n(n表示突发次数)
parameter  BURST_LENGTH = 8'd64    ;  //ddr3读写突发长度,64个128bit的数据
                                                           
//wire define                          
wire         clk_50m         ;  //50mhz时钟,提供给lcd驱动时钟
wire         clk_50m_180deg  ;
wire         locked          ;  //时钟锁定信号
wire         rst_n           ;  //全局复位  
//DDR
wire         ddr_wr_en                 ;  //DDR3控制器模块写使能
wire         wr_en                     ;  //DDR3控制器模块写使能
wire  [15:0] ddr_wr_data               ;  //DDR3控制器模块写数据
wire  [15:0] wr_data                   ;  //DDR3控制器模块写数据
wire         rdata_req                 ;  //DDR3控制器模块读使能
wire  [15:0] rd_data                   ;  //DDR3控制器模块读数据
wire         ddr_init_done             ;  //DDR3初始化完成ddr_init_done  
wire         sys_init_done             ;  //系统初始化完成(DDR初始化+摄像头初始化)
wire         fram_done                 ;  //DDR中已经存入一帧画面标志
wire  [27:0] ddr_max_addr              ;  //存入DDR3的最大读写地址
wire         rd_vsync                  ;  //输出源更新信号     
//SD卡
wire  [15:0] sd_sec_num                ;  //SD卡读扇区个数
wire         sd_rd_start_en            ;  //开始写SD卡数据信号
wire  [31:0] sd_rd_sec_addr            ;  //读数据扇区地址    
wire         sd_rd_busy                ;  //读忙信号
wire         sd_rd_val_en              ;  //数据读取有效使能信号
wire  [15:0] sd_rd_val_data            ;  //读数据
wire         sd_init_done              ;  //SD卡初始化完成信号  
//LCD                                  
wire         lcd_clk                   ;  //分频产生的LCD 采样时钟
wire  [12:0] h_disp                    ;  //LCD屏水平分辨率   
wire  [15:0] lcd_id                    ;  //LCD屏的ID号

//*****************************************************
//**                    main code
//*****************************************************

//待时钟锁定后产生复位结束信号
assign  rst_n = sys_rst_n & locked;
//系统初始化完成:DDR3初始化完成 & SD卡初始化完成
assign  sys_init_done = ddr_init_done & sd_init_done;
//DDR3控制器模块为写使能和写数据赋值
assign  wr_en = ddr_wr_en;
assign  wr_data = ddr_wr_data;


//DDR和SD卡参数计算模块
sd_ddr_size  u_sd_rd_size(
    .clk                (clk_50m  ),  
    .rst_n              (rst_n),
    .ID_lcd             (lcd_id),           //LCD的器件ID    
    
    .ddr_max_addr       (ddr_max_addr),   
    .sd_sec_num         (sd_sec_num)
    );

//读取SD卡图片
sd_read_photo u_sd_read_photo(
    .clk             (clk_50m),
    //系统初始化完成之后,再开始从SD卡中读取图片
    .rst_n           (rst_n & sys_init_done), 
    .ddr_max_addr    (ddr_max_addr),       
    .sd_sec_num      (sd_sec_num), 
    .rd_busy         (sd_rd_busy),
    .sd_rd_val_en    (sd_rd_val_en),
    .sd_rd_val_data  (sd_rd_val_data),
    .rd_start_en     (sd_rd_start_en),
    .rd_sec_addr     (sd_rd_sec_addr),
    .ddr_wr_en       (ddr_wr_en),
    .ddr_wr_data     (ddr_wr_data)
    );     

//SD卡顶层控制模块
sd_ctrl_top u_sd_ctrl_top(
    .clk_ref           (clk_50m),
    .clk_ref_180deg    (clk_50m_180deg),
    .rst_n             (rst_n), //
    //SD卡接口
    .sd_miso           (sd_miso),
    .sd_clk            (sd_clk),
    .sd_cs             (sd_cs),
    .sd_mosi           (sd_mosi),
    //用户写SD卡接口
    .wr_start_en       (1'b0),                      //不需要写入数据,写入接口赋值为0
    .wr_sec_addr       (32'b0),
    .wr_data           (16'b0),
    .wr_busy           (),
    .wr_req            (),
    //用户读SD卡接口
    .rd_start_en       (sd_rd_start_en),
    .rd_sec_addr       (sd_rd_sec_addr),
    .rd_busy           (sd_rd_busy),
    .rd_val_en         (sd_rd_val_en),
    .rd_val_data       (sd_rd_val_data),    
    
    .sd_init_done      (sd_init_done)
    );  

//ddr3
ddr3_top u_ddr3_top(
    .refclk_in             (clk_50m         ),
    .rst_n                 (sys_rst_n       ),
    .ddr_init_done         (ddr_init_done   ),
    //ddr3接口信号         
    .app_addr_rd_min       (28'd0           ),
    .app_addr_rd_max       (ddr_max_addr    ),
    .rd_bust_len           (BURST_LENGTH    ),
    .app_addr_wr_min       (28'd0           ),
    .app_addr_wr_max       (ddr_max_addr    ),
    .wr_bust_len           (BURST_LENGTH    ),
    //用户
    .ddr3_read_valid       (1'b1            ),
    .ddr3_pingpang_en      (1'b0            ),
    .wr_clk                (clk_50m         ),
    .wr_load               (1'b0            ),
    .datain_valid          (wr_en           ),
    .datain                (wr_data         ),
    .rd_clk                (lcd_clk         ),
    .rd_load               (rd_vsync        ),
    .dataout               (rd_data         ),
    .rdata_req             (rdata_req       ),
    // DDR3 IO接口                
    .fram_done             (fram_done       ),
    .pll_lock              (pll_lock        ),
    .ddrphy_rst_done       (                ),
    .pad_loop_in           (pad_loop_in     ),
    .pad_loop_in_h         (pad_loop_in_h   ),
    .pad_rstn_ch0          (pad_rstn_ch0    ),
    .pad_ddr_clk_w         (pad_ddr_clk_w   ),
    .pad_ddr_clkn_w        (pad_ddr_clkn_w  ),
    .pad_csn_ch0           (pad_csn_ch0     ),
    .pad_addr_ch0          (pad_addr_ch0    ),
    .pad_dq_ch0            (pad_dq_ch0      ),
    .pad_dqs_ch0           (pad_dqs_ch0     ),
    .pad_dqsn_ch0          (pad_dqsn_ch0    ),
    .pad_dm_rdqs_ch0       (pad_dm_rdqs_ch0 ),
    .pad_cke_ch0           (pad_cke_ch0     ),
    .pad_odt_ch0           (pad_odt_ch0     ),
    .pad_rasn_ch0          (pad_rasn_ch0    ),
    .pad_casn_ch0          (pad_casn_ch0    ),
    .pad_wen_ch0           (pad_wen_ch0     ),
    .pad_ba_ch0            (pad_ba_ch0      ),
    .pad_loop_out          (pad_loop_out    ),
    .pad_loop_out_h        (pad_loop_out_h  )
    );  

//时钟IP核     
pll_clk u_pll_clk
   (
    // Clock out ports  
    .clkout0              (clk_50m),
    .clkout1              (clk_50m_180deg),
    .pll_rst              (1'b0), 
    .pll_lock             (locked),       
    // Clock in ports
    .clkin1               (sys_clk)
    );     

//LCD驱动显示模块
lcd_rgb_top  u_lcd_rgb_top(
    .sys_clk               (clk_50m),
    .sys_rst_n             (rst_n),
    .sys_init_done         (sys_init_done),     
                           
    //lcd接口                            
    .lcd_id                (lcd_id),                //LCD屏的ID号 
    .lcd_hs                (lcd_hs),                //LCD 行同步信号
    .lcd_vs                (lcd_vs),                //LCD 场同步信号
    .lcd_de                (lcd_de),                //LCD 数据输入使能
    .lcd_rgb               (lcd_rgb),               //LCD 颜色数据
    .lcd_bl                (lcd_bl),                //LCD 背光控制信号
    .lcd_rst               (lcd_rst),               //LCD 复位信号
    .lcd_pclk              (lcd_pclk),              //LCD 采样时钟
    .lcd_clk               (lcd_clk),               //LCD 驱动时钟
    //用户接口                     
    .out_vsync             (rd_vsync),              //lcd场信号
    .h_disp                (h_disp),                //行分辨率  
    .v_disp                (v_disp),                //场分辨率  
    .pixel_xpos            (),
    .pixel_ypos            (),       
    .data_in               (rd_data),               //rfifo输出数据
    .data_req              (rdata_req)              //请求数据输入
    );   

endmodule


时钟模块(pll_clk):时钟模块通过调用时钟 IP 核实现,共输出 2 个时钟,频率分别为 50Mhz 和 50Mhz(相位偏移 180 度)时钟。 50Mhz 时钟和 50Mhz(相位偏移 180 度)作为 SD 卡/DDR3 参数计算模块、 SD卡读取图片控制模块、 SD 卡控制器模块和 LCD 顶层模块的驱动时钟。


SD 卡/DDR3 参数计算模块(sd_rd_size):由于不同分辨率的 LCD 屏, SD 卡中存放的 BMP 分辨率不一样,所以该模块根据 LCD ID,为 SD 卡读取图片控制模块提供需要从 SD 卡中的扇区个数,和 DDR3 读写的最大地址。除此之外,该模块也负责将 SD 卡中读取的 RGB888 格式的数据,转换成 16 位 RGB565 数据。

//****************************************Copyright (c)***********************************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name:           sd_ddr_size
// Last modified Date:  2020/11/22 15:16:38
// Last Version:        V1.0
// Descriptions:        根据LCD ID,计算DDR最大读写地址和SD卡读扇区个数
//                      
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2020/11/22 15:16:38
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module sd_ddr_size (
    input               clk          , //时钟
    input               rst_n        , //复位,低电平有效
                                       
    input        [15:0] ID_lcd       , //LCD ID
                                       
    output  reg  [27:0] ddr_max_addr , //DDR读写最大地址
    output  reg  [15:0] sd_sec_num     //SD卡读扇区个数
);

//parameter define
parameter  ID_4342 = 16'h4342;
parameter  ID_4384 = 16'h4384;
parameter  ID_7084 = 16'h7084;
parameter  ID_7016 = 16'h7016;
parameter  ID_1018 = 16'h1018;

//*****************************************************
//**                    main code                      
//*****************************************************

//根据LCD ID,计算DDR最大读写地址和SD卡读扇区个数
always @(posedge clk or negedge rst_n) begin 
    if(!rst_n) begin
        ddr_max_addr <= 28'd0;   
        sd_sec_num <= 16'd0;        
    end 
    else begin    
        case(ID_lcd ) 
            ID_4342 : begin
                ddr_max_addr <= 28'd130560;    //480*272
                sd_sec_num <= 16'd765 + 1'b1;  //480*272*3/512     
            end 
            ID_4384 : begin
                ddr_max_addr <= 28'd384000;    //800*480
                sd_sec_num <= 16'd2250 + 1'b1; //800*480*3/512 + 1 
            end
            ID_7084 : begin       
                ddr_max_addr <= 28'd384000;    //800*480
                sd_sec_num <= 16'd2250 + 1'b1; //800*480*3/512 + 1
            end 
            ID_7016 : begin         
                ddr_max_addr <= 28'd614400;    //1024*600
                sd_sec_num <= 16'd3600 + 1'b1; //800*480*3/512 + 1  
            end    
            ID_1018 : begin         
                ddr_max_addr <= 28'd1024000;   //1280*800
                sd_sec_num <= 16'd6000 + 1'b1; //800*480*3/512 + 1  
            end 
        default : begin         
                ddr_max_addr <= 28'd384000;    //800*480
                sd_sec_num <= 16'd2250 + 1'b1; //800*480*3/512 + 1  
        end
        endcase
    end    
end 

endmodule 


SD 卡读取图片控制模块(sd_read_photo): SD 卡读取图片控制模块通过控制 SD 卡控制器的读接口,从 SD 卡中读取图像数据,并在读完一张图片后延时一段时间,再去读取另一张图片数据,实现两张图片的循环切换读取。

//****************************************Copyright (c)***********************************//
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com 
//关注微信公众平台微信号:"正点原子",免费获取FPGA & STM32资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved                               
//----------------------------------------------------------------------------------------
// File name:           sd_read_photo
// Last modified Date:  2020/11/22 15:16:38
// Last Version:        V1.0
// Descriptions:        SD卡读取BMP图片
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2020/11/22 15:16:38
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module sd_read_photo(
    input                clk           ,  //时钟信号
    input                rst_n         ,  //复位信号,低电平有效

    input        [27:0]  ddr_max_addr  ,  //DDR读写最大地址  
    input        [15:0]  sd_sec_num    ,  //SD卡读扇区个数
    input                rd_busy       ,  //SD卡读忙信号
    input                sd_rd_val_en  ,  //SD卡读数据有效信号
    input        [15:0]  sd_rd_val_data,  //SD卡读出的数据
    output  reg          rd_start_en   ,  //开始写SD卡数据信号
    output  reg  [31:0]  rd_sec_addr   ,  //读数据扇区地址
    output  reg          ddr_wr_en     ,  //DDR写使能信号
    output       [15:0]  ddr_wr_data      //DDR写数据
    );

//parameter define                          
//设置两张图片的扇区地址,通过上位机WinHex软件查看
parameter PHOTO_SECTION_ADDR0 = 32'd1034496;//1041792;//1,034,496第一张图片扇区起始地址1,040,448
parameter PHOTO_SECTION_ADDR1 = 32'd1045120;//1044096;//1,045,120第二张图片扇区起始地址1,051,072
//BMP文件首部长度=BMP文件头+信息头
parameter BMP_HEAD_NUM = 6'd54;           //BMP文件头+信息头=14+40=54

//reg define
reg    [1:0]          rd_flow_cnt       /* synthesis syn_preserve=1 */;  //读数据流程控制计数器
reg    [15:0]         rd_sec_cnt       ;  //读扇区次数计数器
reg                   rd_addr_sw       ;  //读两张图片切换
reg    [25:0]         delay_cnt        ;  //延时切换图片计数器
reg                   bmp_rd_done      ;  //单张图片读取完成
reg                   rd_busy_d0       ;  //读忙信号打拍,用来采下降沿
reg                   rd_busy_d1       ;  
reg    [1:0]          val_en_cnt       ;  //SD卡数据有效计数器
reg    [15:0]         val_data_t       ;  //SD卡数据有效寄存
reg    [5:0]          bmp_head_cnt     ;  //BMP首部计数器
reg                   bmp_head_flag    ;  //BMP首部标志
reg    [23:0]         rgb888_data      ;  //24位RGB888数据
reg    [27:0]         ddr_wr_cnt       ;  //DDR写入计数器
reg    [1:0]          ddr_flow_cnt     ;  //DDR写数据流程控制器计数器

//wire define
wire                  neg_rd_busy;  //SD卡读忙信号下降沿
      
//*****************************************************
//**                    main code
//*****************************************************

assign  neg_rd_busy = rd_busy_d1 & (~rd_busy_d0);
//24位RGB888格式转成16位RGB565格式
assign  ddr_wr_data = {rgb888_data[23:19],rgb888_data[15:10],rgb888_data[7:3]};

//对rd_busy信号进行延时打拍,用于采rd_busy信号的下降沿
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0) begin
        rd_busy_d0 <= 1'b0;
        rd_busy_d1 <= 1'b0;
    end
    else begin
        rd_busy_d0 <= rd_busy;
        rd_busy_d1 <= rd_busy_d0;
    end
end

//循环读取SD卡中的两张图片(读完之后延时1s再读下一个)
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        rd_flow_cnt <= 2'd0;
        rd_addr_sw <= 1'b0;
        rd_sec_cnt <= 16'd0;
        rd_start_en <= 1'b0;
        rd_sec_addr <= 32'd0;
        bmp_rd_done <= 1'b0;
        delay_cnt <= 26'd0;
    end
    else begin
        rd_start_en <= 1'b0;
        bmp_rd_done <= 1'b0;
        case(rd_flow_cnt)
            2'd0 : begin
                //开始读取SD卡数据
                rd_flow_cnt <= rd_flow_cnt + 2'd1;
                rd_start_en <= 1'b1;
                rd_addr_sw <= ~rd_addr_sw;                     //读数据地址切换
                if(rd_addr_sw == 1'b0)
                    rd_sec_addr <= PHOTO_SECTION_ADDR0;
                else
                    rd_sec_addr <= PHOTO_SECTION_ADDR1;//PHOTO_SECTION_ADDR1;    
            end
            2'd1 : begin
                //读忙信号的下降沿代表读完一个扇区,开始读取下一扇区地址数据
                if(neg_rd_busy) begin                          
                    rd_sec_cnt <= rd_sec_cnt + 1'b1;
                    rd_sec_addr <= rd_sec_addr + 32'd1;
                    //单张图片读完
                    if(rd_sec_cnt == sd_sec_num - 1'b1) begin
                        rd_sec_cnt <= 16'd0;
                        rd_flow_cnt <= rd_flow_cnt + 2'd1;
                        bmp_rd_done <= 1'b1;
                    end    
                    else
                        rd_start_en <= 1'b1;                   
                end                    
            end
            2'd2 : begin
                delay_cnt <= delay_cnt + 1'b1;                 //单张图片读完后延时1秒
                if(delay_cnt == 26'd50_000_000 - 26'd1) begin  //50_000_000*20ns = 1s
                    delay_cnt <= 26'd0;
                    rd_flow_cnt <= 2'd0;
                end 
            end    
            default : ;
        endcase    
    end
end

//SD卡读取的16位数据,转成24位RGB888格式
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        val_en_cnt <= 2'd0;
        val_data_t <= 16'd0; 
        bmp_head_cnt <= 6'd0;
        ddr_wr_en <= 1'b0;
        rgb888_data <= 24'd0;
        ddr_wr_cnt <= 28'd0;
        ddr_flow_cnt <= 2'd0;
    end
    else begin
        ddr_wr_en <= 1'b0;
        case(ddr_flow_cnt)
            2'd0 : begin   //BMP首部         
                if(sd_rd_val_en) begin
                    bmp_head_cnt <= bmp_head_cnt + 1'b1;
                    if(bmp_head_cnt == BMP_HEAD_NUM[5:1] - 1'b1) begin
                        ddr_flow_cnt <= ddr_flow_cnt + 1'b1;
                        bmp_head_cnt <= 6'd0;
                    end    
                end   
            end                
            2'd1 : begin   //BMP有效数据
                if(sd_rd_val_en) begin
                    val_en_cnt <= val_en_cnt + 1'b1;
                    val_data_t <= sd_rd_val_data;                
                    if(val_en_cnt == 2'd1) begin  //3个16位数据转成2个24位数据
                        ddr_wr_en <= 1'b1;
                        rgb888_data <= {sd_rd_val_data[15:8],val_data_t[7:0],
                                       val_data_t[15:8]}; 
                    end
                    else if(val_en_cnt == 2'd2) begin
                        ddr_wr_en <= 1'b1;
                        rgb888_data <= {sd_rd_val_data[7:0],sd_rd_val_data[15:8],
                                        val_data_t[7:0]};
                        val_en_cnt <= 2'd0;
                    end   
                end     
                if(ddr_wr_en) begin
                    ddr_wr_cnt <= ddr_wr_cnt + 1'b1;
                    if(ddr_wr_cnt == ddr_max_addr - 1'b1) begin
                        ddr_wr_cnt <= 28'd0;
                        ddr_flow_cnt <= ddr_flow_cnt + 1'b1;
                    end
                end
            end
            2'd2 : begin //等待单张BMP图片读取结束
                if(bmp_rd_done)
                    ddr_flow_cnt <= 2'd0;
            end
            default :;
        endcase
    end
end

endmodule


SD 卡控制器模块(sd_ctrl_top): SD 卡控制器模块负责驱动 SD 卡,该模块将 SD 卡的 SPI 读写操作封装成方便用户使用的接口。有关该模块的详细介绍请大家参考“SD 卡读写测试实验”章节。

//****************************************Copyright (c)***********************************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name:           sd_ctrl_top
// Last modified Date:  2020/05/28 20:28:08
// Last Version:        V1.0
// Descriptions:        SD卡顶层控制模块
//                      
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2020/05/28 20:28:08
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module sd_ctrl_top(
    input                clk_ref       ,  //时钟信号
    input                clk_ref_180deg,  //时钟信号,与clk_ref相位相差180度
    input                rst_n         ,  //复位信号,低电平有效
    //SD卡接口
    input                sd_miso       ,  //SD卡SPI串行输入数据信号
    output               sd_clk        ,  //SD卡SPI时钟信号    
    output  reg          sd_cs         ,  //SD卡SPI片选信号
    output  reg          sd_mosi       ,  //SD卡SPI串行输出数据信号
    //用户写SD卡接口
    input                wr_start_en   ,  //开始写SD卡数据信号
    input        [31:0]  wr_sec_addr   ,  //写数据扇区地址
    input        [15:0]  wr_data       ,  //写数据                  
    output               wr_busy       ,  //写数据忙信号
    output               wr_req        ,  //写数据请求信号    
    //用户读SD卡接口
    input                rd_start_en   ,  //开始读SD卡数据信号
    input        [31:0]  rd_sec_addr   ,  //读数据扇区地址
    output               rd_busy       ,  //读数据忙信号
    output               rd_val_en     ,  //读数据有效信号
    output       [15:0]  rd_val_data   ,  //读数据    
    
    output               sd_init_done     //SD卡初始化完成信号
    );

//wire define
wire                init_sd_clk   ;       //初始化SD卡时的低速时钟
wire                init_sd_cs    ;       //初始化模块SD片选信号
wire                init_sd_mosi  ;       //初始化模块SD数据输出信号
wire                wr_sd_cs      ;       //写数据模块SD片选信号     
wire                wr_sd_mosi    ;       //写数据模块SD数据输出信号 
wire                rd_sd_cs      ;       //读数据模块SD片选信号     
wire                rd_sd_mosi    ;       //读数据模块SD数据输出信号
wire                sd_clk_t      ;       //SD卡时钟 

//*****************************************************
//**                    main code
//*****************************************************

//SD卡的SPI_CLK  
assign  sd_clk = (sd_init_done==1'b0)  ?  init_sd_clk  :  clk_ref_180deg;

//SD卡接口信号选择
always @(*) begin
    //SD卡初始化完成之前,端口信号和初始化模块信号相连
    if(sd_init_done == 1'b0) begin     
        sd_cs = init_sd_cs;
        sd_mosi = init_sd_mosi;
    end    
    else if(wr_busy) begin
        sd_cs = wr_sd_cs;
        sd_mosi = wr_sd_mosi;   
    end    
    else if(rd_busy) begin
        sd_cs = rd_sd_cs;
        sd_mosi = rd_sd_mosi;       
    end    
    else begin
        sd_cs = 1'b1;
        sd_mosi = 1'b1;
    end    
end    

//SD卡初始化
sd_init u_sd_init(
    .clk_ref            (clk_ref),
    .rst_n              (rst_n),
    
    .sd_miso            (sd_miso),
    .sd_clk             (init_sd_clk),
    .sd_cs              (init_sd_cs),
    .sd_mosi            (init_sd_mosi),
    
    .sd_init_done       (sd_init_done)
    );

//SD卡读数据
sd_read u_sd_read(
    .clk_ref            (clk_ref),
    .clk_ref_180deg     (clk_ref_180deg),
    .rst_n              (rst_n),
    
    .sd_miso            (sd_miso),
    .sd_cs              (rd_sd_cs),
    .sd_mosi            (rd_sd_mosi),    
    //SD卡初始化完成之后响应读操作
    .rd_start_en        (rd_start_en & sd_init_done),  
    .rd_sec_addr        (rd_sec_addr),
    .rd_busy            (rd_busy),
    .rd_val_en          (rd_val_en),
    .rd_val_data        (rd_val_data)
    );

endmodule


DDR3 控制器模块(ddr3_top): DDR3 读写控制器模块负责驱动 DDR3 片外存储器,缓存从 SD 卡中读出的图像数据。该模块将 DDR3 复杂的读写操作封装成类似 FIFO 的用户接口,非常方便用户的使用。

//****************************************Copyright (c)***********************************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name:           ddr3_top
// Last modified Date:  2020/05/04 9:19:08
// Last Version:        V1.0
// Descriptions:        ddr3控制器顶层模块
//                      
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2019/05/04 9:19:08
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module ddr3_top(
    input              refclk_in           ,//外部参考时钟输入
    input              rst_n               ,//外部复位输入
    input   [25:0]     app_addr_rd_min     ,//读ddr3的起始地址
    input   [25:0]     app_addr_rd_max     ,//读ddr3的结束地址
    input   [7:0]      rd_bust_len         ,//从ddr3中读数据时的突发长度
    input   [25:0]     app_addr_wr_min     ,//读ddr3的起始地址
    input   [25:0]     app_addr_wr_max     ,//读ddr3的结束地址
    input   [7:0]      wr_bust_len         ,//从ddr3中读数据时的突发长度
    //用户接口
    input              ddr3_read_valid     ,//DDR3 读使能
    input              ddr3_pingpang_en    ,//DDR3 乒乓操作使能
    input              wr_clk              ,//wfifo时钟
    input              rd_clk              ,//rfifo的读时钟
    input              datain_valid        ,//数据有效使能信号
    input   [15:0]     datain              ,//有效数据
    input              rdata_req           ,//请求像素点颜色数据输入
    input              rd_load             ,//输出源更新信号
    input              wr_load             ,//输入源更新信号
    output  [15:0]     dataout             ,//rfifo输出数据
    output             pll_lock            ,//时钟锁定信号
    output             ddr_init_done       ,//DDR初始化完成
    output             ddrphy_rst_done     ,//DDRPHY 复位完成标志
    output             fram_done           ,//DDR中已经存入一帧画面标志
    //DDR3接口
    input              pad_loop_in         ,
    input              pad_loop_in_h       ,
    output             pad_rstn_ch0        ,
    output             pad_ddr_clk_w       ,
    output             pad_ddr_clkn_w      ,
    output             pad_csn_ch0         ,
    output [15:0]      pad_addr_ch0        ,
    inout  [16-1:0]    pad_dq_ch0          ,
    inout  [16/8-1:0]  pad_dqs_ch0         ,
    inout  [16/8-1:0]  pad_dqsn_ch0        ,
    output [16/8-1:0]  pad_dm_rdqs_ch0     ,
    output             pad_cke_ch0         ,
    output             pad_odt_ch0         ,
    output             pad_rasn_ch0        ,
    output             pad_casn_ch0        ,
    output             pad_wen_ch0         ,
    output [2:0]       pad_ba_ch0          ,
    output             pad_loop_out        ,
    output             pad_loop_out_h
   );

//wire define
    wire  [32-1:0]    axi_awaddr   ;
    wire  [7:0]       axi_awlen    ;
    wire  [2:0]       axi_awsize   ;
    wire  [1:0]       axi_awburst  ;
    wire              axi_awlock   ;
    wire              axi_awready  ;
    wire              axi_awvalid  ;
    wire              axi_awurgent ;
    wire              axi_awpoison ;
    wire  [128-1:0]   axi_wdata    ;
    wire  [16-1:0]    axi_wstrb    ;
    wire              axi_wvalid   ;
    wire              axi_wready   ;
    wire              axi_wlast    ;
    wire  [7:0]       axi_bid      ;
    wire  [1:0]       axi_bresp    ;
    wire              axi_bvalid   ;
    wire              axi_bready   ;
    wire  [32-1:0]    axi_araddr   ;
    wire  [7:0]       axi_arlen    ;
    wire  [2:0]       axi_arsize   ;
    wire  [1:0]       axi_arburst  ;
    wire              axi_arlock   ;
    wire              axi_arpoison ;
    wire              axi_arurgent ;
    wire              axi_arready  ;
    wire              axi_arvalid  ;
    wire  [128-1:0]   axi_rdata    ;
    wire  [7:0]       axi_rid      ;
    wire              axi_rlast    ;
    wire              axi_rvalid   ;
    wire              axi_rready   ;
    wire  [1:0]       axi_rresp    ;
    wire              axi_csysreq  ;
    wire              axi_csysack  ;
    wire              axi_cactive  ;
    wire              axi_clk      ;
    wire [10:0]       wfifo_rcount   ;//rfifo剩余数据计数
    wire [10:0]       rfifo_wcount   ;//wfifo写进数据计数
    wire              wrfifo_en_ctrl ;//写FIFO数据读使能控制位
    wire              wfifo_rden     ;//写FIFO数据读使能
    wire              pre_wfifo_rden ;//写FIFO数据预读使能

//*****************************************************
//**                    main code
//*****************************************************

//因为预读了一个数据所以读使能wfifo_rden要少一个周期通过wrfifo_en_ctrl控制
assign wfifo_rden = axi_wvalid && axi_wready && (~wrfifo_en_ctrl);
assign pre_wfifo_rden = axi_awvalid && axi_awready;

//ddr3读写控制器模块
 rw_ctrl_128bit  u_rw_ctrl_128bit(
    .clk                 (axi_clk          ),
    .rst_n               (rst_n            ),
    .ddr_init_done       (ddr_init_done    ),
    .axi_awaddr          (axi_awaddr       ),
    .axi_awlen           (axi_awlen        ),
    .axi_awsize          (axi_awsize       ),
    .axi_awburst         (axi_awburst      ),
    .axi_awlock          (axi_awlock       ),
    .axi_awready         (axi_awready      ),
    .axi_awvalid         (axi_awvalid      ),
    .axi_awurgent        (axi_awurgent     ),
    .axi_awpoison        (axi_awpoison     ),
    .axi_wstrb           (axi_wstrb        ),
    .axi_wvalid          (axi_wvalid       ),
    .axi_wready          (axi_wready       ),
    .axi_wlast           (axi_wlast        ),
    .axi_bready          (axi_bready       ),
    .fram_done           (fram_done        ),
    .wrfifo_en_ctrl      (wrfifo_en_ctrl   ),
    .axi_araddr          (axi_araddr       ),
    .axi_arlen           (axi_arlen        ),
    .axi_arsize          (axi_arsize       ),
    .axi_arburst         (axi_arburst      ),
    .axi_arlock          (axi_arlock       ),
    .axi_arpoison        (axi_arpoison     ),
    .axi_arurgent        (axi_arurgent     ),
    .axi_arready         (axi_arready      ),
    .axi_arvalid         (axi_arvalid      ),
    .axi_rlast           (axi_rlast        ),
    .axi_rvalid          (axi_rvalid       ),
    .axi_rready          (axi_rready       ),
    .wfifo_rcount        (wfifo_rcount     ),
    .rfifo_wcount        (rfifo_wcount     ),
    .rd_load             (rd_load          ),
    .wr_load             (wr_load          ),
    .app_addr_rd_min     (app_addr_rd_min  ),
    .app_addr_rd_max     (app_addr_rd_max  ),
    .rd_bust_len         (rd_bust_len      ),
    .app_addr_wr_min     (app_addr_wr_min  ),
    .app_addr_wr_max     (app_addr_wr_max  ),
    .wr_bust_len         (wr_bust_len      ),
    .ddr3_read_valid     (ddr3_read_valid  ),
    .ddr3_pingpang_en    (ddr3_pingpang_en )
    );

 //ddr3IP核模块
 ddr3_ip u_ddr3_ip (
    .pll_refclk_in    (refclk_in      ), // input
    .top_rst_n        (rst_n          ), // input
    .ddrc_rst         (0              ), // input
    .csysreq_ddrc     (1'b1           ), // input
    .csysack_ddrc     (               ), // output
    .cactive_ddrc     (               ), // output
    .pll_lock         (pll_lock       ), // output
    .pll_aclk_0       (axi_clk        ), // output
    .pll_aclk_1       (               ), // output
    .pll_aclk_2       (               ), // output
    .ddrphy_rst_done  (ddrphy_rst_done), // output
    .ddrc_init_done   (ddr_init_done  ), // output
    .pad_loop_in      (pad_loop_in    ), // input
    .pad_loop_in_h    (pad_loop_in_h  ), // input
    .pad_rstn_ch0     (pad_rstn_ch0   ), // output
    .pad_ddr_clk_w    (pad_ddr_clk_w  ), // output
    .pad_ddr_clkn_w   (pad_ddr_clkn_w ), // output
    .pad_csn_ch0      (pad_csn_ch0    ), // output
    .pad_addr_ch0     (pad_addr_ch0   ), // output [15:0]
    .pad_dq_ch0       (pad_dq_ch0     ), // inout [15:0]
    .pad_dqs_ch0      (pad_dqs_ch0    ), // inout [1:0]
    .pad_dqsn_ch0     (pad_dqsn_ch0   ), // inout [1:0]
    .pad_dm_rdqs_ch0  (pad_dm_rdqs_ch0), // output [1:0]
    .pad_cke_ch0      (pad_cke_ch0    ), // output
    .pad_odt_ch0      (pad_odt_ch0    ), // output
    .pad_rasn_ch0     (pad_rasn_ch0   ), // output
    .pad_casn_ch0     (pad_casn_ch0   ), // output
    .pad_wen_ch0      (pad_wen_ch0    ), // output
    .pad_ba_ch0       (pad_ba_ch0     ), // output [2:0]
    .pad_loop_out     (pad_loop_out   ), // output
    .pad_loop_out_h   (pad_loop_out_h ), // output
    .areset_0         (0              ), // input
    .aclk_0           (axi_clk        ), // input
    .awid_0           (0              ), // input [7:0]
    .awaddr_0         (axi_awaddr     ), // input [31:0]
    .awlen_0          (axi_awlen      ), // input [7:0]
    .awsize_0         (axi_awsize     ), // input [2:0]
    .awburst_0        (axi_awburst    ), // input [1:0]
    .awlock_0         (axi_awlock     ), // input
    .awvalid_0        (axi_awvalid    ), // input
    .awready_0        (axi_awready    ), // output
    .awurgent_0       (axi_awurgent   ), // input
    .awpoison_0       (axi_awpoison   ), // input
    .wdata_0          (axi_wdata      ), // input [127:0]
    .wstrb_0          (axi_wstrb      ), // input [15:0]
    .wlast_0          (axi_wlast      ), // input
    .wvalid_0         (axi_wvalid     ), // input
    .wready_0         (axi_wready     ), // output
    .bid_0            (axi_bid        ), // output [7:0]
    .bresp_0          (axi_bresp      ), // output [1:0]
    .bvalid_0         (axi_bvalid     ), // output
    .bready_0         (axi_bready     ), // input 
    .arid_0           (0              ), // input [7:0]
    .araddr_0         (axi_araddr     ), // input [31:0]
    .arlen_0          (axi_arlen      ), // input [7:0]
    .arsize_0         (axi_arsize     ), // input [2:0]
    .arburst_0        (axi_arburst    ), // input [1:0]
    .arlock_0         (axi_arlock     ), // input
    .arvalid_0        (axi_arvalid    ), // input
    .arready_0        (axi_arready    ), // output
    .arpoison_0       (axi_arpoison   ), // input 
    .rid_0            (axi_rid        ), // output [7:0]
    .rdata_0          (axi_rdata      ), // output [127:0]
    .rresp_0          (axi_rresp      ), // output [1:0]
    .rlast_0          (axi_rlast      ), // output
    .rvalid_0         (axi_rvalid     ), // output
    .rready_0         (axi_rready     ), // input
    .arurgent_0       (axi_arurgent   ), // input
    .csysreq_0        (1'b1           ), // input
    .csysack_0        (               ), // output
    .cactive_0        (               )  // output
    );

//ddr3控制器fifo控制模块
 ddr3_fifo_ctrl u_ddr3_fifo_ctrl (
    .rst_n               (rst_n &&ddr_init_done     ), //复位
    //输入源接口
    .wr_clk              (wr_clk                    ), //写时钟
    .rd_clk              (rd_clk                    ), //读时钟
    .clk_100             (axi_clk                   ), //用户时钟 
    .datain_valid        (datain_valid              ), //数据有效使能信号
    .datain              (datain                    ), //有效数据 
    .rfifo_din           (axi_rdata                 ), //用户读数据 
    .rdata_req           (rdata_req                 ), //请求像素点颜色数据输入
    .rfifo_wren          (axi_rvalid                ), //ddr3读出数据的有效使能
    .wfifo_rden          (wfifo_rden||pre_wfifo_rden), //ddr3 写使能
    //用户接口
    .wfifo_rcount        (wfifo_rcount              ), //rfifo剩余数据计数
    .rfifo_wcount        (rfifo_wcount              ), //wfifo写进数据计数
    .wfifo_dout          (axi_wdata                 ), //用户写数据
    .rd_load             (rd_load                   ), //输出源更新信号
    .wr_load             (wr_load                   ), //输入源更新信号
    .pic_data            (dataout                   )  //rfifo输出数据
    );

endmodule


LCD 顶层模块(lcd_rgb_top): LCD 顶层模块根据获取到的 LCD ID,驱动 LCD 液晶屏的显示。

//****************************************Copyright (c)***********************************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name:           lcd_rgb_top
// Last modified Date:  2020/05/04 9:19:08
// Last Version:        V1.0
// Descriptions:        LCD顶层模块
//                      
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2019/05/04 9:19:08
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module lcd_rgb_top(
    input           sys_clk      ,  //系统时钟
    input           sys_rst_n,      //复位信号  
    input           sys_init_done, 
    //lcd接口  
    output          lcd_clk,        //LCD驱动时钟    
    output          lcd_hs,         //LCD 行同步信号
    output          lcd_vs,         //LCD 场同步信号
    output          lcd_de,         //LCD 数据输入使能
    inout  [23:0]   lcd_rgb,        //LCD RGB颜色数据
    output          lcd_bl,         //LCD 背光控制信号
    output          lcd_rst,        //LCD 复位信号
    output          lcd_pclk,       //LCD 采样时钟
    output  [15:0]  lcd_id,         //LCD屏ID  
    output          out_vsync,      //lcd场信号 
    output  [10:0]  pixel_xpos,     //像素点横坐标
    output  [10:0]  pixel_ypos,     //像素点纵坐标        
    output  [10:0]  h_disp,         //LCD屏水平分辨率
    output  [10:0]  v_disp,         //LCD屏垂直分辨率         
    input   [23:0]  data_in,        //数据输入   
    output          data_req        //请求数据输入
    
    );

//wire define
wire  [15:0] lcd_rgb_565;           //输出的16位lcd数据
wire  [23:0] lcd_rgb_o ;            //LCD 输出颜色数据
wire  [23:0] lcd_rgb_i ;            //LCD 输入颜色数据
//*****************************************************
//**                    main code
//***************************************************** 
//将摄像头16bit数据转换为24bit的lcd数据
assign lcd_rgb_o = {lcd_rgb_565[15:11],3'b000,lcd_rgb_565[10:5],2'b00,
                    lcd_rgb_565[4:0],3'b000};          

//像素数据方向切换
assign lcd_rgb = lcd_de ?  lcd_rgb_o :  {24{1'bz}};
assign lcd_rgb_i = lcd_rgb;
            
//时钟分频模块    
clk_div u_clk_div(
    .clk                    (sys_clk  ),
    .rst_n                  (sys_rst_n),
    .lcd_id                 (lcd_id   ),
    .lcd_pclk               (lcd_clk  )
    );  

//读LCD ID模块
rd_id u_rd_id(
    .clk                    (sys_clk  ),
    .rst_n                  (sys_rst_n),
    .lcd_rgb                (lcd_rgb_i),
    .lcd_id                 (lcd_id   )
    );  

//lcd驱动模块
lcd_driver u_lcd_driver(           
    .lcd_clk        (lcd_clk),    
    .sys_rst_n      (sys_rst_n & sys_init_done), 
    .lcd_id         (lcd_id),   

    .lcd_hs         (lcd_hs),       
    .lcd_vs         (lcd_vs),       
    .lcd_de         (lcd_de),       
    .lcd_rgb        (lcd_rgb_565),
    .lcd_bl         (lcd_bl),
    .lcd_rst        (lcd_rst),
    .lcd_pclk       (lcd_pclk),
    
    .pixel_data     (data_in), 
    .data_req       (data_req),
    .out_vsync      (out_vsync),
    .h_disp         (h_disp),
    .v_disp         (v_disp), 
    .pixel_xpos     (pixel_xpos), 
    .pixel_ypos     (pixel_ypos)
    ); 
                 
endmodule 


5、下载验证

    在打开下载界面之前,先准备BMP 图片。winhex查看图片对应的扇区地址:

    两张 BMP 图片的起始扇区地址分别为 36992和 61888,这和我们 sd_read_photo 模块定义的 PHOTO_SECTION_ADDR0 = 32'd36992, PHOTO_SECTION_ADDR1 = 32'd61888是一致的。如果查看的值不是上图中的值,需要将代码中定义的这两个参数值改成 WinHex 查看的扇区地址, 需要注意的是如果所选中的图片的第一扇区地址与右下角的物理扇区号如果不对应,需要以物理扇区号的地址为准!实验效果:

2456d06f7c099785f8bdf20789a06939

 

 

最新回复

看来读懂和理解好硬件电路这个比编程要重要的多   详情 回复 发表于 2023-2-20 07:33
点赞(1) 关注(1)
 
 

回复
举报

1701

帖子

0

TA的资源

五彩晶圆(初级)

沙发
 

看来读懂和理解好硬件电路这个比编程要重要的多

点评

我们这个编程和硬件分不开,Veriog本身就是硬件描述语言   。  详情 回复 发表于 2023-3-7 15:20
 
 
 

回复

845

帖子

3

TA的资源

版主

板凳
 
火辣西米秀 发表于 2023-2-20 07:33 看来读懂和理解好硬件电路这个比编程要重要的多

我们这个编程和硬件分不开,Veriog本身就是硬件描述语言

 

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表