文章目錄
- 1 實驗任務
- 2 系統框圖
- 3 硬件設計
- 4 軟件設計
1 實驗任務
本實驗任務是PS端寫彩條數據至DDR3內存中,然后通過PL端的VDMA IP核將彩條數據通過HDMI接口輸出顯示。
2 系統框圖
本實驗是用HDMI接口固定輸出1080P的彩條圖,所以:
- rgb2lcd模塊實際是rgb2dvi模塊
- AXI GPIO不存在,因為不需要讀取LCD屏幕的ID
- 動態時鐘配置改為PLL,輸出固定頻率,與AXI-Interconnect不連
- VTC輸出固定時序,與AXI-Interconnect不連
3 硬件設計
注意事項:
- VTC的clken引腳
- 該引腳不連接,VTC也能正常工作
- pg016中描述該引腳是"Video Core active-High Clock Enable",即高有效
- 在Block Design中添加VTC后,clken引腳前邊有個小圓圈,且雙擊該引腳,Polarity參數顯示為ACTIVE_LOW,即低有效
- 將該引腳接常量1,視頻輸出正常
- 將該引腳接常量0,視頻無法輸出,VTC未工作
- 結論:以文檔為準,clken高電平有效
- rgb2dvi模塊
- 使用正點原子的rgb2dvi模塊,數據的3個字節是G在中間,R和B在兩頭
- 使用Digilent的rgb2dvi模塊,數據的3個字節是B在中間,R和G在兩頭(調試時一臉懵逼)
4 軟件設計
注意事項:
- PS往DDR3寫入數據后,要使用Xil_DCacheFlushRange刷新;
- run_triple_frame_buffer函數并非只能用于三幀緩存的情況,實際1-32幀緩存均可使用該函數(取名triple可能和VDMA模式使用三幀緩存有關);ReadSetup函數和WriteSetup函數會根據VDMA配置時選擇的Frame Buffers數量設置相應數量的幀緩沖區起始地址;本實驗選擇Frame Buffers數量=1,PS端只往DDR3中寫入一幀彩條圖;
- XAxiVdma_DmaStop函數往VDMACR寄存器的bit0寫0(Run / Stop controls the running and stopping of the VDMA channel. ),當前VDMA操作完成后停止(0 = Stop – VDMA stops when current (if any) VDMA operations are complete)
/***************************** Include Files *********************************/
#include "stdio.h"
#include "xparameters.h"
#include "xstatus.h"
#include "xaxivdma.h"
#include "vdma_api.h"
#include "xil_cache.h"
#include "xuartps.h"
#include "sleep.h"
/************************** Constant Definitions *****************************/
#define VDMA_DEVICE_ID XPAR_AXIVDMA_0_DEVICE_ID
#define IMAGE_WIDTH 1920
#define IMAGE_HEIGHT 1080
#define MEMORY_BASEADDR XPAR_PS7_DDR_0_S_AXI_BASEADDR#define UART_DEVICE_ID XPAR_XUARTPS_0_DEVICE_ID
#define UART_BASEADDR XPAR_XUARTPS_0_BASEADDR
/**************************** Type Definitions *******************************//***************** Macros (Inline Functions) Definitions *********************//************************** Function Prototypes ******************************/
s32 UartPsInit(XUartPs *UartPsInstPtr, XUartPsFormat* UartFormatPtr);void GenPureColor(u8* DestAddr, u32 ImageWidth, u32 ImageHeight);
void GenColorBar(u8* DestAddr, u32 ImageWidth, u32 ImageHeight);
/************************** Variable Definitions *****************************/
XAxiVdma VdmaInst;
XUartPs UartInst;int FrameBufferAddr = (MEMORY_BASEADDR + 0x02000000);XUartPsFormat UartFormat = {XUARTPS_DFT_BAUDRATE, // 115200XUARTPS_FORMAT_8_BITS,XUARTPS_FORMAT_NO_PARITY,XUARTPS_FORMAT_1_STOP_BIT
};
/*****************************************************************************/int main()
{//int Status;u8* VdmaBufferAddr = (u8*)FrameBufferAddr;char cmd;// 串口初始化Status = UartPsInit(&UartInst, &UartFormat);if (Status != XST_SUCCESS) {printf("UART Initialization Failed.\n");return XST_FAILURE;}// 寫入純色圖(用于確定RGB的字節位置)
// GenPureColor(VdmaBufferAddr, (u32)IMAGE_WIDTH, (u32)IMAGE_HEIGHT);// 寫入彩條圖GenColorBar(VdmaBufferAddr, (u32)IMAGE_WIDTH, (u32)IMAGE_HEIGHT);//Status = run_triple_frame_buffer(&VdmaInst, VDMA_DEVICE_ID, IMAGE_WIDTH, IMAGE_HEIGHT, FrameBufferAddr, 0, 0);if (Status == XST_FAILURE) {printf("VDMA Run Failed.\n");}//printf("VDMA Control Ready (s=start, q=stop):\n");while (1) {if (XUartPs_IsReceiveData(UART_BASEADDR)) {cmd = XUartPs_ReadReg(UART_BASEADDR, XUARTPS_FIFO_OFFSET);if (cmd == 's') { // 啟動VDMAif (XAxiVdma_DmaStart(&VdmaInst, XAXIVDMA_READ) == XST_SUCCESS) {printf("VDMA Start Succeeded.\n");} else {printf("VDMA Start Failed.\n");}}else if (cmd == 'q') { // 停止VDMAXAxiVdma_DmaStop(&VdmaInst, XAXIVDMA_READ);printf("VDMA Stop Succeeded.\n");}}usleep(10000); // 降低CPU占用}//return 0;
}
/*****************************************************************************/
s32 UartPsInit(XUartPs *UartInstPtr, XUartPsFormat* UartFormatPtr)
{//s32 Status;XUartPs_Config *UartConfigPtr;// 查找UART配置UartConfigPtr = XUartPs_LookupConfig(UART_DEVICE_ID);if(NULL == UartConfigPtr){return XST_FAILURE;}// 初始化UARTStatus = XUartPs_CfgInitialize(UartInstPtr, UartConfigPtr, UartConfigPtr->BaseAddress);if (Status != XST_SUCCESS) {return XST_FAILURE;}// 設置UART數據格式XUartPs_SetDataFormat(UartInstPtr, UartFormatPtr);// 設置UART操作模式XUartPs_SetOperMode(UartInstPtr, XUARTPS_OPER_MODE_NORMAL);//return XST_SUCCESS;
}
/*****************************************************************************/
void GenPureColor(u8* DestAddr, u32 ImageWidth, u32 ImageHeight)
{// 禁用緩存(如果目標內存是非緩存區域)Xil_DCacheDisable();for (u32 y = 0; y < ImageHeight; y++) {for (u32 x = 0; x < ImageWidth; x++) {// 計算當前像素的內存位置(3字節/像素)u32 PixelOffset = (y * ImageWidth + x) * 3;u8* PixelAddr = DestAddr + PixelOffset;// 寫入RGB三個字節PixelAddr[0] = 0x00;PixelAddr[1] = 0x00;PixelAddr[2] = 0xff;}}// 如果需要,刷新緩存Xil_DCacheFlushRange((INTPTR)DestAddr, ImageWidth * ImageHeight * 3);//return;
}/*****************************************************************************/
void GenColorBar(u8* DestAddr, u32 ImageWidth, u32 ImageHeight)
{// 定義8種顏色(R, G, B順序)const u8 color_bars[8][3] = {{0x00, 0x00, 0x00}, // 黑{0xff, 0xff, 0xff}, // 白{0xff, 0x00, 0x00}, // 藍{0x00, 0xff, 0x00}, // 綠{0x00, 0x00, 0xff}, // 紅{0xff, 0xff, 0x00}, // 青{0xff, 0x00, 0xff}, // 紫{0x00, 0xff, 0xff} // 黃};// 計算每個色條的寬度u32 BarWidth = ImageWidth / 8;// 禁用緩存(如果目標內存是非緩存區域)Xil_DCacheDisable();for (u32 y = 0; y < ImageHeight; y++) {for (u32 x = 0; x < ImageWidth; x++) {// 計算當前色條索引u32 BarIndex = x / BarWidth;// 計算當前像素的內存位置(3字節/像素)u32 PixelOffset = (y * ImageWidth + x) * 3;u8* PixelAddr = DestAddr + PixelOffset;// 寫入RGB三個字節PixelAddr[0] = color_bars[BarIndex][0];PixelAddr[1] = color_bars[BarIndex][1];PixelAddr[2] = color_bars[BarIndex][2];}}// 如果需要,刷新緩存Xil_DCacheFlushRange((INTPTR)DestAddr, ImageWidth * ImageHeight * 3);//return;
}