MIPI接口
MIPI(Mobile Industry Processor Interface)是2003年由ARM, Nokia, ST ,TI等公司成立的一个联盟,目的是把手机内部的接口如摄像头、显示屏接口、射频/基带接口等标准化,从而减少手机设计的复杂程度和增加设计灵活性。MIPI联盟下面有不同的WorkGroup,分别定义了一系列的手机内部接口标准,比如摄像头接口CSI、显示接口DSI、射频接口DigRF、麦克风/喇叭接口SLIMbus等。统一接口标准的好处是手机厂商根据需要可以从市面上灵活选择不同的芯片和模组,更改设计和功能时更加快捷方便。下图是按照MIPI的规划下一代智能手机的内部架构.
MIPI是一个比较新的标准,其规范也在不断修改和改进,目前比较成熟的接口应用有DSI(显示接口)和CSI(摄像头接口)。CSI/DSI分别是指其承载的是针对Camera或Display应用,都有复杂的协议结构。以DSI为例,其协议层结构如下 :
CSI/DSI的物理层(Phy Layer)由专门的WorkGroup负责制定,其目前的标准是D-PHY。D-PHY采用1对源同步的差分时钟和1~4对差分数据线来进行数据传输。数据传输采用DDR方式,即在时钟的上下边沿都有数据传输。
D-PHY的物理层支持HS(High Speed)和LP(Low Power)两种工作模式。HS模式下采用低压差分信号,功耗较大,但是可以传输很高的数据速率(数据速率为80M~1Gbps); LP模式下采用单端信号,数据速率很低(<10Mbps),但是相应的功耗也很低。两种模式的结合保证了MIPI总线在需要传输大量数据(如图像)时可以高速传输,而在不需要大数据量传输时又能够减少功耗。
以上内容参考地址:https://zhuanlan.zhihu.com/p/356749516
教程——使用SF1 Light 驱动一款mipi接口的屏幕(1200x1920)
本教程主要目标使用SF1内部的MIPI DSI Controller 与 MIPI D-PHY 模块驱动一块1200x1920的屏幕,显示的内容是利用fpga部分生成的Video信号,包括R、G、B三色纯色显示,RGB三色阶梯显示,网格线等等,这些测试信号可以自行编写。
屏幕套件资料:https://gitee.com/verimaker/sf1-light-lcd-kit-10.1inch
文章中的工程文件在 gitee 上,有需要的自行下载:
https://gitee.com/verimaker/sf1-light-lcd-kit-10.1inch/tree/master/firmware/Test
本次使用的屏幕型号是MX10132010-40A,它是TFT-LCD,10.1‘’,1200x1920,16.7M colors。mipi接口。接口信号如图:
可以看出这个接口与SF1 Light的mipi接口是有差别的,需要有转接板连接屏幕和SF1 Light开发板。这里需要注意,如果选择的不是这块屏幕仍然需要对照屏幕的管脚制作转接板,因为屏幕厂家的管脚定义各不相同,<font color=#FF0000>其次需要注意的还有屏幕的电源供电要求,如果屏幕更大建议另外单独设计电源给屏幕供电,不建议从SF1 Light供电给屏幕</font>。
一、硬件设计
1、生成DSI IP
新建TD工程,存放在非中文目录中,例如MIPI_Display目录下新建td_project目录存放TD工程。
选择Tools—>IP Generator ,新建名为DSI0_TX模块。
DSI的相关介绍参看安路TN803文档。
按照下图选择配置,left对应是mipi0口的,选择TX表示mipi口发送数据输出。
2、创建SF1_SOC
参见教程第一讲,生成MCU,具体配置如图。
参见教程第一讲,创建verilog文件,编写gpio_controler.v用来控制gpio口。代码参见第一讲教程。接下来使用该模块和MCU构成SOC。SF1_SOC的代码如下:
module SF1_SOC(
input wire I_clk,
input wire I_rst,
input wire I_timer_clk,
input wire I_jtag_tck,
output wire O_jtag_tdo,
input wire I_jtag_tms,
input wire I_jtag_tdi,
input wire I_uart_rx,
output wire O_uart_tx,
output wire O_apb_clk,
input wire[31:0] I_apb_prdata,
output wire[31:0] O_apb_pwdata,
output wire[3:0] O_apb_pstrobe,
output wire[2:0] O_apb_pprot,
output wire O_apb_penable,
output wire O_apb_pwrite,
input wire I_apb_pslverr,
input wire I_apb_pready,
output wire[11:0] O_apb_paddr,
output wire O_apb_psel0,
output wire O_apb_psel1,
output wire O_apb_psel2,
inout wire IO_gpio_0,
inout wire IO_gpio_1,
inout wire IO_gpio_2,
inout wire IO_gpio_3,
inout wire IO_gpio_4
);
wire S_gpio0_out;
wire S_gpio0_dir;
wire S_gpio0_in ;
wire S_gpio1_out;
wire S_gpio1_dir;
wire S_gpio1_in ;
wire S_gpio2_out;
wire S_gpio2_dir;
wire S_gpio2_in ;
wire S_gpio3_out;
wire S_gpio3_dir;
wire S_gpio3_in ; //synthesis keep;
wire S_gpio4_out;
wire S_gpio4_dir;
wire S_gpio4_in ;
gpio_controler u0_gpio_controler(
.O_gpio_in ( S_gpio0_in ),
.I_gpio_dir ( S_gpio0_dir ),
.I_gpio_out ( S_gpio0_out ),
.IO_gpio ( IO_gpio_0 )
);
gpio_controler u1_gpio_controler(
.O_gpio_in ( S_gpio1_in ),
.I_gpio_dir ( S_gpio1_dir ),
.I_gpio_out ( S_gpio1_out ),
.IO_gpio ( IO_gpio_1 )
);
gpio_controler u2_gpio_controler(
.O_gpio_in ( S_gpio2_in ),
.I_gpio_dir ( S_gpio2_dir ),
.I_gpio_out ( S_gpio2_out ),
.IO_gpio ( IO_gpio_2 )
);
gpio_controler u3_gpio_controler(
.O_gpio_in ( S_gpio3_in ),
.I_gpio_dir ( S_gpio3_dir ),
.I_gpio_out ( S_gpio3_out ),
.IO_gpio ( IO_gpio_3 )
);
gpio_controler u4_gpio_controler(
.O_gpio_in ( S_gpio4_in ),
.I_gpio_dir ( S_gpio4_dir ),
.I_gpio_out ( S_gpio4_out ),
.IO_gpio ( IO_gpio_4 )
);
SF1_MCU u_SF1_MCU(
.core_clk ( I_clk ),
.timer_clk ( I_timer_clk ),
.core_reset ( I_rst ),
.jtag_tck ( I_jtag_tck ),
.jtag_tdo ( O_jtag_tdo ),
.jtag_tms ( I_jtag_tms ),
.jtag_tdi ( I_jtag_tdi ),
.soft_ip_apbm_en ( 1'b0 ),
.qspi0cfg1_mode ( 1'b1 ),
.qspi0cfg2_mode ( 1'b1 ),
.apb_clk_down ( O_apb_clk ),
.apb_paddr_down ( O_apb_paddr ),
.apb_penable_down ( O_apb_penable ),
.apb_pprot_down ( O_apb_pprot ),
.apb_prdata_down ( I_apb_prdata ),
.apb_pready_down ( I_apb_pready ),
.apb_pslverr_down ( I_apb_pslverr ),
.apb_pstrobe_down ( O_apb_pstrobe ),
.apb_pwdata_down ( O_apb_pwdata ),
.apb_pwrite_down ( O_apb_pwrite ),
.apb_psel0_down ( O_apb_psel0 ),
.apb_psel1_down ( O_apb_psel1 ),
.apb_psel2_down ( O_apb_psel2 ),
.uart_tx ( O_uart_tx ),
.uart_rx ( I_uart_rx ),
.gpio0_out ( S_gpio0_out ),
.gpio0_dir ( S_gpio0_dir ),
.gpio0_in ( S_gpio0_in ),
.gpio1_out ( S_gpio1_out ),
.gpio1_dir ( S_gpio1_dir ),
.gpio1_in ( S_gpio1_in ),
.gpio2_out ( S_gpio2_out ),
.gpio2_dir ( S_gpio2_dir ),
.gpio2_in ( S_gpio2_in ),
.gpio3_out ( S_gpio3_out ),
.gpio3_dir ( S_gpio3_dir ),
.gpio3_in ( S_gpio3_in ),
.gpio4_out ( S_gpio4_out ),
.gpio4_dir ( S_gpio4_dir ),
.gpio4_in ( S_gpio4_in ),
.htrans ( ),
.hwrite ( ),
.haddr ( ),
.hsize ( ),
.hburst ( ),
.hprot ( ),
.hmastlock ( ),
.hwdata ( ),
.hclk ( ),
.hrdata ( ),
.hresp ( ),
.hready ( ),
.i2c_sda_out ( ),
.i2c_sda_sel ( ),
.i2c_scl_out ( ),
.i2c_scl_sel ( ),
.i2c_sda_in ( ),
.i2c_scl_in ( ),
.nmi ( ),
.clic_irq ( ),
.sysrstreq ( )
);
endmodule
与第一讲不同的是这里的SOC将APB端口引出,因为MCU将需要通过APB与DSI相连接进行控制。在TN803文档中可以直到,DSI0的APB基地址为 0xe0080000。这个地址在后面编写C代码时需要用到。
3、创建时钟pll
创建pll IP,配置如图。
4、创建Video测试信号
新建video_tpg.v文件,用来产生Video信号,通过控制输入端口TPG_mode的值可以控制输出的视频信号的模式。
`timescale 1ns / 1ps
/*
// 0x01 : red
// 0x02 : green
// 0x03 : blue
// 0x04 : white
// 0x05 : gray red
// 0x06 : gray green
// 0x07 : gray blue
// 0x08 : gray white
// 0x09 : mosaic
// 0x0A : diagonal gray scan
// 0x0B : grid scan
*/
//1920 * 1080 @60Hz ,148.5M
//1280 * 1024 @60Hz ,108M
//1280 * 720 @60Hz ,74.25M
//1680 * 1050 @60Hz ,119M
//1024*768,65m
//800600,40m
module video_tpg(
input PCLK,
input Reset,
input DEN_TPG,
input [3:0] TPG_mode,
output PDEN,
output HSYNC, //行信号
output VSYNC, //场信号
output [23:0] PDATA
);
reg den_tpg_en_reg_one=1'd0;
reg [11:0] hsync_cnt=12'd1; //行信号计数器
reg [10:0] vsync_cnt=11'd1; //场信号计数器
wire h_end;
wire v_end;
parameter HTOTAL = 1340; // 800;//2200; //2720; //1688; //1344;
parameter VTOTAL = 1944; //1525;//1125; //1646; //1066; //806;
parameter HSA = 24; //96;//44; //32; //112; //136;
parameter HBP = 56; //40; //80; //248; //160;
parameter HFP = 60;///8;//88; //48; //48; //24;
parameter VSA = 2; //2;//5; //6; //3; //6;
parameter VBP = 14; //25;//36; //37; //38; //29;
parameter VFP = 8; //2;//4; //3; //1; //3;
localparam DEN_HSYNC_back_porch = HSA + HBP;
localparam DEN_HSYNC_front_porch = HTOTAL-HFP;
localparam DEN_VSYNC_back_porch = VSA + VBP;
localparam DEN_VSYNC_front_porch = VTOTAL-VFP;
reg [3:0] tpg_mode_reg_one=4'd0;
always @(posedge PCLK)
begin
tpg_mode_reg_one <= TPG_mode;
den_tpg_en_reg_one <= DEN_TPG;
end
//行信号 HTOTAL
always @(posedge PCLK)
begin
if (den_tpg_en_reg_one)
if(h_end)
hsync_cnt <= 12'd1;
else
hsync_cnt <= hsync_cnt + 1;
else
hsync_cnt <= 12'd1;
end
assign h_end = (hsync_cnt == HTOTAL); //HTOTAL
//场信号 VTOTAL
always @(posedge PCLK)
begin
if (Reset)
vsync_cnt <= 10'd1;
else if(h_end)
begin
if(v_end)
vsync_cnt <= 10'd1;
else
vsync_cnt <= vsync_cnt + 1;
end
end
assign v_end = (vsync_cnt == VTOTAL); //VTOTAL
wire den_tmp;
reg den_reg_one=1'd0;
reg den_reg_two=1'd0;
reg den_reg_three=1'd0;
wire hsync_tmp;
wire vsync_tmp;
//DEN--HSYNC : (HSA + HBP + H_Left_Border) <= DE <= (HTOTAL - H_Rignt_Border + HFP)
//DEN--VSYNC : (VSA + VBP + V_Top_Border) <= DE <= (VTOTAL-V_Bottom_Border-VFP)
assign den_tmp = ((hsync_cnt > DEN_HSYNC_back_porch) && (hsync_cnt <= DEN_HSYNC_front_porch))&& ((vsync_cnt > DEN_VSYNC_back_porch) && (vsync_cnt <= DEN_VSYNC_front_porch));
//pipe
always @(posedge PCLK)
begin
den_reg_one <= den_tmp;
den_reg_two <= den_reg_one;
den_reg_three <= den_reg_two;
end
assign PDEN = Reset ? 1'b0 : den_reg_three;
//HSYNC=HSA + HYSNC Enablbe time
//VSYNC=VSA + VYSNC Enablbe time
assign hsync_tmp = (hsync_cnt > HSA);// // > HSA
assign vsync_tmp = (vsync_cnt > VSA);// // > VSA
reg hsync_reg_one=1'd0;
reg vsync_reg_one=1'd0;
reg vsync_reg_two=1'd0;
//pipe
always @(posedge PCLK)
begin
hsync_reg_one <= hsync_tmp;
vsync_reg_one <= vsync_tmp;
end
assign HSYNC = Reset ? 1'b0 : hsync_reg_one;
assign VSYNC = Reset ? 1'b0 : vsync_reg_one;
wire[10:0] x_pos;
wire[10:0] y_pos;
assign x_pos = hsync_cnt - DEN_HSYNC_back_porch ; // //DEN_HSYNC_back_porch
assign y_pos = vsync_cnt - DEN_VSYNC_back_porch-1 ; // //DEN_VSYNC_back_porch
reg [10:0] x_pos_reg_one_a=11'd0;
reg [4:0] x_pos_reg_one_b=5'd0;
reg [7:0] x_pos_reg_two=8'd0;
reg [7:0] x_pos_reg_three=8'd0;
reg [10:0] y_pos_reg_one_a=11'd0;
reg [4:0] y_pos_reg_one_b=11'd0;
//pipe
always @(posedge PCLK)
begin
x_pos_reg_one_a <= x_pos;
x_pos_reg_one_b <= x_pos[4:0];
x_pos_reg_two <= x_pos_reg_one_a[7:0];
x_pos_reg_three <= x_pos_reg_two;
y_pos_reg_one_a <= y_pos;
y_pos_reg_one_b <= y_pos[4:0];
end
reg vsync_begin_flag=1'd0;
//pipe
always @(posedge PCLK)
begin
vsync_reg_two <= vsync_reg_one;
vsync_begin_flag <= vsync_reg_one & (~vsync_reg_two);
end
reg [9:0] frame_cnt=10'd0;
//frame cnt
always @(posedge PCLK)
begin
if (vsync_begin_flag)
frame_cnt <= frame_cnt+1;
end
reg [23:0] pixel_value=24'd0;
reg [7:0] mosaic=8'd0;
reg [7:0] mosaic_reg_one=8'd0;
reg [7:0] diagonal_gray_scan=8'd0;
reg [7:0] diagonal_gray_scan_reg_one=8'd0;
reg [7:0] grid_scan=8'd0;
reg [7:0] grid_scan_reg_one=8'd0;
//mosaic
always @(posedge PCLK)
begin
if ( ((x_pos_reg_one_b[4]) && (y_pos_reg_one_a[4])) || ((~x_pos_reg_one_b[4]) && (~y_pos_reg_one_a[4])) )
mosaic <= 8'd255;
else
mosaic <= 8'd0;
end
//diagonal gray scan
//diagonal gran scan vlaue
always @(posedge PCLK)
begin
if (x_pos_reg_one_b[3:0]== (frame_cnt[9:6]-y_pos_reg_one_b[3:0]))
diagonal_gray_scan <=8'd255;
else
diagonal_gray_scan <=8'd0;
end
//grid scan
always @(posedge PCLK)
begin
if ( (x_pos_reg_one_b[3:0]==frame_cnt[9:6]) || (y_pos_reg_one_a[3:0]==frame_cnt[9:6]) )
grid_scan <= 8'd255;
else
grid_scan <= 8'd0;
end
//pipe
always @(posedge PCLK)
begin
mosaic_reg_one <= mosaic;
diagonal_gray_scan_reg_one <= diagonal_gray_scan;
grid_scan_reg_one <= grid_scan;
end
wire [10:0] debug_data;
assign debug_data=x_pos_reg_three+y_pos_reg_one_b;
always @*
begin
case (1)
tpg_mode_reg_one==4'd1: pixel_value ={16'd0,8'd255};
tpg_mode_reg_one== 4'd2: pixel_value ={8'd0,8'd255,8'd0};
tpg_mode_reg_one== 4'd3: pixel_value ={8'd255,16'd0};
tpg_mode_reg_one== 4'd4: pixel_value ={24'hFFFFFF};
tpg_mode_reg_one== 4'd5: pixel_value ={16'd0,x_pos_reg_three[7:0]};
tpg_mode_reg_one== 4'd6: pixel_value ={8'd0,x_pos_reg_three[7:0],8'd0};
tpg_mode_reg_one== 4'd7: pixel_value ={x_pos_reg_three[7:0],16'd0};
tpg_mode_reg_one== 4'd8: pixel_value ={x_pos_reg_three[7:0],x_pos_reg_three[7:0],x_pos_reg_three[7:0]};
tpg_mode_reg_one== 4'd9: pixel_value ={mosaic_reg_one,mosaic_reg_one,mosaic_reg_one};
tpg_mode_reg_one== 4'd10: pixel_value ={diagonal_gray_scan_reg_one,diagonal_gray_scan_reg_one,diagonal_gray_scan_reg_one};
tpg_mode_reg_one== 4'd11: pixel_value ={grid_scan_reg_one,grid_scan_reg_one,grid_scan_reg_one};
tpg_mode_reg_one>4'd11 && tpg_mode_reg_one<4'd15: pixel_value ={debug_data[7:0],debug_data[7:0],debug_data[7:0]};
default: pixel_value = 24'd0;
endcase
end
reg [23:0] vesa_pixel=8'd0;
always @(posedge PCLK)
begin
if( den_reg_two)
vesa_pixel <= {pixel_value[7:0],pixel_value[15:8],pixel_value[23:16]};
else
vesa_pixel <= 24'd0;
end
assign PDATA = vesa_pixel;
endmodule
为了让测试时能够自动切换视频信号类型,自动完成测试,设计一个video_tpg.v的上层控制器,用来自动切换输出不同的测试信号。新建文件video_source.v。代码如下:
module video_source (
input wire I_clk,
input wire I_rst,
input wire I_config_done,
output wire O_rgb24b_vsync,
output wire O_rgb24b_hsync,
output wire O_rgb24b_de,
output wire[23:0] O_rgb24b_data
);
parameter HTOTAL = 1340;
parameter VTOTAL = 1944;
parameter HSA = 24;
parameter HBP = 56;
parameter HFP = 60;
parameter VSA = 2;
parameter VBP = 14;
parameter VFP = 8;
wire S_24b_vsync;
wire S_24b_hsync;
wire video_rst;
reg S_vsync_1d;
wire S_vsync_p_edge;
reg[7:0] S_frame_cnt;
reg[3:0] S_tgb_mode;
always @(posedge I_clk) begin
S_vsync_1d <= O_rgb24b_vsync;
end
assign S_vsync_p_edge = ~S_vsync_1d & O_rgb24b_vsync;
always @ (posedge I_clk or posedge I_rst) begin
if(I_rst)
S_frame_cnt <= 'd0;
else
if(S_vsync_p_edge)
if(S_frame_cnt == 'd120)
S_frame_cnt <= 'd0;
else
S_frame_cnt <= S_frame_cnt + 1'b1;
else
S_frame_cnt <= S_frame_cnt;
end
always @ (posedge I_clk or posedge I_rst) begin
if(I_rst)
S_tgb_mode <= 'd0;
else
if(S_vsync_p_edge && S_frame_cnt == 'd120)
if(S_tgb_mode == 'd9)
S_tgb_mode <= 'd0;
else
S_tgb_mode <= S_tgb_mode + 1'b1;
else
S_tgb_mode <= S_tgb_mode;
end
assign O_rgb24b_vsync = ~S_24b_vsync;
assign O_rgb24b_hsync = ~S_24b_hsync;
assign video_rst = I_rst | (~I_config_done);
video_tpg #(
.HTOTAL ( HTOTAL ),
.HSA ( HSA ),
.HBP ( HBP ),
.HFP ( HFP ),
.VTOTAL ( VTOTAL ),
.VSA ( VSA ),
.VBP ( VBP ),
.VFP ( VFP )
)u_video_tpg_8001280(
.PCLK ( I_clk ),
.Reset ( video_rst ),
.DEN_TPG ( 1'b1 ),
.TPG_mode ( S_tgb_mode ),
.PDEN ( O_rgb24b_de ),
.HSYNC ( S_24b_hsync ),
.VSYNC ( S_24b_vsync ),
.PDATA ( O_rgb24b_data )
);
endmodule
5、创建顶层电路
将上述的模块组合起来。构建最后的顶层硬件电路。这里需要注意的是MCU和DSI之间是通过apb总线连接,视频Video信号接在DSI上,此外还需要注意的是,DSI硬件的输出端口固定为专用端口不需要配置管脚。新建MIPI_TOP.v代码如下:
module MIPI_TOP(
input wire I_clk_25m,
input wire I_rst_n,
input wire I_jtag_tck,
output wire O_jtag_tdo,
input wire I_jtag_tms,
input wire I_jtag_tdi,
input wire I_uart_rx,
output wire O_uart_tx,
output wire O_buzzer,
output wire O_led0,
output wire O_led1,
output wire O_led2,
inout wire I_key0,
inout wire I_key1,
output wire O_DPHY0_IO2
);
wire S_sys_clk_100m;
wire S_rst;
wire S_osc_clk;
wire S_pixel_clk;
wire S_txbyte_clk;
wire S_apb_clk_0;
wire[31:0] S_apb_prdata_0;
wire[31:0] S_apb_pwdata_0;
wire[3:0] S_apb_pstrobe_0;
wire[2:0] S_apb_pprot_0;
wire S_apb_penable_0;
wire S_apb_pwrite_0;
wire S_apb_pslverr_0;
wire S_apb_pready_0;
wire[11:0] S_apb_paddr_0;
wire S_apb_psel0_0;
wire S_apb_psel1_0;
wire S_apb_psel2_0;
wire S_source_vsync;
wire S_source_hsync;
wire S_source_de;
wire[23:0] S_source_data;
wire S_dsi_esc_clk;
assign S_rst = ~I_rst_n;
// LCD backlit ON
assign O_DPHY0_IO2 = 1'b1;
pll u_pll(
.refclk ( I_clk_25m ),
.reset ( S_rst ),
.extlock ( ),
.clk0_out ( S_sys_clk_100m ),
.clk1_out ( S_dsi_esc_clk )
);
SF1_PHY_OSC u_osc(
.pib_osc_dis( 1'b0 ),
.pib_sel ( 1'b1 ),
.pib_trim ( 5'h1f ),
.osc ( S_osc_clk )
);
SF1_LOGIC_BUFG U_bufg(
.i( S_txbyte_clk ),
.o( S_pixel_clk )
);
SF1_SOC u_SF1_SOC(
.I_clk ( S_sys_clk_100m ),
.I_timer_clk ( I_clk_25m ),
.I_rst ( S_rst ),
.I_jtag_tck ( I_jtag_tck ),
.O_jtag_tdo ( O_jtag_tdo ),
.I_jtag_tms ( I_jtag_tms ),
.I_jtag_tdi ( I_jtag_tdi ),
.I_uart_rx ( I_uart_rx ),
.O_uart_tx ( O_uart_tx ),
.O_apb_clk ( S_apb_clk_0 ),
.I_apb_prdata ( S_apb_prdata_0 ),
.O_apb_pwdata ( S_apb_pwdata_0 ),
.O_apb_pstrobe ( S_apb_pstrobe_0 ),
.O_apb_pprot ( S_apb_pprot_0 ),
.O_apb_penable ( S_apb_penable_0 ),
.O_apb_pwrite ( S_apb_pwrite_0 ),
.I_apb_pslverr ( S_apb_pslverr_0 ),
.I_apb_pready ( S_apb_pready_0 ),
.O_apb_paddr ( S_apb_paddr_0 ),
.O_apb_psel0 ( S_apb_psel0_0 ),
.O_apb_psel1 ( S_apb_psel1_0 ),
.O_apb_psel2 ( S_apb_psel2_0 ),
.IO_gpio_0 ( O_led0 ),
.IO_gpio_1 ( O_led1 ),
.IO_gpio_2 ( O_led2 ),
.IO_gpio_3 ( I_key0 ),
.IO_gpio_4 ( I_key1 ),
.IO_gpio_5 ( )
);
video_source #(
.HTOTAL ( 1341 ),
.HSA ( 10 ),
.HBP ( 50 ),
.HFP ( 80 ),
.VTOTAL ( 1981 ),
.VSA ( 3 ),
.VBP ( 23 ),
.VFP ( 35 )
)u_video_source(
.I_clk ( S_pixel_clk ),
.I_rst ( S_rst ),
.I_config_done ( 1'b1 ),
.O_rgb24b_vsync ( S_source_vsync ),
.O_rgb24b_hsync ( S_source_hsync ),
.O_rgb24b_de ( S_source_de ),
.O_rgb24b_data ( S_source_data )
);
DSI_TX_0 u1_DSI_TX(
.apb_pclk ( S_apb_clk_0 ),
.apb_preset ( S_rst ),
.apb_dmode_up ( 1'b0 ),
.apb_paddr_up ( S_apb_paddr_0 ),
.apb_penable_up ( S_apb_penable_0 ),
.apb_pprot_up ( S_apb_pprot_0 ),
.apb_prdata_up ( S_apb_prdata_0 ),
.apb_pready_up ( S_apb_pready_0 ),
.apb_psel_up ( S_apb_psel2_0 ),
.apb_pslverr_up ( S_apb_pslverr_0 ),
.apb_pstrobe_up ( S_apb_pstrobe_0 ),
.apb_pwdata_up ( S_apb_pwdata_0 ),
.apb_pwrite_up ( S_apb_pwrite_0 ),
.apb_dmode_down ( ),
.apb_paddr_down ( ),
.apb_penable_down ( ),
.apb_pprot_down ( ),
.apb_prdata_down ( ),
.apb_pready_down ( ),
.apb_pslverr_down ( ),
.apb_pstrobe_down ( ),
.apb_pwdata_down ( ),
.apb_pwrite_down ( ),
.interrupt ( ),
.host_dpi_pclk ( S_pixel_clk ),
.host_dpi_vsync ( S_source_vsync ),
.host_dpi_hsync ( S_source_hsync ),
.host_dpi_de ( S_source_de ),
.host_dpi_d ( S_source_data ),
.host_dpi_sd ( 1'b0 ),
.host_dpi_cm ( 1'b0 ),
.host_dpi_packet_en ( 1'b0 ),
.clkesc ( S_dsi_esc_clk ),
.osc_clk_in ( S_osc_clk ),
.txbyteclk ( S_txbyte_clk ),
.cn ( ),
.cp ( ),
.dn0 ( ),
.dp0 ( ),
.dn1 ( ),
.dp1 ( ),
.dn2 ( ),
.dp2 ( ),
.dn3 ( ),
.dp3 ( )
);
endmodule
6、配置管脚
新建管脚配置文件pin.adc或者通过图形化配置管脚如下:
set_pin_assignment { I_clk_25m } { LOCATION = D7; }
set_pin_assignment { I_jtag_tck } { LOCATION = C7; }
set_pin_assignment { I_jtag_tdi } { LOCATION = D5; }
set_pin_assignment { I_jtag_tms } { LOCATION = D6; }
set_pin_assignment { I_key0 } { LOCATION = H2; }
set_pin_assignment { I_key1 } { LOCATION = J4; }
set_pin_assignment { I_rst_n } { LOCATION = J2; }
set_pin_assignment { I_uart_rx } { LOCATION = E4; }
set_pin_assignment { O_jtag_tdo } { LOCATION = C6; }
set_pin_assignment { O_led0 } { LOCATION = J5; }
set_pin_assignment { O_led1 } { LOCATION = H5; }
set_pin_assignment { O_led2 } { LOCATION = G4; }
set_pin_assignment { O_uart_tx } { LOCATION = A4; }
set_pin_assignment { O_DPHY0_IO2 } { LOCATION = G9; }
二、软件设计
1、创建工程,添加驱动
打开FutureDynasty软件,设置工作空间,在非中文路径下新建工程mipi_display,模板选择为空工程。
拷贝DSI和LCD的驱动到application目录下。
在工程名上鼠标右击,选择刷新。
2、修改main
修改main.c代码如下:
#include "nuclei_sdk_soc.h"
#include <stdio.h>
#include "./inc/dsi_configure.h"
int main(void)
{
dsi_0_configure();
lcd_screen_config();
while(1)
{
gpio_wr(0,1);
delay_1ms(1000);
gpio_wr(0,0);
delay_1ms(1000);
}
return 0;
}
3、添加delay_1us()函数
打开工程目录下 nuclei_common.c文件,文件所在位值如图。
在delay_1ms函数下面添加delay_1us函数如下
void delay_1us(uint32_t count)
{
uint64_t start_mtime, delta_mtime;
uint64_t delay_ticks = (SOC_TIMER_FREQ * (uint64_t)count) / 1000000;
start_mtime = SysTimer_GetLoadValue();
do {
delta_mtime = SysTimer_GetLoadValue() - start_mtime;
} while (delta_mtime < delay_ticks);
}
三、下载程序
将生成的bit文件和hex加载到TD的下载工具。下载代码后可以观察到屏幕上测试现象。
添加gif动画