OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 189|回复: 2

[XILINX] ZYNQ&MPSoC系列之嵌入式Vitis软件开发篇(第23讲学习分享)

[复制链接]

2

主题

3

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2025-12-1
在线时间
2 小时
发表于 4 天前 | 显示全部楼层 |阅读模式
第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

屏幕截图 2026-01-26 171719.png
回复

使用道具 举报

4

主题

2167

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
6117
金钱
6117
注册时间
2018-10-21
在线时间
1805 小时
发表于 3 天前 | 显示全部楼层
厉害,感谢分享
回复 支持 反对

使用道具 举报

2

主题

3

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2025-12-1
在线时间
2 小时
 楼主| 发表于 前天 19:55 | 显示全部楼层
QinQZ 发表于 2026-1-27 09:05
厉害,感谢分享

哈哈,老师教的好
回复 支持 反对

使用道具 举报

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

本版积分规则


关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-1-30 15:10

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表