FPGA realizes reading and writing photos from SD card and displaying them on HDMI display (IP call)

Overview: TF card reads and writes data, uses VDMA and HDMI to display video images, and reads pictures from the SD card and displays them on the HDMI display.

Step 1: Configure IP on PL side

  1. SD card configuration

Make sure the SDIO interface is set correctly and SD_0 is the TF card

Configure the SD card in ZYNQ’s IP core. SD0 is the TF card and SD1 is the EMMC.

2.VDMA configuration

Find the official IP:

·VTC IP: This IP is a timing generator that generates the timing signals required for display output.

Enable Generation: Supports generation timing.

Enable Detection: Supports timing capture. This is not necessary. It depends on the needs. With this option, you can capture the input timing first, and then set the output timing to achieve consistent input and output effects.

·PLL clock IP: The setting principle of PLL depends on the size of the resolution. Calculate the required pixel clock size based on the resolution-related configuration parameters in the VTC. The calculation method is: (row Frame size) x (column Frame size) x (refresh frequency).

·VIDEO OUT output IP:

Pixels Per Clock: Set the number of pixels output by each clock, which can be 1, 2, or 4

Input Component Width The width of the input pixel. This parameter affects the bit width of TDATA.

Output Component Width The width of the output pixels

Clock Mode clock mode, you can choose independent clock or shared clock

Video Format video format

FIFO Depth FIFO depth

Hysteresis Level hysteresis output

·VDMA IP configuration:

VDMA is an IP from Xilinx that is used to convert data streams in AXI Stream format into Memory Map format or convert data in Memory Map format into AXI Stream data streams to achieve communication with DDR3. Among them, MM2S and S2MM are the read channel and write channel of the IP respectively.

·HDMI IP:

Just add it directly

The final complete block diagram:

Step 2: Write software code on PS side

void VDMA_init()
{
int i;
for(i=0;i<VIDEO_LENGTH;i + + )
{
Xil_Out32(VIDEO_BASEADDR0 + i*4,0);
}
Xil_DCacheFlush();
Xil_Out32((VDMA_BASEADDR + 0x000), 0x3);
Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0);
Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR0);
Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR0);
Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*4));
Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*4));
Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE);

}

Initialize the VDMA (Video Direct Memory Access) controller. The main function is to set a series of registers to control video transmission.

specific process:

  1. Initialize the video storage area, loop through VIDEO_LENGTH times, and write 0 each time to the address offset by i*4 bytes of VIDEO_BASEADDR0. The purpose of this operation is to clear the video storage area.

  2. Refresh the data cache and write the modified data back to the memory by calling the Xil_DCacheFlush() function.

  3. Configure VDMA control register:

    • 0x000 register, set to 0x3, means enabling the VDMA controller and enabling direct transfer mode.
    • The 0x05c register is set to VIDEO_BASEADDR0, indicating that the transmission destination address is the starting address of the video storage area.
    • The 0x060 register is also set to VIDEO_BASEADDR0, indicating that the transmission source address is the starting address of the video storage area.
    • The 0x064 register is also set to VIDEO_BASEADDR0, indicating that the write-back address after the transmission behavior is the starting address of the video storage area.
    • The 0x058 register is set to H_STRIDE*4, which means setting the step size of the horizontal line. Multiply by 4 because each pixel occupies 4 bytes.
    • The 0x054 register is set to H_ACTIVE*4, which means setting the number of active pixels in the horizontal row.
    • 0x050 register, set to V_ACTIVE, means setting the active number of vertical rows.

Through the above configuration, the initialization of the VDMA controller is completed, and the video transmission operation can be started.

int SD_init()
{
FRESULT result;
//-----------------------mount dev----------------------- --------------------------
result = f_mount( & amp;SD_Dev,SD_Path, 0);
if (result != 0) {
return XST_FAILURE;
}
return XST_SUCCESS;
}

SD card initialization. The program is loaded into the file that reads the SD card.
int main()
{

VDMA_init();
SD_init();
BMP_Picture((u8 *)"1.bmp" , RD_Buf1 ,BUF_SIZE);
BMP_Picture((u8 *)"2.bmp" , RD_Buf2 ,BUF_SIZE);
//BMP_Picture((u8 *)"3.bmp" , RD_Buf3 ,BUF_SIZE);
//BMP_Picture((u8 *)"4.bmp" , RD_Buf4 ,BUF_SIZE);

while(1)
{
show_img(RD_Buf1,1280,720);
sleep(2);
show_img(RD_Buf2,1280,720);
sleep(2);
//show_img(RD_Buf3,1280,720);
//sleep(5);
//show_img(RD_Buf4,1280,720);
//sleep(5);
}

    return 0;
}

main function In this function, the pictures in the SD card are read. 1.bmp is the name of the picture, which is saved in 24bit. Displayed on the monitor, the size of the test picture is 1280*720P and the picture format is BMP format.

Bmp function:

#include "bmp.h"
#include "ff.h"



void BMP_ReadHeader(uint8_t *header, BMP_HeaderTypeDef *bmp)
{

bmp->fileHeader.bfType = ((*header) << 8) | (*(header + 1));
header + = 2;
\t
bmp->fileHeader.bfSize = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
((*(header + 1)) << 8) | (*header);
header + = 8;

bmp->fileHeader.bfOffBits = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
((*(header + 1)) << 8) | (*header);
header + = 4;

bmp->infoHeader.bitSize = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
((*(header + 1)) << 8) | (*header);
header + = 4;

bmp->infoHeader.biWidth = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
((*(header + 1)) << 8) | (*header);
header + = 4;

bmp->infoHeader.biHeight = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
((*(header + 1)) << 8) | (*header);
header + = 6;

bmp->infoHeader.biBitCount = ((*(header + 1)) << 8) | (*header);
\t                         
header + = 2;

bmp->infoHeader.biCompression = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
((*(header + 1)) << 8) | (*header);
header + = 4;

bmp->infoHeader.biSizeImage = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
((*(header + 1)) << 8) | (*header);
header + = 4;

bmp->infoHeader.biXPelsPerMeter = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
((*(header + 1)) << 8) | (*header);
header + = 4;

bmp->infoHeader.biYPelsPerMeter = ((*(header + 3)) << 24) | ((*(header + 2)) << 16) |
((*(header + 1)) << 8) | (*header);
}
void BMP_Picture(uint8_t *dir , uint8_t * buf ,uint32_t len)
{
FRESULT res;
FIL fsrc;
UINT br;
UINT a;

uint8_t buffer[1024];

BMP_HeaderTypeDef bmpHeader;
\t\t
/* Open the file to be read */
res = f_open( & amp;fsrc, (const TCHAR*)dir, FA_READ);

if(res == FR_OK) //Open successfully
{
/* Read the file information of the BMP file */
res = f_read( & amp;fsrc, buffer, sizeof(buffer), & amp;br);

/* Put the data in the array into the structure array and sort it */
BMP_ReadHeader(buffer, & amp;bmpHeader);

a = bmpHeader.fileHeader.bfOffBits; //Remove the file information and start with pixel data

res=f_lseek( & amp;fsrc, a);
if(res)
{
return 0;
}
res = f_read( & amp;fsrc, buf, len, & amp;br);
}
    f_close( & amp;fsrc);
}

The important thing in the Bmp.c function is to parse the header of the BMP image format and obtain the starting position of the image data, and then use the f_lseek(&fsrc, a) function to locate the position of the image data, and then read it out image data.

typedef struct
{
uint16_t bfType; //File type, BMP format is string BM
uint32_t bfSize; //Picture size in KB
uint16_t bfReserved1; //Reserved bits
uint16_t bfReserved2; //Reserved bits
uint32_t bfOffBits; //Byte offset from file header to actual image data
} BMP_FileHeaderTypeDef;
typedef struct
{
uint32_t bitSize; //The number of bytes required by the BMP_InfoHeaderTypeDef structure
uint32_t biWidth; //Picture width, pixel unit
int32_t biHeight; //Picture height in pixels. Positive is inverted, negative is forward.
uint16_t biPlanes; //Number of color planes, total 1
uint16_t biBitCount; //Number of bits/pixels. Its value is: 1, 4, 8, 16, 24 or 32
uint32_t biCompression; //Data compression type
uint32_t biSizeImage; //Image size
uint32_t biXPelsPerMeter; //Horizontal resolution
uint32_t biYPelsPerMeter;//vertical resolution
uint32_t biClrUsed; //Color index number
uint32_t biClrImportant; //Number of important color indexes
}BMP_InfoHeaderTypeDef

The structure function converts the read array function into the BPM file information structure type. Since the storage method of arrays in memory is different from that of structures, conversion is required, and the file information read by SD is in little-endian mode. The high bit is the low byte, the low bit is the high byte