编写驱动实现六盏灯点亮以及马达、风扇、蜂鸣器的控制

文章描述了一个基于STM32MP1XX微控制器的GPIO和RCC驱动程序实现。它包含了头文件定义、LED控制功能、以及PWM设备的初始化和控制。驱动程序使用内核I/O操作函数进行物理地址映射和寄存器访问,并通过ioctl接口控制LED和PWM设备的开关状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

head.c

#ifndef __HEAD_H__
#define __HEAD_H__

//封装寄存器结体
typedef struct{
    volatile unsigned int MODER;
    volatile unsigned int OTYPER;
    volatile unsigned int  OSPEEDR;
    volatile unsigned int  PUPDR;
    volatile unsigned int  IDR;
    volatile unsigned int  ODR;
    volatile unsigned int   BSRR;
}gpio_t;

#define PHY_RCC_ADDR  0X50000A28
#define AHB5_RCC_ADDR 0x50000210
#define PHY_LED1_ADDR 0X50006000
#define PHY_LED2_ADDR 0X50007000
#define PHY_LED3_ADDR 0X50006000
#define AHB5_LED_ADDR 0x54004000
//封装LED1开关的功能码
#define LED_ON _IOW('l',1,int)//开灯
#define LED_OFF _IOW('l',0,int)//关灯

#endif

led_dev.c

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

int major;
struct class *cls;
struct device *dev;
//定义一些变量接收映射后的虚拟地址
unsigned int *vir_rcc;
unsigned int *AHB5_rcc;
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
gpio_t *AHB5_LED;
char kbuf[128]={0};
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 *off)
{
    int ret; 
    //判断kbuf的大小,如果<size,把size的数值修改为kbuf的大小
    if(size>sizeof(kbuf))
    size=sizeof(kbuf);
    ret=copy_to_user(ubuf,kbuf,size);
    if(ret)
    {
        printk("copy_to_user filed\n");
        return -EIO;//拷贝失败返回错误码
    }
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
ssize_t  mycdev_write(struct file *file, const char  *ubuf, size_t size, loff_t *off)
{
    int ret;
    if(size>sizeof(kbuf))
    size=sizeof(kbuf);
    ret=copy_from_user(kbuf,ubuf,size);
    if(ret)
    {
        printk("copy_from_user filed\n");
        return -EIO;//拷贝失败返回错误码
    }

    return 0;
}
//ioctl
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  {
    int which,ret;
    switch(cmd)
    {
        case LED_ON:
           ret=copy_from_user(&which,(void *)arg,sizeof(int));//把ioctl第三个参数的数值获取到
           if(ret)
           {
            printk("copy_from_user err\n");
            return -ENOMEM;
           }
           switch(which)
           {
            case 1:
                vir_led1->ODR |= (1<<10);
                printk("LED1开灯\n");
                break;
            case 2:
                vir_led2->ODR |= (1<<10);
                printk("LED2开灯\n");
                break;
            case 3:
                vir_led3->ODR  |= (1<<8);
                printk("LED3开灯");
                break;
            case 4:
                AHB5_LED->ODR |= (1<<5);
                printk("LEDa开灯");
                break;
            case 5:
                AHB5_LED->ODR |= (1<<6);
                printk("LEDb开灯");
                break;
            case 6:
                AHB5_LED->ODR |= (1<<7);
                printk("LEDc开灯");
                break;                
           }
    
            break;
        case LED_OFF:
              ret=copy_from_user(&which,(void *)arg,sizeof(int));//把ioctl第三个参数的数值获取到
           if(ret)
           {
            printk("copy_from_user err\n");
            return -ENOMEM;
           }
           switch(which)
           {
            case 1:
                vir_led1->ODR &= (~(1<<10));
                printk("LED1关灯\n");
                break;
            case 2:
                vir_led2->ODR &= (~(1<<10));
                printk("LED2关灯\n");
                break;
            case 3:
                vir_led3->ODR &= (~(1<<8));
                printk("LED3关灯");
                break;
            case 4:
                AHB5_LED->ODR &= (~(1<<5));
                printk("LEDa关灯");
                break;

            case 5:
                AHB5_LED->ODR &= (~(1<<6));
                printk("LEDb关灯");
                break;

            case 6:
                AHB5_LED->ODR &= (~(1<<7));
                printk("LEDc关灯");
                break;

           }
            break;
    }

    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,
    .unlocked_ioctl=mycdev_ioctl,
    .release=mycdev_close,
};
void all_led_init(void)
{
    //进行物理地址的映射
    vir_led1=ioremap(PHY_LED1_ADDR,sizeof(gpio_t));
    if(vir_led1==NULL)
    {
        printk("LED1寄存器映射失败\n");
      
    }
    vir_led2=ioremap(PHY_LED2_ADDR,sizeof(gpio_t));
    if(vir_led2==NULL)
    {
        printk("LED2寄存器映射失败\n");
    
    }
    vir_led3=ioremap(PHY_LED3_ADDR,sizeof(gpio_t));
    if(vir_led3==NULL)
    {
        printk("LED3寄存器映射失败\n");
      
    }
    AHB5_LED=ioremap(AHB5_LED_ADDR,sizeof(gpio_t));

    vir_rcc=ioremap(PHY_RCC_ADDR,4);
    if(vir_rcc==NULL)
    {
        printk("vir_rcc寄存器映射失败\n");
       
    }

    /*AHB5_rcc=ioremap(AHB5_RCC_ADDR,4);
    if(AHB5_rcc==NULL)
    {
        printk("AHB5_RCC寄存器映射失败\n");
       
    }*/    
    printk("寄存器物理地址映射成功\n");
    //寄存器的初始化
    vir_led1->MODER &= (~(3<<20));//设置为输出模式
    vir_led1->MODER |= (1<<20);
    vir_led1->ODR &= (~(1<<10));//输出低电平

    vir_led2->MODER &= (~(3<<20));//设置为输出模式
    vir_led2->MODER |= (1<<20);
    vir_led2->ODR &= (~(1<<10));//输出低电平

    vir_led3->MODER &= (~(3<<16));//设置为输出模式
    vir_led3->MODER |= (1<<16);
    vir_led3->ODR &= (~(1<<8));//输出低电平
 
    AHB5_LED->MODER &= (~(3<<10));//设置为输出模式
    AHB5_LED->MODER |= (1<<10);
    AHB5_LED->ODR &= (~(1<<5));//输出低电平

    AHB5_LED->MODER &= (~(3<<12));//设置为输出模式
    AHB5_LED->MODER |= (1<<12);
    AHB5_LED->ODR &= (~(1<<6));//输出低电平

    AHB5_LED->MODER &= (~(3<<14));//设置为输出模式
    AHB5_LED->MODER |= (1<<14);
    AHB5_LED->ODR &= (~(1<<7));//输出低电平

    (*vir_rcc) |= (3<<4);//rcc使能
    printk("寄存器初始化成功\n");
    //(*AHB5_rcc) |=(1);

}
//入口函数
static int __init mycdev_init(void)
{
      int i;
    //进行字符设备驱动的注册
    major=register_chrdev(0,"mycdev",&fops);
    if(major<0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功,major=%d\n",major);
    //向上提交目录
    cls=class_create(THIS_MODULE,"mycdev");
    if(IS_ERR(cls))//指针指向预留空间,函数调用失败
    {
        printk("向上提交目录失败\n");
        return PTR_ERR(cls);
    }
     printk("向上提交目录成功\n");
     //向上提交设备节点
    
     for(i=0;i<3;i++)
     {
        dev=device_create(cls,NULL,MKDEV(major,i),NULL,"mycdev%d",i);
         if(IS_ERR(dev))//指针指向预留空间,函数调用失败
        {
             printk("向上提交目录失败\n");
            return PTR_ERR(dev);
        }
     }
     printk("设备节点向上提交成功\n");
    //led寄存器初始化
    all_led_init();

    return 0;
}
//出口函数
static void __exit mycdev_exit(void)
{
      int i;
    //取消物理内存的映射
    iounmap(vir_led1);
    iounmap(vir_led2);
    iounmap(vir_led3);
    iounmap(vir_rcc);
    iounmap(AHB5_LED);
    //iounmap(AHB5_rcc);
    //删除节点信息
  
    for(i=0;i<3;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //删除目录信息
    class_destroy(cls);
    //字符设备驱动的注销
    unregister_chrdev(major,"mycdev");

}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

led.c

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include<string.h>
#include <sys/ioctl.h>  
#include"head.h"
int main(int argc, char const *argv[])
{
    char buf[128]={0};
    int which,a;
    int fd=open("/dev/mycdev0",O_RDWR);
    if(fd<0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
    //在终端输入数据
    while(1)
    {
      printf("请输入要进行的操作:1(开灯) 0(关灯)->");
      scanf("%d",&a);
      if(a==1)
      {
        printf("请输入要进行操作的灯:1(LED1) 2(LED2) 3(LED3) 4(LEDa) 5(LEDb) 6(LEDc) ->");
        scanf("%d",&which);
        ioctl(fd,LED_ON,&which);
      }
      else
      {
        printf("请输入要进行操作的灯:1(LED1) 2(LED2) 3(LED3) 4(LEDa) 5(LEDb) 6(LEDc) ->");
        scanf("%d",&which);
        ioctl(fd,LED_OFF,&which);
      }
      
    }
    close(fd);
    return 0;
}

现象:

_____________________________________________________________________________

head.h

#ifndef __HEAD_H__
#define __HEAD_H__

#include "rcc.h"
#include "gpio.h"
//封装LED开关的功能码
#define PWM_ON _IOW('p',1,int)//开
#define PWM_OFF _IOW('p',0,int)//关

#endif

rcc.h

#ifndef __STM32MP1XX_RCC_H__
#define __STM32MP1XX_RCC_H__ 

typedef struct {
	volatile unsigned int TZCR;     	// 0x000
	volatile unsigned int res1[2]; 		// 0x004-0x008
	volatile unsigned int OCENSETR;     // 0x00C
	volatile unsigned int OCENCLRR;  	// 0x010
	volatile unsigned int res2[1]; 		// 0x014
	volatile unsigned int HSICFGR; 		// 0x018
	volatile unsigned int CSICFGR; 		// 0x01C
	volatile unsigned int MPCKSELR; 	// 0x020
	volatile unsigned int ASSCKSELR; 	// 0x024
	volatile unsigned int PCK12SELR; 	// 0x028
	volatile unsigned int MPCKDIVR; 	// 0x02C
	volatile unsigned int AXIDIVR; 		// 0x030
	volatile unsigned int res3[2];      
	volatile unsigned int APB4DIVR; 	// 0x03C
	volatile unsigned int APB5DIVR; 	// 0x040
	volatile unsigned int RTCDIVR; 		// 0x044
	volatile unsigned int MSSCKSELR;    // 0x048
	volatile unsigned int res4[13];
	volatile unsigned int PLL1CR; 		// 0x080
	volatile unsigned int PLL1CFGR1; 	// 0x084
	volatile unsigned int PLL1CFGR2; 	// 0x088
	volatile unsigned int PLL1FRACR; 	// 0x08C
	volatile unsigned int PLL1CSGR;     // 0x090
	volatile unsigned int PLL2CR; 		// 0x094
	volatile unsigned int PLL2CFGR1; 	// 0x098
	volatile unsigned int PLL2CFGR2; 	// 0x09C
	volatile unsigned int PLL2FRACR;    // 0x0A0
	volatile unsigned int PLL2CSGR;     // 0x0A4
	volatile unsigned int res5[6];
	volatile unsigned int I2C46CKSELR;  // 0x0C0
	volatile unsigned int SPI6CKSELR;   // 0x0C4
	volatile unsigned int UART1CKSELR;  // 0x0C8
	volatile unsigned int RNG1CKSELR;   // 0x0CC
	volatile unsigned int CPERCKSELR;   // 0x0D0
	volatile unsigned int STGENCKSELR;  // 0x0D4
	volatile unsigned int DDRITFCR; 	// 0x0D8
	volatile unsigned int res6[9];
	volatile unsigned int MP_BOOTCR;  	// 0x100
	volatile unsigned int MP_SREQSETR;  // 0x104
	volatile unsigned int MP_SREQCLRR;  // 0x108
	volatile unsigned int MP_GCR;  		// 0x10C
	volatile unsigned int MP_APRSTCR; 	// 0x110 
	volatile unsigned int MP_APRSTSR;   // 0x114
	volatile unsigned int res7[10];
	volatile unsigned int BDCR; 		// 0x140
	volatile unsigned int RDLSICR;  	// 0x144
	volatile unsigned int res8[14];
	volatile unsigned int APB4RSTSETR; 	// 0x180
	volatile unsigned int APB4RSTCLRR; 	// 0x184
	volatile unsigned int APB5RSTSETR;  // 0x188
	volatile unsigned int APB5RSTCLRR;  // 0x18C
	volatile unsigned int AHB5RSTSETR;  // 0x190
	volatile unsigned int AHB5RSTCLRR;  // 0x194
	volatile unsigned int AHB6RSTSETR;  // 0x198
	volatile unsigned int AHB6RSTCLRR;  // 0x19C
	volatile unsigned int TZAHB6RSTSELR;// 0x1A0
	volatile unsigned int TZAHB6RSTCLRR;// 0x1A4
	volatile unsigned int res9[22];
	volatile unsigned int MP_APB4ENSETR;// 0x200
	volatile unsigned int MP_APB4ENCLRR;// 0x204
	volatile unsigned int MP_APB5ENSETR;// 0x208
	volatile unsigned int MP_APB5ENCLRR;// 0x20C
	volatile unsigned int MP_AHB5ENSETR;// 0x210
	volatile unsigned int MP_AHB5ENCLRR;// 0x214
	volatile unsigned int MP_AHB6ENSETR;// 0x218
	volatile unsigned int MP_AHB6ENCLRR;// 0x21C
	volatile unsigned int MP_TZAHB6ENSELR;// 0x220
	volatile unsigned int MP_TZAHB6ENCLRR;// 0x224
	volatile unsigned int res10[22];
	volatile unsigned int MC_APB4ENSETR; // 0x280
	volatile unsigned int MC_APB4ENCLRR; // 0x284
	volatile unsigned int MC_APB5ENSETR; // 0x288
	volatile unsigned int MC_APB5ENCLRR; // 0x28C
	volatile unsigned int MC_AHB5ENSETR; // 0x290
	volatile unsigned int MC_AHB5ENCLRR; // 0x294
	volatile unsigned int MC_AHB6ENSETR; // 0x298
	volatile unsigned int MC_AHB6ENCLRR; // 0x29C
	volatile unsigned int res11[24];
	volatile unsigned int MP_APB4LPENSETR; // 0x300
	volatile unsigned int MP_APB4LPENCLRR; // 0x304
	volatile unsigned int MP_APB5LPENSETR; // 0x308
	volatile unsigned int MP_APB5LPENCLRR; // 0x30C
	volatile unsigned int MP_AHB5LPENSETR; // 0x310
	volatile unsigned int MP_AHB5LPENCLRR; // 0x314
	volatile unsigned int MP_AHB6LPENSETR; // 0x318
	volatile unsigned int MP_AHB6LPENCLRR; // 0x31C
	volatile unsigned int MP_TZAHB6LPENSETR; // 0x320
	volatile unsigned int MP_TZAHB6LPENCLRR; // 0x324
	volatile unsigned int res12[22];
	volatile unsigned int MC_APB4LPENSETR; // 0x380
	volatile unsigned int MC_APB4LPENCLRR; // 0x384
	volatile unsigned int MC_APB5LPENSETR; // 0x388
	volatile unsigned int MC_APB5LPENCLRR; // 0x38C
	volatile unsigned int MC_AHB5LPENSETR; // 0x390
	volatile unsigned int MC_AHB5LPENCLRR; // 0x394
	volatile unsigned int MC_AHB6LPENSETR; // 0x398
	volatile unsigned int MC_AHB6LPENCLRR; // 0x39C
	volatile unsigned int res13[24];
	volatile unsigned int BR_RSTSCLRR; 		// 0x400
	volatile unsigned int MP_GRSTCSETR; 	// 0x404
	volatile unsigned int MP_RSTSR; 		// 0x408 
	volatile unsigned int MP_IWDGFZSETR; 	// 0x40C
	volatile unsigned int MP_IWDGFZCLRR;  	// 0x410
	volatile unsigned int MP_CIER; 			// 0x414
	volatile unsigned int MP_CIFR; 			// 0x418
	volatile unsigned int PWRLPDLYCR; 		// 0x41C
	volatile unsigned int MP_RSTSS; 		// 0x420
	volatile unsigned int res14[247];
	volatile unsigned int MCO1CFGR; 		// 0x800
	volatile unsigned int MCO2CFGR; 		// 0x804 
	volatile unsigned int OCRDYR; 			// 0x808
	volatile unsigned int DBGCFGR; 			// 0x80C
	volatile unsigned int res15[4];
	volatile unsigned int RCK3SELR; 		// 0x820
	volatile unsigned int RCK4SELR; 		// 0x824
	volatile unsigned int TIMG1PRER;  		// 0x828
	volatile unsigned int TIMG2PRER; 		// 0x82C
	volatile unsigned int MCUDIVR; 			// 0x830
	volatile unsigned int APB1DIVR; 		// 0x834
	volatile unsigned int APB2DIVR; 		// 0x838
	volatile unsigned int APB3DIVR; 		// 0x83C
	volatile unsigned int res16[16];
	volatile unsigned int PLL3CR;   		// 0x880
	volatile unsigned int PLL3CFGR1; 		// 0x884
	volatile unsigned int PLL3CFGR2; 		// 0x888
	volatile unsigned int PLL3FRACR; 		// 0x88C
	volatile unsigned int PLL3CSGR; 		// 0x890
	volatile unsigned int PLL4CR; 			// 0x894
	volatile unsigned int PLL4CFGR1; 		// 0x898
	volatile unsigned int PLL4CFGR2; 		// 0x89C
	volatile unsigned int PLL4FRACR; 		// 0x8A0
	volatile unsigned int PLL4CSGR; 		// 0x8A4
	volatile unsigned int res17[6];
	volatile unsigned int I2C12CKSELR; 		// 0x8C0
	volatile unsigned int I2C35CKSELR;  	// 0x8C4
	volatile unsigned int SAI1CKSELR; 		// 0x8C8
	volatile unsigned int SAI2CKSELR; 		// 0x8CC
	volatile unsigned int SAI3CKSELR; 		// 0x8D0
	volatile unsigned int SAI4CKSELR; 		// 0x8D4
	volatile unsigned int SPI2S1CKSELR; 	// 0x8D8
	volatile unsigned int SPI2S23CKSELR; 	// 0x8DC
	volatile unsigned int SPI45CKSELR; 		// 0x8E0
	volatile unsigned int UART6CKSELR; 		// 0x8E4
	volatile unsigned int UART24CKSELR; 	// 0x8E8
	volatile unsigned int UART35CKSELR; 	// 0x8EC
	volatile unsigned int UART78CKSELR; 	// 0x8F0
	volatile unsigned int SDMMC12CKSELR; 	// 0x8F4
	volatile unsigned int SDMMC3CKSELR; 	// 0x8F8
	volatile unsigned int ETHCKSELR; 		// 0x8FC
	volatile unsigned int QSPICKSELR; 		// 0x900
	volatile unsigned int FMCCKSELR; 		// 0x904
	volatile unsigned int res18[1];
	volatile unsigned int FDCANCKSELR; 		// 0x90C
	volatile unsigned int res19[1];
	volatile unsigned int SPDIFCKSELR; 		// 0x914
	volatile unsigned int CECCKSELR; 		// 0x918
	volatile unsigned int USBCKSELR; 		// 0x91C
	volatile unsigned int RNG2CKSELR;  		// 0x920
	volatile unsigned int DSICKSELR; 		// 0x924
	volatile unsigned int ADCCKSELR; 		// 0x928
	volatile unsigned int LPTIM45CKSELR; 	// 0x92C
	volatile unsigned int LPTIM23CKSELR;    // 0x930
	volatile unsigned int LPTIM1CKSELR; 	// 0x934
	volatile unsigned int res20[18];
	volatile unsigned int APB1RSTSETR; 		// 0x980
	volatile unsigned int APB1RSTCLRR; 		// 0x984
	volatile unsigned int APB2RSTSETR; 		// 0x988
	volatile unsigned int APB2RSTCLRR; 		// 0x98C
	volatile unsigned int APB3RSTSETR; 		// 0x990
	volatile unsigned int APB3RSTCLRR; 		// 0x994
	volatile unsigned int AHB2RSTSETR; 		// 0x998
	volatile unsigned int AHB2RSTCLRR;  	// 0x99C
	volatile unsigned int AHB3RSTSETR; 		// 0x9A0
	volatile unsigned int AHB3RSTCLRR; 		// 0x9A4
	volatile unsigned int AHB4RSTSETR; 		// 0x9A8
	volatile unsigned int AHB4RSTCLRR; 		// 0x9AC
	volatile unsigned int res21[20];
	volatile unsigned int MP_APB1ENSETR; 	// 0xA00
	volatile unsigned int MP_APB1ENCLRR; 	// 0xA04
	volatile unsigned int MP_APB2ENSETR; 	// 0xA08
	volatile unsigned int MP_APB2ENCLRR;  	// 0xA0C
	volatile unsigned int MP_APB3ENSETR; 	// 0xA10
	volatile unsigned int MP_APB3ENCLRR; 	// 0xA14
	volatile unsigned int MP_AHB2ENSETR; 	// 0xA18
	volatile unsigned int MP_AHB2ENCLRR; 	// 0xA1C
	volatile unsigned int MP_AHB3ENSETR; 	// 0xA20
	volatile unsigned int MP_AHB3ENCLRR; 	// 0xA24
	volatile unsigned int MP_AHB4ENSETR; 	// 0xA28
	volatile unsigned int MP_AHB4ENCLRR; 	// 0xA2C
	volatile unsigned int res22[2];
	volatile unsigned int MP_MLAHBENSETR; 	// 0xA38
	volatile unsigned int MP_MLAHBENCLRR; 	// 0xA3C
	volatile unsigned int res23[16];
	volatile unsigned int MC_APB1ENSETR; 	// 0xA80
	volatile unsigned int MC_APB1ENCLRR; 	// 0xA84
	volatile unsigned int MC_APB2ENSETR; 	// 0xA88
	volatile unsigned int MC_APB2ENCLRR; 	// 0xA8C
	volatile unsigned int MC_APB3ENSETR; 	// 0xA90
	volatile unsigned int MC_APB3ENCLRR; 	// 0xA94
	volatile unsigned int MC_AHB2ENSETR; 	// 0xA98
	volatile unsigned int MC_AHB2ENCLRR; 	// 0xA9C
	volatile unsigned int MC_AHB3ENSETR; 	// 0xAA0
	volatile unsigned int MC_AHB3ENCLRR; 	// 0xAA4
	volatile unsigned int MC_AHB4ENSETR; 	// 0xAA8
	volatile unsigned int MC_AHB4ENCLRR; 	// 0xAAC
	volatile unsigned int MC_AXIMENSETR; 	// 0xAB0
	volatile unsigned int MC_AXIMENCLRR; 	// 0xAB4
	volatile unsigned int MC_MLAHBENSETR; 	// 0xAB8
	volatile unsigned int MC_MLAHBENCLRR; 	// 0xABC
	volatile unsigned int res24[16];
	volatile unsigned int MP_APB1LPENSETR; 	// 0xB00
	volatile unsigned int MP_APB1LPENCLRR; 	// 0xB04
	volatile unsigned int MP_APB2LPENSETR;  // 0xB08
	volatile unsigned int MP_APB2LPENCLRR; 	// 0xB0C
	volatile unsigned int MP_APB3LPENSETR; 	// 0xB10
	volatile unsigned int MP_APB3LPENCLRR;  // 0xB14
	volatile unsigned int MP_AHB2LPENSETR;  // 0xB18
	volatile unsigned int MP_AHB2LPENCLRR;  // 0xB1C
	volatile unsigned int MP_AHB3LPENSETR;  // 0xB20
	volatile unsigned int MP_AHB3LPENCLRR;  // 0xB24
	volatile unsigned int MP_AHB4LPENSETR;  // 0xB28
	volatile unsigned int MP_AHB4LPENCLRR;  // 0xB2C
	volatile unsigned int MP_AXIMLPENSETR;  // 0xB30
	volatile unsigned int MP_AXIMLPENCLRR;  // 0xB34
	volatile unsigned int MP_MLAHBLPENSETR; // 0xB38
	volatile unsigned int MP_MLAHBLPENCLRR; // 0xB3C
	volatile unsigned int res25[16];
	volatile unsigned int MC_APB1LPENSETR;  // 0xB80
	volatile unsigned int MC_APB1LPENCLRR; 	// 0xB84
	volatile unsigned int MC_APB2LPENSETR;  // 0xB88
	volatile unsigned int MC_APB2LPENCLRR;  // 0xB8C
	volatile unsigned int MC_APB3LPENSETR;  // 0xB90 
	volatile unsigned int MC_APB3LPENCLRR;  // 0xB94
	volatile unsigned int MC_AHB2LPENSETR;  // 0xB98
	volatile unsigned int MC_AHB2LPENCLRR;  // 0xB9C
	volatile unsigned int MC_AHB3LPENSETR;  // 0xBA0 
	volatile unsigned int MC_AHB3LPENCLRR;  // 0xBA4
	volatile unsigned int MC_AHB4LPENSETR;  // 0xBA8
	volatile unsigned int MC_AHB4LPENCLRR;  // 0xBAC
	volatile unsigned int MC_AXIMLPENSETR;  // 0xBB0
	volatile unsigned int MC_AXIMLPENCLRR;  // 0xBB4
	volatile unsigned int MC_MLAHBLPENSETR; // 0xBB8
	volatile unsigned int MC_MLAHBLPENCLRR; // 0xBBC
	volatile unsigned int res26[16];
	volatile unsigned int MC_RSTSCLRR;  	// 0xC00
	volatile unsigned int res27[4];
	volatile unsigned int MC_CIER;  		// 0xC14
	volatile unsigned int MC_CIFR; 			// 0xC18
	volatile unsigned int res28[246];
	volatile unsigned int VERR; 			// 0xFF4
	volatile unsigned int IDR; 				// 0xFF8
	volatile unsigned int SIDR; 			// 0xFFC
}rcc_t;

#define RCC   0x50000000

#endif  // __STM32MP1XX_RCC_H__

gpio.h

#ifndef __STM32MP1xx_GPIO_H__
#define __STM32MP1xx_GPIO_H__

typedef struct {
	volatile unsigned int MODER;   // 0x00
	volatile unsigned int OTYPER;  // 0x04
	volatile unsigned int OSPEEDR; // 0x08
	volatile unsigned int PUPDR;   // 0x0C
	volatile unsigned int IDR;     // 0x10
	volatile unsigned int ODR;     // 0x14
	volatile unsigned int BSRR;    // 0x18
	volatile unsigned int LCKR;    // 0x1C 
	volatile unsigned int AFRL;    // 0x20 
	volatile unsigned int AFRH;    // 0x24
	volatile unsigned int BRR;     // 0x28
	volatile unsigned int res;
	volatile unsigned int SECCFGR; // 0x30

}gpio_t;


#define GPIOB   0x50003000

#define GPIOF   0x50007000



#endif // __STM32MP1xx_GPIO_H__

pwm_dev.c

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

int major;
struct class *cls;
struct device *dev;
//定义一些变量接收映射后的虚拟地址
gpio_t* beep_GPIOB;
gpio_t* mada_GPIOF;
rcc_t* pwm_RCC;

char kbuf[128]={0};
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 *off)
{
    int ret; 
    //判断kbuf的大小,如果<size,把size的数值修改为kbuf的大小
    if(size>sizeof(kbuf))
    size=sizeof(kbuf);
    ret=copy_to_user(ubuf,kbuf,size);
    if(ret)
    {
        printk("copy_to_user filed\n");
        return -EIO;//拷贝失败返回错误码
    }
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
ssize_t  mycdev_write(struct file *file, const char  *ubuf, size_t size, loff_t *off)
{
    int ret;
    if(size>sizeof(kbuf))
    size=sizeof(kbuf);
    ret=copy_from_user(kbuf,ubuf,size);
    if(ret)
    {
        printk("copy_from_user filed\n");
        return -EIO;//拷贝失败返回错误码
    }

    return 0;
}
//ioctl
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  {
    int which,ret;
    switch(cmd)
    {
        case PWM_ON:
           ret=copy_from_user(&which,(void *)arg,sizeof(int));//把ioctl第三个参数的数值获取到
           if(ret)
           {
            printk("copy_from_user err\n");
            return -ENOMEM;
           }
           switch(which)
           {
            case 1:
                //RCC
                pwm_RCC->MP_APB4ENSETR|=(0x1<<1);
                pwm_RCC->MP_APB1ENSETR|=(0X1<<2);
 
                //GPIO
                beep_GPIOB->MODER&=(~(0x3<<12));
                beep_GPIOB->MODER|=(0x1<<13);
                
                beep_GPIOB->AFRL&=(~(0xF<<24));
                beep_GPIOB->AFRL|=(0x1<<25);
                printk("蜂鸣器开\n");
                break;
            case 2:
                //RCC
                pwm_RCC->MP_AHB4ENSETR|=(0x1<<5);
                pwm_RCC->MP_APB2ENSETR|=(0x1<<3);
                //GPIO
                mada_GPIOF->MODER&=(~(0x3<<12)); 
                mada_GPIOF->MODER|=(0x1<<13); 
                mada_GPIOF->AFRL&=(~(0xF<<24)); 
                mada_GPIOF->AFRL|=(0x1<<24); 
                printk("马达开\n");
                break;
            case 3:
                printk("\n");
                break;
           }
    
            break;
        case PWM_OFF:
              ret=copy_from_user(&which,(void *)arg,sizeof(int));//把ioctl第三个参数的数值获取到
           if(ret)
           {
            printk("copy_from_user err\n");
            return -ENOMEM;
           }
           switch(which)
           {
            case 1:
                printk("\n");
                break;
            case 2:
                printk("\n");
                break;
            case 3:
                printk("\n");
                break;
           }
            break;
    }
    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,
    .unlocked_ioctl=mycdev_ioctl,
    .release=mycdev_close,
};
void all_led_init(void)
{
    //进行物理地址的映射
    beep_GPIOB=ioremap(GPIOB,sizeof(gpio_t));
    if(beep_GPIOB==NULL)
    {
        printk("LED1寄存器映射失败\n");
      
    }
    mada_GPIOF=ioremap(GPIOF,sizeof(gpio_t));
    if(mada_GPIOF==NULL)
    {
        printk("LED2寄存器映射失败\n");
    
    }
    pwm_RCC=ioremap(RCC,sizeof(rcc_t));
    if(mada_GPIOF==NULL)
    {
        printk("LED2寄存器映射失败\n");
    
    }    
    printk("寄存器物理地址映射成功\n");
    //寄存器的初始化


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

}
//入口函数
static int __init mycdev_init(void)
{
      int i;
    //进行字符设备驱动的注册
    major=register_chrdev(0,"mycdev",&fops);
    if(major<0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功,major=%d\n",major);
    //向上提交目录
    cls=class_create(THIS_MODULE,"mycdev");
    if(IS_ERR(cls))//指针指向预留空间,函数调用失败
    {
        printk("向上提交目录失败\n");
        return PTR_ERR(cls);
    }
     printk("向上提交目录成功\n");
     //向上提交设备节点
    
     for(i=0;i<3;i++)
     {
        dev=device_create(cls,NULL,MKDEV(major,i),NULL,"mycdev%d",i);
         if(IS_ERR(dev))//指针指向预留空间,函数调用失败
        {
             printk("向上提交目录失败\n");
            return PTR_ERR(dev);
        }
     }
     printk("设备节点向上提交成功\n");
    //led寄存器初始化
    all_led_init();

    return 0;
}
//出口函数
static void __exit mycdev_exit(void)
{
      int i;
    //取消物理内存的映射
    iounmap(pwm_RCC);
    iounmap(beep_GPIOB);
    iounmap(mada_GPIOF);
    //删除节点信息
  
    for(i=0;i<3;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //删除目录信息
    class_destroy(cls);
    //字符设备驱动的注销
    unregister_chrdev(major,"mycdev");

}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

pwm.c

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include<string.h>
#include <sys/ioctl.h>  
#include"head.h"
int main(int argc, char const *argv[])
{
    char buf[128]={0};
    int which,a;
    int fd=open("/dev/mycdev0",O_RDWR);
    if(fd<0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
    //在终端输入数据
    while(1)
    {
      printf("请输入要进行的操作:1(开) 0(关)->");
      scanf("%d",&a);
      if(a==1)
      {
        printf("请输入要进行操作的设备:1(蜂鸣器) 2(马达) 3(风扇)->");
        scanf("%d",&which);
        ioctl(fd,PWM_ON,&which);
      }
      else
      {
        printf("请输入要进行操作的设备:1(蜂鸣器) 2(马达) 3(风扇)->");
        scanf("%d",&which);
        ioctl(fd,PWM_OFF,&which);
      }
      
    }
    close(fd);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值