Video Pipeline Example - 1.0 English

AXI4-Stream Video IP and System Design Guide (UG934)

Document ID
UG934
Release Date
2022-11-16
Version
1.0 English

Refer to the video subsystem depicted in This Figure in the following example operations and C code snippets. This video subsystem contains three video pipelines. The three pipelines consist of the following cores:

Pipeline 1:

° Video to AXI4-Stream

° Video IP 1

° AXI VDMA 1 (S2MM Channel)

Pipeline 2:

° AXI VDMA 1 (MM2S Channel)

° Video Processing Subsystem

° AXI VDMA 2 (S2MM Channel)

Pipeline 3:

° AXI VDMA 2 (MM2S Channel)

° Video IP 2

° AXI4-Stream to Video

Figure 2-14: Example Video Subsystem with Three Video Pipelines

X-Ref Target - Figure 2-14

sw_sys1.jpg

To bring up this system in software, the following operations should be performed in the following order:

1. Initialize core drivers (Perform One time only) using the <core>_CfgInitialize() functions.

2. Bring up Pipeline 1 (Input Video Pipeline)

a. SW Reset AXI VDMA 1 (S2MM Channel)

b. SW Reset Video IP 1

c. SW Reset VTC detector

d. Configure AXI VDMA 1 (S2MM Channel)

e. Configure Video IP 1

f. Configure VTC detector

g. Enable AXI VDMA 1 (S2MM Channel)

h. Enable Video IP 1

i. Enable VTC detector

3. Bring up Pipeline 2 (Scaler Pipeline)

a. SW Reset AXI VDMA 2 (S2MM Channel)

b. SW Reset Scaler

c. SW Reset AXI VDMA 1 (MM2S Channel)

d. Configure AXI VDMA 2 (MM2S Channel)

e. Configure Scaler

f. Configure AXI VDMA 1 (MM2S Channel)

g. Enable AXI VDMA 2 (MM2S Channel)

h. Enable Scaler

i. Enable AXI VDMA 1 (MM2S Channel)

4. Bring up Pipeline 3 (Output Video Pipeline)

a. SW Reset VTC generator

b. SW Reset Video IP 2

c. SW Reset AXI VDMA 2 (MM2S Channel)

d. Configure VTC generator

e. Configure Video IP 2

f. Configure AXI VDMA 2 (MM2S Channel)

g. Enable VTC generator

h. Enable Video IP 2

i. Enable AXI VDMA 2 (MM2S Channel)

To reconfigure this system, perform the above operations except step 1 (Initialize core drivers).

Note: VDMA S2MM and MM2S channels should be reset, configured, reconfigured and enabled separately. Each VDMA channel should be treated as individual cores belonging to separate video pipelines. Avoid operating on both channels at the same time. The channel operations should be synchronized to the pipeline to which the channel belongs.

The following C code snippet shows the code needed to bring up the VDMA 1, Scaler, VDMA 2 pipeline:

#include <stdio.h>

#include "platform.h"

#include "xparameters.h"

#include "xscaler.h"

#include "xaxivdma.h"

////////////////////////////////////////////////////////////////////

// Global Defines

////////////////////////////////////////////////////////////////////

#define VIDIN_FBADDR     0x31800000

#define SCALEROUT_FBADDR 0x33000000

#define FRAME_STORE_WIDTH      2048

#define FRAME_STORE_HEIGHT     2048

#define FRAME_STORE_DATA_BYTES 2

#define VDMA_CIRC        1

#define VDMA_NOCIRC      0

#define VDMA_EXT_GENLOCK 0

#define VDMA_INT_GENLOCK 2

#define VDMA_S2MM_FSYNC  8

#define COEFF_SET_INDEX  0

////////////////////////////////////////////////////////////////////

// Function Prototypes

////////////////////////////////////////////////////////////////////

void vdma_init(XAxiVdma *VDMAPtr, int device_id);

int vdma_reset(XAxiVdma *VDMAPtr, int direction);

int vdma_setup(XAxiVdma *VDMAPtr,

int direction,

int width,

int height,

int frame_stores,

int start_address,

int mode

);

void scaler_init(XScaler *ScalerPtr, int device_id);

int scaler_setup(XScaler *ScalerInstPtr,

int ScalerInWidth,

int ScalerInHeight,

int ScalerOutWidth,

int ScalerOutHeight);

////////////////////////////////////////////////////////////////////

// Global Core Driver Structures

////////////////////////////////////////////////////////////////////

XAxiVdma VDMA1;

XAxiVdma VDMA2;

XScaler  Scaler;

XScalerAperture Aperture; /* Aperture setting */

XScalerStartFraction StartFraction; /* Luma/Chroma Start Fraction setting*/

XScalerCoeffBank CoeffBank; /* Coefficient bank */

////////////////////////////////////////////////////////////////////

// Function: configure_scaler_pipeline()

// Configure Scaler Pipeline (Pipeline 2)

////////////////////////////////////////////////////////////////////

int configure_scaler_pipeline(

int input_x,

int input_y,

int output_x,

int output_y)

{

int Status;

////////////////////////////////////////////////////////////

// Initialize Drivers – Order not important

// Do after clocks are setup

///////////////////////////////////////////////////////////

vdma_init  (&VDMA1,  0);

vdma_init  (&VDMA2,  1);

scaler_init(&Scaler, 0);

///////////////////////////////////////////////////////////////////////////

// Pipeline 2: Reset Cores

///////////////////////////////////////////////////////////////////////////

vdma_reset  (&VDMA2, XAXIVDMA_WRITE);

scaler_reset(&Scaler);

vdma_reset  (&VDMA1, XAXIVDMA_READ);

///////////////////////////////////////////////////////////////////////////

// Pipeline 2: Configure Cores

///////////////////////////////////////////////////////////////////////////

printf("Setting up VDMA Writer...\n");

vdma_setup(&VDMA2,

XAXIVDMA_WRITE,

output_x,

output_y,

3,

SCALEROUT_FBADDR,

VDMA_NOCIRC|VDMA_INT_GENLOCK);

printf("Setting up Scaler...\n");

scaler_setup(&Scaler, input_x, input_y, output_x, output_y);

printf("Setting up VDMA Reader...\n");

vdma_setup(&VDMA1,

XAXIVDMA_READ,

input_x,

input_y,

3,

VIDIN_FBADDR,

VDMA_NOCIRC|VDMA_INT_GENLOCK|VDMA_S2MM_FSYNC);

///////////////////////////////////////////////////////////////////////////

// Pipeline 2: Enable cores

///////////////////////////////////////////////////////////////////////////

//Enable write VDMA, VDMA2 (S2MM Channel)

Status = XAxiVdma_DmaStart(&VDMA2, XAXIVDMA_WRITE);

if (Status != XST_SUCCESS)

{

printf("ERROR: VDMA2 Start write transfer failed %d\r\n", Status);

return XST_FAILURE;

}

XScaler_Enable(&Scaler);

Status = XAxiVdma_DmaStart(&VDMA1, XAXIVDMA_READ);

if (Status != XST_SUCCESS)

{

printf("ERROR: VDMA1 Start read transfer failed %d\r\n", Status);

return XST_FAILURE;

}

return 1;

}

///////////////////////////////////////////////////////////////////

// Function: vdma_init()

// Initialize VDMA Driver

////////////////////////////////////////////////////////////////////

void vdma_init(XAxiVdma *VDMAPtr, int device_id)

{

int Status;

XAxiVdma_Config *VDMACfgPtr;

VDMACfgPtr = XAxiVdma_LookupConfig(device_id);

if (!VDMACfgPtr)

{

printf("ERROR: No VDMA found for ID %d\r\n", device_id);

}

Status = XAxiVdma_CfgInitialize(VDMAPtr,

VDMACfgPtr,

VDMACfgPtr->BaseAddress

);

if (Status != XST_SUCCESS) {

printf( "ERROR: VDMA Configuration Initialization failed %d\r\n",

Status);

}

}

////////////////////////////////////////////////////////////////////

// VDMA Channel Reset

////////////////////////////////////////////////////////////////////

int vdma_reset(XAxiVdma *VDMAPtr, int direction)

{

int Polls;

printf("Resetting VDMA ...\n");

XAxiVdma_Reset(VDMAPtr, direction);

Polls = 100000;

while (Polls && XAxiVdma_ResetNotDone(VDMAPtr, direction)) {

Polls -= 1;

}

if (!Polls) {

printf( "ERROR: VDMA %s channel reset failed %x\n\r",

(direction==XAXIVDMA_READ)?"Read":"Write", 0);

return XST_FAILURE;

}

return 1;

}

////////////////////////////////////////////////////////////////////

//  VDMA Channel Configure/Setup

////////////////////////////////////////////////////////////////////

int vdma_setup(XAxiVdma *VDMAPtr, int direction, int width, int height, int frame_stores, int start_address, int mode)

{

int Status, i, Addr;

XAxiVdma_DmaSetup DmaSetup;

//printf("Setting up VDMA Read Config...\n");

DmaSetup.VertSizeInput = height;

DmaSetup.HoriSizeInput = width * FRAME_STORE_DATA_BYTES ;

DmaSetup.Stride = FRAME_STORE_WIDTH * FRAME_STORE_DATA_BYTES ;

DmaSetup.FrameDelay = 0;

DmaSetup.EnableCircularBuf = mode&1;

DmaSetup.EnableSync = mode&1;

DmaSetup.PointNum = (mode>>2) & 1;

DmaSetup.EnableFrameCounter = 0; /* Endless transfers */

DmaSetup.FixedFrameStoreAddr = 0; /* We are not doing parking */

//Only set the number of frames if the VDMA can support more that we need

//NOTE: the VDMA debug features for write to the frame store

//      num reg must be enabled.

if(VDMAPtr->MaxNumFrames > frame_stores)

{

Status = XAxiVdma_SetFrmStore(VDMAPtr, frame_stores, direction);

if (Status != XST_SUCCESS) {

printf("WARNING %d: VDMA - Setting Frame Store Number to %d Failed for %s Channel. Exiting config.\r\n",

Status, frame_stores,

(direction==XAXIVDMA_READ)?"Read":"Write");

return XST_FAILURE;

}

}

Status = XAxiVdma_DmaConfig(VDMAPtr, direction, &DmaSetup);

if (Status != XST_SUCCESS) {

printf("ERROR: VDMA - %s channel config failed. (%d)\r\n",

(direction==XAXIVDMA_READ)?"Read":"Write", Status);

return XST_FAILURE;

}

/* Initialize buffer addresses

*

* These addresses are physical addresses

*/

Addr = start_address;

for(i=0; i < frame_stores; i++) {

printf(" vdma_setup: Address %d = 0x%08x.\n\r", i, Addr);

DmaSetup.FrameStoreStartAddr[i] = Addr;

Addr += FRAME_STORE_WIDTH * FRAME_STORE_HEIGHT * FRAME_STORE_DATA_BYTES;

}

/* Set the buffer addresses for transfer in the DMA engine

* The buffer addresses are physical addresses

*/

Status = XAxiVdma_DmaSetBufferAddr(VDMAPtr, direction,

DmaSetup.FrameStoreStartAddr);

if (Status != XST_SUCCESS) {

printf("ERROR: VDMA - %s channel set buffer address failed %d\r\n",

(direction==XAXIVDMA_READ)?"Read":"Write",Status);

return XST_FAILURE;

}

if(direction==XAXIVDMA_WRITE)

{

// use the TUSER bit for the frame sync for the write (S2MM side)

XAxiVdma_FsyncSrcSelect(VDMAPtr,

XAXIVDMA_S2MM_TUSER_FSYNC,

XAXIVDMA_WRITE);

}

else

{

if(mode&0x08)

{

// VDMA Read (MM2S side) for the scaler input must be synced

// to the S2MM frame Sync

XAxiVdma_FsyncSrcSelect(VDMAPtr,

XAXIVDMA_CHAN_OTHER_FSYNC,

XAXIVDMA_READ); // DMA_CR[6:5] = 0b01

}

else

{

// VDMA 2 Read (MM2S side) must be not by synced and in free run

// Its timing is governed by the output VTC generator

// and AXI4-Stream to Video Out

XAxiVdma_FsyncSrcSelect(VDMAPtr, XAXIVDMA_CHAN_FSYNC, XAXIVDMA_READ);

// DMA_CR[6:5] = 0b00

}

}

Status = XAxiVdma_GenLockSourceSelect(VDMAPtr, (mode>>1)&1, direction);

if (Status != XST_SUCCESS) {

printf("ERROR: VDMA - %s channel set gen-lock %s src failed %d\r\n",

(direction==XAXIVDMA_READ)?"Read":"Write",

(((mode>>1)&1)==XAXIVDMA_INTERNAL_GENLOCK)?"Internal":"External",

Status);

return XST_FAILURE;

}

return 1;

}

////////////////////////////////////////////////////////////////////

// Initialize Scaler Driver

////////////////////////////////////////////////////////////////////

void scaler_init(XScaler *ScalerPtr, int device_id)

{

int Status;

XScaler_Config *ScalerCfgPtr;

ScalerCfgPtr = XScaler_LookupConfig(device_id);

if (!ScalerCfgPtr)

{

printf("ERROR: No Scaler found for ID %d\r\n", device_id);

}

Status = XScaler_CfgInitialize(ScalerPtr,

ScalerCfgPtr,

ScalerCfgPtr->BaseAddress);

if (Status != XST_SUCCESS) {

printf( "ERROR: Scaler Configuration Initialization failed %d\r\n",

Status);

}

}

////////////////////////////////////////////////////////////////////

// Scaler Configure/Setup

////////////////////////////////////////////////////////////////////

int scaler_setup(XScaler *ScalerInstPtr,

int ScalerInWidth, int ScalerInHeight,

int ScalerOutWidth, int ScalerOutHeight)

{

u8 ChromaFormat;

u8 ChromaLumaShareCoeffBank;

u8 HoriVertShareCoeffBank;

/*

* Disable the scaler before setup and tell the device not to pick up

* the register updates until all are done

*/

XScaler_DisableRegUpdate(ScalerInstPtr);

XScaler_Disable(ScalerInstPtr);

/*

* Load a set of Coefficient values

*/

/* Fetch Chroma Format and Coefficient sharing info */

XScaler_GetCoeffBankSharingInfo(ScalerInstPtr,

&ChromaFormat,

&ChromaLumaShareCoeffBank,

&HoriVertShareCoeffBank);

CoeffBank.SetIndex = COEFF_SET_INDEX;

CoeffBank.PhaseNum = ScalerInstPtr->Config.MaxPhaseNum;

CoeffBank.TapNum = ScalerInstPtr->Config.VertTapNum;

/* Locate coefficients for Horizontal scaling */

CoeffBank.CoeffValueBuf = (s16 *)

XScaler_CoefValueLookup(ScalerInWidth,

ScalerOutWidth,

CoeffBank.TapNum,

CoeffBank.PhaseNum);

/* Load coefficient bank for Horizontal Luma */

XScaler_LoadCoeffBank(ScalerInstPtr, &CoeffBank);

/* Horizontal Chroma bank is loaded only if chroma/luma sharing flag

* is not set */

if (!ChromaLumaShareCoeffBank)

XScaler_LoadCoeffBank(ScalerInstPtr, &CoeffBank);

/* Vertical coeff banks are loaded only if horizontal/vertical sharing

* flag is not set

*/

if (!HoriVertShareCoeffBank) {

/* Locate coefficients for Vertical scaling */

CoeffBank.CoeffValueBuf = (s16 *)

XScaler_CoefValueLookup(ScalerInHeight,

ScalerOutHeight,

CoeffBank.TapNum,

CoeffBank.PhaseNum);

/* Load coefficient bank for Vertical Luma */

XScaler_LoadCoeffBank(ScalerInstPtr, &CoeffBank);

/* Vertical Chroma coeff bank is loaded only if chroma/luma

* sharing flag is not set

*/

if (!ChromaLumaShareCoeffBank)

XScaler_LoadCoeffBank(ScalerInstPtr, &CoeffBank);

}

/*

* Load phase-offsets into scaler

*/

StartFraction.LumaLeftHori = 0;

StartFraction.LumaTopVert = 0;

StartFraction.ChromaLeftHori = 0;

StartFraction.ChromaTopVert = 0;

XScaler_SetStartFraction(ScalerInstPtr, &StartFraction);

/*

* Set up Aperture.

*/

Aperture.InFirstLine = 0;

Aperture.InLastLine = ScalerInHeight - 1;

Aperture.InFirstPixel = 0;

Aperture.InLastPixel = ScalerInWidth - 1;

Aperture.OutVertSize = ScalerOutHeight;

Aperture.OutHoriSize = ScalerOutWidth;

// Added by Xilinx 2012.12.10

Aperture.SrcVertSize = ScalerInHeight;

Aperture.SrcHoriSize = ScalerInWidth;

XScaler_SetAperture(ScalerInstPtr, &Aperture);

/*

* Set up phases

*/

XScaler_SetPhaseNum(ScalerInstPtr, ScalerInstPtr->Config.MaxPhaseNum,

ScalerInstPtr->Config.MaxPhaseNum);

/*

* Choose active set indexes for both vertical and horizontal directions

*/

XScaler_SetActiveCoeffSet(ScalerInstPtr, COEFF_SET_INDEX,

COEFF_SET_INDEX);

/*

* Enable the scaling operation

*/

XScaler_EnableRegUpdate(ScalerInstPtr);

return 1;

}