1. 程式人生 > >IMX6Q學習筆記———編寫LED驅動和測試程式以及相關管腳配置

IMX6Q學習筆記———編寫LED驅動和測試程式以及相關管腳配置

剛接觸IMX6Q不久,通過一個簡單的LED驅動和測試程式的編寫來了解管腳配置過程。

LED驅動

  • 找到以前編寫驅動的基本框架,如下:
static long xxx_ioctl(struct file *filp, unsigned int cmd,unsigned long arg)
      static struct file_operations xxx_dev_fops
static struct miscdevice xxx_dev
static int __init xxx_dev_init(void)
static void __exit xxx_dev_exit(void
) module_init(xxx_dev_init); module_exit(xxx_dev_exit); MODULE_LICENSE("GPL");
  • 找LED燈對應的管腳
    在底板尋找LED,然後在底板看不到LED燈
    在核心板找LED。如圖:

現在確認LED是連在GPIO_2這個引腳

  • 現在知道,它連著GPIO_2,搜GPIO_2再找在CPU裡的位置,如圖:
    現在確認LED是連在GPIO_2這個引腳

    現在確認LED是連在GPIO_2這個引腳,去文件(IMX6DQRM)查詢關於GPIO_2的功能模式,如圖:
    這裡寫圖片描述
    現在我們知道GPIO_2有以下5個功能,作為LED亮滅的功能選擇第三個功能,
    GPIO1_IO02,搜尋SW_PAD_CTL_PAD_GPIO02,結果如下:
    這裡寫圖片描述


    知道它的偏移量是604H
    知道偏移量是604,source insight開啟的檔案裡找到iomux-mx6q.h,搜尋604,如圖:
    這裡寫圖片描述
    現在知道這個IO功能,要使用時該怎麼定義了:_MX6Q_PAD_GPIO_2__GPIO_1_2
    新增管腳功能
    在檔案board-mxq.h中搜索X6Q_PAD_GPIO_2,看到:
    這裡寫圖片描述
    說明原本已經預設定義了中個GPIO_2這個管腳的功能是作為GPIO口來使用,所有我們不用再新增進去了,如果沒有則新增。
    檢視巨集定義
    在檔案board-mx6q.c中,我們可以看到,如圖:
    這裡寫圖片描述
    所以,後面我們編寫程式碼在申請管腳時,可以直接
    ret = gpio_request(SABRESD_USR_DEF_RED_LED, “LED”);
    或者你可以在你的驅動程式碼裡重新define:#define my_led IMX_GPIO_NR(1, 2)

編寫驅動程式

先編寫初始化程式碼:
這裡寫圖片描述
ret = gpio_request(my_led, “LED”);申請管腳
gpio_direction_output(my_led, 1);設定輸出方向
gpio_set_value(my_led, 1);設定初值為1,即是亮
ret = misc_register(&my_led_dev);註冊一個混雜裝置。
下面的IOCTL不寫了,依個人情況而定
附驅動程式碼:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <mach/gpio.h>

#define DEVICE_NAME "leds"
#define my_led  IMX_GPIO_NR(1, 2)





static long s5pv210_leds_ioctl(struct file *filp, unsigned int cmd,
        unsigned long arg)
{
    switch(cmd) {
        case 0:
        case 1:
            if (arg > 5) {
                return -EINVAL;
            }

            gpio_set_value(my_led, !cmd);
            //printk(DEVICE_NAME": %d %d\n", arg, cmd);
            break;

        default:
            return -EINVAL;
    }

    return 0;
}

static struct file_operations s5pv210_led_dev_fops = {
    .owner          = THIS_MODULE,
    .unlocked_ioctl = s5pv210_leds_ioctl,
};

static struct miscdevice s5pv210_led_dev = {
    .minor          = MISC_DYNAMIC_MINOR,
    .name           = DEVICE_NAME,
    .fops           = &s5pv210_led_dev_fops,
};

static int __init s5pv210_led_dev_init(void) {
    int ret;
    int i;
    gpio_free(my_led);

        ret = gpio_request(my_led, "LED");//第一個引數,為要申請的引腳,第二個為你要定義的名字
        if (ret) {

            return ret;
        }

        gpio_direction_output(my_led, 1);//設定是什麼裝置,第二為改引腳為輸入還是輸出
        gpio_set_value(my_led, 1);//初始化值


    ret = misc_register(&s5pv210_led_dev);

    printk(DEVICE_NAME"\tinitialized\n");

    return ret;
}

static void __exit s5pv210_led_dev_exit(void) {
    int i;


        gpio_free(my_led);


    misc_deregister(&s5pv210_led_dev);
}

module_init(s5pv210_led_dev_init);
module_exit(s5pv210_led_dev_exit);

MODULE_LICENSE("GPL");

附測試程式程式碼:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char **argv)
{
    int num, fd, cmd, I;
    fd = open("/dev/zsq_beep, O_RDWR);//選擇裝置名稱,和模式
    if(fd < 0)
        printf("can't open!\n");
    while(1)
    {
    scanf("%d",&num);
        switch(num)//選擇輸入的值,來控制IOCTL函式的CMD值

        case 0:
             ioctl(fd, 0, 4);//LED燈滅
             break;
        case 1:
             ioctl(fd, 1, 4);//LED燈亮
             break;
        default:
           for(i=0;i<num;i++)//LED燈閃爍num次
           {
              ioctl(fd, 0, 4);
              sleep(1);//間隔1秒
              ioctl(fa, 1, 4);
              sleep(1);//間隔1秒
           }   
              break; 
              return 0;
    }
    return 0;
}

這就是基本的過程。

本人原創文章,歡迎附帶本文連結轉載。