• 0
BYTEMAN

Cmod A7-35T: UART Lite with interrupt AXI interrupt and Generic Interrupt question

Question

Hi All,

I'm start working with the AXI UART Lite in my Block Design with a Microblaze soft core.

Actually I've the whole design working, using the xil_printf I'm able to send data out the board to the PC through the Virtual COM Port exposed by the board itself.

The better approach involve the use of interrupts in order to manage the RX and TX operations.

My first try was to found some documents about this point, found it into the yourdesign_bsp > BSP Documentation > uartlite_v3_2 folder:

image.png.404919891cdcaf7997b21fa84b8a8785.png

right click and select Open Documentation give the API list on the browser, the documentation reside locally on the following path (I'm using VIVADO 2016.1):

C:/Xilinx/SDK/2016.1/data/embeddedsw/XilinxProcessorIPLib/drivers/uartlite_v3_2/doc/html/api/index.html

Opening the:

C:/Xilinx/SDK/2016.1/data/embeddedsw/XilinxProcessorIPLib/drivers/uartlite_v3_2

image.png.a35fdf5b757383322e46021845e79607.png

inside the examples there are several examples how to use interrupt with this peripheral, I took the xuartlite_intr_tapp_example.c file.

Concerning this example I've some question to asking.

Looking through the source code I see:

#ifdef XPAR_INTC_0_DEVICE_ID
#include "xintc.h"
#include <stdio.h>
#else
#include "xscugic.h"
#include "xil_printf.h"
#endif

First question is about this conditional statement.

Starting from the SDK I've opened the xparameters.h file:

image.png.68793ddd956c50628211fbdbad3fd854.png

 

 

scroll down until you reach the xparameters.h file.

image.png.f82d49363999250003076c416b7be509.png

Double click on to open the file and make a search for the XPAR_INTC_0_DEVICE_ID label:

image.png.4f70e323be75d38d30494da778056ce1.png

This label should be the reference to the AXI Interrupt Controller present into the Block Design (system.pdf).with name microblaze_0_axi_intc.

Now I need to know the exact difference between this two type of controller, the AXI is into the Fabric and I think is automatically managed from the Microblaze side by means of a dedicated software layer also the Generic Interrupt Controller I think is also managed by Microblaze but may be I've to configure it in order to instruct what peripheral have to use I'm correct?

In this example I'm using the AXI Interrupt Controller so I can avoid to insert the whole code related the Generic Interrupt Controller, correct?

Another question is if I'm using the AXI Interrupt Controller there are some reason to use also the Generic Interrupt Controller or I can't use it due to some constraints or other reasons? Someone can give me some explanation about this point?

Thank!

Share this post


Link to post
Share on other sites

6 answers to this question

Recommended Posts

  • 0

FIRST WORKING TEST WITH TX INTERRUPT ON UARTLITE (VIVADO 2016.1 - Cmod A7-35T)

Waiting for some help on the precedent question, I've made a test starting from the xuartlite_intr_example.c code (not the xuartlite_intr_tapp_example.c code, see my previous post about this point).Here below my full implemented code:

Spoiler


/*
 * helloworld.c: simple test application
 *
 * This application configures UART 16550 to baud rate 9600.
 * PS7 UART (Zynq) is not initialized by this application, since
 * bootrom/bsp configures it to baud rate 115200
 *
 * ------------------------------------------------
 * | UART TYPE   BAUD RATE                        |
 * ------------------------------------------------
 *   uartns550   9600
 *   uartlite    Configurable only in HW design
 *   ps7_uart    115200 (configured by bootrom/bsp)
 */

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "microblaze_sleep.h"

#include "xparameters.h"
#include "xuartlite.h"
#include "xintc.h"
#include "xil_exception.h"

// ----------------------------------------------------
// CONSTANT
// ----------------------------------------------------

/*
 * 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 UARTLITE_DEVICE_ID      XPAR_UARTLITE_0_DEVICE_ID
#define INTC_DEVICE_ID          XPAR_INTC_0_DEVICE_ID
#define UARTLITE_INT_IRQ_ID     XPAR_INTC_0_UARTLITE_0_VEC_ID

/*
 * The following constant controls the length of the buffers to be sent
 * and received with the UartLite device.
 */
#define TEST_BUFFER_SIZE        100

// ----------------------------------------------------
// FUNCTION PROTOTYPE
// ----------------------------------------------------
int UartLiteInit(u16 DeviceId);
int SetupInterruptSystem(XUartLite *UartLitePtr);
void SendHandler(void *CallBackRef, unsigned int EventData);
void RecvHandler(void *CallBackRef, unsigned int EventData);

// ----------------------------------------------------
// VARIABLE DEFINITIONS
// ----------------------------------------------------
XUartLite UartLite;            		// The instance of the UartLite Device
XIntc InterruptController;     		// The instance of the Interrupt Controller

u8 SendBuffer[TEST_BUFFER_SIZE];	// UART TX buffer (shared with interrupt code)
u8 ReceiveBuffer[TEST_BUFFER_SIZE];	// UART RX buffer (shared with interrupt code)

static volatile int TotalReceivedCount;	// UART RX char counter (shared with interrupt code)
static volatile int TotalSentCount;		// UART TX char counter (shared with interrupt code)
static volatile int TxIsDone=TRUE;		// UART TX flag (TRUE=tx is possible) (shared with interrupt code)
static volatile int TxMaxChr;			// UART TX chars number to transmit (shared with interrupt code)

// ----------------------------------------------------
// FUNCTION DEFINITION
// ----------------------------------------------------

/****************************************************************************/
/**
*
* This function does a minimal test on the UartLite device and driver as a
* design example. The purpose of this function is to illustrate
* how to use the XUartLite component.
*
* This function uses interrupt driver mode of the UartLite device. The calls
* to the UartLite driver in the handlers should only use the non-blocking
* calls.
*
* @param	DeviceId is the Device ID of the UartLite Device and is the
*			XPAR_<uartlite_instance>_DEVICE_ID value from xparameters.h.
*
* @return	XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note
*
*
****************************************************************************/
int UartLiteInit(u16 DeviceId)
{
	int Status;

	//Initialize the UartLite driver so that it's ready to use.
	Status = XUartLite_Initialize(&UartLite, DeviceId);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	// Perform a self-test to ensure that the hardware was built correctly.
	Status = XUartLite_SelfTest(&UartLite);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	// Connect the UartLite to the interrupt subsystem such that interrupts can
	// occur. This function is application specific.
	Status = SetupInterruptSystem(&UartLite);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	// Setup the handlers for the UartLite that will be called from the
	// interrupt context when data has been sent and received, specify a
	// pointer to the UartLite driver instance as the callback reference so
	// that the handlers are able to access the instance data.
	XUartLite_SetSendHandler(&UartLite, SendHandler, &UartLite);
	XUartLite_SetRecvHandler(&UartLite, RecvHandler, &UartLite);

	// Enable the interrupt of the UartLite so that interrupts will occur.
	XUartLite_EnableInterrupt(&UartLite);

	return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* This function is the handler which performs processing to send data to the
* UartLite. It is called from an interrupt context such that the amount of
* processing performed should be minimized. It is called when the transmit
* FIFO of the UartLite is empty and more data can be sent through the UartLite.
*
* This handler provides an example of how to handle data for the UartLite,
* but is application specific.
*
* @param	CallBackRef contains a callback reference from the driver.
*			In this case it is the instance pointer for the UartLite driver.
* @param	EventData contains the number of bytes sent or received for sent
*			and receive events.
*
* @return	None.
*
* @note		None.
*
****************************************************************************/
void SendHandler(void *CallBackRef, unsigned int EventData)
{
	// Get the number of transmitted chars
	TotalSentCount = EventData;

	// Check if all is done
	if (TotalSentCount >= TxMaxChr){
		TxIsDone = TRUE;
	}else{
		TxIsDone = FALSE;
	}

}

/****************************************************************************/
/**
*
* This function is the handler which performs processing to receive data from
* the UartLite. It is called from an interrupt context such that the amount of
* processing performed should be minimized.  It is called data is present in
* the receive FIFO of the UartLite such that the data can be retrieved from
* the UartLite. The size of the data present in the FIFO is not known when
* this function is called.
*
* This handler provides an example of how to handle data for the UartLite,
* but is application specific.
*
* @param	CallBackRef contains a callback reference from the driver, in
*		this case it is the instance pointer for the UartLite driver.
* @param	EventData contains the number of bytes sent or received for sent
*		and receive events.
*
* @return	None.
*
* @note		None.
*
****************************************************************************/
void RecvHandler(void *CallBackRef, unsigned int EventData)
{
	TotalReceivedCount = EventData;
}

/****************************************************************************/
/**
*
* This function setups the interrupt system such that interrupts can occur
* for the UartLite device. This function is application specific since the
* actual system may or may not have an interrupt controller. The UartLite
* could be directly connected to a processor without an interrupt controller.
* The user should modify this function to fit the application.
*
* @param    UartLitePtr contains a pointer to the instance of the UartLite
*           component which is going to be connected to the interrupt
*           controller.
*
* @return   XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note     None.
*
****************************************************************************/
int SetupInterruptSystem(XUartLite *UartLitePtr)
{

	int Status;

	// Initialize the interrupt controller driver so that it is ready to use
	Status = XIntc_Initialize(&InterruptController, INTC_DEVICE_ID);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Connect a device driver handler that will be called when an interrupt
	 * for the device occurs, the device driver handler performs the
	 * specific interrupt processing for the device.
	 */
	Status = XIntc_Connect(&InterruptController, UARTLITE_INT_IRQ_ID,
			   (XInterruptHandler)XUartLite_InterruptHandler,
			   (void *)UartLitePtr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Start the interrupt controller such that interrupts are enabled for
	 * all devices that cause interrupts, specific real mode so that
	 * the UartLite can cause interrupts through the interrupt controller.
	 */
	Status = XIntc_Start(&InterruptController, XIN_REAL_MODE);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	// Enable the interrupt for the UartLite device.
	XIntc_Enable(&InterruptController, UARTLITE_INT_IRQ_ID);

	// Initialize the exception table.
	Xil_ExceptionInit();

	// Register the interrupt controller handler with the exception table.
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
			 (Xil_ExceptionHandler)XIntc_InterruptHandler,
			 &InterruptController);

	// Enable exceptions.
	Xil_ExceptionEnable();

	return XST_SUCCESS;
}

/***************************************************************************
* MAIN
****************************************************************************/
int main()
{
	int Status;

    init_platform();

    xil_printf("System start\n\r");

    // UARTLite initialization and interrupt setup
    Status = UartLiteInit(UARTLITE_DEVICE_ID);
    if (Status != XST_SUCCESS) {
        cleanup_platform();
        return 0;
    }

    // Infinite loop for microcontroller activity
    while(1){

    	if (TxIsDone == TRUE){
			TxIsDone = FALSE;
			SendBuffer[0]='H';
			SendBuffer[1]='e';
			SendBuffer[2]='l';
			SendBuffer[3]='l';
			SendBuffer[4]='o';
			SendBuffer[5]='!';
			SendBuffer[6]='\n';
			SendBuffer[7]='\r';
			TxMaxChr = 8;
			XUartLite_Send(&UartLite, SendBuffer, TxMaxChr);
    	}

    	// xil_printf("System running\n\r");
    	// MB_Sleep(100);
    }

    cleanup_platform();
    return 0;
}


 

I've do some simple change to adapt the code to my case, the change reside in how to manage the interrupt transmission, I've used the TxIsDone flag to know when the transmission was finished and then get another one, in this way I'm sure to start a new transmission just after the old one is completed (see the SendHandler function).

Actually the system is working properly into the SDK Debug Mode (GDB), into the RealTerm monitor I can see the transmitted chars:

image.png.923e765ca7dc8ec09a38de4e040f7daa.png

Total transmissione time check
Now I can see a CPS equal approximatively to 2000, if this value reflect the Chars Per Seconds sounds to me higher than the correct value should be.
For a 9600,8,N,1 setting we have a 10 bit (1 start + 8 data + 1 stop) for every char to be transmitted then a final time equal to 10/9600=1.042 ms. This give theorically 960 character every seconds if we suppose zero delay time between the frame so is a upper theoretical limit. This is a know bug of the Realterm that effectively show twice regarding the correct value so the UART Lite behaviour should be correct also from this point (https://sourceforge.net/p/realterm/bugs/37/).

QUESTION #1 - SDK Debug behavior in GDB mode
A question is related to the SDK debugger, when I run the Debug (GDB mode) I'm able to step the code, but if I choose the Resume option (then to run freely the code) the debug can't be paused and the only choice is to terminate the debug (the pause button on the toolbar is greyed and no way to stop the debugging with it).
Someone have seen this behaviour and found a way to overcome this problem?

Thank!

Best regards

Edited by JColvin
condensed for visual compactness

Share this post


Link to post
Share on other sites
  • 0

Hi @BYTEMAN,

I'm not certain on the differences between the two interrupt controllers, you will likely need to contact Xilinx to see if they have any additional thoughts or concerns on this.

As for the SDK debugging behavior, according to this Xilinx site, the GDB mode is depreciated, so you will likely want to instead use the "Launch on Hardware (System Debugger)" option instead for some better results, as this Xilinx forum thread seems to indicate as well.

Thanks,
JColvin

Share this post


Link to post
Share on other sites
  • 0
16 hours ago, JColvin said:

Hi @BYTEMAN,

I'm not certain on the differences between the two interrupt controllers, you will likely need to contact Xilinx to see if they have any additional thoughts or concerns on this.

As for the SDK debugging behavior, according to this Xilinx site, the GDB mode is depreciated, so you will likely want to instead use the "Launch on Hardware (System Debugger)" option instead for some better results, as this Xilinx forum thread seems to indicate as well.

Thanks,
JColvin

thank you @JColvin,

I've did some test but already get following error:

Error while launching program:
Failed to call get_cpu_nr
Reason: ERROR: [Common 17-55] 'get_property' expects at least one object.
Resolution: If [get_<value>] was used to populate the object, check to make sure this command returns at least one valid object.

Failed to call get_cpu_nr
Reason: ERROR: [Common 17-55] 'get_property' expects at least one object.
Resolution: If [get_<value>] was used to populate the object, check to make sure this command returns at least one valid object.


Here the sequence of step I've used:

system-debugger-1.jpg.8bb7053b88610cb9039f265a408e12cf.jpgsystem-debugger-1.jpg.8bb7053b88610cb9039f265a408e12cf.jpg

system-debugger-2.thumb.jpg.a160588d6acf0ac5b0190c01d0e17495.jpg

system-debugger-3.jpg.90d95164e7a39e524e509fef18d7fadd.jpg

Do you have some advice how to solve this issue?

Thank

Best regards

Share this post


Link to post
Share on other sites
  • 0

Hello @BYTEMAN,

Taking a look at this thread, you may need to re-generate your BSP sources, or potentially delete it and create a new one. I would also make sure that all of the SDK settings (I'm not certain if you have changed any) are on their default settings.

Thanks,
JColvin

Share this post


Link to post
Share on other sites
  • 0
2 hours ago, JColvin said:

Hello @BYTEMAN,

Taking a look at this thread, you may need to re-generate your BSP sources, or potentially delete it and create a new one. I would also make sure that all of the SDK settings (I'm not certain if you have changed any) are on their default settings.

Thanks,
JColvin

Thank you @JColvin,

I've did many test with the System Debugger but results is still the same and I'm unable to perform the debugging.

With the GDB debugger all is fine and no error arise and I'm able to debug the system.

I don't know why isn't possible doing the System Debugger and over the net I've not found any useful info on this specific error "Failed to call get_cpu_nr".

Best regards

Share this post


Link to post
Share on other sites
  • 0

UPDATE FOR THE XILINX SYSTEM DEBUGGER ERROR (VIVADO 2016.1)

From XILINX this error appear as a software bugs, I've asked for a patch.

Best regards

UPDATE - 19/04/2018

The patch tried was not working with the 2016.1 (I'm able to debug only with the GDB) then I've make a test by importing all design into the VIVADO 2017.4 and now I'm able to debug with GDB and also with the Xilinx System Debugger.

Best regards

Edited by BYTEMAN
UPDATE

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now