新聞中心

        EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 基于STEP FPGA的SPI RGB液晶屏顯示驅(qū)動(dòng)

        基于STEP FPGA的SPI RGB液晶屏顯示驅(qū)動(dòng)

        作者: 時(shí)間:2023-12-05 來(lái)源:電子森林 收藏

        硬件說(shuō)明

        我們的STEP-BaseBoard底板上集成了1.8寸彩色液晶屏TFT_LCD模塊,大家可以驅(qū)動(dòng)LCD顯示文字、圖片或動(dòng)態(tài)的波形。
        首先了解一下液晶屏模塊,相關(guān)資料下載:https://pan.baidu.com/s/1bp6AYsR

        本文引用地址:http://www.104case.com/article/202312/453553.htm

        框圖如下:

        原理圖如下:

        原理圖中的器件U1為液晶屏,液晶屏為1.8寸,128RGB160像素,串行總線(SPI),液晶屏集成了ST7735S的驅(qū)動(dòng)器,處理器與ST7735S通信完成液晶屏的顯示控制

        ST7735S為132RGBx162像素點(diǎn)262K控制器/驅(qū)動(dòng)器,芯片可以直接跟外部處理器連接,支持串行SPI通信和8/9/16/18位并行通信(本液晶屏集成ST7735S時(shí)沒(méi)有留并行接口,所以只能使用串行通信),詳細(xì)參數(shù)請(qǐng)參考數(shù)據(jù)手冊(cè):st7735s_datasheet.pdf


        Verilog代碼

        // --------------------------------------------------------------------
        // >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
        // --------------------------------------------------------------------
        // Module: LCD_RGB
        // 
        // Author: Step
        // 
        // Description: Drive TFT_RGB_LCD_1.8 to display
        // 
        // --------------------------------------------------------------------
        // Code Revision History :
        // --------------------------------------------------------------------
        // Version: |Mod. Date:   |Changes Made:
        // V1.1     |2016/10/30   |Initial ver
        // --------------------------------------------------------------------
        module LCD_RGB #(
        	parameter LCD_W = 8'd132,			//液晶屏像素寬度
        	parameter LCD_H = 8'd162			//液晶屏像素高度)(
        	input				clk_in,			//12MHz系統(tǒng)時(shí)鐘
        	input				rst_n_in,		//系統(tǒng)復(fù)位,低有效 	
        	output	reg			ram_lcd_clk_en,	//RAM時(shí)鐘使能
        	output	reg	[7:0]	ram_lcd_addr,	//RAM地址信號(hào)
        	input		[131:0]	ram_lcd_data,	//RAM數(shù)據(jù)信號(hào) 	
        	output	reg			lcd_rst_n_out,	//LCD液晶屏復(fù)位
        	output	reg			lcd_bl_out,		//LCD背光控制
        	output	reg			lcd_dc_out,		//LCD數(shù)據(jù)指令控制
        	output	reg			lcd_clk_out,	//LCD時(shí)鐘信號(hào)
        	output	reg			lcd_data_out	//LCD數(shù)據(jù)信號(hào)
        	); 	
        	localparam			INIT_DEPTH = 16'd73; //LCD初始化的命令及數(shù)據(jù)的數(shù)量 	
        	localparam			RED		=	16'hf800;	//紅色
        	localparam			GREEN	=	16'h07e0;	//綠色
        	localparam			BLUE	=	16'h001f;	//藍(lán)色
        	localparam			BLACK	=	16'h0000;	//黑色
        	localparam			WHITE	=	16'hffff;	//白色
        	localparam			YELLOW	=	16'hffe0;	//黃色 	
        	localparam			IDLE	=	3'd0;
        	localparam			MAIN	=	3'd1;
        	localparam			INIT	=	3'd2;
        	localparam			SCAN	=	3'd3;
        	localparam			WRITE	=	3'd4;
        	localparam			DELAY	=	3'd5; 	
        	localparam			LOW		=	1'b0;
        	localparam			HIGH	=	1'b1; 	
        	//assign	lcd_bl_out = HIGH;				// backlight active high level 	
        	wire		[15:0]	color_t	=	YELLOW;		//頂層色為黃色
        	wire		[15:0]	color_b	=	BLACK;		//背景色為黑色 	
        	reg			[7:0]	x_cnt;
        	reg			[7:0]	y_cnt;
        	reg			[131:0]	ram_data_r; 	
        	reg			[8:0]	data_reg;				//
        	reg			[8:0]	reg_setxy	[10:0];
        	reg			[8:0]	reg_init	[72:0];
        	reg			[2:0]	cnt_main;
        	reg			[2:0]	cnt_init;
        	reg			[2:0]	cnt_scan;
        	reg			[5:0]	cnt_write;
        	reg			[15:0]	cnt_delay;
        	reg			[15:0]	num_delay;
        	reg			[15:0]	cnt;
        	reg					high_word;
        	reg			[2:0] 	state = IDLE;
        	reg			[2:0] 	state_back = IDLE;
        	always@(posedge clk_in or negedge rst_n_in) begin
        		if(!rst_n_in) begin
        			x_cnt <= 8'd0;
        			y_cnt <= 8'd0;
        			ram_lcd_clk_en <= 1'b0;
        			ram_lcd_addr <= 8'd0;
        			cnt_main <= 3'd0;
        			cnt_init <= 3'd0;
        			cnt_scan <= 3'd0;
        			cnt_write <= 6'd0;
        			cnt_delay <= 16'd0;
        			num_delay <= 16'd50;
        			cnt <= 16'd0;
        			high_word <= 1'b1;
        			lcd_bl_out <= LOW;
        			state <= IDLE;
        			state_back <= IDLE;
        		end else begin
        			case(state)
        				IDLE:begin
        						x_cnt <= 8'd0;
        						y_cnt <= 8'd0;
        						ram_lcd_clk_en <= 1'b0;
        						ram_lcd_addr <= 8'd0;
        						cnt_main <= 3'd0;
        						cnt_init <= 3'd0;
        						cnt_scan <= 3'd0;
        						cnt_write <= 6'd0;
        						cnt_delay <= 16'd0;
        						num_delay <= 16'd50;
        						cnt <= 16'd0;
        						high_word <= 1'b1;
        						state <= MAIN;
        						state_back <= MAIN;
        					end
        				MAIN:begin
        						case(cnt_main)	//MAIN狀態(tài)
        							3'd0:	begin state <= INIT; cnt_main <= cnt_main + 1'b1; end
        							3'd1:	begin state <= SCAN; cnt_main <= cnt_main + 1'b1; end
        							3'd2:	begin cnt_main <= 1'b1; 
        							end
        							default: state <= IDLE;
        						endcase
        					end
        				INIT:begin	//初始化狀態(tài)
        						case(cnt_init)
        							3'd0:	begin lcd_rst_n_out <= 1'b0; 
        							cnt_init <= cnt_init + 1'b1; 
        							end	//復(fù)位有效
        							3'd1:	begin num_delay <= 16'd3000; 
        							state <= DELAY; 
        							state_back <= INIT; 
        							cnt_init <= cnt_init + 1'b1; end	//延時(shí)
        							3'd2:	begin lcd_rst_n_out <= 1'b1; 
        							cnt_init <= cnt_init + 1'b1; 
        							end	//復(fù)位恢復(fù)
        							3'd3:	begin num_delay <= 16'd3000; 
        							state <= DELAY; 
        							state_back <= INIT; 
        							cnt_init <= cnt_init + 1'b1; 
        							end	//延時(shí)
        							3'd4:	begin 
        										if(cnt>=INIT_DEPTH) begin	
        										//當(dāng)73條指令及數(shù)據(jù)發(fā)出后,配置完成
        											cnt <= 16'd0;
        											cnt_init <= cnt_init + 1'b1;
        										end else begin
        											data_reg <= reg_init[cnt];	
        											if(cnt==16'd0) num_delay <= 16'd50000; //第一條指令需要較長(zhǎng)延時(shí)
        											else num_delay <= 16'd50;
        											cnt <= cnt + 16'd1;
        											state <= WRITE;
        											state_back <= INIT;
        										end
        									end
        							3'd5:	begin cnt_init <= 1'b0; 
        							state <= MAIN; end	//初始化完成,返回MAIN狀態(tài)
        							default: state <= IDLE;
        						endcase
        					end
        				SCAN:begin	//刷屏狀態(tài),從RAM中讀取數(shù)據(jù)刷屏
        						case(cnt_scan)
        							3'd0:	begin //確定刷屏的區(qū)域坐標(biāo),這里為全屏
        										if(cnt >= 11) begin	//
        											cnt <= 16'd0;
        											cnt_scan <= cnt_scan + 1'b1;
        										end else begin
        											data_reg <= reg_setxy[cnt];
        											cnt <= cnt + 16'd1;
        											num_delay <= 16'd50;
        											state <= WRITE;
        											state_back <= SCAN;
        										end
        									end
        							3'd1:	begin ram_lcd_clk_en <= HIGH; 
        							ram_lcd_addr <= y_cnt; 
        							cnt_scan <= cnt_scan + 1'b1; 
        							end	//RAM時(shí)鐘使能
        							3'd2:	begin cnt_scan <= cnt_scan + 1'b1; 
        							end	//延時(shí)一個(gè)時(shí)鐘
        							3'd3:	begin ram_lcd_clk_en <= LOW; 
        							ram_data_r <= ram_lcd_data; 
        							cnt_scan <= cnt_scan + 1'b1; 
        							end	//讀取RAM數(shù)據(jù),同時(shí)關(guān)閉RAM時(shí)鐘使能
        							3'd4:	begin 
        							//每個(gè)像素點(diǎn)需要16bit的數(shù)據(jù),SPI每次傳8bit,兩次分別傳送高8位和低8位
        										if(x_cnt>=LCD_W) begin	
        										//當(dāng)一個(gè)數(shù)據(jù)(一行屏幕)寫(xiě)完后,
        											x_cnt <= 8'd0;	
        											if(y_cnt>=LCD_H) begin y_cnt <= 8'd0; 
        											cnt_scan <= cnt_scan + 1'b1; 
        											end	//如果是最后一行就跳出循環(huán)
        											else begin y_cnt <= y_cnt + 1'b1; 
        											cnt_scan <= 3'd1; 
        											end		//否則跳轉(zhuǎn)至RAM時(shí)鐘使能,循環(huán)刷屏
        										end else begin
        											if(high_word) data_reg <= {1'b1,(ram_data_r[x_cnt]? color_t[15:8]:color_b[15:8])};	
        											//根據(jù)相應(yīng)bit的狀態(tài)判定顯示頂層色或背景色,根據(jù)high_word的狀態(tài)判定寫(xiě)高8位或低8位
        											else begin data_reg <= {1'b1,(ram_data_r[x_cnt]? color_t[7:0]:color_b[7:0])}; 
        											x_cnt <= x_cnt + 1'b1; 
        											end	//根據(jù)相應(yīng)bit的狀態(tài)判定顯示頂層色或背景色,根據(jù)high_word的狀態(tài)判定寫(xiě)高8位或低8位,同時(shí)指向下一個(gè)bit
        											high_word <= ~high_word;	
        											//high_word的狀態(tài)翻轉(zhuǎn)
        											num_delay <= 16'd50;	
        											//設(shè)定延時(shí)時(shí)間
        											state <= WRITE;	//跳轉(zhuǎn)至WRITE狀態(tài)
        											state_back <= SCAN;	
        											//執(zhí)行完WRITE及DELAY操作后返回SCAN狀態(tài)
        										end
        									end
        							3'd5:	begin cnt_scan <= 1'b0; 
        							lcd_bl_out <= HIGH; 
        							state <= MAIN; 
        							end
        							default: state <= IDLE;
        						endcase
        					end
        				WRITE:begin	//WRITE狀態(tài),將數(shù)據(jù)按照SPI時(shí)序發(fā)送給屏幕
        						if(cnt_write >= 6'd17) cnt_write <= 1'b0;
        						else cnt_write <= cnt_write + 1'b1;
        						case(cnt_write)
        							6'd0:	begin lcd_dc_out <= data_reg[8]; 
        							end	//9位數(shù)據(jù)最高位為命令數(shù)據(jù)控制位
        							6'd1:	begin lcd_clk_out <= LOW; 
        							lcd_data_out <= data_reg[7]; 
        							end	//先發(fā)高位數(shù)據(jù)
        							6'd2:	begin lcd_clk_out <= HIGH; 
        							end
        							6'd3:	begin lcd_clk_out <= LOW; 
        							lcd_data_out <= data_reg[6]; 
        							end
        							6'd4:	begin lcd_clk_out <= HIGH; 
        							end
        							6'd5:	begin lcd_clk_out <= LOW; 
        							lcd_data_out <= data_reg[5]; 
        							end
        							6'd6:	begin lcd_clk_out <= HIGH; 
        							end
        							6'd7:	begin lcd_clk_out <= LOW; 
        							lcd_data_out <= data_reg[4]; 
        							end
        							6'd8:	begin lcd_clk_out <= HIGH; e
        							nd
        							6'd9:	begin lcd_clk_out <= LOW; 
        							lcd_data_out <= data_reg[3]; 
        							end
        							6'd10:	begin lcd_clk_out <= HIGH; 
        							end
        							6'd11:	begin lcd_clk_out <= LOW; 
        							lcd_data_out <= data_reg[2]; 
        							end
        							6'd12:	begin lcd_clk_out <= HIGH; 
        							end
        							6'd13:	begin lcd_clk_out <= LOW; 
        							lcd_data_out <= data_reg[1]; 
        							end
        							6'd14:	begin lcd_clk_out <= HIGH; 
        							end
        							6'd15:	begin lcd_clk_out <= LOW; 
        							lcd_data_out <= data_reg[0]; 
        							end	//后發(fā)低位數(shù)據(jù)
        							6'd16:	begin lcd_clk_out <= HIGH; 
        							end
        							6'd17:	begin lcd_clk_out <= LOW; 
        							state <= DELAY; 
        							end	//
        							default: state <= IDLE;
        						endcase
        					end
        				DELAY:begin	//延時(shí)狀態(tài)
        						if(cnt_delay >= num_delay) begin
        							cnt_delay <= 16'd0;
        							state <= state_back; 
        						end else cnt_delay <= cnt_delay + 1'b1;
        					end
        				default:state <= IDLE;
        			endcase
        		end
        	end 	// data for setxy
        	initial	//設(shè)定顯示區(qū)域指令及數(shù)據(jù)
        		begin
        			reg_setxy[0]	=	{1'b0,8'h2a};
        			reg_setxy[1]	=	{1'b1,8'h00};
        			reg_setxy[2]	=	{1'b1,8'h00};
        			reg_setxy[3]	=	{1'b1,8'h00};
        			reg_setxy[4]	=	{1'b1,LCD_W-1};
        			reg_setxy[5]	=	{1'b0,8'h2b};
        			reg_setxy[6]	=	{1'b1,8'h00};
        			reg_setxy[7]	=	{1'b1,8'h00};
        			reg_setxy[8]	=	{1'b1,8'h00};
        			reg_setxy[9]	=	{1'b1,LCD_H-1};
        			reg_setxy[10]	=	{1'b0,8'h2c};
        		end 	// data for init
        	initial	//LCD初始化的命令及數(shù)據(jù)
        		begin
        			reg_init[0]		=	{1'b0,8'h11}; 
        			reg_init[1]		=	{1'b0,8'hb1}; 
        			reg_init[2]		=	{1'b1,8'h05}; 
        			reg_init[3]		=	{1'b1,8'h3c}; 
        			reg_init[4]		=	{1'b1,8'h3c}; 
        			reg_init[5]		=	{1'b0,8'hb2}; 
        			reg_init[6]		=	{1'b1,8'h05}; 
        			reg_init[7]		=	{1'b1,8'h3c}; 
        			reg_init[8]		=	{1'b1,8'h3c}; 
        			reg_init[9]		=	{1'b0,8'hb3}; 
        			reg_init[10]	=	{1'b1,8'h05}; 
        			reg_init[11]	=	{1'b1,8'h3c}; 
        			reg_init[12]	=	{1'b1,8'h3c}; 
        			reg_init[13]	=	{1'b1,8'h05}; 
        			reg_init[14]	=	{1'b1,8'h3c}; 
        			reg_init[15]	=	{1'b1,8'h3c}; 
        			reg_init[16]	=	{1'b0,8'hb4}; 
        			reg_init[17]	=	{1'b1,8'h03}; 
        			reg_init[18]	=	{1'b0,8'hc0}; 
        			reg_init[19]	=	{1'b1,8'h28}; 
        			reg_init[20]	=	{1'b1,8'h08}; 
        			reg_init[21]	=	{1'b1,8'h04}; 
        			reg_init[22]	=	{1'b0,8'hc1}; 
        			reg_init[23]	=	{1'b1,8'hc0}; 
        			reg_init[24]	=	{1'b0,8'hc2}; 
        			reg_init[25]	=	{1'b1,8'h0d}; 
        			reg_init[26]	=	{1'b1,8'h00}; 
        			reg_init[27]	=	{1'b0,8'hc3}; 
        			reg_init[28]	=	{1'b1,8'h8d}; 
        			reg_init[29]	=	{1'b1,8'h2a}; 
        			reg_init[30]	=	{1'b0,8'hc4}; 
        			reg_init[31]	=	{1'b1,8'h8d}; 
        			reg_init[32]	=	{1'b1,8'hee}; 
        			reg_init[32]	=	{1'b0,8'hc5}; 
        			reg_init[33]	=	{1'b1,8'h1a}; 
        			reg_init[34]	=	{1'b0,8'h36}; 
        			reg_init[35]	=	{1'b1,8'hc0}; 
        			reg_init[36]	=	{1'b0,8'he0}; 
        			reg_init[37]	=	{1'b1,8'h04}; 
        			reg_init[38]	=	{1'b1,8'h22}; 
        			reg_init[39]	=	{1'b1,8'h07}; 
        			reg_init[40]	=	{1'b1,8'h0a}; 
        			reg_init[41]	=	{1'b1,8'h2e}; 
        			reg_init[42]	=	{1'b1,8'h30}; 
        			reg_init[43]	=	{1'b1,8'h25}; 
        			reg_init[44]	=	{1'b1,8'h2a}; 
        			reg_init[45]	=	{1'b1,8'h28}; 
        			reg_init[46]	=	{1'b1,8'h26}; 
        			reg_init[47]	=	{1'b1,8'h2e}; 
        			reg_init[48]	=	{1'b1,8'h3a}; 
        			reg_init[49]	=	{1'b1,8'h00}; 
        			reg_init[50]	=	{1'b1,8'h01}; 
        			reg_init[51]	=	{1'b1,8'h03}; 
        			reg_init[52]	=	{1'b1,8'h13}; 
        			reg_init[53]	=	{1'b0,8'he1}; 
        			reg_init[54]	=	{1'b1,8'h04}; 
        			reg_init[55]	=	{1'b1,8'h16}; 
        			reg_init[56]	=	{1'b1,8'h06}; 
        			reg_init[57]	=	{1'b1,8'h0d}; 
        			reg_init[58]	=	{1'b1,8'h2d}; 
        			reg_init[59]	=	{1'b1,8'h26}; 
        			reg_init[60]	=	{1'b1,8'h23}; 
        			reg_init[61]	=	{1'b1,8'h27}; 
        			reg_init[62]	=	{1'b1,8'h27}; 
        			reg_init[63]	=	{1'b1,8'h25}; 
        			reg_init[64]	=	{1'b1,8'h2d}; 
        			reg_init[65]	=	{1'b1,8'h3b}; 
        			reg_init[66]	=	{1'b1,8'h00}; 
        			reg_init[67]	=	{1'b1,8'h01}; 
        			reg_init[68]	=	{1'b1,8'h04}; 
        			reg_init[69]	=	{1'b1,8'h13}; 
        			reg_init[70]	=	{1'b0,8'h3a}; 
        			reg_init[71]	=	{1'b1,8'h05}; 
        			reg_init[72]	=	{1'b0,8'h29};  		
        			end	
        			endmodule

        小結(jié)

        本節(jié)主要為大家講解了1.8寸RGB液晶屏圖片顯示的框架,需要大家掌握的同時(shí)自己創(chuàng)建工程,通過(guò)整個(gè)設(shè)計(jì)流程,生成FPGA配置文件加載測(cè)試。



        評(píng)論


        相關(guān)推薦

        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 竹北市| 万载县| 新营市| 房产| 运城市| 尉犁县| 上蔡县| 沙雅县| 晋城| 安阳县| 年辖:市辖区| 子长县| 奇台县| 巩留县| 石景山区| 包头市| 奉贤区| 卓资县| 满洲里市| 北辰区| 英吉沙县| 满城县| 横山县| 琼海市| 松阳县| 观塘区| 龙州县| 肥西县| 绿春县| 平舆县| 通渭县| 云霄县| 仁布县| 淮北市| 大邑县| 永登县| 静海县| 太谷县| 齐河县| 澄迈县| 双柏县|