2016.4 xuartps_polled_example.c Comments and Explanation


This post lists additional comments and explanation on the 2016.4 release of xuartps_polled_example.c from: https://github.com/Xilinx/embeddedsw/blob/xilinx-v2016.4/XilinxProcessorIPLib/drivers/uartps/examples/xuartps_polled_example.c


Need Help?


Click https://www.centennialsoftwaresolutions.com/post/import-xuartps_polled_example-c-into-a-xilinx-sdk-project if you need help bringing this example into and SDK project


Comments and Additional Explanation


/******************************************************************************

*

* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved.

*

* Permission is hereby granted, free of charge, to any person obtaining a copy

* of this software and associated documentation files (the "Software"), to deal

* in the Software without restriction, including without limitation the rights

* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

* copies of the Software, and to permit persons to whom the Software is

* furnished to do so, subject to the following conditions:

*

* The above copyright notice and this permission notice shall be included in

* all copies or substantial portions of the Software.

*

* Use of the Software is limited solely to applications:

* (a) running on a Xilinx device, or

* (b) that interact with a Xilinx device through a bus or interconnect.

*

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL

* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,

* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF

* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

* SOFTWARE.

*

* Except as contained in this notice, the name of the Xilinx shall not be used

* in advertising or otherwise to promote the sale, use or other dealings in

* this Software without prior written authorization from Xilinx.

*

******************************************************************************/

/****************************************************************************/

/**

*

* @file xuartps_polled_example.c

*

* This file contains an example using the XUartPs driver in polled mode.

*

* This function sends data and expects to receive the data thru the device

* using the local loopback mode.

*

* @note

* If the device does not work properly, the example may hang.

*

* MODIFICATION HISTORY:

* <pre>

* Ver Who Date Changes

* ----- ------ -------- -----------------------------------------------

* 1.00a drg/jz 01/13/10 First Release

* 1.03a sg 07/16/12 Modified the device ID to use the first Device Id

* Removed the printf at the start of the main

* </pre>

******************************************************************************/


/***************************** Include Files *********************************/


#include "xparameters.h"

#include "xuartps.h"

#include "xil_printf.h"


/************************** Constant Definitions *****************************/


/*

* The following constants map to the XPAR parameters created in the

* xparameters.h file. They are defined here such that a user can easily

* change all the needed parameters in one place.

*/

#define UART_DEVICE_ID XPAR_XUARTPS_0_DEVICE_ID


Where is XPAR_XUARTPS_0_DEVICE_ID defined?


XPAR_XUARTPS_0_DEVICE_ID comes from xparameters.h in the ps7_cortexa9_0/include/ directory of the BSP project used in the Xilinx SDK project.


In xparameters.h you'll see:


/* Canonical definitions for peripheral PS7_UART_0 */

#define XPAR_XUARTPS_0_DEVICE_ID XPAR_PS7_UART_0_DEVICE_ID

#define XPAR_XUARTPS_0_BASEADDR 0xE0000000

#define XPAR_XUARTPS_0_HIGHADDR 0xE0000FFF

#define XPAR_XUARTPS_0_UART_CLK_FREQ_HZ 100000000

#define XPAR_XUARTPS_0_HAS_MODEM 0


Where is XPAR_PS7_UART_0_DEVICE_ID defined?


XPAR_PS7_UART_0_DEVICE_ID is defined right above:

/* Definitions for peripheral PS7_UART_0 */

#define XPAR_PS7_UART_0_DEVICE_ID 0

#define XPAR_PS7_UART_0_BASEADDR 0xE0000000

#define XPAR_PS7_UART_0_HIGHADDR 0xE0000FFF

#define XPAR_PS7_UART_0_UART_CLK_FREQ_HZ 100000000

#define XPAR_PS7_UART_0_HAS_MODEM 0


Steps to Find where the Include Path is Specified


Step #1: Right-click on your SDK project

Step #2: Select C/C++ Build Settings

Step #3: Select ARM v7 gcc compiler

The include path is specified in the All options: window


/*

* The following constant controls the length of the buffers to be sent

* and received with the device, this constant must be 32 bytes or less since

* only as much as FIFO size data can be sent or received in polled mode.

*/

#define TEST_BUFFER_SIZE 32


/**************************** Type Definitions *******************************/


/***************** Macros (Inline Functions) Definitions *********************/


/************************** Function Prototypes ******************************/


int UartPsPolledExample(u16 DeviceId);


/************************** Variable Definitions *****************************/


XUartPs Uart_PS; /* Instance of the UART Device */


Where is XUartPs defined?


XUartPs is defined in xuartps.h in the ps7_cortexa9_0/include/ directory of the BSP project used in the Xilinx SDK project.


How is XUartPs defined?


/**

* The XUartPs driver instance data structure. A pointer to an instance data

* structure is passed around by functions to refer to a specific driver

* instance.

*/

typedef struct {

XUartPs_Config Config; /* Configuration data structure */

u32 InputClockHz; /* Input clock frequency */

u32 IsReady; /* Device is initialized and ready */

u32 BaudRate; /* Current baud rate */


XUartPsBuffer SendBuffer;

XUartPsBuffer ReceiveBuffer;


XUartPs_Handler Handler;

void *CallBackRef; /* Callback reference for event handler */

u32 Platform;

u8 is_rxbs_error;

} XUartPs;


/*

* The following buffers are used in this example to send and receive data

* with the UART.

*/

static u8 SendBuffer[TEST_BUFFER_SIZE]; /* Buffer for Transmitting Data */

static u8 RecvBuffer[TEST_BUFFER_SIZE]; /* Buffer for Receiving Data */


Why are these buffers 32 bytes?

I'm not sure. The receive FIFO is 64 bytes and the transmit FIFO is 64 bytes as listed on page 590 of the Zynq-7000 TRM [link].


/*****************************************************************************/

/**

*

* Main function to call the Uart Polled mode example.

*

* @param None

*

* @return XST_SUCCESS if succesful, otherwise XST_FAILURE

*

* @note None

*

******************************************************************************/

#ifndef TESTAPP_GEN

int main(void)

{

int Status;



/*

* Run the Uart_PS polled example , specify the the Device ID that is

* generated in xparameters.h

*/

Status = UartPsPolledExample(UART_DEVICE_ID);

if (Status != XST_SUCCESS) {

xil_printf("UART Polled Mode Example Test Failed\r\n");

return XST_FAILURE;

}


xil_printf("Successfully ran UART Polled Mode Example Test\r\n");


Does the xil_printf still work?

There appears to be a problem here, but there isn't. xil_printf() uses UART0 in Normal Mode (see page 598 of the Zynq-7000 TRM [link]). UartPsPolledExample() also uses UART0 and places UART0 into Local Loopback Mode. It appears that xil_printf() wouldn't work. However, xil_printf() does still work because UartPsPolledExample() restores UART0 to Normal Mode.


return XST_SUCCESS;

}

#endif

/*****************************************************************************/

/**

*

* This function does a minimal test on the XUartPs device in polled mode.

*

* This function sends data and expects to receive the data thru the UART

* using the local loopback mode.

*

*

* @param DeviceId is the unique device id from hardware build.

*

* @return XST_SUCCESS if successful, XST_FAILURE if unsuccessful

*

* @note

* This function polls the UART, it may hang if the hardware is not

* working correctly.

*

****************************************************************************/

int UartPsPolledExample(u16 DeviceId)

{

int Status;

XUartPs_Config *Config;

unsigned int SentCount;

unsigned int ReceivedCount;

u16 Index;

u32 LoopCount = 0;


/*

* Initialize the UART driver so that it's ready to use.

* Look up the configuration in the config table, then initialize it.

*/

Config = XUartPs_LookupConfig(DeviceId);

if (NULL == Config) {

return XST_FAILURE;

}


Where is XUartPs_LookupConfig() and what does it do?


XUartPs_LookupConfig() is located in xuart_sint.c which is located in the ps7_cortexa9_0/libsrc/uartps_v3_3/src/ directory of the BSP project used in the Xilinx SDK project.


It performs the following operations:


/****************************************************************************/

/**

*

* Looks up the device configuration based on the unique device ID. The table

* contains the configuration info for each device in the system.

*

* @param DeviceId contains the ID of the device

*

* @return A pointer to the configuration structure or NULL if the

* specified device is not in the system.

*

* @note None.

*

******************************************************************************/

XUartPs_Config *XUartPs_LookupConfig(u16 DeviceId)

{

XUartPs_Config *CfgPtr = NULL;


u32 Index;


for (Index = 0U; Index < (u32)XPAR_XUARTPS_NUM_INSTANCES; Index++) {

if (XUartPs_ConfigTable[Index].DeviceId == DeviceId) {

CfgPtr = &XUartPs_ConfigTable[Index];

break;

}

}


return (XUartPs_Config *)CfgPtr;

}


Where is XUartPs_ConfigTable[] defined and what does it contain?


XUartPs_ConfigTable[] is defined in xuartps_g.c which is included in ps7_cortexa9_0/libsrc/uartps_v3_3/src/ and generated by HSI from the HDF.


Here's an example of how XUartPs_ConfigTable[] is defined:


/*******************************************************************

*

* CAUTION: This file is automatically generated by HSI.

* Version:

* DO NOT EDIT.

*

* Copyright (C) 2010-2019 Xilinx, Inc. All Rights Reserved.*

*Permission is hereby granted, free of charge, to any person obtaining a copy

*of this software and associated documentation files (the Software), to deal

*in the Software without restriction, including without limitation the rights

*to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

*copies of the Software, and to permit persons to whom the Software is

*furnished to do so, subject to the following conditions:

*

*The above copyright notice and this permission notice shall be included in

*all copies or substantial portions of the Software.

*

* Use of the Software is limited solely to applications:

*(a) running on a Xilinx device, or

*(b) that interact with a Xilinx device through a bus or interconnect.

*

*THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

*IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

*FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL

*XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,

*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT

*OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

*

*Except as contained in this notice, the name of the Xilinx shall not be used

*in advertising or otherwise to promote the sale, use or other dealings in

*this Software without prior written authorization from Xilinx.

*


*

* Description: Driver configuration

*

*******************************************************************/


#include "xparameters.h"

#include "xuartps.h"


/*

* The configuration table for devices

*/


XUartPs_Config XUartPs_ConfigTable[] =

{

{

XPAR_PS7_UART_0_DEVICE_ID,

XPAR_PS7_UART_0_BASEADDR,

XPAR_PS7_UART_0_UART_CLK_FREQ_HZ,

XPAR_PS7_UART_0_HAS_MODEM

}

};


Status = XUartPs_CfgInitialize(&Uart_PS, Config, Config->BaseAddress);

if (Status != XST_SUCCESS) {

return XST_FAILURE;

}


Where is XUartPs_CfgInitialize() and what does it do?


XUartPs_CfgInitialize() is located in xuartps.c which is located in the ps7_cortexa9_0/libsrc/uartps_v3_3/src/ directory of the BSP project used in the Xilinx SDK project.


XUartPs_CfgInitialize() performs the following function:


/****************************************************************************/

/**

*

* Initializes a specific XUartPs instance such that it is ready to be used.

* The data format of the device is setup for 8 data bits, 1 stop bit, and no

* parity by default. The baud rate is set to a default value specified by

* Config->DefaultBaudRate if set, otherwise it is set to 19.2K baud. The

* receive FIFO threshold is set for 8 bytes. The default operating mode of the

* driver is polled mode.

*

* @param InstancePtr is a pointer to the XUartPs instance.

* @param Config is a reference to a structure containing information

* about a specific XUartPs driver.

* @param EffectiveAddr is the device base address in the virtual memory

* address space. The caller is responsible for keeping the address

* mapping from EffectiveAddr to the device physical base address

* unchanged once this function is invoked. Unexpected errors may

* occur if the address mapping changes after this function is

* called. If address translation is not used, pass in the physical

* address instead.

*

* @return

*

* - XST_SUCCESS if initialization was successful

* - XST_UART_BAUD_ERROR if the baud rate is not possible because

* the inputclock frequency is not divisible with an acceptable

* amount of error

*

* @note

*

* The default configuration for the UART after initialization is:

*

* - 19,200 bps or XPAR_DFT_BAUDRATE if defined

* - 8 data bits

* - 1 stop bit

* - no parity

* - FIFO's are enabled with a receive threshold of 8 bytes

* - The RX timeout is enabled with a timeout of 1 (4 char times)

*

* All interrupts are disabled.

*

*****************************************************************************/


/* Check hardware build. */

Status = XUartPs_SelfTest(&Uart_PS);

if (Status != XST_SUCCESS) {

return XST_FAILURE;

}


XUartPs_SelfTest() performs a test very similar to the current test being documented. It only differs in sending and receiving data one byte at a time as opposed to 32 bytes at a time. Like the test calling it (this test) XUartPs_SelfTest also places the UART in local loopback. Before the XUartPs_SelfTest() function ends it restores the mode and saves the interrupt state and restores the mode.


It specifically:


/* Disable all interrupts in the interrupt disable register */

IntrRegister = XUartPs_ReadReg(InstancePtr->Config.BaseAddress,

XUARTPS_IMR_OFFSET);


>>> InstancePtr->Config.BaseAddress is 0xE0000000 as listed above

>>> XUARTPS_IMR_OFFSET is 0x10. This is the Interrupt Mask Register as listed on page 1774 of the TRM [link]. So here the Interrupt Mask Register is getting saved.


XUartPs_WriteReg(InstancePtr->Config.BaseAddress, XUARTPS_IDR_OFFSET,

XUARTPS_IXR_MASK);


>>> Writes 0x00003FFF (XUARTPS_IXR_MASK) to 0xC (XUARTPS_IDR_OFFSET aka the Interrupt Disable Register) which turns off all of the interrupts UART0 can send.


/* Setup for local loopback */

ModeRegister = XUartPs_ReadReg(InstancePtr->Config.BaseAddress,

XUARTPS_MR_OFFSET);


>>> Saves the current mode of the UART. XUARTPS_MR_OFFSET is at 0x4 and is documented on pages 1776 and 1777 in the TRM.


XUartPs_WriteReg(InstancePtr->Config.BaseAddress, XUARTPS_MR_OFFSET,

((ModeRegister & (u32)(~XUARTPS_MR_CHMODE_MASK)) |

(u32)XUARTPS_MR_CHMODE_L_LOOP));


>>> This call is the modify and write part of a read, modify and write to the XUARTPS_MR_OFFSET register. It clears the 2 bit mode field and writes a mode of 2 which is local loopback.


/* Send a number of bytes and receive them, one at a time. */

for (Index = 0U; Index < XUARTPS_TOTAL_BYTES; Index++) {

/*

* Send out the byte and if it was not sent then the failure

* will be caught in the comparison at the end

*/

(void)XUartPs_Send(InstancePtr, &TestString[Index], 1U);


>>> XUartPs_Send() is located in xuartps.c in ps7_cortexa9_0/libsrc/uartps_v3_3/src/. It does

* This functions sends the specified buffer using the device in either

* polled or interrupt driven mode. This function is non-blocking, if the device

* is busy sending data, it will return and indicate zero bytes were sent.

* Otherwise, it fills the TX FIFO as much as it can, and return the number of

* bytes sent.

*

* In a polled mode, this function will only send as much data as TX FIFO can

* buffer. The application may need to call it repeatedly to send the entire

* buffer.

*

* In interrupt mode, this function will start sending the specified buffer,

* then the interrupt handler will continue sending data until the entire

* buffer has been sent. A callback function, as specified by the application,

* will be called to indicate the completion of sending.


/*

* Wait until the byte is received. This can hang if the HW

* is broken. Watch for the FIFO empty flag to be false.

*/

ReceiveDataResult = Xil_In32((InstancePtr->Config.BaseAddress) + XUARTPS_SR_OFFSET) &

XUARTPS_SR_RXEMPTY;

while (ReceiveDataResult == XUARTPS_SR_RXEMPTY ) {

ReceiveDataResult = Xil_In32((InstancePtr->Config.BaseAddress) + XUARTPS_SR_OFFSET) &

XUARTPS_SR_RXEMPTY;

}


>>> These lines wait for bit 1 aka Receiver FIFO Full continuous status (0: Rx FIFO is not empty, 1: Rx FIFO is empty) of XUARTPS_SR_OFFSET aka the Channel Status Register the @ 0x2C to become not 1 indicating that the Rx FIFO is not empty.


/* Receive the byte */

(void)XUartPs_Recv(InstancePtr, &ReturnString[Index], 1U);

}


>>> Receive the byte


/*

* Compare the bytes received to the bytes sent to verify the exact data

* was received

*/

for (Index = 0U; Index < XUARTPS_TOTAL_BYTES; Index++) {

if (TestString[Index] != ReturnString[Index]) {

Status = XST_UART_TEST_FAIL;

}

}


/*

* Restore the registers which were altered to put into polling and

* loopback modes so that this test is not destructive

*/

XUartPs_WriteReg(InstancePtr->Config.BaseAddress, XUARTPS_IER_OFFSET,

IntrRegister);

XUartPs_WriteReg(InstancePtr->Config.BaseAddress, XUARTPS_MR_OFFSET,

ModeRegister);


/* Use local loopback mode. */

XUartPs_SetOperMode(&Uart_PS, XUARTPS_OPER_MODE_LOCAL_LOOP);


XUartPs_SetOperMode() sets the previously mentioned Local Loopback Mode.


/*

* Initialize the send buffer bytes with a pattern and zero out

* the receive buffer.

*/

for (Index = 0; Index < TEST_BUFFER_SIZE; Index++) {

SendBuffer[Index] = '0' + Index;

RecvBuffer[Index] = 0;

}


/* Block sending the buffer. */

SentCount = XUartPs_Send(&Uart_PS, SendBuffer, TEST_BUFFER_SIZE);

if (SentCount != TEST_BUFFER_SIZE) {

return XST_FAILURE;

}


/*

* Wait while the UART is sending the data so that we are guaranteed

* to get the data the 1st time we call receive, otherwise this function

* may enter receive before the data has arrived

*/

while (XUartPs_IsSending(&Uart_PS)) {

LoopCount++;

}


/* Block receiving the buffer. */

ReceivedCount = 0;

while (ReceivedCount < TEST_BUFFER_SIZE) {

ReceivedCount +=