驱动开发,stm32mp157a开发板的led灯控制实验

这篇具有很好参考价值的文章主要介绍了驱动开发,stm32mp157a开发板的led灯控制实验。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.实验目的

        编写LED灯的驱动,在应用程序中编写控制LED灯亮灭的代码逻辑实现LED灯功能的控制;

2.LED灯相关寄存器分析

LED1->PE10 LED1亮灭:

RCC寄存器[4]->1 0X50000A28

GPIOE_MODER[21:20]->01 (输出) 0X50006000

GPIOE_ODR[10]->1(输出高电平) 0(输出低电平)0X50006014

LED2->PF10 LED2亮灭:

RCC寄存器[5]->1 0X50000A28

GPIOE_MODER[21:20]->01 (输出) 0X50006000

GPIOE_ODR[10]->1(输出高电平) 0(输出低电平)0X50006014

LED3->PE8 LED3亮灭:

RCC寄存器[4]->1 0X50000A28

GPIOE_MODER[17:16]->01 (输出) 0X50006000

GPIOE_ODR[8]->1(输出高电平) 0(输出低电平)0X50006014

GPIOE_OTYPER默认为00

GPIOE_PUPDR默认为0

GPIOE_OSPEEDR默认为00

3.编写代码

---Makefile---工程管理文件

modname?=demo
arch?=arm
ifeq ($(arch),arm)
KERNELDIR:= /home/ubuntu/FSMP1A/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61 #编译生成ARM架构
else
KERNELDIR:=/lib/modules/$(shell uname -r)/build #编译生成X86架构
endif

PWD:=$(shell pwd) #模块化编译文件路径
all:
	make -C $(KERNELDIR) M=$(PWD) modules
clean:
	make -C $(KERNELDIR) M=$(PWD) clean

obj-m:=$(modname).o

---head.h---头文件

#ifndef __HEAD_H__
#define __HEAD_H__

typedef struct
{
    unsigned int MODER;
    unsigned int OTYPER;
    unsigned int OSPEEDR;
    unsigned int PUPDR;
    unsigned int IDR;
    unsigned int ODR;   
}gpio_t;

//LED1和LED3寄存器地址
#define LED1_ADDR 0x50006000
#define LED2_ADDR 0x50007000
#define LED3_ADDR 0x50006000
#define RCC_ADDR 0x50000A28

#endif

---mychrdev.c---驱动程序

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "head.h"
#include<linux/device.h>

char kbuf[128] = {0};
unsigned int major;
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;

struct class *cls;
struct device *dev;

//封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}

ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
    int ret;
    if(size > sizeof(kbuf))
    {
        size = sizeof(kbuf);
    }
    ret = copy_to_user(ubuf,kbuf,size);
    if(ret)
    {
        printk("copy_to_user err\n");
        return -EIO;
    }

    return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
    unsigned long ret;
    if(size > sizeof(kbuf))
    {
        size = sizeof(kbuf);
    }
    ret = copy_from_user(kbuf,ubuf,size);
    if(ret)
    {
        printk("copy_from_user err\n"); 
        return -EIO;   
    }
    
    switch(kbuf[0])
    {
        case '1':
            if(kbuf[1] == '1')  //开灯
                vir_led1->ODR |= (0x1 << 10);
            else if(kbuf[1] == '0')  //关灯
                vir_led1->ODR &= (~(0x1 << 10));
            break;
         case '2':
            if(kbuf[1] == '1')  //开灯
                vir_led2->ODR |= (0x1 << 10);
            else if(kbuf[1] == '0') //关灯
                vir_led2->ODR &= (~(0x1 << 10));
            break;
         case '3':
            if(kbuf[1] == '1')  //开灯
                vir_led3->ODR |= (0x1 << 8);
            else if(kbuf[1] == '0') //关灯
                vir_led3->ODR &= (~(0x1 << 8));
            break;
        default:
            printk("输入错误\n"); 
    }
    return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}

struct file_operations fops={
    .open=mycdev_open,
    .read=mycdev_read,
    .write=mycdev_write,
    .release=mycdev_close,
};

//相关寄存器地址映射及初始化
int all_led_init(void)
{
    //相关寄存器的内存映射
    vir_led1=ioremap(LED1_ADDR,sizeof(gpio_t));
    if(vir_led1 == NULL)
    {
        printk("物理内存映射失败%d\n",__LINE__);
        return -ENOMEM;
    }

    vir_led2=ioremap(LED2_ADDR,sizeof(gpio_t));
    if(vir_led2 == NULL)
    {
        printk("物理内存映射失败%d\n",__LINE__);
        return -ENOMEM;
    }

    vir_led3 = vir_led1;

    vir_rcc=ioremap(RCC_ADDR,4);
    if(vir_rcc == NULL)
    {
        printk("物理内存映射失败%d\n",__LINE__);
        return -ENOMEM;
    }
    printk("寄存器内存映射成功\n");

    //硬件寄存器的初始化
    (*vir_rcc) |= (0x3 << 4);
    
    //LED1
    vir_led1->MODER &= (~(0x3 << 20));
    vir_led1->MODER |= (0x1 << 20);
    vir_led1->ODR &= (~(0x1 << 10));

    //LED2
    vir_led2->MODER &= (~(0x3 << 20));
    vir_led2->MODER |= (0x1 << 20);
    vir_led2->ODR &= (~(0x1 << 10));

    //LED3
    vir_led3->MODER &= (~(0x3 << 16));
    vir_led3->MODER |= (0x1 << 16);
    vir_led3->ODR &= (~(0x1 << 8));

    printk("寄存器初始化成功\n");
    return 0;
}

//入口函数
static int __init mycdev_init(void)
{
	major = register_chrdev(0,"mychrdev",&fops);
    if(major < 0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功:major=%d\n",major);

    //寄存器映射及初始化
    all_led_init();

    //向上提交目录
    cls = class_create(THIS_MODULE,"mychrdev");
    if(IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        return -PTR_ERR(cls);
    }
    printk("向上提交目录成功\n");

    //向上提交设备节点信息
    int i;
    for(i=0; i<3; i++)
    {
        dev = device_create(cls,NULL,MKDEV(major,i),NULL,"mychrdev%d",i);
        if(IS_ERR(dev))
        {
            printk("向上提交设备节点信息失败\n");
            return -PTR_ERR(dev);
        }
    }
    printk("向上提交设备节点信息成功\n");

	return 0;
}

//出口函数
static void __exit mycdev_exit(void)
{
    //销毁设备节点信息
    int i;
    for(i=0; i<3; i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }

    //销毁目录信息
    class_destroy(cls);

    //取消物理内存的映射
    iounmap(vir_led1);
    iounmap(vir_led2);
    iounmap(vir_rcc);
    
    //字符设备驱动注销
    unregister_chrdev(major,"mychrdev");
}

//声明
//入口函数地址
module_init(mycdev_init);
//出口函数地址
module_exit(mycdev_exit);
//遵循的GPL协议
MODULE_LICENSE("GPL");

---test.c---应用程序测试程序

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

int main(int argc,char const *argv[])
{
    char buf[128]={0};
    int fd = open("/dev/mychrdev0",O_RDWR);

    if(fd < 0)
    {
        printf("设备文件打开失败\n");
        exit(-1);
    }
    while(1)
    {
        printf("第一个字符:1(LED1) 2(LED2) 3(LED3)\n");
        printf("第二个字符1(开灯)0(关灯)\n");
        printf("输入控制灯的两个字符>>> ");
       
        fgets(buf,sizeof(buf),stdin);
        buf[strlen(buf)-1] = '\0';
        //像设备文件中写
        write(fd,buf,sizeof(buf));
    }

    close(fd);
    
    return 0;  
}

4.测试

驱动开发,stm32mp157a开发板的led灯控制实验,驱动开发,驱动开发,stm32,嵌入式硬件

驱动开发,stm32mp157a开发板的led灯控制实验,驱动开发,驱动开发,stm32,嵌入式硬件文章来源地址https://www.toymoban.com/news/detail-706567.html

到了这里,关于驱动开发,stm32mp157a开发板的led灯控制实验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32MP157驱动开发——按键驱动(tasklet)

    阅读Linux 系统中异常与中断可知,Linux 系统对中断处理的演进过程中,实现了中断的扩展:硬件中断、软件中断 硬件中断有:GPIO,网络中断(net),系统滴答中断(tick)等 软件中断有:定时器,tasklet等 内核中的软中断: 该数组里面有个action成员,该成员是个函数,函数会调

    2024年02月14日
    浏览(43)
  • STM32MP157驱动开发——按键驱动(异步通知)

    Linux 系统中也有很多信号,在 Linux 内核源文件 includeuapiasm-genericsignal.h 中,有很多信号的宏定义: 就 APP 而言,你想处理 SIGIO 信息,那么需要提供信号处理函数,并且要跟 SIGIO 挂钩。这可以通过一个 signal 函数 来“给某个信号注册处理函数”,用法如下: 重点从②开始:

    2024年02月15日
    浏览(52)
  • STM32MP157驱动开发——按键驱动(休眠与唤醒)

    当应用程序必须等待某个事件发生,比如必须等待按键被按下时,可以使用“休眠-唤醒”机制: ① APP 调用 read 等函数试图读取数据,比如读取按键; ② APP 进入内核态,也就是调用驱动中的对应函数,发现有数据则复制到用户空间并马上返回; ③ 如果 APP 在内核态,也就

    2024年02月16日
    浏览(41)
  • STM32MP157驱动开发——按键驱动(POLL 机制)

    使用休眠-唤醒的方式等待某个事件发生时,有一个缺点:等待的时间可能很久。我们可以加上一个超时时间,这时就可以使用 poll 机制。 ① APP 不知道驱动程序中是否有数据,可以先调用 poll 函数查询一下,poll 函数可以传入超时时间; ② APP 进入内核态, 调用到驱动程序的

    2024年02月15日
    浏览(37)
  • STM32MP157驱动开发——USB设备驱动

    参考文章:【正点原子】I.MX6U嵌入式Linux驱动开发——Linux USB驱动   由于 USB 协议太过庞大和复杂,所以本节只对 STM32MP157 自带的 USB 驱动进行使能和测试。详细的 USB 接口和协议的介绍,可以参考原子哥的资料《USB2.0 协议中文版.pdf》和《USB3.0 协议中文版.pdf》。   USB 全

    2023年04月14日
    浏览(53)
  • STM32MP157驱动开发——按键驱动(线程化处理)

    工作队列是在内核的线程的上下文中执行的 工作队列中有多个 work,前一个 work 没处理完会影响后面的 work。解决方法有如下2种: 比如自己创建一个内核线程,不跟别的 work 在一块。例如存储设备比如 SD/TF采用的就是单独一个线程。 使用线程化的中断处理。中断的处理仍然

    2024年02月16日
    浏览(42)
  • STM32MP157驱动开发——按键驱动(定时器)

    定时器涉及函数参考内核源码:includelinuxtimer.h 给定时器的各个参数赋值: 设置定时器 :主要是初始化 timer_list 结构体,设置其中的函数、参数。 a) 向内核添加定时器。timer-expires 表示超时时间。 b) 当超时时间到达,内核就会调用这个函数:timer-function(timer-data)。 修改定时

    2024年02月15日
    浏览(52)
  • STM32MP157驱动开发——Linux LCD驱动(上)

      LCD 是很常用的一个外设,通过 LCD 可以显示图片、界面UI等,提高人机交互的效率。STM32MP1 提供了一个 LTDC 接口用于连接 RGB 接口的液晶屏。本节就来学习如何使用这个接口。   LCD 全称是 Liquid Crystal Display,也就是液晶显示器,是现在最常用到的显示器。网上对于 LCD

    2024年02月08日
    浏览(42)
  • ARM开发,stm32mp157a-A7核(UART总线实验)

    ---.h头文件--- ---.c功能实现文件--- ---.c主函数测试文件--- 结果: 字符:  字符串: 

    2024年02月11日
    浏览(46)
  • ARM开发,stm32mp157a-A7核中断实验(实现按键中断功能)

    ---key.h头文件--- ---key.c函数实现--- ---do_irq.c终端处理函数--- ---main.c测试文件---

    2024年02月11日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包