编写基于stm32f407-uclinux下的led灯驱动

       在前文已经成功移植好linux内核在stm32中稳定地运行,下面是要编写简单的驱动程序,先选择写最简单的led灯驱动。

       led灯驱动归属于linux驱动的字符驱动这一类,而参考Uclinux源代码中usart设备驱动发现其采用的是平台设备驱动,不同于编写字符驱动。

       于是找编写字符驱动的资料,这在网上一抓一大把,对于这个led灯驱动的底层关键是各种GPIO寄存器的设置,通过查阅stm32f407的数据手册可知,需要设置GPIOx_MODER、OTYPER、OSPEEDR、PUPDR这几个寄存器,注意到的是我现在用的是stm32f407,与网上大把部分的s3c2440寄存器设置是大不一样的,因为平台的不同,需要根据实际参照数据手册来进行你的设置。 我的板子只有一个led灯,输出gpio口为PC0,于是参照手册先设置GPIOC_MODER,查到寄存器地址为0x40020808,如下图:


这里写图片描述

       直接取地址进行设置:

*#define GPIOC_MODER 0x40020800

((volatile unsigned )GPIOC_MODER) |= 0xffffff11;

其它寄存设置也是作类似的修改,以下是代码:

/*

 * Simple character interface to GPIOs.  Allows you to read/write values and

 * control the direction.  Maybe add wakeup when gpio framework supports it ...

 *

 * based on the work of "Mike Frysinger <vapier@gentoo.org>"

 * 

 * Adapted to drive the STM32 MCU, GPIO Port F PINs

 *

 * Copyright 2008 Analog Devices Inc.

 * Licensed under the GPL-2 or later.

 */



#ifndef __CONFIG_H

#define __CONFIG_H



#include <linux/cdev.h>

#include <linux/device.h>

#include <linux/errno.h>

#include <linux/fs.h>

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/platform_device.h>

#include <linux/types.h>





#include<linux/module.h>  

#include<linux/init.h>  

#include<linux/cdev.h>  

#include<linux/fs.h>  

#include<linux/io.h> /* writel */ 



#include <asm/atomic.h>

#include <asm/gpio.h>

#include <asm/uaccess.h>



#include <mach/iomux.h>

#include <mach/platform.h>

#include <mach/stm32.h>









/*configue for stm32f407 GPio C*/

#define GPIOC_MODER  0x40020800 

#define GPIOC_OTYPER  0x40020804 

#define GPIOC_OSPEEDR  0x40020808

#define GPIOC_PUPDR  0x4002080C

#define GPIOC_ODR  0x40020814

#define RCC_AHB1ENR  0x40023830

#define RCC_APB2ENR  0x40023844



#define LED_MAJOR_NR 231 

#define DEVICE_NAME "led"               

#define SET_LED_OFF 0 

#define SET_LED_ON   1



//struct cdev led_dev;

//dev_t devno;

static struct class *led_class;  

static struct device *led_device; 



#endif



static int led_open(struct inode *inode, struct file *filp);



static int led_release(struct inode *inode, struct file *filp);



static int led_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,unsigned long param);



int led_init(void);

void led_exit(void);



int led_open(struct inode *node, struct file *filp)  

{  

    printk("open a led driver.\n");



    (*(volatile unsigned *)RCC_AHB1ENR) |=0x00d00004; //open gpioc clock

//**************************

    (*(volatile unsigned *)RCC_APB2ENR) |=0x00000800;   

/*************************/

    (*(volatile unsigned *)GPIOC_MODER) |= 0xffffff11; 

    (*(volatile unsigned *)GPIOC_OTYPER) |= 0xffffff00; 

    (*(volatile unsigned *)GPIOC_OSPEEDR) |= 0xffffff33;

    (*(volatile unsigned *)GPIOC_PUPDR) |= 0xffffff11;



        return 0;           



}  

static int led_release(struct inode *inode, struct file *filp) 

{ 



   return(0); 

} 





static int led_ioctl(struct inode *inode, struct file *filp, 

                        unsigned int cmd, unsigned long arg) 

{ 



    if( arg > 2 )

         return -1; 

 switch(cmd) 

    { 

        case 0:

          (*(volatile unsigned *)GPIOC_ODR) |= 0x1 << arg; 

             break; 



         case 1:

            (*(volatile unsigned *)GPIOC_ODR) &= 0x0 << arg; 

             break; 



             default: 

                    return -1; 

                         break; 

    }    



    return 0; 

} 



static struct file_operations led_fops =   

{  

   .owner=THIS_MODULE,

   .open = led_open,  

    .ioctl = led_ioctl, 

    .release=led_release

};  



int led_init(void) 

{ 

     int   result;

    result = register_chrdev(231, "led", &led_fops); //register char device



#if defined(CONFIG_GPIOLIB) && defined(CONFIG_GPIO_SYSFS)



        /* PC0 = LED LD3 */

        gpio_dsc.port = 2;

        gpio_dsc.pin  = 0;

        stm32f2_gpio_config(&gpio_dsc, STM32F2_GPIO_ROLE_OUT);





    if (result < 0) 

 { 

         printk(KERN_ERR DEVICE_NAME ": Unable to get major %d\n", LED_MAJOR_NR ); 

           return(result); 

     } 

    printk("register_chrdev_region OK\n");






    led_class = class_create(THIS_MODULE, "led");  //create led_class



led_device = device_create(led_class, NULL, MKDEV(231, 0), NULL, "led"); //create led device



    return(0); 

} 



void led_exit()  

{  





     unregister_chrdev(231, "led");  

    device_unregister(led_device);    

    class_destroy(led_class);      

}  





module_init(led_init);  

module_exit(led_exit);  





MODULE_AUTHOR("dq");

MODULE_DESCRIPTION("STM32 led driver");

MODULE_LICENSE("GPL");

       保存为led.c文件,存放在linux的/driver/char目录下,led.c文件中的关键部分是文件操作函数:fops。

       我在编译busybox时进行了裁剪,没有insmod命令,因此我采用的是静态加载驱动编译进内核的方式:

1、修改linux/driver/char/makefile

加入obj-$(CONFIG_GPIO_STM32_LED)+= led.o

2、在同目录下的Kconfig文件

config GPIO_STM32_LED

bool “STM32-LED GPIO support”

在编译内核时,make menuconfig中的Device中选上添加的选项

3、在根文件系统dev/目录手工添加设备节点led

mknod -m 666 led c 231 0

4、编译ledtest.c,放入根文件系统目录,编译内核,运行应用程序ledtest。

       敲指令ledtest on 灯亮

       敲指令ledtest off 灯灭

应用程序ledtest.c如下:

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

void delay(int delay)
{
    int i;
    for(;delay>0;delay--)
    {
    for(i=0 ; i < 5000 ; i ++);

    }
}

int main(int argc ,char *argv[])
{
    int fd1;
    int j;
    int val = 0;  

   fd1= open("/dev/led" , O_RDWR);

    if(fd1 == -1)
{
    printf ( "file can not be open.\n" );
          return -1;
}
    if (argc != 2)  
    {  
        printf("Usage:\n");  
        printf("%s <on|off>\n",argv[0]);  
        return 0;  
    }  

    if(strncmp(argv[1],"on",2) == 0)  
    {  
        val = 1;  
    }  
    else if (strncmp(argv[1],"off",3) == 0)  
    {  
        val = 0;  
    }   
    ioctl(fd1 , val , 0);
return 0;

}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值