개발/Xilinx Zynq

axi-gpio uio

slayernoone 2017. 6. 2. 14:29
&axi_gpio_0 {
    compatible = "generic-uio";
};
axi_gpio_0: gpio@41200000 {
            #gpio-cells = <2>;
            compatible = "xlnx,xps-gpio-1.00.a";
            gpio-controller ;
            reg = <0x41200000 0x10000>;
            xlnx,all-inputs = <0x0>;
            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 = <0x18>;
            xlnx,gpio2-width = <0x20>;
            xlnx,interrupt-present = <0x0>;
            xlnx,is-dual = <0x0>;
            xlnx,tri-default = <0xFFFFFFFF>;
            xlnx,tri-default-2 = <0xFFFFFFFF>;
        };
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>

#define GPIO_MAP_SIZE 		0x10000
#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

volatile int counter;

inline void gpio_write(void *gpio_base, unsigned int offset, unsigned int value)
{
	*((volatile unsigned *)(gpio_base + offset)) = value;
}

inline unsigned int gpio_read(void *gpio_base, unsigned int offset)
{
	return *((volatile unsigned *)(gpio_base + offset));
}

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) {
		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 wait_for_interrupt(int fd, void *gpio_ptr)
{
	int pending = 0;
	int reenable = 1;
	unsigned int reg;


	// block on the file waiting for an interrupt */
	read(fd, (void *)&pending, sizeof(int));

	counter = counter + 1;


	// the interrupt occurred for the 1st GPIO channel so clear it
	reg = gpio_read(gpio_ptr, GPIO_IRQ_STATUS);
	if (reg)
		gpio_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, (void *)&reenable, sizeof(int));
	}

int main()
{
	int uio1_fd;
	void *ptr;
	int gpio_size;


	if ((uio1_fd = open("/dev/uio1", O_RDWR)) < 0)
		{
			perror("open uio1");
		}
		else{printf("uio1 opened \n");}

	gpio_size = get_memory_size("/sys/class/uio/uio1/maps/map0/size");

	ptr = mmap(NULL, gpio_size, PROT_READ|PROT_WRITE, MAP_SHARED, uio1_fd, 0);

	if (ptr == MAP_FAILED) {
			printf("Mmap call failure.\n");
			return -1;
		}
	gpio_write(ptr, GPIO_TRI_OFFSET, 0xFF); // GPIO Channel 1 input

	gpio_write(ptr, GPIO_GLOBAL_IRQ, 0x80000000); // GIER, 31. Bit
	gpio_write(ptr, GPIO_IRQ_CONTROL, 1);  // Channel 1 Interrupt enable

	//wait for interrupt
	while(1)
	{
		wait_for_interrupt(uio1_fd, ptr);
		printf("Interrupt: %d", counter);
		puts("");
	}


	munmap(ptr, gpio_size);

	return 0;
}