溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

全志A33 linux led驅(qū)動編程(附實測參考代碼)

發(fā)布時間:2020-03-03 02:52:36 來源:網(wǎng)絡(luò) 閱讀:902 作者:sinlinx123 欄目:系統(tǒng)運(yùn)維

開發(fā)平臺

全志A33 linux led驅(qū)動編程(附實測參考代碼)

開發(fā)平臺

*  芯靈思SinlinxA33開發(fā)板

淘寶店鋪: https://sinlinx.taobao.com/

全志A33 linux led驅(qū)動編程(附實測參考代碼)

嵌入式linux 開發(fā)板交流 QQ:641395230

#實驗原理
全志A33 linux led驅(qū)動編程(附實測參考代碼)

在芯靈思開發(fā)板上,沒有l(wèi)ed燈模塊,只能通過引腳電平觀察: 這里我選擇LS-INT引腳。

全志A33一共有10組IO口,每組IO有9個相關(guān)功能控制器,LS-INT屬于PB7,相關(guān)寄存器如圖

本次實驗只用到這兩個寄存器,在程序中命名為gpio_con,gpio_dat ,設(shè)置為輸出引腳。

  • 1)注冊 class_register(class) 將class注冊到內(nèi)核中。調(diào)用前,必須手動分配class內(nèi)存;調(diào)用后必須設(shè)置class的name等參數(shù)注冊 class_create(owner,name) 創(chuàng)建class并將class注冊到內(nèi)核中。返回值為class結(jié)構(gòu)體指針。注銷 void class_unregister(struct class cls) 注銷class,與class_register()配對使用。注銷void class_destroy(struct class cls) 注銷class,與class_create()配對使用內(nèi)核中定義了struct class結(jié)構(gòu)體顧名思義,一個struct class結(jié)構(gòu)體類型變量對應(yīng)一個類,內(nèi)核同時提供了class_create(…)函數(shù),可以用它來創(chuàng)建一個類,這個類存放于sysfs下面,一旦創(chuàng)建好了這個類,再調(diào)用device_create(…)函數(shù)來在/dev目錄下創(chuàng)建相應(yīng)的設(shè)備節(jié)點(diǎn)。這樣,加載模塊的時候,用戶空間中的udev會自動響應(yīng)device_create(…)函數(shù),去/sysfs下尋找對應(yīng)的類從而創(chuàng)建設(shè)備節(jié)點(diǎn).
  • 2)void ioremap(unsigned long phys_addr , unsigned long size , unsigned long flags)用mmap映射一個設(shè)備意味著使用戶空間的一段地址關(guān)聯(lián)到設(shè)備內(nèi)存上,這使得只要程序在分配的地址范圍內(nèi)進(jìn)行讀取或?qū)懭雽嶋H上就是對設(shè)備的訪問。解除映射void iounmap(void addr)//取消ioremap所映射的IO地址
  • 3)register_chrdev(unsigned int major, const char name,const struct file_operations fops);
    但其實這個函數(shù)是linux版本2.4之前的注冊方式,它的原理是:
    • (1)確定一個主設(shè)備號,如果major=0,則會自動分配設(shè)備號
    • (2)構(gòu)造一個file_operations結(jié)構(gòu)體, 然后放在chrdevs數(shù)組中
    • (3)注冊:register_chrdev,cat /proc/devices查看內(nèi)核中已經(jīng)注冊過的字符設(shè)備驅(qū)動(和塊設(shè)備驅(qū)動),注意這里并不是驅(qū)動文件設(shè)備節(jié)點(diǎn)!
  • 4) Linux使用file_operations結(jié)構(gòu)訪問驅(qū)動程序的函數(shù),這個結(jié)構(gòu)的每一個成員的名字都對應(yīng)著一個調(diào)用
  • 5) class_device_create() 調(diào)用class_create為該設(shè)備創(chuàng)建一個class,再為每個設(shè)備調(diào)用 class_device_create創(chuàng)建對應(yīng)的設(shè)備。大致用法如下:struct class *myclass = class_create(THIS_MODULE, “my_device_driver”);class_device_create(myclass, NULL, MKDEV(major_num, 0), NULL, “my_device”);這樣的module被加載時,udev daemon就會自動在/dev下創(chuàng)建my_device設(shè)備件。

總體代碼框架

1)先要有file_operations先要有引腳初始化函數(shù)myled_init(void),在myled_init里面注冊class并將class類注冊到內(nèi)核中
創(chuàng)建設(shè)備節(jié)點(diǎn),初始化引腳已經(jīng)將寄存器地址映射到虛擬內(nèi)存中,最后調(diào)用module_init(myled_init)驅(qū)動的加載就靠它
2)創(chuàng)建這個file_operations結(jié)構(gòu)體
    static struct file_operations myled_oprs = {
    .owner = THIS_MODULE,
    .open  = led_open,
    .write = led_write,
    .release = led_release,
    }; 
下面就圍繞這個結(jié)構(gòu)體寫函數(shù)led_write() led_open() led_release()
3)最后要注銷設(shè)備

附實測代碼,參考下

LED驅(qū)動代碼:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
static int major;
static struct class *led_class;
volatile unsigned long *gpio_con = NULL;
volatile unsigned long *gpio_dat = NULL;
static int led_open (struct inode *node, struct file *filp)
{
    /* PB7 - 0x01C20824 */
   if (gpio_con) {
        printk("ioremap  0x%x\n", gpio_con);
        }
        else {
            return -EINVAL;
        }
    return 0;
}

static ssize_t led_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
{
     unsigned char val;        
     copy_from_user(&val, buf, 1);

        if (val)
        {
             *gpio_dat |= (1<<7);
        }
        else
        {
              *gpio_dat &= ~(1<<7);
        }

        return 1; 
}

static int led_release (struct inode *node, struct file *filp)
{
    printk("iounmap(0x%x)\n", gpio_con);
    iounmap(gpio_con);
    return 0;
}

static struct file_operations myled_oprs = {
    .owner = THIS_MODULE,
    .open  = led_open,
    .write = led_write,
    .release = led_release,
};
static int myled_init(void)
{
   major = register_chrdev(0, "myled", &myled_oprs);
   led_class = class_create(THIS_MODULE, "myled");
   device_create(led_class, NULL, MKDEV(major, 0), NULL, "ledzzzzzzzz"); 
   gpio_con = (volatile unsigned long *)ioremap(0x01C20824, 1);   //0x01C20824
   gpio_dat = gpio_con + 4;     //0x01C20834        
   *gpio_con &= ~(7<<28);
   *gpio_con |=  (1<<28);
   *gpio_dat &= ~(1<<7);
   return 0;
}

APP代碼:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
static int major;
static struct class *led_class;
volatile unsigned long *gpio_con = NULL;
volatile unsigned long *gpio_dat = NULL;
static int led_open (struct inode *node, struct file *filp)
{
    /* PB7 - 0x01C20824 */
   if (gpio_con) {
             printk("ioremap  0x%x\n", gpio_con);
        }
        else {
             return -EINVAL;
        }
    return 0;
}

static ssize_t led_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
{
     unsigned char val;        
     copy_from_user(&val, buf, 1);

        if (val)
        {
              *gpio_dat |= (1<<7);
        }
        else
        {
             *gpio_dat &= ~(1<<7);
        }

        return 1; 
}

static int led_release (struct inode *node, struct file *filp)
{
    printk("iounmap(0x%x)\n", gpio_con);
    iounmap(gpio_con);
    return 0;
}

static struct file_operations myled_oprs = {
    .owner = THIS_MODULE,
    .open  = led_open,
    .write = led_write,
    .release = led_release,
};
static int myled_init(void)
{
   major = register_chrdev(0, "myled", &myled_oprs);
   led_class = class_create(THIS_MODULE, "myled");
   device_create(led_class, NULL, MKDEV(major, 0), NULL, "ledzzzzzzzz"); 
   gpio_con = (volatile unsigned long *)ioremap(0x01C20824, 1);   //0x01C20824
   gpio_dat = gpio_con + 4;     //0x01C20834        
   *gpio_con &= ~(7<<28);
   *gpio_con |=  (1<<28);
   *gpio_dat &= ~(1<<7);
   return 0;
}

Makefile代碼:


#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
/* ledtest on
 *   * ledtest off
 *     */
int main(int argc, char **argv)
{
    int fd;
    unsigned char val = 1;
    fd = open("/dev/ledzzzzzzzz", O_RDWR);
    if (fd < 0)
    {
        printf("can't open!\n");
    }
    if (argc != 2)
    {
        printf("Usage :\n");
        printf("%s <on|off>\n", argv[0]);
        return 0;
    }

    if (strcmp(argv[1], "on") == 0)
    {
        val  = 1;
    }
    else
    {
        val = 0;
    }
    write(fd, &val, 1);
    return 0;
}
向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI