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
- 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:
-
Initialize the video storage area, loop through
VIDEO_LENGTH
times, and write 0 each time to the address offset by i*4 bytes ofVIDEO_BASEADDR0
. The purpose of this operation is to clear the video storage area. -
Refresh the data cache and write the modified data back to the memory by calling the
Xil_DCacheFlush()
function. -
Configure VDMA control register:
0x000
register, set to 0x3, means enabling the VDMA controller and enabling direct transfer mode.- The
0x05c
register is set toVIDEO_BASEADDR0
, indicating that the transmission destination address is the starting address of the video storage area. - The
0x060
register is also set toVIDEO_BASEADDR0
, indicating that the transmission source address is the starting address of the video storage area. - The
0x064
register is also set toVIDEO_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 toH_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 toH_ACTIVE*4
, which means setting the number of active pixels in the horizontal row. 0x050
register, set toV_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