首页 > 技术文章 > Learn ZYNQ Programming(1)

shenerguang 2014-05-15 15:10 原文

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):

1.custom_ip ( only led exists)

2.custom_ip ( led with key)

3.custom_ip (led key and interrupts)

my driver package ( ready to download):

gpio_driver.tar.bz2

(1)Block Design:

Screenshot from 2014-05-15 14_56_47

(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\n\r");

    u32 btn_data;
    //XGpio
    //btn_data = Xil_In32(0x41200000);
      //      printf("data is xxx %d\n",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\n",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\n",cmd);
                        return 0;
                case 3:
                        //printk("debug3 cmd=%d\n",cmd);
                        status = ioread32(key_addr);
                        ret = __put_user(status, (u32 *)arg);
                        printk("key print = 0x%x\n",status);
                        return 0;
                default:
                        printk("default cmd=%d\n",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\n",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\n");
                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\n");
                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!\n");
                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!\n");
                exit(1);
        }

        printf("Please look at the leds\n");

        // 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\n",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

 Screenshot Screenshot from3Screenshot from2  Screenshot from4

(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:\n");
    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!\n");

    /*
     * 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\n",status);
			return 0;
		default:
			printk("default cmd=%d\n",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\n",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\n",key_addr+XGPIO_IER_OFFSET);
	//			  0x128
	val = ioread32(key_addr + XGPIO_IER_OFFSET);
	printk("debug2 val=%lx\n",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!\n");
	InterruptEnable();
	printk("interrupt Enabled!\n");
	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!\n");
	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\n");
		return ret;
	}

	gpio_major = ret;
	gpio_class = class_create(THIS_MODULE, "gpio_class");
	if(IS_ERR(gpio_class))
	{
		printk("gpio: failed in creating class\n");
		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!\n");
		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!\n");
	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

Screenshot from 2014-05-17 10_03_07

Part2: we can use commands below to see interrupts status.

cat /proc/interrupts
cat /proc/stat

Screenshot from 2014-05-19 14_41_27

推荐阅读