【吃灰板子捡起来】LED驱动开发实验

一、地址映射

#include <asm/io.h>

#define ioremap(cookie,size)		__arm_ioremap((cookie), (size), MT_DEVICE)

#define iounmap				__arm_iounmap

二、内存访问

#include <asm/io.h>

#define readb(c)		({ u8  __v = readb_relaxed(c); __iormb(); __v; })
#define readw(c)		({ u16 __v = readw_relaxed(c); __iormb(); __v; })
#define readl(c)		({ u32 __v = readl_relaxed(c); __iormb(); __v; })

#define writeb(v,c)		({ __iowmb(); writeb_relaxed(v,c); })
#define writew(v,c)		({ __iowmb(); writew_relaxed(v,c); })
#define writel(v,c)		({ __iowmb(); writel_relaxed(v,c); })

三、应用源码

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"

int main(int argc, char *argv[])
{

  int retvalue = 0;
  int fd;
  char *filename;
  unsigned char databuf[2];

  if(argc != 4)
  {
    printf(" Usage Error!\r\n");
    return -1;
  }

  filename = argv[1];
  fd = open(filename, O_RDWR);
  if(fd < 0)
  {
    printf("file %s open failed~\r\n",filename);
    return -1;
  }

  databuf[0] = atoi(argv[2]);
  databuf[1] = atoi(argv[3]);

  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",filename);
    return -1;
  } 
  return 0;
}

四、驱动源码

led.c

#include <linux/module.h>
#include <linux/kernel.h> 
#include <linux/types.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/fs.h>

#include <asm/mach/map.h> 
#include <asm/uaccess.h>
#include <asm/io.h>

#define LED_MAJOR 200
#define LED_NAME "led"

#define LED_ON  1
#define LED_OFF 0

#define CLK_PCLKEN0_BASE  (0xB0000218)
#define GPIOB_DIR_BASE    (0XB8003040)
#define GPIOBDATAOUT_BASE (0xB8003044)

static void __iomem *CLK_PCLKEN0;
static void __iomem *GPIOB_DIR;
static void __iomem *GPIOBDATAOUT;

 
static void led_switch(char led1_sw, char led2_sw)
{
  u32 val = 0;

  val = readl(GPIOBDATAOUT);
  //LED1
  if(led1_sw == LED_ON)
  {
    val &= ~(1<<4);
  }else if(led1_sw == LED_OFF)
  {
    val |= (1<<4);
  }else
  {
    printk("LED1 Control cmd error!\r\n");
  } 

  //LED2
  if(led2_sw == LED_ON)
  {
    val &= ~(1<<5);
  }else if(led2_sw == LED_OFF)
  {
    val |= (1<<5);
  }else
  {
    printk("LED2 Control cmd error!\r\n");
  } 
  writel(val,GPIOBDATAOUT);

}
static int led_open(struct inode *inode, struct file *filp){

  return 0;
}

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

  return 0;
}

static ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos){

  int retvalue = 0;
  char databuf[2];

  copy_from_user(databuf,buf,count);
  if(retvalue < 0)
  {
    printk("Control LED Failed!\r\n");
    return -1;
  }

  led_switch(databuf[0],databuf[1]);

  return 0;

}


static struct file_operations led_fops = {
  .owner = THIS_MODULE,
  .open = led_open,
  .write = led_write,
  .release = led_release,
};

static int __init led_init(void)
{
  int retvalue = 0;
  u32 val = 0;
  /* init led */
  CLK_PCLKEN0 = ioremap(CLK_PCLKEN0_BASE,4);
  GPIOB_DIR   = ioremap(GPIOB_DIR_BASE,4);
  GPIOBDATAOUT= ioremap(GPIOBDATAOUT_BASE,4);

  val  = readl(CLK_PCLKEN0);
  val |= (1<<3);
  writel(val, CLK_PCLKEN0);

  val  = readl(GPIOB_DIR);
  val |= ((1<<4)|(1<<5));  //PB4 and PB5
  writel(val, GPIOB_DIR);

  val = readl(GPIOBDATAOUT);
  val &= ~(unsigned int)((1<<4)|(1<<5));

  retvalue = register_chrdev(LED_MAJOR,LED_NAME,&led_fops);
  if(retvalue < 0){
    printk("register chrdev failed!\r\n");
    return -1;
  }

  printk("led_init\r\n");

  return 0;
}

static void __exit led_exit(void)
{
  u32 val = 0; 
  /* close the led */
  val = readl(GPIOBDATAOUT);
  val |= (1<<4)|(1<<5); 
  writel(val, GPIOBDATAOUT);

  iounmap(CLK_PCLKEN0);
  iounmap(GPIOB_DIR);
  iounmap(GPIOBDATAOUT);

  unregister_chrdev(LED_MAJOR,LED_NAME);

  printk("led_exit\r\n");
}
module_init(led_init);
module_exit(led_exit);


MODULE_LICENSE("GPL");
MODULE_AUTHOR("mx");

五、实验总结

1.和操作单片机寄存器不同,写驱动涉及到的单片机,需要将物理寄存器地址映射到虚拟内存地址,通过操作虚拟内存地址来修改物理地址的值;
2.提供了内存操作函数readl 和writel,读和写4字节数据,对应32位寄存器数据;
3.按照正点原子视频教程实现点灯操作,可同时控制两个LED灯的独立亮灭。

./ledAPP /dev/led 0 0
./ledAPP /dev/led 0 1

在这里插入图片描述在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值