新手上路
- 积分
- 21
- 金钱
- 21
- 注册时间
- 2025-12-1
- 在线时间
- 2 小时
|
第23讲的扩展训练,老师是用sleep(1)延时来实现每秒切换显示一章图片,我这里使用的是定时器中断的方法来实现切换图片,功能一样,给大家提供一些参考,vivado工程Block design我以图片的形式发出来,我没有定义IP核,直接导入的RTL代码
#include "xparameters.h"
#include "xaxivdma.h"
#include "vdma_api/vdma_api.h"
#include "xil_cache.h"
#include "stdio.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "xscutimer.h"
#include <ff.h>
#define VDMA_ID XPAR_AXI_VDMA_0_DEVICE_ID
#define BYTES_PIXEL 3
#define LCD_WIDTH 800
#define LCD_HEIGHT 480
#define file_name1 "0:hajimi.bmp"
#define file_name2 "0:manout.bmp"
//定时器
#define TIMER_ID XPAR_XSCUTIMER_0_DEVICE_ID
#define TIMER_INTR_ID XPAR_SCUTIMER_INTR
#define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID //GIC ID
TCHAR* Path = "0:";
unsigned int Frame_buffer_addr1 = (XPAR_PS7_DDR_0_S_AXI_BASEADDR + 0x01000000);
unsigned int Frame_buffer_addr2 = (XPAR_PS7_DDR_0_S_AXI_BASEADDR + 0x02000000);
XAxiVdma vdma;
XScuTimer Timer; //定时器结构体
XScuGic Intc;
void load_sd_bmp(u8* frame_buffer_addr,char *filename);
void Intr_init(XScuGic *Intc,XScuTimer *Timer);
void timer_init(XScuTimer *Timer);
void Timer_handler(void *CallbackRef);
volatile u8 Picture_flag = 0;
int main()
{
FATFS Fatfs; //FATFS驱动的结构体指针
FRESULT res;
u8 last_flag = 0xff;
//硬件初始化
//必须先使用timer_init,因为内部有XScuTimer_CfgInitialize会把已经配置好的定时器寄存器重置
timer_init(&Timer);
Intr_init(&Intc,&Timer);
//挂载SD卡
res = f_mount(&Fatfs,Path,1);
if(res != FR_OK){
xil_printf("SD Card mount failed! (res:%d)\r\n", res);
}
//加载数据
load_sd_bmp((u8*) Frame_buffer_addr1,file_name1);
load_sd_bmp((u8*) Frame_buffer_addr2,file_name2);
while(1)
{
if(Picture_flag != last_flag){
//写数据到DDR
if(Picture_flag == 0)
{
run_triple_frame_buffer(&vdma,VDMA_ID,LCD_WIDTH,LCD_HEIGHT,
Frame_buffer_addr1,0,0,ONLY_READ);
xil_printf("show hajimi bmp\r\n");
}
else if(Picture_flag == 1)
{
run_triple_frame_buffer(&vdma,VDMA_ID,LCD_WIDTH,LCD_HEIGHT,
Frame_buffer_addr2,0,0,ONLY_READ);
xil_printf("show laoda bmp\r\n");
}
last_flag = Picture_flag;
//xil_printf("Picture_flag = %d \r\n", Picture_flag);
}
}
return 0;
}
void load_sd_bmp(u8* frame_buffer_addr,char *filename)
{
int i;
UINT br;
u8 bmp_read[54];
UINT *bmp_width,*bmp_height;
// FATFS Fatfs; //FATFS驱动的结构体指针
FIL Fil; //File object 结构体指针
// //挂载SD卡
// f_mount(&Fatfs,Path,1);
//打开bmp文件
f_open(&Fil, filename ,FA_READ);
//选择从文件的开头进行读取
f_lseek (&Fil,0);
//读取文件的信息头和文件头
f_read (&Fil, bmp_read, 54, &br);
//获取文件的宽和高
bmp_width = (UINT *) (bmp_read + 0x12);
bmp_height = (UINT *) (bmp_read + 0x16);
//打印出文件分辨率
// xil_printf("file width : %d ,file height : %d",*bmp_width,*bmp_height);
//由于BMP的图片数据存储是(从左往右,从下往上)
//更改为从左往右,从上往下
int row_size = (*bmp_width) * BYTES_PIXEL;
for(i = *bmp_height - 1; i>=0 ; i--)
{
f_read (&Fil, frame_buffer_addr + ( i * (*bmp_width) * BYTES_PIXEL), row_size, &br);
Xil_DCacheFlush();//把cache里面的数据更新到DDR
}
//关闭文件
f_close (&Fil);
//Xil_DCacheFlushRange(frame_buffer_addr, WIDTH * BYTES_PIXEL * HEIGHT);
}
void Intr_init(XScuGic *Intc,XScuTimer *Timer)
{
XScuGic_Config *IntcConfig; //GUI配置信息的驱动实例
//初始化GIC(中断控制器)
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); //内部函数就是一个大型的表格,去对应参数
XScuGic_CfgInitialize(Intc, IntcConfig,IntcConfig->CpuBaseAddress);
//注册异常
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
Intc);
//连接 Timer 中断
XScuGic_Connect(Intc, TIMER_INTR_ID,
(Xil_ExceptionHandler)Timer_handler,
(void *)Timer);
//使能中断
XScuGic_Enable(Intc, TIMER_INTR_ID);
//此条中断使能为Timer专属,不使能定时器不工作
XScuTimer_EnableInterrupt(Timer);
XScuGic_SetPriorityTriggerType(Intc, TIMER_INTR_ID, 0xA0, 0x3);
Xil_ExceptionEnable();
}
void timer_init(XScuTimer *Timer)
{
XScuTimer_Config *Timer_Cfg;
Timer_Cfg = XScuTimer_LookupConfig(TIMER_ID);
XScuTimer_CfgInitialize(Timer,Timer_Cfg,Timer_Cfg->BaseAddr);
XScuTimer_EnableAutoReload(Timer);
//定时一秒,CPU频率为666.666666MHZ,私有定时器为其一半
XScuTimer_LoadTimer(Timer, 999999999);
XScuTimer_Start(Timer);
}
void Timer_handler(void *CallbackRef)
{
XScuTimer *Timer = (XScuTimer *)CallbackRef;
XScuTimer_ClearInterruptStatus(Timer);
//更改图片标志位
Picture_flag = Picture_flag ^ 1;
}
//后面为RTL模块代码,主要是我不需要适配多个LCD屏幕,只需要转一下位宽,所以写了RTL代码
module rgb888_rgb565
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [23:0] rgb888_data,
input wire video_de ,
input wire video_hsync,
input wire video_vsync,
output reg [15:0] rgb565_data,
output reg LCD_DE ,
output reg H_SYNC ,
output reg V_SYNC ,
output wire LCD_BL ,
output wire LCD_RST ,
output wire LCD_CLK
);
assign LCD_BL = 1'b1;
assign LCD_RST = sys_rst_n;
assign LCD_CLK = sys_clk;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)begin
rgb565_data <= 16'b0;
LCD_DE <= 1'b0;
H_SYNC <= 1'b0;
V_SYNC <= 1'b0;
end
else begin
rgb565_data <= {rgb888_data[23:19],rgb888_data[15:10],rgb888_data[7:3]};
LCD_DE <= video_de;
H_SYNC <= video_hsync;
V_SYNC <= video_vsync;
end
endmodule
|
-
|