手搓8080接口,封装成AXI4‐ip,用zynq驱动(二) - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki

手搓8080接口,封装成AXI4-ip,用zynq驱动(二)

1)用zynq驱动之模块设计

image

8)引脚约束

create_clock -period 20.000 -name sys_clk [get_ports sys_clk]
set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]

# GPIO2 fmc_8080_st7796
set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports {im[2]}]
set_property -dict {PACKAGE_PIN G15 IOSTANDARD LVCMOS33} [get_ports {im[1]}]
set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports {im[0]}]

set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {dout[15]}]
set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS33} [get_ports {dout[14]}]
set_property -dict {PACKAGE_PIN H16 IOSTANDARD LVCMOS33} [get_ports {dout[13]}]
set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports {dout[12]}]
set_property -dict {PACKAGE_PIN B19 IOSTANDARD LVCMOS33} [get_ports {dout[11]}]
set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports {dout[10]}]
set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {dout[9]}]
set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports {dout[8]}]
set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports {dout[7]}]
set_property -dict {PACKAGE_PIN D20 IOSTANDARD LVCMOS33} [get_ports {dout[6]}]
set_property -dict {PACKAGE_PIN J18 IOSTANDARD LVCMOS33} [get_ports {dout[5]}]
set_property -dict {PACKAGE_PIN H18 IOSTANDARD LVCMOS33} [get_ports {dout[4]}]
set_property -dict {PACKAGE_PIN F19 IOSTANDARD LVCMOS33} [get_ports {dout[3]}]
set_property -dict {PACKAGE_PIN F20 IOSTANDARD LVCMOS33} [get_ports {dout[2]}]
set_property -dict {PACKAGE_PIN G19 IOSTANDARD LVCMOS33} [get_ports {dout[1]}]
set_property -dict {PACKAGE_PIN G20 IOSTANDARD LVCMOS33} [get_ports {dout[0]}]

set_property -dict {PACKAGE_PIN H20 IOSTANDARD LVCMOS33} [get_ports rst_o]
set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports miso]
set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS33} [get_ports mosi]
set_property -dict {PACKAGE_PIN K19 IOSTANDARD LVCMOS33} [get_ports rdx]
set_property -dict {PACKAGE_PIN J19 IOSTANDARD LVCMOS33} [get_ports wrx]
set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS33} [get_ports dcx]
set_property -dict {PACKAGE_PIN L17 IOSTANDARD LVCMOS33} [get_ports csx]

2)c代码

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xil_io.h"
#include "sleep.h"

#define FMC16_BASE XPAR_MY_FMC16_IP_0_S00_AXI_BASEADDR

#define  RED        0xF800
#define  ORANGE     0xFC00
#define  YELLOW     0xFFE0
#define  GREEN      0x07E0
#define  CYAN       0x07FF
#define  BLUE       0x001F
#define  PURPPLE    0xF81F
#define  BLACK      0x0000
#define  WHITE      0xFFFF
#define  GRAY       0xD69A

const u16 colors[] = {
	RED,
	GREEN,
	BLUE,
	ORANGE,
	YELLOW,
	CYAN,
	PURPPLE,
	BLACK,
	WHITE,
	GRAY
};


void xfer_data(u16 data){
    Xil_Out32(FMC16_BASE+0x4, data);
    Xil_Out32(FMC16_BASE+0x0, 0x01);

    while(Xil_In32(FMC16_BASE+0xc)==0x0);
    Xil_Out32(FMC16_BASE+0xc, 0x00);
}

void xfer_cmd_pdata(u8 cmd, u16* pdata, u32 length){
    Xil_Out32(FMC16_BASE+0x8, length);
    xfer_data(cmd);

    while(length--){
    	xfer_data(*pdata++);
    }
}

void xfer_cmd_cdata(u8 cmd, u16 data, u32 length){
    Xil_Out32(FMC16_BASE+0x8, length);
    xfer_data(cmd);

    while(length--){
    	xfer_data(data);
    }
}

void xfer_cmd(u8 cmd){
	xfer_cmd_pdata(cmd,NULL,0);
}

void xfer_win(u16 xstart, u16 ystart, u16 width, u16 height)
{
    u16 cmd_list[2][5]={
    		{0x2a, xstart>>8, xstart&0xff, (xstart+width-1)>>8, (xstart+width-1)&0xff},
    		{0x2b, ystart>>8, ystart&0xff, (ystart+height-1)>>8, (ystart+height-1)&0xff},
    };

    xfer_cmd_pdata(cmd_list[0][0], (u16*)&(cmd_list[0][1]),4);
    xfer_cmd_pdata(cmd_list[1][0], (u16*)&(cmd_list[1][1]),4);
}

void xfer_color(u16 color, u16 width, u16 height){
	u32 length=width*height;
	xfer_cmd_cdata(0x2C, color, length);
}

int main()
{
    init_platform();

    print("Hello World\n\r");

    u16 cmd_list[][2]={
    		{0x11,0x00},
			{0x29,0x00},
    		{0x36,0x48},
			{0x3a,0x05}
    };

    xfer_cmd_pdata(cmd_list[0][0], NULL, 0);
    xfer_cmd_pdata(cmd_list[1][0], NULL, 0);
    usleep(120*1000);
    xfer_cmd_pdata(cmd_list[2][0], (u16*)&(cmd_list[2][1]), 1);
    xfer_cmd_pdata(cmd_list[3][0], (u16*)&(cmd_list[3][1]), 1);

    while(1){
		for(int i=0; i<sizeof(colors)/sizeof(*colors); i++){
			xfer_win(0,0,320,480);
			xfer_color(colors[i],320,480);
			sleep(1);
		}
    }

    cleanup_platform();
    return 0;
}

10)效果

image

11) mark_debug波形

image image

从xfer_end到下一次xfer_start之间,需要63个cycles。还是非常慢的。它其实经历了多次读写过程:轮询读0xc,清零0xc,写数据0x4,写启动0x0。每次写寄存器都需要10几个cycles,这么多条指令执行,确实需要这么多cycles。

12) 增加fats,从sd卡读取bmp图片并显示

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xil_io.h"
#include "sleep.h"
#include "ff.h"
#include "xil_cache.h"
#include "xtime_l.h"

#define FMC16_BASE XPAR_MY_FMC16_IP_0_S00_AXI_BASEADDR

#define  RED        0xF800
#define  ORANGE     0xFC00
#define  YELLOW     0xFFE0
#define  GREEN      0x07E0
#define  CYAN       0x07FF
#define  BLUE       0x001F
#define  PURPPLE    0xF81F
#define  BLACK      0x0000
#define  WHITE      0xFFFF
#define  GRAY       0xD69A

const u16 colors[] = {
	RED,
	GREEN,
	BLUE,
	ORANGE,
	YELLOW,
	CYAN,
	PURPPLE,
	BLACK,
	WHITE,
	GRAY
};

/*************************************************
 * basic xfer functions
 ************************************************/
void xfer_data(u16 data){
    Xil_Out32(FMC16_BASE+0x4, data);
    Xil_Out32(FMC16_BASE+0x0, 0x01);

    while(Xil_In32(FMC16_BASE+0xc)==0x0);
    Xil_Out32(FMC16_BASE+0xc, 0x00);
}

void xfer_cmd_pdata(u8 cmd, u16* pdata, u32 length){
    Xil_Out32(FMC16_BASE+0x8, length);
    xfer_data(cmd);

    while(length--){
    	xfer_data(*pdata++);
    }
}

void xfer_cmd_cdata(u8 cmd, u16 data, u32 length){
    Xil_Out32(FMC16_BASE+0x8, length);
    xfer_data(cmd);

    while(length--){
    	xfer_data(data);
    }
}

void xfer_cmd(u8 cmd){
	xfer_cmd_pdata(cmd,NULL,0);
}

/*************************************************
 * xfer_color functions
 ************************************************/
void xfer_win(u16 xstart, u16 ystart, u16 width, u16 height)
{
    u16 cmd_list[2][5]={
    		{0x2a, xstart>>8, xstart&0xff, (xstart+width-1)>>8, (xstart+width-1)&0xff},
    		{0x2b, ystart>>8, ystart&0xff, (ystart+height-1)>>8, (ystart+height-1)&0xff},
    };

    xfer_cmd_pdata(cmd_list[0][0], (u16*)&(cmd_list[0][1]),4);
    xfer_cmd_pdata(cmd_list[1][0], (u16*)&(cmd_list[1][1]),4);
}

void xfer_color(u16 color, u16 width, u16 height){
	u32 length=width*height;
	xfer_cmd_cdata(0x2C, color, length);
}

void xfer_pic(u16 *pcolor, u16 width, u16 height){
	u32 length=width*height;
	xfer_cmd_pdata(0x2C, pcolor, length);
}

/*************************************************
 * application functions
 ************************************************/
u8 frame_src[1920*1080*3];
u16 frame_target[320*480];

void load_sd_bmp(u8 *frame, const char *bmp_name);
void convertRGB888toRGB565(
		const uint8_t *input,
		uint16_t *output,
		int inputWidth, int inputHeight,
		int startX, int startY,
		int outputWidth, int outputHeight
		) ;

void dram_eight_colors()
{
	for(int i=0; i<sizeof(colors)/sizeof(*colors); i++){
		xfer_win(0,0,320,480);
		xfer_color(colors[i],320,480);
		sleep(1);
	}
}


void draw_bmp()
{
	load_sd_bmp(frame_src, "aa_320x480.bmp"); //320x480
	convertRGB888toRGB565(
			frame_src,
			frame_target,
			320,480,
			0,0,
			320,480
			);

	xfer_win(0,0,320,480);
	xfer_pic(frame_target,320,480);

	sleep(2);

	load_sd_bmp(frame_src, "bb_320x480.bmp"); //320x480
	convertRGB888toRGB565(
			frame_src,
			frame_target,
			320,480,
			0,0,
			320,480
			);
	xfer_win(0,0,320,480);
	xfer_pic(frame_target,320,480);

	load_sd_bmp(frame_src, "shatan.bmp");	//1920x1080
	convertRGB888toRGB565(
			frame_src,
			frame_target,
			1920,1080,
			0,0,
			320,480
			);
	xfer_win(0,0,320,480);
	xfer_pic(frame_target,320,480);
}

void draw_movie()
{
	load_sd_bmp(frame_src, "shatan.bmp");	//1920x1080
	int x=300,y=400;
	int dir_x=1, dir_y=1;
	while(1){
		if(dir_x) x+=100; else x-=100;
		if(dir_y) y+=50; else y-=50;

		if(x+320>1920) {x=1920-320; dir_x=0;} else if(x<0) {x=0; dir_x=1;}
		if(y+480>1080) {y=1080-480; dir_y=0;} else if(y<0) {y=0; dir_y=1;}
//		xil_printf("x=%d, y=%d\r\n", x,y);

		XTime_SetTime(0);
		XTime t1,t2,t3;
		XTime_GetTime(&t1);
		convertRGB888toRGB565(
				frame_src,
				frame_target,
				1920,1080,
				x,y,
				320,480
				);
		XTime_GetTime(&t2);
		xfer_win(0,0,320,480);
		xfer_pic(frame_target,320,480);
		XTime_GetTime(&t3);

		XTime dt1 = ((t2-t1) * 1000000) / (COUNTS_PER_SECOND);
		XTime dt2 = ((t3-t2) * 1000000) / (COUNTS_PER_SECOND);
		xil_printf("dt1=%d, dt2=%d\r\n", dt1,dt2);
	}
}


int main()
{
    init_platform();

    print("Hello World\n\r");

    u16 cmd_list[][2]={
    		{0x11,0x00},
			{0x29,0x00},
    		{0x36,0x48},
			{0x3a,0x05}
    };

    xfer_cmd_pdata(cmd_list[0][0], NULL, 0);
    xfer_cmd_pdata(cmd_list[1][0], NULL, 0);
    usleep(120*1000);
    xfer_cmd_pdata(cmd_list[2][0], (u16*)&(cmd_list[2][1]), 1);
    xfer_cmd_pdata(cmd_list[3][0], (u16*)&(cmd_list[3][1]), 1);

    //dram_eight_colors();
    draw_bmp();
    draw_movie();

    cleanup_platform();
    return 0;
}

//从SD卡中读取BMP图片
void load_sd_bmp(u8 *frame, const char *bmp_name)
{
	static 	FATFS fatfs;
	FIL 	fil;
	u8		bmp_head[54];
	UINT 	bmp_width,bmp_height,bmp_size;
	UINT 	br;

	f_mount(&fatfs,"",1);//挂载文件系统

	f_open(&fil, bmp_name,FA_READ);	//打开文件, 注意是bmp_24bits格式
	xil_printf("open bmp\n\r");
	f_lseek(&fil,0);//移动文件读写指针到文件开头

	f_read(&fil,bmp_head,54,&br);//读取BMP文件头

	//BMP图片的分辨率和大小
	bmp_width  = *(UINT *)(bmp_head + 0x12);
	bmp_height = *(UINT *)(bmp_head + 0x16);
	bmp_size   = *(UINT *)(bmp_head + 0x22);
	xil_printf("bmp information:\n\r");
	xil_printf(" width  = %d,\n\r height = %d,\n\r size   = %d bytes \n\r",
			bmp_width,bmp_height,bmp_size);

	//读出图片,写入DDR
	f_read(&fil, frame, bmp_width*bmp_height*3,&br);
	xil_printf("br=%d\r\n", br);

	for(int i=0; i<20; i++){
		xil_printf("%x\r\n", frame[i]);
	}

	//关闭文件
	f_close(&fil);

	Xil_DCacheFlush();     //刷新Cache,将数据更新至DDR3中
	xil_printf("display bmp\n\r");
}

void convertRGB888toRGB565(const uint8_t *input, uint16_t *output, int inputWidth, int inputHeight, int startX, int startY, int outputWidth, int outputHeight)
{
    int i, j;

    for (i = 0; i < outputHeight; i++) {
        for (j = 0; j < outputWidth; j++) {
            // Calculate the index in the RGB888 array
            int inputIndex = ((startY + i) * inputWidth + startX + j) * 3;

            // Extract RGB888 components
            uint8_t b = input[inputIndex];
            uint8_t g = input[inputIndex + 1];
            uint8_t r = input[inputIndex + 2];

            // Convert to RGB565 format
            uint16_t rgb565 = ((r>>3) << 11) | ((g>>2) << 5) | (b>>3);

            // Store in the output array
            output[i * outputWidth + j] = rgb565;
        }
    }
}
⚠️ **GitHub.com Fallback** ⚠️