GPIO LED AND KEY:
part1:gpio leds and gpio btns combination. (include 1~4)
part2:use gpio btns interrupt to trigger led on and off. (include 5, 6, 7)
part3:some useful tips. (include 8)
my vivado & sdk projects ( ready to download):
my driver package ( ready to download):
(1)Block Design:
(2)Constraints:
set_property PACKAGE_PIN T22 [get_ports {leds_8bits_tri_o[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {leds_8bits_tri_o[0]}] set_property PACKAGE_PIN T21 [get_ports {leds_8bits_tri_o[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {leds_8bits_tri_o[1]}] set_property PACKAGE_PIN U22 [get_ports {leds_8bits_tri_o[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {leds_8bits_tri_o[2]}] set_property PACKAGE_PIN U21 [get_ports {leds_8bits_tri_o[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {leds_8bits_tri_o[3]}] set_property PACKAGE_PIN V22 [get_ports {leds_8bits_tri_o[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {leds_8bits_tri_o[4]}] set_property PACKAGE_PIN W22 [get_ports {leds_8bits_tri_o[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {leds_8bits_tri_o[5]}] set_property PACKAGE_PIN U19 [get_ports {leds_8bits_tri_o[6]}] set_property IOSTANDARD LVCMOS33 [get_ports {leds_8bits_tri_o[6]}] set_property PACKAGE_PIN U14 [get_ports {leds_8bits_tri_o[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {leds_8bits_tri_o[7]}] set_property PACKAGE_PIN P16 [get_ports {btns_5bits_tri_i[0]}] set_property IOSTANDARD LVCMOS25 [get_ports {btns_5bits_tri_i[0]}] set_property PACKAGE_PIN N15 [get_ports {btns_5bits_tri_i[2]}] set_property IOSTANDARD LVCMOS25 [get_ports {btns_5bits_tri_i[2]}] set_property PACKAGE_PIN T18 [get_ports {btns_5bits_tri_i[4]}] set_property IOSTANDARD LVCMOS25 [get_ports {btns_5bits_tri_i[4]}] set_property PACKAGE_PIN R18 [get_ports {btns_5bits_tri_i[3]}] set_property IOSTANDARD LVCMOS25 [get_ports {btns_5bits_tri_i[3]}] set_property PACKAGE_PIN R16 [get_ports {btns_5bits_tri_i[1]}] set_property IOSTANDARD LVCMOS25 [get_ports {btns_5bits_tri_i[1]}]
(3) Standalone Program
#include <stdio.h> #include "platform.h" #include "xil_io.h" #include "xgpio.h" #include "xparameters.h" //void print(char *str); int main() { init_platform(); print("Hello World "); u32 btn_data; //XGpio //btn_data = Xil_In32(0x41200000); // printf("data is xxx %d ",btn_data); Xil_Out32(0x41200000 , 0x08); sleep(1); //Xil_Out32(0x41200000 , 0x00); while(1){ //Xil_Out32(0x41210000 , 0x00000000); btn_data = Xil_In32(0x41210000); //if(btn_data & 0x01){ //Xil_Out32(0x41210000 , 0x01); sleep(1); printf("data is %ld ",btn_data); //} /*if(btn_data & 0x00000001) Xil_Out32(0x41200000 , 0x01); if(btn_data & 0x00000002) Xil_Out32(0x41200000 , 0x02); if(btn_data & 0x00000004) Xil_Out32(0x41200000 , 0x04); if(btn_data & 0x00000008) Xil_Out32(0x41200000 , 0x08); */ } //sleep(1); return 0; }
(4) Linux Driver:
#include <linux/module.h> #include <linux/version.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/device.h> #include <linux/types.h> #include <linux/ioctl.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/atomic.h> #include <linux/wait.h> #include <linux/cdev.h> #define DEVICE_NAME "gpio_dev" #define LED_PHY_ADDR 0x41200000 #define KEY_PHY_ADDR 0X41210000 /* #define ULTRASONIC_IOC_MAGIC 'Z' #define LED_SHUTDOWN _IOR(ULTRASONIC_IOC_MAGIC, 0, int) #define LED_OPEN _IOR(ULTRASONIC_IOC_MAGIC, 1, int) #define GET_KEY_STATUS _IOR(ULTRASONIC_IOC_MAGIC, 2, int) */ static unsigned long led_addr = 0; static unsigned long key_addr = 0; static struct class* gpio_class = NULL; static struct device* gpio_device = NULL; static int gpio_major = 0; //arg means the led number, cmd controls it on or off static ssize_t gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { //printk("fun(gpio_ioctl):"); u32 status = 0xff; int ret; switch(cmd){ case 0: case 1: //if(arg > 8) // return -EINVAL; status = ioread32(led_addr); if(0 == cmd) status &= ~(0x1 << arg); else if(1 == cmd) status |= (0x1 << arg); iowrite32(status,led_addr); //printk("debug1 cmd= %d ",cmd); return 0; case 3: //printk("debug3 cmd=%d ",cmd); status = ioread32(key_addr); ret = __put_user(status, (u32 *)arg); printk("key print = 0x%x ",status); return 0; default: printk("default cmd=%d ",cmd); return -EINVAL; } } /* static ssize_t key_read(struct file *file,u32 __user *buf, size_t count, loff_t *ppos) { u32 data; int ret = 0; data = ioread32(key_addr); ret = __put_user(data, (u32 *)buf); printk("key print = 0x%x ",data); return (sizeof(u32)); } */ static struct file_operations gpio_fops = { .owner = THIS_MODULE, .unlocked_ioctl = gpio_ioctl, // .read = key_read, }; static int __init gpio_init(void) { int ret; printk("debug0"); ret = register_chrdev(0,DEVICE_NAME, &gpio_fops); if(ret < 0) { printk("gpio: can't get major number "); return ret; } printk("debug1"); gpio_major = ret; gpio_class = class_create(THIS_MODULE, "gpio_class"); if(IS_ERR(gpio_class)) { printk("gpio: failed in creating class "); unregister_chrdev(gpio_major, DEVICE_NAME); return -1; } printk("debug2"); gpio_device = device_create(gpio_class,NULL,MKDEV(gpio_major,0),NULL,DEVICE_NAME); if(IS_ERR(gpio_device)) { printk("gpio: failed in creating device! "); unregister_chrdev(gpio_major, DEVICE_NAME); class_unregister(gpio_class); class_destroy(gpio_class); return -1; } led_addr = (unsigned long) ioremap(LED_PHY_ADDR, sizeof(u32)); key_addr = (unsigned long) ioremap(KEY_PHY_ADDR, sizeof(u32)); /* iowrite32(0x00,led_addr); mdelay(100); iowrite32(0xff,led_addr); */ printk("gpio installed successfully!"); return 0; } static void __exit gpio_exit(void) { /* iowrite32(0x00,led_addr); mdelay(100); iowrite32(0xff,led_addr); */ device_destroy(gpio_class,MKDEV(gpio_major, 0)); class_unregister(gpio_class); class_destroy(gpio_class); unregister_chrdev(gpio_major,DEVICE_NAME); printk("gpio module exit!"); } module_init(gpio_init); module_exit(gpio_exit); MODULE_AUTHOR("seg"); MODULE_LICENSE("GPL");
(5) Linux App:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/select.h> #include <sys/time.h> static int led_fd; int main(void) { int i; // open device led_fd = open("/dev/gpio_dev", 0); if (led_fd < 0) { perror("open device gpio_dev error! "); exit(1); } printf("Please look at the leds "); // led all off ioctl(led_fd, 1, 0); ioctl(led_fd, 1, 1); ioctl(led_fd, 1, 2); ioctl(led_fd, 1, 3); ioctl(led_fd, 1, 4); ioctl(led_fd, 1, 5); ioctl(led_fd, 1, 6); ioctl(led_fd, 1, 7); for(i=0;i<2;i++) { ioctl(led_fd, 0, 0); usleep(50000); ioctl(led_fd, 0, 1); usleep(50000); ioctl(led_fd, 0, 2); usleep(50000); ioctl(led_fd, 0, 3); usleep(50000); ioctl(led_fd, 0, 4); usleep(50000); ioctl(led_fd, 0, 5); usleep(50000); ioctl(led_fd, 0, 6); usleep(50000); ioctl(led_fd, 0, 7); usleep(50000); // led off one by one ioctl(led_fd, 1, 0); usleep(50000); ioctl(led_fd, 1, 1); usleep(50000); ioctl(led_fd, 1, 2); usleep(50000); ioctl(led_fd, 1, 3); usleep(50000); ioctl(led_fd, 1, 4); usleep(50000); ioctl(led_fd, 1, 5); usleep(50000); ioctl(led_fd, 1, 6); usleep(50000); ioctl(led_fd, 1, 7); usleep(50000); } while(1) { unsigned int key = 0; //printf("original = %d , %x",key,key); ioctl(led_fd, 3, &key); printf("key = %d ",key); for(i=0;i<8;i++) ioctl(led_fd,0,i); if(key & (0x01<<0)) ioctl(led_fd, 1, 0); else if(key & (0x01<<1)) ioctl(led_fd, 1, 1); else if(key & (0x01<<2)) ioctl(led_fd, 1, 2); else if(key & (0x01<<3)) ioctl(led_fd, 1, 3); else if(key & (0x01<<4)) ioctl(led_fd, 1, 4); else{} usleep(1000000); } close(led_fd); return 0; }
(5)Hardware Interrupt Vivado Project
(6)Hardware Interrupt SDK Project
#include "xparameters.h" #include "xgpio.h" #include "xil_exception.h" #include "xscugic.h" /************************** Constant Definitions *****************************/ #define LED_ADDR 0x41200000 #define KEY_ADDR 0X41210000 #define GPIO_DEVICE_ID XPAR_AXI_GPIO_1_DEVICE_ID #define INTC_GPIO_INTERRUPT_ID XPAR_FABRIC_GPIO_1_VEC_ID #define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID #define INTC XScuGic #define INTC_HANDLER XScuGic_InterruptHandler #define GPIO_ALL_LEDS 0xFFFF #define GPIO_ALL_BUTTONS 0xFFFF /* * The following constants define the GPIO channel that is used for the buttons * and the LEDs. They allow the channels to be reversed easily. */ #define BUTTON_CHANNEL 1 /* Channel 1 of the GPIO Device */ #define LED_CHANNEL 2 /* Channel 2 of the GPIO Device */ #define BUTTON_INTERRUPT XGPIO_IR_CH1_MASK /* Channel 1 Interrupt Mask */ /* * The following constant is used to wait after an LED is turned on to make * sure that it is visible to the human eye. This constant might need to be * tuned for faster or slower processor speeds. */ #define LED_DELAY 1000000 /**************************** Type Definitions *******************************/ typedef struct { u32 ButtonMask; /* The bit corresponding to the button */ u32 LedMask; /* The bit corresponding to the LED */ } MapButtonTable; /************************** Function Prototypes ******************************/ int MapButton2Led(u32 Buttons, u32 *ButtonFoundPtr); void SequenceLeds(); void GpioIsr(void *InstancePtr); int SetupInterruptSystem(); /************************** Variable Definitions *****************************/ static XGpio Gpio; /* The Instance of the GPIO Driver */ static INTC Intc; /* The Instance of the Interrupt Controller Driver */ volatile int InterruptCount; /* Count of interrupts that have occured */ int main(void) { int Status; SequenceLeds(); /* Initialize the GPIO driver. If an error occurs then exit */ Status = XGpio_Initialize(&Gpio, GPIO_DEVICE_ID); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Perform a self-test on the GPIO. This is a minimal test and only * verifies that there is not any bus error when reading the data * register */ XGpio_SelfTest(&Gpio); /* * Setup the interrupts such that interrupt processing can occur. If * an error occurs then exit */ Status = SetupInterruptSystem(); if (Status != XST_SUCCESS) { return XST_FAILURE; } printf("in the loop: "); while (1) { } return XST_SUCCESS; } void SequenceLeds() { u32 led = 0x01; u32 out = 0x0; int i; for (i = 0; i < 8; i++) { out = led << i; Xil_Out32(LED_ADDR, out); sleep(1); } Xil_Out32(LED_ADDR, 0x00); } /********************************************************************************************************************************************************/ void GpioIsr(void *InstancePtr) { XGpio *GpioPtr = (XGpio *)InstancePtr; u32 Led; u32 LedState; u32 Buttons; u32 ButtonFound; u32 ButtonsChanged = 0; static u32 PreviousButtons; printf("Enter GpioIsr! "); /* * Disable the interrupt */ XGpio_InterruptDisable(GpioPtr, BUTTON_INTERRUPT); /* Keep track of the number of interrupts that occur */ InterruptCount++; Xil_Out32(LED_ADDR,0x00); ButtonsChanged = Xil_In32(KEY_ADDR); printf("BUTTON:%d;",ButtonsChanged); //while (ButtonsChanged != 0) { /* * Determine which button changed state and then get * the current state of the associated LED */ printf("SET_LED=%d",ButtonsChanged); Xil_Out32(LED_ADDR,ButtonsChanged); // LedState = Xil_In32(LED_ADDR) & Led; /* * Clear the button that is being processed so that it is * done and others can be handled also */ // ButtonsChanged &= ~ButtonFound; /* Toggle the state of the LED */ // if (LedState) { // Xil_Out32(LED_ADDR,LedState & ~Led); // } else { // Xil_Out32(LED_ADDR,Led); // } // } /* Clear the interrupt such that it is no longer pending in the GPIO */ (void)XGpio_InterruptClear(GpioPtr, BUTTON_INTERRUPT); /* * Enable the interrupt */ XGpio_InterruptEnable(GpioPtr, BUTTON_INTERRUPT); } int SetupInterruptSystem() { int Result; INTC *IntcInstancePtr = &Intc; XScuGic_Config *IntcConfig; /* * Initialize the interrupt controller driver so that it is ready to * use. */ IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); if (NULL == IntcConfig) { return XST_FAILURE; } Result = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress); if (Result != XST_SUCCESS) { return XST_FAILURE; } XScuGic_SetPriorityTriggerType(IntcInstancePtr, INTC_GPIO_INTERRUPT_ID, 0xA0, 0x3); /* * Connect the interrupt handler that will be called when an * interrupt occurs for the device. */ Result = XScuGic_Connect(IntcInstancePtr, INTC_GPIO_INTERRUPT_ID, (Xil_ExceptionHandler)GpioIsr, &Gpio); if (Result != XST_SUCCESS) { return Result; } printf("XST_SUCCESS"); /* * Enable the interrupt for the GPIO device. */ XScuGic_Enable(IntcInstancePtr, INTC_GPIO_INTERRUPT_ID); /* * Enable the GPIO channel interrupts so that push button can be * detected and enable interrupts for the GPIO device */ XGpio_InterruptEnable(&Gpio, BUTTON_INTERRUPT); XGpio_InterruptGlobalEnable(&Gpio); /* * Initialize the exception table and register the interrupt * controller handler with the exception table */ Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)INTC_HANDLER, IntcInstancePtr); /* Enable non-critical exceptions */ Xil_ExceptionEnable(); return XST_SUCCESS; }
(7) Interrupt driver edition
#include <linux/module.h> #include <linux/version.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/device.h> #include <linux/types.h> #include <linux/ioctl.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/atomic.h> #include <linux/wait.h> #include <linux/cdev.h> #include <linux/interrupt.h> #include <asm/signal.h> #include <linux/gpio.h> #include <linux/irq.h> #define DEVICE_NAME "gpio_dev" #define GPIO_BASEADDR 0x41200000 #define LED_PHY_ADDR 0x41200000 #define KEY_PHY_ADDR 0X41210000 #define INTERRUPT_ID 91 #define IRQ_MASK 0x1 #define IRQ_DEVICE_ID 0 #define XGPIO_GIE_OFFSET 0x11C /**< Glogal interrupt enable register */ #define XGPIO_ISR_OFFSET 0x120 /**< Interrupt status register */ #define XGPIO_IER_OFFSET 0x128 /**< Interrupt enable register */ #define XGPIO_GIE_GINTR_ENABLE_MASK 0x80000000 //#define is_keypad_irq() (!(inb(IRQ_STAT_ADDR) & IRQ_MASK)) //#define disable_irq() (iowrite32(IRQ_DIST_BASEADDR+XGPIO_IER_OFFSET,ioread32(IRQ_DIST_BASEADDR+XGPIO_IER_OFFSET) & ~IRQ_MASK)) //#define enable_irq() (iowrite32(IRQ_DIST_BASEADDR+XGPIO_IER_OFFSET,ioread32(IRQ_DIST_BASEADDR+XGPIO_IER_OFFSET) | IRQ_MASK)) //#define clear_irq() (iowrite32(KEY_PHY_ADDR+XGPIO_IER_OFFSET,ioread32(KEY_PHY_ADDR+XGPIO_IER_OFFSET) & IRQ_MASK)) static unsigned long led_addr = 0; static unsigned long key_addr = 0; static struct class* gpio_class = NULL; static struct device* gpio_device = NULL; static int gpio_major = 0; typedef struct { dev_t dev_no; u32 IsReady; int InterruptPresent; u32 BaseAddress; // spinlock_t lock; atomic_t lock; } KEY_DEV; static KEY_DEV keydev; //arg means the led number, cmd controls it on or off static ssize_t gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { //printk("fun(gpio_ioctl):"); u32 status = 0xff; int ret; switch(cmd){ case 0: case 1: //if(arg > 8) // return -EINVAL; status = ioread32(led_addr); if(0 == cmd) status &= ~(0x1 << arg); else if(1 == cmd) status |= (0x1 << arg); iowrite32(status,led_addr); return 0; case 3: status = ioread32(key_addr); ret = __put_user(status, (u32 *)arg); printk("key print = 0x%x ",status); return 0; default: printk("default cmd=%d ",cmd); return -EINVAL; } } static void InterruptClear() { u32 val; val = ioread32(key_addr + XGPIO_ISR_OFFSET); iowrite32(val & IRQ_MASK,key_addr + XGPIO_ISR_OFFSET); printk("int cleared"); } static irqreturn_t key_interrupt(int irq, void *dev_id, struct pt_regs *regs) { u32 status = 0xff; //disable_irq(INTERRUPT_ID); // disable_irq(); status = ioread32(key_addr); iowrite32(status,led_addr); printk("key print = 0x%x ",status); // clear_irq(); //enable_irq(INTERRUPT_ID); // enable_irq(); InterruptClear(); return 0; } static void InterruptEnable() { //from stand alone program //XGpio_InterruptEnable(&Gpio, BUTTON_INTERRUPT); //XGpio_InterruptGlobalEnable(&Gpio); u32 val; printk("debug1 read addr = %lx ",key_addr+XGPIO_IER_OFFSET); // 0x128 val = ioread32(key_addr + XGPIO_IER_OFFSET); printk("debug2 val=%lx ",val); // 0x128 0x1 iowrite32(val | IRQ_MASK,key_addr + XGPIO_IER_OFFSET); printk("debug3 "); // 0x11c 0x80000000 iowrite32(XGPIO_GIE_GINTR_ENABLE_MASK,key_addr + XGPIO_GIE_OFFSET); } static int key_open(struct inode *inode, struct file *filp) { int ret; printk("open! "); InterruptEnable(); printk("interrupt Enabled! "); ret = request_irq(INTERRUPT_ID, key_interrupt,IRQF_TRIGGER_RISING, DEVICE_NAME, &keydev); if(ret) { printk("could not register interrupt!"); return ret; } //disable_irq(INTERRUPT_ID); //enable_irq(INTERRUPT_ID); // enable_irq(); printk("register interrupt success! "); return 0; } static struct file_operations gpio_fops = { .owner = THIS_MODULE, .unlocked_ioctl = gpio_ioctl, .open = key_open, // .read = key_read, }; static int __init gpio_init(void) { int ret; ret = register_chrdev(0,DEVICE_NAME, &gpio_fops); if(ret < 0) { printk("gpio: can't get major number "); return ret; } gpio_major = ret; gpio_class = class_create(THIS_MODULE, "gpio_class"); if(IS_ERR(gpio_class)) { printk("gpio: failed in creating class "); unregister_chrdev(gpio_major, DEVICE_NAME); return -1; } gpio_device = device_create(gpio_class,NULL,MKDEV(gpio_major,0),NULL,DEVICE_NAME); if(IS_ERR(gpio_device)) { printk("gpio: failed in creating device! "); unregister_chrdev(gpio_major, DEVICE_NAME); class_unregister(gpio_class); class_destroy(gpio_class); return -1; } led_addr = (unsigned long) ioremap(LED_PHY_ADDR, sizeof(u32)); key_addr = (unsigned long) ioremap(KEY_PHY_ADDR, sizeof(u32)); /* iowrite32(0x00,led_addr); mdelay(100); iowrite32(0xff,led_addr); */ printk("gpio installed successfully! "); return 0; } static void __exit gpio_exit(void) { /* iowrite32(0x00,led_addr); mdelay(100); iowrite32(0xff,led_addr); */ device_destroy(gpio_class,MKDEV(gpio_major, 0)); class_unregister(gpio_class); class_destroy(gpio_class); unregister_chrdev(gpio_major,DEVICE_NAME); printk("gpio module exit!"); } module_init(gpio_init); module_exit(gpio_exit); MODULE_AUTHOR("seg"); MODULE_LICENSE("GPL");
(8) Useful Tips for write linux driver
Part1: we can use commands below to test gpio led.
cd /sys/class/gpio/ echo 248 > ./export cd gpio248/ echo "out" > ./direction echo 1 > ./value
Part2: we can use commands below to see interrupts status.
cat /proc/interrupts cat /proc/stat