Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

USART Interrupt in Zynq

Status
Not open for further replies.

aminpix

Full Member level 2
Full Member level 2
Joined
Sep 30, 2008
Messages
120
Helped
2
Reputation
4
Reaction score
2
Trophy points
1,298
Activity points
2,474
I am trying to develop a simple UART interrupt code based on PS on Zynq. The plan is when the Zynq receives any character from RX_UART, take it and send it back to the TX_UART line.
It has to be with interrupt.
It looks very simple buy almost weeks I cant find solution for it.
Anyone can help me! This code doesn't do anything!
Here is my code.


C:
#include <stdio.h>
 #include "xparameters.h"
 #include "xil_printf.h"
 #include "xuartps.h"
 #include "xscugic.h"

 #define UART_DEVICE_ID        XPAR_XUARTPS_0_DEVICE_ID
 #define INTC_DEVICE_ID        XPAR_SCUGIC_SINGLE_DEVICE_ID
 #define UART_INT_IRQ_ID        XPAR_XUARTPS_1_INTR

 #define RECV_BUFFER_SIZE    3

XUartPs UartPs    ;            /* Instance of the UART Device */
static XScuGic InterruptController;    /* Instance of the Interrupt Controller */

int UartIntrInit(XScuGic *IntcInstPtr, XUartPs *UartInstPtr, u16 DeviceId, u16 UartIntrId);
static int SetupInterruptSystem(XScuGic *IntcInstancePtr, XUartPs *UartInstancePtr, u16 UartIntrId);
void UARTHandler(void *CallBackRef, u32 Event, unsigned int EventData);
static u8 RecvBuffer[RECV_BUFFER_SIZE];    /* Buffer for Receiving Data */


int main(void)
{
    int Status;
    Status = UartIntrInit(&InterruptController, &UartPs, UART_DEVICE_ID, UART_INT_IRQ_ID);
    if (Status != XST_SUCCESS)
    {
        xil_printf("UART Interrupt Example Test Failed\r\n");
        return XST_FAILURE;
    }


    while(1);

    return 0;
}




int UartIntrInit(XScuGic *IntcInstPtr, XUartPs *UartInstPtr, u16 DeviceId, u16 UartIntrId)
{
    int Status;
    XUartPs_Config *Config;
    u32 IntrMask;

    /*
     * 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;
    }

    Status = XUartPs_CfgInitialize(UartInstPtr, Config, Config->BaseAddress);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    /* Check hardware build */
    Status = XUartPs_SelfTest(UartInstPtr);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    /*
     * Connect the UART to the interrupt subsystem such that interrupts
     * can occur. This function is application specific.
     */
    Status = SetupInterruptSystem(IntcInstPtr, UartInstPtr, UartIntrId);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    /*
     * Setup the handlers for the UART that will be called from the
     * interrupt context when data has been sent and received, specify
     * a pointer to the UART driver instance as the callback reference
     * so the handlers are able to access the instance data
     */
    XUartPs_SetHandler(UartInstPtr, (XUartPs_Handler)UARTHandler, UartInstPtr);

    /*
     * Enable the interrupt of the UART so interrupts will occur, setup
     * a local loopback so data that is sent will be received.
     */
    IntrMask =
        XUARTPS_IXR_TOUT | XUARTPS_IXR_PARITY | XUARTPS_IXR_FRAMING |
        XUARTPS_IXR_OVER | XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXFULL |
        XUARTPS_IXR_RXOVR;

    XUartPs_SetInterruptMask(UartInstPtr, IntrMask);

    XUartPs_SetOperMode(UartInstPtr, XUARTPS_OPER_MODE_NORMAL);

    /*
     * Set the receiver timeout. If it is not set, and the last few bytes
     * of data do not trigger the over-water or full interrupt, the bytes
     * will not be received. By default it is disabled.
     *
     * The setting of 8 will timeout after 8 x 4 = 32 character times.
     * Increase the time out value if baud rate is high, decrease it if
     * baud rate is low.
     */
    XUartPs_SetRecvTimeout(UartInstPtr, 8);

    return XST_SUCCESS;
}

static int SetupInterruptSystem(XScuGic *IntcInstancePtr, XUartPs *UartInstancePtr, u16 UartIntrId)
{
    int Status;
    XScuGic_Config *IntcConfig; /* Config for interrupt controller */


    /* Initialize the interrupt controller driver */
    IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
    if (NULL == IntcConfig) {
        return XST_FAILURE;
    }

    Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
                    IntcConfig->CpuBaseAddress);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    /*
     * Connect the interrupt controller interrupt handler to the
     * hardware interrupt handling logic in the processor.
     */
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
                (Xil_ExceptionHandler) XScuGic_InterruptHandler,
                IntcInstancePtr);

    /*
     * 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 = XScuGic_Connect(IntcInstancePtr, UartIntrId,
                  (Xil_ExceptionHandler) XUartPs_InterruptHandler,
                  (void *) UartInstancePtr);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    /* Enable the interrupt for the device */
    XScuGic_Enable(IntcInstancePtr, UartIntrId);

    /* Enable interrupts */
         Xil_ExceptionEnable();

     return XST_SUCCESS;
}

void UARTHandler(void *CallBackRef, u32 Event, unsigned int EventData)
{
    XUartPs_Recv(&UartPs, RecvBuffer, RECV_BUFFER_SIZE);
    XUartPs_Send(&UartPs, RecvBuffer, 1);
    //make sure the TX buffer is empty
    while (XUartPs_IsSending(&UartPs));
}
 

Solution
@aminpix
The problem should be in the block design or hardware. I want to use MIO24 and MIO25 (with no extra PL hardware) as RX and TX of the UART. Therefore I didn't use AXI UART IPs.
Are you sure the Zynq block (or your design) contains dedicated hardware that can handle UART traffic at the front end and convert them to parallel data which the C code running on Zynq can handle?
If not you need to come up with the front end UART hardware first and make sure it is functioning correctly before you do firmware development for it.
Hi,

"Doesn't do anything" is not very descriptive.
How did you test it?
What happeded?
Any compiler warnings / errors?

What about simple debugging methods like:
* checking the Rx datastream
* checking Rx interrupt line state
* checking ISR processing
* sending dummy bytes from main()
* sending dummy bytes from ISR
... and so on

Do tests step by step. And give feedback to every step.

Klaus
 

Hi,

"Doesn't do anything" is not very descriptive.
How did you test it?
What happeded?
Any compiler warnings / errors?

What about simple debugging methods like:
* checking the Rx datastream
* checking Rx interrupt line state
* checking ISR processing
* sending dummy bytes from main()
* sending dummy bytes from ISR
... and so on

Do tests step by step. And give feedback to every step.

Klaus


It compiles successfully and programs successfully, but what ever i sent in UART, no reply from the FPGA.
 

Hi,

I asked some more questions. My idea was to find out the reason for the problem.

Klaus
 

Hi,

I asked some more questions. My idea was to find out the reason for the problem.

Klaus
I have connected the board to a PC through a USB to UART adaptor.
At RX FPGA pin we receives the data, but nothing on TX FPGA. I have tried to send some data before and after UartIntrInit() in the main, it works fine.
I have noticed Zynq doesn't enter the UARThandler when I enter any key in the console (I wrote a code to send a character when zynq enters the UARThandler function).

However, Zynq enters to the UARThandler four times after
XUartPs_SetOperMode(UartInstPtr, XUARTPS_OPER_MODE_NORMAL);
and once after
XUartPs_SetRecvTimeout(UartInstPtr, 8);
and three times after
Status = UartIntrInit(&InterruptController, &UartPs, UART_DEVICE_ID, UART_INT_IRQ_ID);
in the main function.
I reset the RXUART of the zynq, but doesn't help.
 

It compiles successfully and programs successfully, but what ever i sent in UART, no reply from the FPGA
Do you know that a way to debug software code is to use breakpoints and stepping-in-to your code to see what happening? Have you tried that?

I am not in to firmware development, but those are the basics of debugging as far as I know.

You have the hardware setup, we don't. So it is you who has to debug step by step.
 

Do you know that a way to debug software code is to use breakpoints and stepping-in-to your code to see what happening? Have you tried that?

I am not in to firmware development, but those are the basics of debugging as far as I know.

You have the hardware setup, we don't. So it is you who has to debug step by step.
I dig into the code more and it looks the code doesn't have issue. The problem should be in the block design or hardware. I want to use MIO24 and MIO25 (with no extra PL hardware) as RX and TX of the UART. Therefore I didn't use AXI UART IPs.
You can see my block design in the picture. Also I didn't activate Fabric interrupts (I assume no interrupt is coming from PL to PS).
My hardware is correct?

1.jpg
 

@aminpix
The problem should be in the block design or hardware. I want to use MIO24 and MIO25 (with no extra PL hardware) as RX and TX of the UART. Therefore I didn't use AXI UART IPs.
Are you sure the Zynq block (or your design) contains dedicated hardware that can handle UART traffic at the front end and convert them to parallel data which the C code running on Zynq can handle?
If not you need to come up with the front end UART hardware first and make sure it is functioning correctly before you do firmware development for it.
 

Solution
Hello,
I am trying to develop a simple UART interrupt code based on PS on Zynq. The plan is when the Zynq receives any character from RX_UART, take it and send it back to the TX_UART line.
It has to be with interrupt.
It looks very simple buy almost weeks I cant find solution for it.
Anyone can help me! This code doesn't do anything!
Here is my code.


C:
#include <stdio.h>
 #include "xparameters.h"
 #include "xil_printf.h"
 #include "xuartps.h"
 #include "xscugic.h"

[B] #define UART_DEVICE_ID        XPAR_XUARTPS_0_DEVICE_ID[/B]
 #define INTC_DEVICE_ID        XPAR_SCUGIC_SINGLE_DEVICE_ID
[B] #define UART_INT_IRQ_ID        XPAR_XUARTPS_1_INTR[/B]

 #define RECV_BUFFER_SIZE    3

XUartPs UartPs    ;            /* Instance of the UART Device */
static XScuGic InterruptController;    /* Instance of the Interrupt Controller */

int UartIntrInit(XScuGic *IntcInstPtr, XUartPs *UartInstPtr, u16 DeviceId, u16 UartIntrId);
static int SetupInterruptSystem(XScuGic *IntcInstancePtr, XUartPs *UartInstancePtr, u16 UartIntrId);
void UARTHandler(void *CallBackRef, u32 Event, unsigned int EventData);
static u8 RecvBuffer[RECV_BUFFER_SIZE];    /* Buffer for Receiving Data */


int main(void)
{
    int Status;
    Status = UartIntrInit(&InterruptController, &UartPs, UART_DEVICE_ID, UART_INT_IRQ_ID);
    if (Status != XST_SUCCESS)
    {
        xil_printf("UART Interrupt Example Test Failed\r\n");
        return XST_FAILURE;
    }


    while(1);

    return 0;
}




int UartIntrInit(XScuGic *IntcInstPtr, XUartPs *UartInstPtr, u16 DeviceId, u16 UartIntrId)
{
    int Status;
    XUartPs_Config *Config;
    u32 IntrMask;

    /*
     * 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;
    }

    Status = XUartPs_CfgInitialize(UartInstPtr, Config, Config->BaseAddress);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    /* Check hardware build */
    Status = XUartPs_SelfTest(UartInstPtr);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    /*
     * Connect the UART to the interrupt subsystem such that interrupts
     * can occur. This function is application specific.
     */
    Status = SetupInterruptSystem(IntcInstPtr, UartInstPtr, UartIntrId);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    /*
     * Setup the handlers for the UART that will be called from the
     * interrupt context when data has been sent and received, specify
     * a pointer to the UART driver instance as the callback reference
     * so the handlers are able to access the instance data
     */
    XUartPs_SetHandler(UartInstPtr, (XUartPs_Handler)UARTHandler, UartInstPtr);

    /*
     * Enable the interrupt of the UART so interrupts will occur, setup
     * a local loopback so data that is sent will be received.
     */
    IntrMask =
        XUARTPS_IXR_TOUT | XUARTPS_IXR_PARITY | XUARTPS_IXR_FRAMING |
        XUARTPS_IXR_OVER | XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXFULL |
        XUARTPS_IXR_RXOVR;

    XUartPs_SetInterruptMask(UartInstPtr, IntrMask);

    XUartPs_SetOperMode(UartInstPtr, XUARTPS_OPER_MODE_NORMAL);

    /*
     * Set the receiver timeout. If it is not set, and the last few bytes
     * of data do not trigger the over-water or full interrupt, the bytes
     * will not be received. By default it is disabled.
     *
     * The setting of 8 will timeout after 8 x 4 = 32 character times.
     * Increase the time out value if baud rate is high, decrease it if
     * baud rate is low.
     */
    XUartPs_SetRecvTimeout(UartInstPtr, 8);

    return XST_SUCCESS;
}

static int SetupInterruptSystem(XScuGic *IntcInstancePtr, XUartPs *UartInstancePtr, u16 UartIntrId)
{
    int Status;
    XScuGic_Config *IntcConfig; /* Config for interrupt controller */


    /* Initialize the interrupt controller driver */
    IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
    if (NULL == IntcConfig) {
        return XST_FAILURE;
    }

    Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
                    IntcConfig->CpuBaseAddress);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    /*
     * Connect the interrupt controller interrupt handler to the
     * hardware interrupt handling logic in the processor.
     */
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
                (Xil_ExceptionHandler) XScuGic_InterruptHandler,
                IntcInstancePtr);

    /*
     * 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 = XScuGic_Connect(IntcInstancePtr, UartIntrId,
                  (Xil_ExceptionHandler) XUartPs_InterruptHandler,
                  (void *) UartInstancePtr);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    /* Enable the interrupt for the device */
    XScuGic_Enable(IntcInstancePtr, UartIntrId);

    /* Enable interrupts */
         Xil_ExceptionEnable();

     return XST_SUCCESS;
}

void UARTHandler(void *CallBackRef, u32 Event, unsigned int EventData)
{
    XUartPs_Recv(&UartPs, RecvBuffer, RECV_BUFFER_SIZE);
    XUartPs_Send(&UartPs, RecvBuffer, 1);
    //make sure the TX buffer is empty
    while (XUartPs_IsSending(&UartPs));
}
Hello, I used your code to test with the UART0 of my system and it didn't work. Then I checked the params you defined at the beginning and realized the UART ID is 0 but the interrupt was set for UART1. I changed it to UART0 and it is perfectly working now:

Just change this:
#define UART_INT_IRQ_ID XPAR_XUARTPS_1_INTR
For this:
#define UART_INT_IRQ_ID XPAR_XUARTPS_0_INTR

Regards!
 
Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top