深圳市航顺芯片技术研发有限公司
直播中

张健

7年用户 1328经验值
私信 关注
[问答]

如何使用文件IO去控制LED灯呢

怎样通过控制寄存器去控制高低电平呢?
如何使用文件IO去控制LED灯呢?

回帖(1)

张新里

2021-10-29 17:30:09
  Linux驱动
  晴空霹雳一阵响,开始写自己的技术博客了。深思熟虑后编写此系列文章记录自己学习过程中遇到的问题和今后复习所用。Linux驱动IO输出高低电平和单片机类似,也是通过控制寄存器控制高低电平,不过在linux中就进行了分层。将程序分成了驱动和应用层程序,驱动负责底层操作和控制,应用层负责逻辑,侧重于怎么使用。驱动在驱动层将控制的接口写好,注册驱动时将IO口寄存器进行配置。应用层直接操作设备节点,使用文件IO控制LED灯。
  基本步骤:
  1、 开发环境介绍:迅为开发板:iTop4412,Ubuntu14
  2、 查看芯片的技术手册,确定LED连接的IO口控制寄存器。
  3、 编写驱动代码。
  4、 编写应用代码。
  5、 编写Makefile文件,编译驱动程序和应用程序。
  6、 导入板子运行测试。
  1、威廉希尔官方网站 图如下:
  
  通过查询官方给出的技术手册和硬件威廉希尔官方网站 连接图可知具体的寄存器如下:
  LED2配置寄存器和数据寄存器
  
  
  LED3配置寄存器和数据寄存器
  
  
  2、编写驱动代码:
  #include 《linux/init.h》
  #include 《linux/module.h》
  #include 《linux/fs.h》
  #include 《linux/device.h》
  #include 《linux/uaccess.h》
  #include 《asm/io.h》
  //LED2
  #define CPX2_CON 0x11000100
  #define GPX2_SIZE 2
  //LED3
  #define CPX3_CON 0x11000060
  #define GPX3_SIZE 2
  //指针存放虚拟地址
  volatile unsigned long *gpx2conf;
  volatile unsigned long *gpx2dat;
  volatile unsigned long *gpx3conf;
  volatile unsigned long *gpx3dat;
  static unsigned int dev_major = 125;
  static struct class *devcls;
  static struct device *dev;
  static int kernel_val = 555;
  int chr_dev_open(struct inode *inode,struct file *filp)
  {
  printk(“******dev %s***********n”,__FUNCTION__);
  return 0;
  }
  //read(fd,buffer,size);
  //fd --》 filp
  //buffer --》 buffer
  //size --》 count
  //必须通过copy_to_user进行传递数据。
  ssize_t chr_dev_read(struct file *filp, char __user *buffer,size_t count,loff_t *fpos)
  {
  int ret = copy_to_user(buffer,&kernel_val,count);
  printk(“******%s**********n”,__FUNCTION__);
  if(ret 》 0){
  printk(“ copy_to_user error ret:%dn”,ret);
  return -EFAULT;
  }
  return 0;
  }
  ssize_t chr_dev_write(struct file *filp, const char __user *buffer,unsigned int count ,loff_t *fpos)
  {
  int value;
  int ret = copy_from_user(&value,buffer,count);
  if(ret 》 0){
  printk(“ copy_from_user error ret:%dn”,ret);
  return -EFAULT;
  }
  printk(“******%s*********n”,__FUNCTION__);
  printk(“ value = %dn”,value);
  if(value){
  *gpx2dat |= 0x01; //led2点灯
  *gpx3dat |= 0x02; //led3点灯
  }else{
  *gpx2dat &= ~(0x01); //led2灭灯
  *gpx3dat &= ~(0x02);//led3灭灯
  }
  return 0;
  }
  int chr_dev_close(struct inode *inode,struct file *filp)
  {
  printk(“******%s*********n”,__FUNCTION__);
  return 0;
  }
  const struct file_operations my_fops = {
  .open = chr_dev_open,
  .read = chr_dev_read,
  .write = chr_dev_write,
  .release = chr_dev_close,
  };
  static int __init chr_dev_init(void)
  {
  //申请设备号
  int ret;
  ret = register_chrdev(dev_major,“chr_dev_test”,&my_fops);
  if(ret == 0){
  printk(“register okn”);
  }else{
  printk(“register failedn”);
  return -EINVAL;
  }
  // /dev/chr2 创建类
  devcls = class_create(THIS_MODULE,“chr_dev_test”);
  if(devcls != NULL){
  printk(“register class ok!n”);
  }else
  {
  printk(“register class faild!n”);
  }
  //创建设备节点 以device_create()最后一个参数为准。
  dev = device_create(devcls,NULL,MKDEV(dev_major,0),NULL,“chr_dev_cls2”);
  if(dev != NULL){
  printk(“register dev okn”);
  }else{
  printk(“register dev failedn”);
  }
  //LED2 地址映射。
  gpx2conf = ioremap(CPX2_CON,GPX2_SIZE);
  gpx2dat = gpx2conf + 1;
  //LED3
  gpx3conf = ioremap(CPX3_CON,GPX3_SIZE);
  gpx3dat = gpx3conf +1;
  //LED2配置
  *gpx2conf &= ~(0xFF);
  *gpx2conf |= (0x1);
  //LED3 配置
  *gpx3conf &= ~(0xFF);
  *gpx3conf |= (0x10);
  return 0;
  }
  static void __exit chr_dev_exit(void)
  {
  //一般释放资源
  //和注册时顺序相反
  iounmap(gpx3conf);
  iounmap(gpx2conf);
  device_destroy(devcls,MKDEV(dev_major,0));
  class_destroy(devcls);
  unregister_chrdev(dev_major,“chr_dev_cls2”);
  printk(“*************chr_dev_exit OK!********n”);
  }
  module_init(chr_dev_init);
  module_exit(chr_dev_exit);
  MODULE_LICENSE(“GPL”);
  驱动的Makefile编写:
  KERN_DIR = /home/usr/iTop4412_Kernel_3.0
  obj-m +=chr_dev.o
  all:
  make -C $(KERN_DIR) M=$(PWD) modules
  clean:
  make -C $(KERN_DIR) M=$(PWD) modules clean
  rm -rf modules.order
  应用层程序编写:
  #include 《fcntl.h》
  #include 《unistd.h》
  #include 《string.h》
  #include 《stdlib.h》
  #include 《stdio.h》
  #include 《sys/types.h》
  #include 《sys/stat.h》
  int main(int argc,char *argv[])
  {
  int fd = open(“/dev/chr_dev_cls2”,O_RDWR); //路径和驱动设备节点名字保持一致
  int value = 0;
  if(fd 《 0){
  perror(“open failed”);
  exit(0);
  }
  read(fd,&value,4);
  printf(“__USER__ value : %dn”,value);
  //重新给value赋值
  value = 666;
  write(fd,&value,4);
  while(1)
  {
  value = 0;
  write(fd,&value,4);
  sleep(1);
  value = 1;
  write(fd,&value,4);
  sleep(1);
  }
  close(fd);
  return 0;
  }
  3、将编译好的驱动程序和引用程序在arm上运行
  
举报

更多回帖

发帖
×
20
完善资料,
赚取积分