Jump to content
  • 0

How to detect and handle UIO interrupt.


Saad Zia

Question

Dear Experts

I need help regarding interrupt handling using UIO. I am using Vivado 2015.4 and Petalinux 2015.4. The board used is Zedboard.

I made the following vivado project attached as image. The interrupts from AXI and Fabric (PL-PS) are enabled. 

Afterwards i was able to export it as UIO and it shows in /dev as uio0.

Now I implemented the following code by following this link: 

 

My code is as follows: 
 

/* 
 * File:   main.c
 * Author: fss
 *
 * Created on August 23, 2017, 12:35 PM
 */
#include <sys/mman.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <poll.h>
#include <fcntl.h>
#include <errno.h>

#define GPIO_DATA_OFFSET 0x00 
#define GPIO_TRI_OFFSET 0x04 
#define GPIO_DATA2_OFFSET 0x08 
#define GPIO_TRI2_OFFSET 0x0C 
#define GPIO_GLOBAL_IRQ 0x11C 
#define GPIO_IRQ_CONTROL 0x128 
#define GPIO_IRQ_STATUS 0x120 

unsigned int get_memory_size(char *sysfs_path_file)

    FILE *size_fp; 
    unsigned int size; 
    // open the file that describes the memory range size that is based on the 
    // reg property of the node in the device tree 
    size_fp = fopen(sysfs_path_file, "r"); 
    if (size_fp == NULL) { 
        printf("unable to open the uio size file\n"); 
        exit(-1); 
    } 
    // get the size which is an ASCII string such as 0xXXXXXXXX and then be stop 
    // using the file 
    fscanf(size_fp, "0x%08X", &size); 
    fclose(size_fp); 
    return size; 


void reg_write(void *reg_base, unsigned long offset, unsigned long value) 

    *((volatile unsigned long *)(reg_base + offset)) = value; 

unsigned long reg_read(void *reg_base, unsigned long offset) 

    return *((volatile unsigned long *)(reg_base + offset)); 

uint8_t wait_for_interrupt(int fd_int, void *gpio_ptr) 

    static unsigned int count = 0, bntd_flag = 0, bntu_flag = 0; 
        int flag_end=0;
    int pending = 0; 
    int reenable = 1; 
    unsigned int reg; 
    unsigned int value; 
    // block (timeout for poll) on the file waiting for an interrupt 
    struct pollfd fds = {
        .fd = fd_int,
        .events = POLLIN,
    };

    int ret = poll(&fds, 1, 100);
    printf("ret is : %d\n", ret);
    if (ret >= 1) {
        read(fd_int, (void *)&reenable, sizeof(int));   // &reenable -> &pending
        // channel 1 reading 
        value = reg_read(gpio_ptr, GPIO_DATA_OFFSET); 
        if ((value & 0x00000001) != 0) { 
                    printf("Interrupt recieved");
        } 
    
        count++; 
        usleep(50000); // anti rebond 
        if(count == 10) 
            flag_end = 1; 
        // the interrupt occurred for the 1st GPIO channel so clear it 
        reg = reg_read(gpio_ptr, GPIO_IRQ_STATUS); 
        if (reg != 0) 
            reg_write(gpio_ptr, GPIO_IRQ_STATUS, 1);  
        // re-enable the interrupt in the interrupt controller thru the 
        // the UIO subsystem now that it's been handled 
        write(fd_int, (void *)&reenable, sizeof(int));
    } 
    return ret;


int main(void)
{
    
    int fd = open("/dev/uio0", O_RDWR);
    if (fd < 0) {
        perror("open");
        exit(EXIT_FAILURE);
    }
    int gpio_size = get_memory_size("/sys/class/uio/uio0/maps/map0/size");
    /* mmap the UIO devices */
    void * ptr_axi_gpio = mmap(NULL, gpio_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    while (1) 
    {
       wait_for_interrupt(fd,ptr_axi_gpio); 
    }

    close(fd);
    exit(EXIT_SUCCESS);
}

 

But the issue is that this code is not catching the interrupt. Kindly help me in this. Any suggestion/links are more than welcomed

Regards

forum.PNG

Link to comment
Share on other sites

16 answers to this question

Recommended Posts

Looking at your code again, it doesn't look like you ever initialize your gpio controller to trigger interrupts. When you load the UIO driver for a GPIO device instead of the GPIO driver, it doesn't know anything about how to properly initialize the controller as you need it. You have to handle this by accessing the mmaped physical registers (ptr_axi_gpio) to configure the TRIS register for the buttons to make them inputs, and then enable the proper channel interrupt and global interrupts. For information on how to do this, see the AXI_GPIO product guide from xilinx.

https://www.xilinx.com/support/documentation/ip_documentation/axi_gpio/v2_0/pg144-axi-gpio.pdf

Note that it will also be up to you to properly reset the Interrupt status register once an interrupt has been detected.

Link to comment
Share on other sites

hi @Saad Zia,

which is the third argument that i should select...

On 12/09/2017 at 1:15 PM, Saad Zia said:

reg_write(ptr_axi_gpio,GPIO_TRI_OFFSET ,0x1F);
    reg_write(ptr_axi_gpio,GPIO_IRQ_CONTROL,0x1);
    reg_write(ptr_axi_gpio,GPIO_GLOBAL_IRQ,0x1);

this is the details from the link u forwarded.

	// channel1 = input 
	reg_write(ptr_axi_gpio, GPIO_TRI_OFFSET, 0xffffffff); 
	// Global interrupt enable, Bit 31 = 1 
	reg_write(ptr_axi_gpio, GPIO_GLOBAL_IRQ, 0x80000000); 
	// Channel 1 Interrupt enable 
	reg_write(ptr_axi_gpio, GPIO_IRQ_CONTROL, 1); 
	// enable the interrupt controller thru the UIO subsystem 
	write(fd_int, (void *)&reenable, sizeof(int)); 
Link to comment
Share on other sites

I changed my code in the following manner: 

/* 
 * File:   main.c
 * Author: fss
 *
 * Created on August 23, 2017, 12:35 PM
 */
#include <sys/mman.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <poll.h>
#include <fcntl.h>
#include <errno.h>

#define GPIO_DATA_OFFSET 0x00 
#define GPIO_TRI_OFFSET 0x04 
#define GPIO_DATA2_OFFSET 0x08 
#define GPIO_TRI2_OFFSET 0x0C 
#define GPIO_GLOBAL_IRQ 0x11C 
#define GPIO_IRQ_CONTROL 0x128 
#define GPIO_IRQ_STATUS 0x120 

unsigned int get_memory_size(char *sysfs_path_file)

    FILE *size_fp; 
    unsigned int size; 
    // open the file that describes the memory range size that is based on the 
    // reg property of the node in the device tree 
    size_fp = fopen(sysfs_path_file, "r"); 
    if (size_fp == NULL) { 
        printf("unable to open the uio size file\n"); 
        exit(-1); 
    } 
    // get the size which is an ASCII string such as 0xXXXXXXXX and then be stop 
    // using the file 
    fscanf(size_fp, "0x%08X", &size); 
    fclose(size_fp); 
    return size; 


void reg_write(void *reg_base, unsigned long offset, unsigned long value) 

    *((volatile unsigned long *)(reg_base + offset)) = value; 

unsigned long reg_read(void *reg_base, unsigned long offset) 

    return *((volatile unsigned long *)(reg_base + offset)); 

uint8_t wait_for_interrupt(int fd_int, void *gpio_ptr) 

    static unsigned int count = 0, bntd_flag = 0, bntu_flag = 0; 
        int flag_end=0;
    int pending = 0; 
    int reenable = 1; 
    unsigned int reg; 
    unsigned int value; 
    // block (timeout for poll) on the file waiting for an interrupt 
    struct pollfd fds = {
        .fd = fd_int,
        .events = POLLIN,
    };

    int ret = poll(&fds, 1, 100);
    printf("ret is : %d\n", ret);
    if (ret >= 1) {
        read(fd_int, (void *)&reenable, sizeof(int));   // &reenable -> &pending
        // channel 1 reading 
        value = reg_read(gpio_ptr, GPIO_DATA_OFFSET); 
        if ((value & 0x00000001) != 0) { 
                    printf("Interrupt recieved");
        } 
    
        count++; 
        usleep(50000); // anti rebond 
        if(count == 10) 
            flag_end = 1; 
        // the interrupt occurred for the 1st GPIO channel so clear it 
        reg = reg_read(gpio_ptr, GPIO_IRQ_STATUS); 
        if (reg != 0) 
            reg_write(gpio_ptr, GPIO_IRQ_STATUS, 1);  
        // re-enable the interrupt in the interrupt controller thru the 
        // the UIO subsystem now that it's been handled 
        write(fd_int, (void *)&reenable, sizeof(int));
    } 
    return ret;


int main(void)
{
    
    int fd = open("/dev/uio0", O_RDWR);
    if (fd < 0) {
        perror("open");
        exit(EXIT_FAILURE);
    }
    int gpio_size = get_memory_size("/sys/class/uio/uio0/maps/map0/size");
    /* mmap the UIO devices */
    void * ptr_axi_gpio = mmap(NULL, gpio_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    reg_write(ptr_axi_gpio,GPIO_TRI_OFFSET ,0x1F);
    reg_write(ptr_axi_gpio,GPIO_IRQ_CONTROL,0x1);
    reg_write(ptr_axi_gpio,GPIO_GLOBAL_IRQ,0x1);

    while (1) 
    {
       wait_for_interrupt(fd,ptr_axi_gpio); 
    }

    close(fd);
    exit(EXIT_SUCCESS);
}

*changes= bold and underlined.

But it still won't catch any interrupt. 

Link to comment
Share on other sites

Following is my device tree node.

 

/*
 * CAUTION: This file is automatically generated by Xilinx.
 * Version: HSI 2015.4
 * Today is: Wed Aug 30 14:03:34 2017
*/


/ {
    amba_pl: amba_pl {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "simple-bus";
        ranges ;
        axi_gpio_0: gpio@41200000 {
            #gpio-cells = <2>;
            compatible = "generic-uio";
            gpio-controller ;
            interrupt-parent = <&intc>;
            interrupts = <0 29 4>;
            reg = <0x41200000 0x10000>;
            xlnx,all-inputs = <0x1>;
            xlnx,all-inputs-2 = <0x0>;
            xlnx,all-outputs = <0x0>;
            xlnx,all-outputs-2 = <0x0>;
            xlnx,dout-default = <0x00000000>;
            xlnx,dout-default-2 = <0x00000000>;
            xlnx,gpio-width = <0x5>;
            xlnx,gpio2-width = <0x20>;
            xlnx,interrupt-present = <0x1>;
            xlnx,is-dual = <0x0>;
            xlnx,tri-default = <0xFFFFFFFF>;
            xlnx,tri-default-2 = <0xFFFFFFFF>;
        };
    };
};

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...