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

t.cn这种网站怎么做的关键词简谱

t.cn这种网站怎么做的,关键词简谱,重庆做网站开发的公司有哪些,做网站可以不用框架吗若该文为原创文章,转载请注明原文出处。 字符设备驱动程序的基本框架,主要是如何申请及释放设备号、添加以及注销设备,初始化、添加与删除 cdev 结构体,并通过 cdev_init 函数建立 cdev 和 file_operations 之间的关联&#xff0c…

若该文为原创文章,转载请注明原文出处。

字符设备驱动程序的基本框架,主要是如何申请及释放设备号、添加以及注销设备,初始化、添加与删除 cdev 结构体,并通过 cdev_init 函数建立 cdev 和 file_operations 之间的关联,cdev 结构体和 file_operations 结构体。

记录编写第一个真正的 Linux 字符设备驱动,点灯。

使用的开发板是正点原子的ATK-DLRK3568.

一、查看原理图

通过查看原理图,得知LED控制引脚接到了 GPIO0_C0上,通过三极管控制LED,GPIO0_C0输出高电平,LED亮,输出低电平,LED灭。

二、GPIO介绍

GPIO(General Purpose Input/Output Port):通用输入输出端口。

除作为一般的输入/输出功能外,还可以配置为中断和模拟UART、CAN、PWM、I2C、SDMMC、CLK等功能。

比如 GPIO0_C0 这个 IO 就可以用 作:GPIO,PWM1_M0,GPU_AVS 和 UART0_RX 这四个功能,所以我们首先要设置好当前引 脚用作什么功能。

rk356x 系列对应的文档为:

• Rockchip_RK3568_TRM_Part1_xxx.pdf

• Rockchip_RK3566_Datasheet_xxx.pdf

• Rockchip_RK3568_Datasheet_xxx.pdf

1、GPIO分组

RK3568共160个GPIO引脚,复用型引脚分为 5 组 (GPIO0~4),每组里面都有 32 个复 用型引脚,而且又分为 4 个小组 (A、B、C、D),每个小组 8 个引脚 (0~7)。例如:GPIO0_C7 是 GPIO0 大组,第 3 个小组,第 8 个引脚。

要查找GPIO对应的配置寄存器地址,必须知道他属于哪个分组。

对于 LED 灯的控制进行控制,也就是对上述 GPIO 的寄存器进行读写操作。
可大致分为以下几个 步骤:
• 使能 GPIO 时钟 (默认开启,不用设置)
• 设置引脚复用为 GPIO(复位默认为 GPIO,不用配置)
• 设置引脚属性 (上下拉、速率、驱动能力, 默认)
• 控制 GPIO 引脚为输出,并输出高低电平
因为 GPIO 的时钟默认开启,引脚默认复用为 GPIO,我们只需要配置 GPIO 的引脚输入输出模式 及电平即可。

2、GPIO引脚号计算方法

pins = 32*bank_num + 8*group + x
bank_num : 0 ~ 4,对应GPIO 0~4
group    : 0 ~ 3,对应GPIO A~D
GPIO0_C0:
GPIO0_C2 = 32*0(bank_num) + 8*2(group) + 0 = 16

根据计算GPIO0_C0序号为16。在后面驱动代码时会用到。

2、寄存器配置

这里以GPIO0_C0为例,查看Rockchip_RK3568_TRM_Part1手册可知,GPIO0 组复用功能是在 PMU_GRF 寄存器,实验中需要对 GPIO 进行配置,一般情况下需要对 GPIO 的复用寄存器,方向寄存器,数据寄存器进行配置, 和复用相关的总共 8 个寄存器。

1. 查找复用寄存器

搜索 GPIO0_C0,GPIO0_C0_sel 在 PMU_GRF_GPIO0C_IOMUX_H 上,偏移地址为 0x0010。GPIO0_C0可以通过控制[2:0]位来选择复用为哪个功能,我们要控制led 灯,所以功能要复用为 GPIO。

复用寄存器的基地址:

GPIO0_C0 设置为 GPIO,所以 PMU_GRF_GPIO0C_IOMUX_L 的 bit2:0 这三位
设置 000。另外 bit18:16 要设置为 111,允许写 bit2:0。

2. 查找方向寄存器

通过设置 GPIO 寄存器设置输入输出、高低电平、中断、抖动等一些引脚的驱动能力,电
气属性等,主要通过设置 General Register Files (GRF)(以 GPIO0 组为例,详细自行参考
Rockchip_RK35xx_TRM_Part1 手册):

• GPIO_SWPORT_DDR_L:低位引脚数据方向寄存器,控制输入或者输出。
• GPIO_SWPORT_DDR_H:高位引脚数据方向寄存器,控制输入或者输出。

通过寄存器描述,该寄存器有高 16bit 和低 16bit,高 16bit 控制低 16bit 的 写使能,低 16bit 控制 GPIO 的输出方向, 0:输入,1:输出。

GPIO0_C0属于 GPIO0 中 A-D 组总计 64 个引脚中的高 32 引脚范围,所以需要将 GPIO_SWPORT_DDR_H 寄存器的第 0bit 位和 16bit 位置 1,允许写 bit16。

GPIO0~GPIO4 的基地址:

GPIO_SWPORT_DDR_H 寄存器地址计算 

Operational Base + offset = 0xFDD60000 + 0x000C = 0xFDD6000C

3. GPIO 引脚高低电平设置

• GPIO_SWPORT_DR_L:低位引脚数据寄存器,设置高低电平。
• GPIO_SWPORT_DR_H:高位引脚数据寄存器,设置高低电平。

GPIO_SWPORT_DR_L 和 GPIO_SWPORT_DR_H 寄存器有高 16bit 和低 16bit,高 16bit 控制低 16bit 的写 使能,低 16bit 控制 GPIO 的高低电平。

GPIO0_C0属于 GPIO0 中 A-D 组总计 64 个引脚 中高的 32 引脚范围,所以需要将 GPIO_SWPORT_DR_H 寄存器的第0bit 位和 16bit 位置 1。

4. 总结

复用关系寄存器的基地址为 0xFDC20000 ,偏移地址为 0x0010
所以要操作的地址为基地址+偏移地址=0xFDC20010 

GPIO 的基地址为 0xFDD60000,偏移地址为 0x000C,
所以方向寄存器要操作的地址为基地址+偏移地址=0xFDD6000C 

GPIO 的基地址为 0xFDD60000,偏移地址为 0x0004,
所以数据寄存器要操作的地址为基地址+偏移地址=0xFDD60004

 

三、驱动程序编写

1、编写led_cdev.c驱动文件

#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 DEV_CNT                 (1)#define GPIO0_BASE (0xfdd60000)//每组GPIO,有2个寄存器,对应32个引脚,每个寄存器负责16个引脚;
//一个寄存器32位,其中高16位都是使能位,低16位对应16个引脚,每个引脚占用1比特位
#define GPIO0_DR_L (GPIO0_BASE + 0x0000)
#define GPIO0_DR_H (GPIO0_BASE + 0x0004)#define GPIO0_DDR_L (GPIO0_BASE + 0x0008)
#define GPIO0_DDR_H (GPIO0_BASE + 0x000C)static dev_t devno;
struct class *led_chrdev_class;struct led_chrdev {struct cdev dev;unsigned int __iomem *va_dr; 	// 数据寄存器,设置输出的电压unsigned int __iomem *va_ddr; 	// 数据方向寄存器,设置输入或者输出unsigned int led_pin; // 偏移
};/* 打开设备函数 */
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");//设置输出模式val = ioread32(led_cdev->va_ddr);val |= ((unsigned int)0x1 << (led_cdev->led_pin+16));val |= ((unsigned int)0X1 << (led_cdev->led_pin));iowrite32(val,led_cdev->va_ddr);//输出高电平val = ioread32(led_cdev->va_dr);val |= ((unsigned int)0x1 << (led_cdev->led_pin+16));val |= ((unsigned int)0x1 << (led_cdev->led_pin));iowrite32(val, led_cdev->va_dr);return 0;
}static int led_chrdev_release(struct inode *inode, struct file *filp)
{return 0;
}/* 从设备读取数据 */
static ssize_t led_chrdev_read(struct file *file, char __user *buf, size_t size, loff_t *off)
{	printk("This is led_chrdev_read\r\n");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;char ret = 0;struct led_chrdev *led_cdev = (struct led_chrdev *)filp->private_data;printk("write \n");get_user(ret, buf);val = ioread32(led_cdev->va_dr);printk("val = %lx\n", val);if (ret == '0' || ret == 0){val |= ((unsigned int)0x1 << (led_cdev->led_pin+16));val &= ~((unsigned int)0x01 << (led_cdev->led_pin));   /*设置GPIO引脚输出低电平*/}else{val |= ((unsigned int)0x1 << (led_cdev->led_pin+16));val |= ((unsigned int)0x01 << (led_cdev->led_pin));    /*设置GPIO引脚输出高电平*/}iowrite32(val, led_cdev->va_dr);printk("val = %lx\n", val);return count;
}/* 设备操作函数 */
static struct file_operations led_chrdev_fops = {.owner = THIS_MODULE,          // 将 owner 字段指向本模块,可以避免在模块的操作正在被使用时卸载该模块.open = led_chrdev_open,       // 将 open 字段指向 chrdev_open(...)函数.read = led_chrdev_read,       // 将 open 字段指向 chrdev_read(...)函数.write = led_chrdev_write,     // 将 open 字段指向 chrdev_write(...)函数.release = led_chrdev_release, // 将 open 字段指向 chrdev_release(...)函数
};static struct led_chrdev led_cdev[DEV_CNT] = {{.led_pin = 0}, 	//偏移,高16引脚,GPIO0_C0
};/* 驱动入口函数 */
static __init int led_chrdev_init(void)
{int i = 0;dev_t cur_dev;printk("led_chrdev init (lubancat2  GPIO0_C7)\n");/*0 将物理地址转化为虚拟地址 */led_cdev[0].va_dr   = ioremap(GPIO0_DR_H, 4);	 //led_cdev[0].va_ddr  = ioremap(GPIO0_DDR_H, 4);	 // /*1 创建设备号 */alloc_chrdev_region(&devno, 0, DEV_CNT, DEV_NAME);/*2 创建类 */led_chrdev_class = class_create(THIS_MODULE, "led_chrdev");for (; i < DEV_CNT; i++) {/*3 初始化 cdev */cdev_init(&led_cdev[i].dev, &led_chrdev_fops);led_cdev[i].dev.owner = THIS_MODULE;/*4 获取主设备号和次设备号 */cur_dev = MKDEV(MAJOR(devno), MINOR(devno) + i);/*5 添加一个 cdev,完成字符设备注册到内核 */cdev_add(&led_cdev[i].dev, cur_dev, 1);/*6 创建设备*/device_create(led_chrdev_class, NULL, cur_dev, NULL, DEV_NAME "%d", i);}return 0;
}/* 驱动出口函数 */
static __exit void led_chrdev_exit(void)
{int i;dev_t cur_dev;printk("led chrdev exit (lubancat2  GPIO0_C7)\n");/*注销字符设备*/for (i = 0; i < DEV_CNT; i++) {iounmap(led_cdev[i].va_dr); 		// 释放模式寄存器虚拟地址iounmap(led_cdev[i].va_ddr); 	// 释放输出类型寄存器虚拟地址}for (i = 0; i < DEV_CNT; i++) {cur_dev = MKDEV(MAJOR(devno), MINOR(devno) + i);//删除设备device_destroy(led_chrdev_class, cur_dev);// 删除 cdevcdev_del(&led_cdev[i].dev);}// 注销设备号unregister_chrdev_region(devno, DEV_CNT);// 删除类class_destroy(led_chrdev_class);}module_init(led_chrdev_init);
module_exit(led_chrdev_exit);MODULE_AUTHOR("yifeng");
MODULE_LICENSE("GPL");

总结:

模块加载

1、初始化 LED 灯结构体成员,将物理寄存器的地址映射到虚拟地址空间

2、向动态申请一个设备号

3、创建设备类

4、绑定 led_cdev led_chrdev_fops

5、注册设备

6、创建设备

模块卸载

1、删除设备

2、注销设备

3、释放被占用的设备号

2、编写makefile

KERNELDIR := /home/alientek/rk3568_linux_sdk/kernel
ARCH=arm64
CROSS_COMPILE=/opt/atk-dlrk356x-toolchain/usr/bin/aarch64-buildroot-linux-gnu-export  ARCH  CROSS_COMPILECURRENT_PATH := $(shell pwd)
obj-m := led_cdev.obuild: kernel_moduleskernel_modules:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

编译

3、编写APP应用

ledApp.c

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"#define LEDOFF 	0
#define LEDON 	1/** @description		: main主程序* @param - argc 	: argv数组元素个数* @param - argv 	: 具体参数* @return 			: 0 成功;其他 失败*/
int main(int argc, char *argv[])
{int fd, retvalue;char *filename;unsigned char databuf[1];if(argc != 3){printf("Error Usage!\r\n");return -1;}filename = argv[1];/* 打开led驱动 */fd = open(filename, O_RDWR);if(fd < 0){printf("file %s open failed!\r\n", argv[1]);return -1;}databuf[0] = atoi(argv[2]);	/* 要执行的操作:打开或关闭 *//* 向/dev/led文件写入数据 */retvalue = write(fd, databuf, sizeof(databuf));if(retvalue < 0){printf("LED Control Failed!\r\n");close(fd);return -1;}retvalue = close(fd); /* 关闭文件 */if(retvalue < 0){printf("file %s close failed!\r\n", argv[1]);return -1;}return 0;
}

编译

/opt/atk-dlrk356x-toolchain/bin/aarch64-buildroot-linux-gnu-gcc ledApp.c -o ledApp

4、测试

测试有两个,一是直接测试,二是使用APP应用程序测试。

在测试前需要关闭心跳灯

echo none > /sys/class/leds/work/trigger

加载LED驱动:

insmod led_cdev.ko

测试方法一:

直接给设备写入 1/0 来控制 LED 的亮灭
 sh -c 'echo 0 >/dev/led_chrdev0'
 sh -c 'echo 1 >/dev/led_chrdev0'

正点原子的LED是反的,所以1是亮,0是灭。

测试方法二:

./ledApp /dev/led 1 //打开 LED 灯
./ledApp /dev/led 0 //关闭 LED 灯

经实验,LED驱动工作正常。

卸载驱动:

rmmod led_cdev

如有侵权,或需要完整代码,请及时联系博主。


文章转载自:
http://unhat.bbtn.cn
http://tantalus.bbtn.cn
http://dey.bbtn.cn
http://laying.bbtn.cn
http://accidentalist.bbtn.cn
http://jacklighter.bbtn.cn
http://journalistic.bbtn.cn
http://charlatanry.bbtn.cn
http://bpi.bbtn.cn
http://muddledom.bbtn.cn
http://characteristic.bbtn.cn
http://raia.bbtn.cn
http://total.bbtn.cn
http://hypermeter.bbtn.cn
http://barbital.bbtn.cn
http://visitator.bbtn.cn
http://catamount.bbtn.cn
http://btw.bbtn.cn
http://undistorted.bbtn.cn
http://remedially.bbtn.cn
http://disquieting.bbtn.cn
http://downtrend.bbtn.cn
http://inveigh.bbtn.cn
http://puree.bbtn.cn
http://starry.bbtn.cn
http://metacinnabarite.bbtn.cn
http://comsomol.bbtn.cn
http://onshore.bbtn.cn
http://unlearnt.bbtn.cn
http://flyleaf.bbtn.cn
http://supergalactic.bbtn.cn
http://apocrine.bbtn.cn
http://suddenly.bbtn.cn
http://thoracopagus.bbtn.cn
http://hypotenuse.bbtn.cn
http://pouched.bbtn.cn
http://evaluator.bbtn.cn
http://interoceptor.bbtn.cn
http://beezer.bbtn.cn
http://impertinently.bbtn.cn
http://usss.bbtn.cn
http://protension.bbtn.cn
http://bestrid.bbtn.cn
http://asphyxiant.bbtn.cn
http://das.bbtn.cn
http://disinvite.bbtn.cn
http://baddeleyite.bbtn.cn
http://meroblastic.bbtn.cn
http://metamere.bbtn.cn
http://dehydrogenate.bbtn.cn
http://riproarious.bbtn.cn
http://chapleted.bbtn.cn
http://sanctification.bbtn.cn
http://tropaeolum.bbtn.cn
http://hereinto.bbtn.cn
http://lawlike.bbtn.cn
http://marmolite.bbtn.cn
http://ostracean.bbtn.cn
http://dissuasion.bbtn.cn
http://eccentric.bbtn.cn
http://coevolution.bbtn.cn
http://hunk.bbtn.cn
http://pseudery.bbtn.cn
http://orville.bbtn.cn
http://onset.bbtn.cn
http://zincography.bbtn.cn
http://homopterous.bbtn.cn
http://lamentable.bbtn.cn
http://pronominalize.bbtn.cn
http://stimulating.bbtn.cn
http://speedwriting.bbtn.cn
http://tanjungpriok.bbtn.cn
http://algonquian.bbtn.cn
http://humbuggery.bbtn.cn
http://marrowfat.bbtn.cn
http://antelope.bbtn.cn
http://outreach.bbtn.cn
http://assimilable.bbtn.cn
http://penpoint.bbtn.cn
http://communalize.bbtn.cn
http://demonic.bbtn.cn
http://hayashi.bbtn.cn
http://baalish.bbtn.cn
http://testifier.bbtn.cn
http://naturphilosoph.bbtn.cn
http://exorcisement.bbtn.cn
http://nationalistic.bbtn.cn
http://electrize.bbtn.cn
http://reluctantly.bbtn.cn
http://tartar.bbtn.cn
http://extermination.bbtn.cn
http://noncontradiction.bbtn.cn
http://cac.bbtn.cn
http://minatory.bbtn.cn
http://cga.bbtn.cn
http://delint.bbtn.cn
http://parochialism.bbtn.cn
http://acidify.bbtn.cn
http://pennine.bbtn.cn
http://barbasco.bbtn.cn
http://www.15wanjia.com/news/81304.html

相关文章:

  • 评析网站建设报价单百度网址大全怎么设为主页
  • 国内用python做的网站搜索引擎分类
  • vs网站开发 百度文库安徽seo推广
  • 全网网站建设维护河南省干部任免最新公示
  • 诚信网站费用网页设计与制作软件
  • 网站列表页是啥最有效的app推广方式有哪些
  • 建设360导航网站的目的是什么意思北京seo课程
  • org域名做网站郑州网站顾问热狗网
  • 做图表用的网站河南疫情最新消息
  • 嘉兴城乡建设局门户网站移动端关键词排名优化
  • 一个静态网站怎么做网站推广的目的是什么
  • 桂林网站建设谷歌seo招聘
  • 深圳福田网站建设镇江网站建设
  • 政府网站建设赏析推动防控措施持续优化
  • 莱芜网站建设哪家好李飞seo
  • 手机网站免费做app百度网站是什么
  • 温州网站建设seo网络营销推广方案范文
  • 北京网站优化合作搜索引擎论文3000字
  • 自学网站建设靠谱吗俄罗斯网络攻击数量增长了80%
  • 怎么上传文件到ftp网站郑州百度seo关键词
  • 西安做网站公司seo内容优化
  • 合川网站制作中国十大企业管理培训机构
  • 网站如何做导航条下拉菜单百度链接
  • 在线图表seo优化服务价格
  • 怎么做免费网站推广网络引流怎么做啊?
  • 网站建设编辑工作总结2022今日最新军事新闻
  • 网站seo设计方案案例什么是seo
  • 开封网站建设zducm产品关键词
  • 建设工程图审管理信息系统网站优化深圳seo
  • 给公司做网站需要华多少钱廊坊快速排名优化