百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

linux梦的开始.点灯(具体实现)

bigegpt 2024-08-12 14:29 4 浏览

接上一篇(基础概念),为ap autosar 做准备。(两篇linux的入门点灯 + 两篇 C++ 基本操作 正式开始 AP AUTOSAR)

下面我们开始试着去实现梦的开始 -- 点灯!!


硬件原理图


官方SDK定义


#include "fsl_iomuxc.h" //file here. please find it in official SDK,

#define IOMUXC_CSI_HSYNC_GPIO4_IO20 0x020E01E0U, 0x5U, 0x00000000U, 0x0U, 0x020E046CU

**IOMUXC**: 引脚复用宏定义

**CSI_HSYNC**: 原理图引脚名称

**GPIO4_IO20**: 引脚的复用功能


时钟配置


芯片手册clock config module 查出 相关时钟配置寄存器

时钟CCM 寄存器具体配置bit位 含义

所以这里如果我们想打开 IOMUXC_CSI_HSYNC_GPIO4_IO20的时钟。就需要对地址0x020C4074 的12-13位 用11b去取或。

引脚复用

所有pin角名称:CSI_HSYNC(上面已经说明了)

  1. 把引脚复用成需要的功能

这里需要对地址0x020E01E0进行操作


2. 对pin角控制寄存器进行配置

这里需要对地址0x020E046C进行操作

这两个地址可以直接从官方SDK 里面找到,这里只是进行了芯片手册查询(很重要)。

ok到现在已经把前期准备工作做好了。下面实现linux 内核驱动点灯。

这里请结合上文的硬件解释 和 上一篇linux字符驱动基础知识 来完成下面代码。

GPIO4 相关寄存器地址

20A_8000

GPIO data register (GPIO4_DR)

32

R/W

0000_0000h

28.5.1/1358

20A_8004

GPIO direction register (GPIO4_GDIR)

32

R/W

0000_0000h

28.5.2/1359

20A_8008

GPIO pad status register (GPIO4_PSR)

32

R

0000_0000h

28.5.3/1359

20A_800C

GPIO interrupt configuration register1 (GPIO4_ICR1)

32

R/W

0000_0000h

28.5.4/1360

20A_8010

GPIO interrupt configuration register2 (GPIO4_ICR2)

32

R/W

0000_0000h

28.5.5/1364

20A_8014

GPIO interrupt mask register (GPIO4_IMR)

32

R/W

0000_0000h

28.5.6/1367

20A_8018

GPIO interrupt status register (GPIO4_ISR)

32

w1c

0000_0000h

28.5.7/1368

20A_801C

GPIO edge select register (GPIO4_EDGE_SEL)

32

R/W

0000_0000h

28.5.8/136



如何计算管角号(下面需要定义管角号)

GPIOn_IOx = (n-1)*32+x

所以例子中GPIO4_IO20 是 116

代码实现

/*  Include necessary linux header files */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>

#define DEV_NAME    "led_chrdev"    //define device name
#define DEV_CNT     (1) //how many leds. here we only define 1
?
static dev_t devno;
struct class *led_chrdev_class;
?
/*led char device structure*/
struct led_chrdev{
    struct cdev dev;                            // describe a char device structure
    unsigned int __iomem    *va_dr;             // data register virtual address pointer
    unsigned int __iomem    *va_gdir;           // input output direction register virtual address pointer
    unsigned int __iomem    *va_iomuxc_mux;     // port multiplexer register virtual address pointer
    unsigned int __iomem    *va_ccm_ccgrx;      // clock config register virtual address pointer
    unsigned int __iomem    *va_iomux_pad;      // port pin property register virtual address pointer
?
// below parameters are physical address. you can check virtual address comment.
    unsigned long   pa_dr;
    unsigned long   pa_gdir;
    unsigned long   pa_iomuxc_mux;
    unsigned long   pa_ccm_ccgrx;
    unsigned long   pa_iomux_pad;
?
    unsigned int    led_pin;                    // led pin
    unsigned int    clock_offset;               // clock offset address. base on CCM_CCGRx
};
?
// physical address, you can find in previous chapters.  EACH ADDRESS can be found... CHUN SHOU DA...
?
static struct led_chrdev led_cdev[DEV_CNT] = {
    {
        .pa_dr          = 0x020A8000, \
        .pa_gdir        = 0x020A8004, \
        .pa_ccm_ccgrx   = 0x020C4074, \
        .pa_iomuxc_mux  = 0x020E01E0, \
        .pa_iomux_pad   = 0x020E046C, \
        .led_pin        = 116, \
        .clock_offset   = 12,
    }
};
?
/*
static struct led_chrdev led_cdev[DEV_CNT] = {
    {
        .pa_dr          = 0x0209C000, \
        .pa_gdir        = 0x0209C004, \
        .pa_ccm_ccgrx   = 0x20C406C, \
        .pa_iomuxc_mux  = 0x20E006C, \
        .pa_iomux_pad   = 0x20E02F8, \
        .led_pin        = 4, \
        .clock_offset   = 26,
    }
};
*/
?
static int led_chrdev_open(struct inode *inode, struct file *filp)
{
    unsigned int    val = 0;
    struct led_chrdev   *led_cdev = (struct led_chrdev *)container_of(inode->i_cdev, struct led_chrdev, dev);
?
    filp->private_data = container_of(inode->i_cdev,struct led_chrdev, dev);
?
    printk("Open \n");
?
?
    led_cdev->va_dr             = ioremap(led_cdev->pa_dr, 4);
    led_cdev->va_gdir           = ioremap(led_cdev->pa_gdir, 4);
    led_cdev->va_iomuxc_mux     = ioremap(led_cdev->pa_iomuxc_mux, 4);
    led_cdev->va_ccm_ccgrx      = ioremap(led_cdev->pa_ccm_ccgrx, 4);
    led_cdev->va_iomux_pad      = ioremap(led_cdev->pa_iomux_pad, 4);
?
    val     = ioread32(led_cdev->va_ccm_ccgrx);
    val    &= ~(3 << (led_cdev->clock_offset));
    val    |= (3 << (led_cdev->clock_offset));
?
    iowrite32(val, led_cdev->va_ccm_ccgrx);
    iowrite32(5, led_cdev->va_iomuxc_mux);
    iowrite32(0x1F838, led_cdev->va_iomux_pad);
?
    val     = ioread32(led_cdev->va_gdir);
    val    &= ~(1 << (led_cdev->led_pin));
    val    |= (1 << (led_cdev->led_pin));
    iowrite32(val, led_cdev->va_gdir);
?
    val     = ioread32(led_cdev->va_dr);
    val    |= (0x01 << (led_cdev->led_pin));
    iowrite32(val, led_cdev->va_dr);
?
    return 0;
}
?
?
static int led_chrdev_release(struct inode *inode, struct file *filp)
{
    struct led_chrdev *led_cdev = (struct led_chrdev *) container_of(inode->i_cdev, struct led_chrdev, dev);
?
    iounmap(led_cdev->va_dr);
    iounmap(led_cdev->va_gdir);
    iounmap(led_cdev->va_iomuxc_mux);
    iounmap(led_cdev->va_ccm_ccgrx);
    iounmap(led_cdev->va_iomux_pad);
    return 0;
}
?
?
static ssize_t led_chrdev_write(struct file *filp, const char __user * buf, size_t count, loff_t * ppos)
{
    unsigned long val       = 0;
    unsigned long ret       = 0;
?
    int tmp = count;
?
    kstrtoul_from_user(buf,tmp,10,&ret);
    struct led_chrdev *led_cdev = (struct led_chrdev *) filp->private_data;
?
    val         = ioread32(led_cdev->va_dr);
    if(ret == 0)
    {
        val    &= ~(0x01 << led_cdev->led_pin);
    }
    else 
    {
        val    |= (0x01 << led_cdev->led_pin);
    }
?
    iowrite32(val, led_cdev->va_dr);
    *ppos += tmp;
?
    return tmp;
}
?
static struct file_operations led_chrdev_fops = {
    .owner      = THIS_MODULE,
    .open       = led_chrdev_open,
    .release    = led_chrdev_release,
    .write      = led_chrdev_write,
};
?
//kernel module init(load) and exit(release)
static __init int led_chrdev_init(void)
{
    int i       = 0;
    dev_t cur_dev;
    printk("Led chrdev Init\n");
/**
 * alloc_chrdev_region() - register a range of char device numbers
 * @dev: output parameter for first assigned number
 * @baseminor: first of the requested range of minor numbers
 * @count: the number of minor numbers required
 * @name: the name of the associated device or driver
 *
 * Allocates a range of char device numbers.  The major number will be
 * chosen dynamically, and returned (along with the first minor number)
 * in @dev.  Returns zero or a negative error code.
 */
?
    alloc_chrdev_region(&devno,0,DEV_CNT,DEV_NAME);  //dynamic apply device number, detail can be found in previous comment.
?
/*
 * class_create - create a struct class structure
 * @owner: pointer to the module that is to "own" this struct class
 * @name: pointer to a string for the name of this class.
 * @key: the lock_class_key for this class; used by mutex lock debugging
 *
 * This is used to create a struct class pointer that can then be used
 * in calls to device_create().
 *
 * Returns &struct class pointer on success, or ERR_PTR() on error.
 *
 * Note, the pointer created here is to be destroyed when finished by
 * making a call to class_destroy().
 */
?
/*  源码备注
THIS_MODULE
__visible struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
    .name = KBUILD_MODNAME,
    .init = init_led_chrdev_fopsmodule,
#ifdef CONFIG_MODULE_UNLOAD
    .exit = cleanup_module,
#endif
    .arch = MODULE_ARCH_INIT,
};
网上找的 对 THIS_MODULE 的 解释
#define THIS_MODULE (&__this_module)
是 一个struct module变量,代表当前模块,与那个著名的current有几分相似,可以通过THIS_MODULE宏来引用模块的struct module结构,比如使用THIS_MODULE->state可以获得当前模块的状态。现在你应该明白为啥在那个岁月里,你需要毫不犹豫毫不迟 疑的将struct usb_driver结构里的owner设置为THIS_MODULE了吧,这个owner指针指向的就是你的模块自己。那现在owner咋就说没就没了 那?这个说来可就话长了,咱就长话短说吧。不知道那个时候你有没有忘记过初始化owner,反正是很多人都会忘记,大家都把注意力集中到probe、 disconnect等等需要动脑子的角色上面了,这个不需要动脑子,只需要花个几秒钟指定一下的owner反倒常常被忽视,这个就是容易得到的往往不去 珍惜,不容易得到的往往日日思量着去争取。于是在2006年的春节前夕,在咱们都无心工作无心学习等着过春节的时候,Greg坚守一线,去掉了 owner,于是千千万万个写usb驱动的人再也不用去时刻谨记初始化owner了。咱们是不用设置owner了,可core里不能不设置,struct usb_driver结构里不是没有owner了么,可它里面嵌的那个struct device_driver结构里还有啊,设置了它就可以了。于是Greg同时又增加了usb_register_driver()这么一 层,usb_register()可以通过将参数指定为THIS_MODULE去调用它,所有的事情都挪到它里面去做。反正usb_register() 也是内联的,并不会增加调用的开销。
?
*/
    led_chrdev_class    = class_create(THIS_MODULE, "led_chrdev");
?
    for(i=0; i<DEV_CNT;i++)
    {
        cdev_init(&led_cdev[i].dev, &led_chrdev_fops);  //combine led_cdev to file operations
        led_cdev[i].dev.owner = THIS_MODULE;
        cur_dev = MKDEV(MAJOR(devno),MINOR(devno)+i);   // get devno's major and minor number to cur_dev
        cdev_add(&led_cdev[i].dev, cur_dev, 1);         // add a device to system
        device_create(led_chrdev_class,NULL,cur_dev,NULL,DEV_NAME "%d",i);  // load and create a device.
    }
?
    return 0;
}
?
module_init(led_chrdev_init);
?
static __exit void led_chrdev_exit(void)
{
    int i;
    dev_t cur_dev;
    printk("led chrdev exit\n");
    for(i = 0; i<DEV_CNT;i++)
    {
        cur_dev  =   MKDEV(MAJOR(devno), MINOR(devno) +i);
        device_destroy(led_chrdev_class,cur_dev);
        cdev_del(&led_cdev[i].dev);
    }
?
    unregister_chrdev_region(devno, DEV_CNT);
    class_destroy(led_chrdev_class);
}
?
module_exit(led_chrdev_exit);
?
MODULE_AUTHOR("caiji");
MODULE_LICENSE("GPL");


完结撒花。内容参考书本例程,过程纯手打,图来自芯片手册,yeah. 希望对 想学习 ap autosar 的小伙伴 有 一丢丢丢丢丢丢丢丢帮助。

内容来源:零束开发者论坛

相关推荐

了解Linux目录,那你就了解了一半的Linux系统

大到公司或者社群再小到个人要利用Linux来开发产品的人实在是多如牛毛,每个人都用自己的标准来配置文件或者设置目录,那么未来的Linux则就是一团乱麻,也对管理造成许多麻烦。后来,就有所谓的FHS(F...

Linux命令,这些操作要注意!(linux命令?)

刚玩Linux的人总觉得自己在演黑客电影,直到手滑输错命令把公司服务器删库,这才发现命令行根本不是随便乱用的,而是“生死簿”。今天直接上干货,告诉你哪些命令用好了封神!喜欢的一键三连,谢谢观众老爷!!...

Linux 命令速查手册:这 30 个高频指令,拯救 90% 的运维小白!

在Linux系统的世界里,命令行是强大的武器。对于运维小白而言,掌握一些高频使用的Linux命令,能极大提升工作效率,轻松应对各种系统管理任务。今天,就为大家奉上精心整理的30个Linu...

linux必学的60个命令(linux必学的20个命令)

以下是Linux必学的20个基础命令:1.cd:切换目录2.ls:列出文件和目录3.mkdir:创建目录4.rm:删除文件或目录5.cp:复制文件或目录6.mv:移动/重命名文件或目录7....

提高工作效率的--Linux常用命令,能够决解95%以上的问题

点击上方关注,第一时间接受干货转发,点赞,收藏,不如一次关注评论区第一条注意查看回复:Linux命令获取linux常用命令大全pdf+Linux命令行大全pdf为什么要学习Linux命令?1、因为Li...

15 个实用 Linux 命令(linux命令用法及举例)

Linux命令行是系统管理员、开发者和技术爱好者的强大工具。掌握实用命令不仅能提高效率,还能解锁Linux系统的无限潜力,本文将深入介绍15个实用Linux命令。ls-列出目录内容l...

Linux 常用命令集合(linux常用命令全集)

系统信息arch显示机器的处理器架构(1)uname-m显示机器的处理器架构(2)uname-r显示正在使用的内核版本dmidecode-q显示硬件系统部件-(SMBIOS/DM...

Linux的常用命令就是记不住,怎么办?

1.帮助命令1.1help命令#语法格式:命令--help#作用:查看某个命令的帮助信息#示例:#ls--help查看ls命令的帮助信息#netst...

Linux常用文件操作命令(linux常用文件操作命令有哪些)

ls命令在Linux维护工作中,经常使用ls这个命令,这是最基本的命令,来写几条常用的ls命令。先来查看一下使用的ls版本#ls--versionls(GNUcoreutils)8.4...

Linux 常用命令(linux常用命令)

日志排查类操作命令查看日志cat/var/log/messages、tail-fxxx.log搜索关键词grep"error"xxx.log多条件过滤`grep-E&#...

简单粗暴收藏版:Linux常用命令大汇总

号主:老杨丨11年资深网络工程师,更多网工提升干货,请关注公众号:网络工程师俱乐部下午好,我的网工朋友在Linux系统中,命令行界面(CLI)是管理员和开发人员最常用的工具之一。通过命令行,用户可...

「Linux」linux常用基本命令(linux常用基本命令和用法)

Linux中许多常用命令是必须掌握的,这里将我学linux入门时学的一些常用的基本命令分享给大家一下,希望可以帮助你们。总结送免费学习资料(包含视频、技术学习路线图谱、文档等)1、显示日期的指令:d...

Linux的常用命令就是记不住,怎么办?于是推出了这套教程

1.帮助命令1.1help命令#语法格式:命令--help#作用:查看某个命令的帮助信息#示例:#ls--help查看ls命令的帮助信息#netst...

Linux的30个常用命令汇总,运维大神必掌握技能!

以下是Linux系统中最常用的30个命令,精简版覆盖日常操作核心需求,适合快速掌握:一、文件/目录操作1.`ls`-列出目录内容`ls-l`(详细信息)|`ls-a`(显示隐藏文件)...

Linux/Unix 系统中非常常用的命令

Linux/Unix系统中非常常用的命令,它们是进行文件操作、文本处理、权限管理等任务的基础。下面是对这些命令的简要说明:**文件操作类:*****`ls`(list):**列出目录内容,显...