IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 【嵌入式】 基于STM32MP1的简单LED驱动程序 -> 正文阅读

[嵌入式]【嵌入式】 基于STM32MP1的简单LED驱动程序

注意参考内核例程

一、驱动

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <linux/device.h>


static int major;
static struct class *led_class;

/* 寄存器 */
//RCC PLL4 Control Register (RCC_PLL4CR) 0x50000000+0x894	//使能PLL4时钟
static volatile unsigned int *RCC_PLL4CR;	

//RCC_MP_AHB4ENSETR地址:0x50000000 + 0xA28					//使能GPIO
static volatile unsigned int *RCC_MP_AHB4ENSETR;

//GPIOA_MODER地址:0x50002000 + 0x00,设置bit[21:20]=0b01,		//PA10输出
static volatile unsigned int *GPIOA_MODER;

//GPIOA_ODR地址: 0x50002000 + 0x14							//读寄存、修改值、写回去(低效)
static volatile unsigned int *GPIOA_ODR;

//GPIOA_BSRR地址: 0x50002000 + 0x18							// 直接写寄存器,一次操作即可,高效
static volatile unsigned int *GPIOA_BSRR;





static ssize_t led_write(struct file *filp, const char __user *buf,
			 size_t count, loff_t *ppos)
{
	printk("%s %s %d\n",__FILE__, __FUNCTION__,__LINE__);
	char val;
	/* copy_from_user: 从应用程序中获取数据*/
	copy_from_user(&val, buf, 1);
	/* 设置数据,设置gpio输出,0/1 */
	if(val)
	{	
		//灯亮
		*GPIOA_BSRR = (1<<26);	//输出低电平 GPIOA10
	}
	else
	{
		//灯灭
		*GPIOA_BSRR = (1<<10); //输出高电平
	}
	return 1;
}


static int led_open(struct inode *inode, struct file *filp)
{
	/* 配置gpio,使能、配置为gpio,配置输入输出 */

	//配置时钟
	*RCC_PLL4CR |= (1<<0);
	while((*RCC_PLL4CR & (1<<1)) == 0);

	//使能GPIOA
	*RCC_MP_AHB4ENSETR |= (1<<0);

	//设置PA10用作输出,先清零,在设置为输出
	*GPIOA_MODER &= ~(3<<20);
	*GPIOA_MODER |= (0x01<<20);

	
	return 0;
}


static const struct file_operations led_fops = {
	.owner		= THIS_MODULE,
	//.read		= led_read,
	.write		= led_write,
	.open		= led_open,
	//.release	= led_close,
	//.poll		= led_poll,
	//.llseek		= no_llseek,
};


/* 入口函数 */
static int __init led_init(void)
{
	

	major = register_chrdev(0, "tanzhenwen_led", &led_fops);	//在/proc/devices会显示
	if (major < 0) {
		printk("could not get major number\n");
		class_destroy(led_class);
		return major;
	}

	
	led_class = class_create(THIS_MODULE, "led_calss");
	//if (IS_ERR(led_class))
	//	return PTR_ERR(led_class);
	device_create(led_class, NULL, MKDEV(major, 0), NULL, "led_drv");	// /dev/led_drv
	

	/* ioremap :使用虚拟地址,后期可以用虚拟地址来访问寄存器 */
	//ioremap(mem_addr, mem_len);
	//RCC PLL4 Control Register (RCC_PLL4CR) 0x50000000+0x894	//使能PLL4时钟
	RCC_PLL4CR = ioremap(0x50000000+0x894, 4);	

	//RCC_MP_AHB4ENSETR地址:0x50000000 + 0xA28					//使能GPIO
	RCC_MP_AHB4ENSETR = ioremap(0x50000000 + 0xA28, 4);
	
	//GPIOA_MODER地址:0x50002000 + 0x00,设置bit[21:20]=0b01,		//PA10输出
	GPIOA_MODER = ioremap(0x50002000 + 0x00, 4);

	//GPIOA_ODR地址: 0x50002000 + 0x14							//读寄存、修改值、写回去(低效)
	GPIOA_ODR = ioremap(0x50002000 + 0x14, 4);;

	//GPIOA_BSRR地址: 0x50002000 + 0x18							// 直接写寄存器,一次操作即可,高效
	GPIOA_BSRR = ioremap(0x50002000 + 0x18, 4);

	
	return 0;
}

static void __exit led_exit(void)
{
	iounmap(RCC_PLL4CR);
	iounmap(RCC_MP_AHB4ENSETR);
	iounmap(GPIOA_MODER);
	iounmap(GPIOA_ODR);
	iounmap(GPIOA_BSRR);
	
	unregister_chrdev(major, "tanzhenwen_led");
	
	device_destroy(led_class,  MKDEV(major, 0));
	class_destroy(led_class);
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

二、测试程序

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>





//ledtest /dev/led_drv on
//ledtest /dev/led_drv off
int main(int argc, char *argv[])
{
 	int fd;
	char status = 0;
	if(argc != 3 )
	{
		printf("Usage: %s <dev> <on|off>\n",argv[0]);
		printf("   eg: %s /dev/led_drv on\n");
		printf("   eg: %s /dev/led_drv off\n");
	}

	//open
	fd = open(argv[1],O_RDWR);
	if(fd < 0)
	{
		printf("can not open %s\n",argv[1]);
		return -1;
	}
	//write

	if(strcmp(argv[2],"on") == 0)
	{
		status = 1;
	}
	else
	{
		status = 0;
	}
	write(fd,&status,1);
	return 0;
}

三、测试

让心跳灯不闪烁

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

cat /proc/devices可以看见tanzhenwen_led字符设备节点
在这里插入图片描述
执行ls /dev/led_drv -al,可以看见具有led_drv的设备。
在这里插入图片描述

执行./led_test /dev/led_drv off以及./led_test /dev/led_drv on可以观察到LED灯的亮灭。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-26 10:20:39  更:2021-09-26 10:22:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 3:26:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码