当前位置: 首页 > wzjs >正文

网站基本功能如何建设自己的小说网站

网站基本功能,如何建设自己的小说网站,通用cms网站,做微信推送用什么网站IMX6ULL学习整理篇——Linux驱动开发的基础2 老框架的一次实战:LED驱动 ​ 在上一篇博客中,我们实现了从0开始搭建的字符设备驱动框架,但是这个框架还是空中楼阁,没有应用,很难说明我们框架的正确性。这里&#xff0c…

IMX6ULL学习整理篇——Linux驱动开发的基础2 老框架的一次实战:LED驱动

​ 在上一篇博客中,我们实现了从0开始搭建的字符设备驱动框架,但是这个框架还是空中楼阁,没有应用,很难说明我们框架的正确性。这里,我们就准备好驱动正点原子开发板上的一个LED小灯外设。他被接在了GPIO01_IO03上。

开始之前,复习一下架构体系对外设的地址处理

​ 毫无疑问,任何一个搞过单片机的朋友都知道:在 ARM 架构中,外设的地址处理主要通过内存映射(Memory-Mapped I/O)方式进行。这意味着,外设的寄存器被映射到处理器的内存地址空间,CPU 可以像访问内存一样访问这些外设寄存器。这个技术连x86开始就在使用了!每个外设的寄存器都被分配了特定的物理地址,处理器通过读写这些地址来控制外设的操作。这种方式简化了处理器与外设之间的通信,因为不需要专门的 I/O 指令,统一了内存和外设的访问方式。

​ 当然,对于我们复杂的ARM芯片上的主板一般还有MMU内存管理单元。我们的地址访问都被认为是一个虚拟地址时,这个时候MMU 会根据页表将其转换为相应的物理地址。这不仅实现了内存的虚拟化,还允许操作系统为不同的应用程序提供独立的地址空间,提高了系统的安全性和稳定性。

​ 关于虚拟内存和物理内存,复习微机原理可以帮助你理解这些知识,笔者这里是驱动笔记整理,不是计算机体系架构笔记整理,所以请你自行翻阅相关的知识!

​ 这也就意味着,我们没法子直接拿物理地址访问我们的GPIO寄存器了,那咋办呢?答案是:Linux考虑到了这类情况,提供了一组API,让我们添加IO设备的外设地址映射,告诉我们我们操作的虚拟地址是哪个!

ioremap和iounmap函数

​ 在 Linux 内核中,ioremapiounmap 函数用于在内核虚拟地址空间中映射和解除映射物理 I/O 内存区域,以便内核能够安全地访问硬件设备的寄存器或内存。ioremap 函数用于将指定的物理地址范围映射到内核的虚拟地址空间,使内核能够通过虚拟地址访问对应的物理 I/O 内存区域。

void __iomem *ioremap(resource_size_t phys_addr, unsigned long size);

​ 其中:phys_addr是要映射的物理起始地址。size:要映射的内存区域大小。成功时,返回指向映射后虚拟地址空间的指针;失败时,返回 NULL。调用 ioremap 后,内核可以通过返回的虚拟地址指针访问对应的物理 I/O 内存区域。

iounmap 函数用于解除先前通过 ioremap 建立的映射关系,释放对应的虚拟地址空间。

void iounmap(void __iomem *addr);

​ 这里的addr:要解除映射的虚拟地址,即先前 ioremap 的返回值。调用 iounmap 后,内核将不再能够通过该虚拟地址访问对应的物理 I/O 内存区域。

​ 当然笔者提醒:

  • 在访问硬件设备的寄存器或内存时,必须先使用 ioremap 将物理地址映射到内核虚拟地址空间,然后通过返回的虚拟地址进行读写操作。
  • 在不再需要访问该 I/O 内存区域时,应调用 iounmap 解除映射,以释放资源。
  • 直接访问物理地址可能导致不可预期的行为,因此应始终通过 ioremapiounmap 函数进行 I/O 内存的映射和解除映射。

read蔟函数和write蔟函数——操作我们的IO设备

​ 拿到地址了,咋写呢?别自己手搓,我们的Linux还是给我们提供了API:在 Linux 内核中,readbreadwreadl 以及 writebwritewwritel 等函数用于在内存映射的 I/O 空间中读取和写入数据。

读取操作函数:readbreadwreadl 函数用于从内存映射的 I/O 空间读取 8 位、16 位和 32 位的数据。

readb:从指定的内存映射 I/O 地址读取 8 位(1 字节)数据。

unsigned char readb(const volatile void __iomem *addr);

readw:从指定的内存映射 I/O 地址读取 16 位(2 字节)数据。

unsigned short readw(const volatile void __iomem *addr);

readl:从指定的内存映射 I/O 地址读取 32 位(4 字节)数据。

unsigned int readl(const volatile void __iomem *addr);

写入操作函数:writebwritewwritel 函数用于向内存映射的 I/O 空间写入 8 位、16 位和 32 位的数据。

writeb:向指定的内存映射 I/O 地址写入 8 位(1 字节)数据。

void writeb(u8 value, volatile void __iomem *addr);

writew:向指定的内存映射 I/O 地址写入 16 位(2 字节)数据。

void writew(u16 value, volatile void __iomem *addr);

writel:向指定的内存映射 I/O 地址写入 32 位(4 字节)数据。

void writel(u32 value, volatile void __iomem *addr);
  • addr:指向内存映射 I/O 空间中目标地址的指针。
  • value:要写入的数据。

编程,启动!

​ 具体是啥地址,这个事情三个字:翻手册。没了,还不懂看如何裸机驱动LED,这就跟LKM驱动开发半毛钱关系没有了

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>	
#include <asm/io.h>
#include <linux/types.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("charliechen<charliechen114514@demo.com>");#define LED_MAJOR_DEV_N         (114)
#define LED_DEV_NAME            ("charlies_led")/* LED Physical Address See the manual
*/
#define CCM_CCGR1_BASE          (0x020C406C)
#define GPIO1_IOLED_BASE        (0x020E0068)
#define GPIO1_IOPAD_BASE        (0x020E02F4)
#define GPIO1_IODR_BASE         (0x0209C000)
#define GPIO1_GDIR_BASE         (0x0209C004)/* mappings of the io phe*/
static void* __iomem LED_CCGR1;
static void* __iomem LEDBASE;
static void* __iomem LEDPAD_BASE;
static void* __iomem LEDDR_BASE;
static void* __iomem LEDGDIR_BASE;/* operations cached */
static char operations_cached[20];static void __led_turn_on(void)
{u32 val = 0;val = readl(LEDDR_BASE);val &= ~(1 << 3);writel(val, LEDDR_BASE);
}static void __led_turn_off(void)
{u32 val = 0;val = readl(LEDDR_BASE);val |= (1 << 3);writel(val, LEDDR_BASE);
}static u8 __fetch_led_status(void)
{u32 val = 0;val = readl(LEDDR_BASE);return !(val & (1 << 3));
}static void __enable_led_mappings(void)
{int val = 0;pr_info("Ready to mappings the registers...\n");LED_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);LEDBASE = ioremap(GPIO1_IOLED_BASE, 4);LEDPAD_BASE = ioremap(GPIO1_IOPAD_BASE, 4);LEDDR_BASE = ioremap(GPIO1_IODR_BASE, 4);LEDGDIR_BASE = ioremap(GPIO1_GDIR_BASE, 4);pr_info("mappings the registers done!\n");pr_info("LED_CCGR1     ioremap to: %p\n", LED_CCGR1);pr_info("LEDBASE       ioremap to: %p\n", LEDBASE);pr_info("LEDPAD_BASE   ioremap to: %p\n", LEDPAD_BASE);pr_info("LEDDR_BASE    ioremap to: %p\n", LEDDR_BASE);pr_info("LEDGDIR_BASE  ioremap to: %p\n", LEDGDIR_BASE);pr_info("initialize the led registers\n");val = readl(LED_CCGR1);// clear the bitsval &= ~(3 << 26);val |= (3 << 26);writel(val, LED_CCGR1);writel(0x5, LEDBASE);writel(0x10B0, LEDPAD_BASE);val = readl(LEDGDIR_BASE);val |= 1 << 3;writel(val, LEDGDIR_BASE);pr_info("operations of led is accessable!\n");
}static void __disable_led_mappings(void)
{__led_turn_off();pr_info("set the led turning off...\n");pr_info("set the led turning off done!\n");pr_info("Ready to unmappings the registers...\n");    iounmap(LED_CCGR1);iounmap(LEDBASE);iounmap(LEDPAD_BASE);iounmap(LEDDR_BASE);iounmap(LEDGDIR_BASE);pr_info("unmappings the registers done\n");
}static int led_open(struct inode* inode, struct file* filp)
{pr_info("\nled device is opened!\n");return 0;
}static int led_close(struct inode* inode, struct file* filp)
{pr_info("\nled device is released!\n");return 0;
}static ssize_t led_read(struct file* filp, char* buffer, size_t count, loff_t* ppos)
{const char* status = "opened";int ret = 0;pr_info("\nled device is reading!\n");if(!__fetch_led_status()){status = "closed";} ret = copy_to_user(buffer, status, strlen(status));if(ret < 0){pr_warn("Copy to the user failed\n");return -EFAULT;}return 0;
}                        static ssize_t led_write(struct file* filp,const char* buffer, size_t count, loff_t* ppos)
{int check = 0;pr_info("\nled device is ready writing!\n");check = copy_from_user(operations_cached, buffer, count);if(check < 0){pr_warn("Can not copy from user!\n");return -EFAULT;}if(!strcmp(operations_cached, "open")){__led_turn_on();}else if(!strcmp(operations_cached, "close")){__led_turn_off();}else{pr_warn("Can not find the indications operations!\n""check the business: %s", operations_cached);}return 0;
}   static struct file_operations led_ops = {.owner = THIS_MODULE,.read = led_read,.write = led_write,.open = led_open,.release = led_close
};static int __init led_init(void)
{int result = 0;pr_info("LED Device is setting up\n");result = register_chrdev(LED_MAJOR_DEV_N, LED_DEV_NAME, &led_ops);if(result < 0){pr_warn("can not register the device!\n");return -EIO;}__enable_led_mappings();return 0;
}static void __exit led_exit(void)
{unregister_chrdev(LED_MAJOR_DEV_N, LED_DEV_NAME);__disable_led_mappings();pr_info("LED Device is unhooked!\n");
}module_init(led_init);
module_exit(led_exit);

书写测试程序

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>#define ISSUE_BUFFER_N      (40)static void display_help(const char* app_name)
{fprintf(stderr, "do: %s <dev_file> <operations>\n""op: read : read the data from char dev\n""op: write: write the data to char dev:\n""   open: turn on the led\n""   close: turn off the led\n", app_name);
}int main(int argc, char* argv[])
{int check = 0;if(argc < 3){display_help(argv[0]);return -1;}char* filename = argv[1];check = open(filename, O_RDWR);if(check < 0){fprintf(stderr, "Hey, Error in open filename: %s!\n", filename);return -1;}int result = 0;if(!strcmp(argv[2], "read")){// process reading issueprintf("user process the read issue\n");char buffer[ISSUE_BUFFER_N];result = read(check, buffer, ISSUE_BUFFER_N);if(result < 0){fprintf(stderr, "Hey, Error in read! filename: %s!\n", filename);goto close_issue;   }printf("user receive from driver: %s\n", buffer);// done!}else if(!strcmp(argv[2], "write")){// process the writeprintf("args: %d\n", argc);if(argc != 4){display_help(argv[0]);goto close_issue;}printf("user process the write issue: %s\n", argv[3]);result = write(check, argv[3], strlen(argv[3]));if(result < 0){fprintf(stderr, "Hey, Error in write! filename: %s!\n", filename);goto close_issue; }    }else{fprintf(stderr, "Unknown options!\n");display_help(argv[0]);goto close_issue;}close_issue:result = close(check);if(result < 0){fprintf(stderr, "Hey, Error in close device! filename: %s!\n", filename);return -1;        }        return 0;
}

​ 无比怀念CLI框架的一天.jpg

​ 下面我们测试一下:

测试

/module_test # ls
chrdev_application  led.ko
/module_test # mknod /dev/ccled c 114 0
/module_test # insmod led.ko 
LED Device is setting up
Ready to mappings the registers...
mappings the registers done!
LED_CCGR1     ioremap to: f42c406c
LEDBASE       ioremap to: f42e0068
LEDPAD_BASE   ioremap to: f42e02f4
LEDDR_BASE    ioremap to: a092e000
LEDGDIR_BASE  ioremap to: a0936004
initialize the led registers
operations of led is accessable!
/module_test # ./chrdev_application /dev/ccled readled device is opened!
user process the read issue
led device is reading!user receive from driver: closed
led device is released!
v 
/module_test # ./chrdev_application /dev/ccled write openled device is opened!
args: 4
led device is ready writing!user process the write issue: o
led device is released!
pen
/module_test # ./chrdev_application /dev/ccled write closeled device is opened!
args: 4
user process the write issue: 
led device is ready writing!
closeled device is released!
/module_test # rmmod led.ko 
set the led turning off...
set the led turning off done!
Ready to unmappings the registers...
unmappings the registers done
LED Device is unhooked!

在这里插入图片描述
在这里插入图片描述


文章转载自:

http://qTeEV4gg.Lfmwt.cn
http://D76oiVcf.Lfmwt.cn
http://7tiMDK5D.Lfmwt.cn
http://yWKWtSlV.Lfmwt.cn
http://pUDCYhp3.Lfmwt.cn
http://Xn2c6OPp.Lfmwt.cn
http://Nu7GgICQ.Lfmwt.cn
http://4ZYN8PRb.Lfmwt.cn
http://qKZl28gO.Lfmwt.cn
http://OSKTv908.Lfmwt.cn
http://HbJIjWJ6.Lfmwt.cn
http://Cv74a1Gq.Lfmwt.cn
http://hohcPNj1.Lfmwt.cn
http://9WFb4JqP.Lfmwt.cn
http://H3y0GDZy.Lfmwt.cn
http://7TWjTjyY.Lfmwt.cn
http://O6edomt5.Lfmwt.cn
http://J7K4aZKi.Lfmwt.cn
http://bY7e90MU.Lfmwt.cn
http://dSncPt5y.Lfmwt.cn
http://1dYAhT0S.Lfmwt.cn
http://bZUn86fr.Lfmwt.cn
http://aRLzl86J.Lfmwt.cn
http://qSvUlXW4.Lfmwt.cn
http://Oqif6Zed.Lfmwt.cn
http://HEXKNQDD.Lfmwt.cn
http://f5LsXfrQ.Lfmwt.cn
http://YBQhZpi8.Lfmwt.cn
http://lgIT4jJl.Lfmwt.cn
http://l9fYRBOz.Lfmwt.cn
http://www.dtcms.com/wzjs/775598.html

相关文章:

  • 集群网站开发网站工程师证书
  • 湖南网站开发公司姜堰网站定制
  • 网站建设html手套网站模板
  • 汽车网站名称网站建设怎么问问题
  • 怎么做定位钓鱼网站金坛网页设计
  • 信阳网站建设制作视频的软件哪个最好免费的
  • 网站开发需求清单做网站有底薪吗
  • 书写网站建设策划书景观设计公司有哪些
  • app网站开发合同wordpress apple
  • excel可以做网站吗电脑软件推广联盟
  • 太原网站建设 网站制作wordpress分类添加自定义字段
  • 四川省住房与城乡建设厅网站官网手机房屋平面设计软件
  • 秦皇岛网站开发做网站的费用怎么做账
  • 甘肃网站建设的过程建设网贷网站
  • 自助做网站齐家网装修官网
  • 申请微官网的网站长沙做网站企业
  • 做网站比较好的公司大同工程建设信息网
  • 青岛网站建设服务器wordpress 是谁开发的
  • 河北省建设安全监督站的网站苏州品牌网站设计
  • 有哪些可以做兼职翻译的网站造价师在哪个网站做继续教育
  • 优购商城网站建设苏宁易购网站建设的不足之处
  • 做it的兼职网站支付宝网页版
  • 网站架构模式用哪种网站域名登陆
  • 响应式网站开发支持ie6解决自学摄影教程的网站有哪些
  • 中国各大网站排名邵阳汽车网站建设
  • 网站付费推广有哪些建设工程施工合同的当事人包括
  • 合肥外贸网站建设公司广州网站建设与网页设计
  • 用pc网站建设手机网站门户网站开发注意事项
  • 什么网站做h5不收费怎么做网站推广图片
  • 可信网站认证的区别怎么做软文网站