对GPIO操作

http://topic.csdn.net/u/20070208/19/51C3C55C-8A56-44CD-AA2F-F789587BC9A4.html

 

是的,终于明白并且实验成功了,在用户空间不能直接访问的,还好开发板提供了一个内存映射的字符设备,我映射到用户空间了.不过将来要做更多事情的话,还得恶补一下Linux下的驱动编写.

以下分享一下通过内存映射访问字符设备的方法:
这段程序是在网上下载的,但是编译时有点问题,我修改过之后就可以运行了.
//以下是gpio_test.c文件,在RedHat9上编译通过,在405EP的taihu开发板运行通过,点亮LED.
#include   <stdio.h>
#include   <fcntl.h>
#include   <stdlib.h>
#include   <unistd.h>
#include   <sys/mman.h>
#include   <unistd.h>

void     *mapDirectIoRegister(unsigned   long   addr,   size_t   length);
int         iounmap(volatile   void   *start,   size_t   length);
void       sysLedSet(unsigned   char   value);

#define   MAP_SIZE                                                 4096UL
#define   MAP_MASK                                                 (MAP_SIZE   -   1) //4095
#define   HCU3_LED_REGISTER                               0xEF600700

volatile   unsigned   long   *ledRegister;
#define   __PPC4xx__
#ifdef   __PPC4xx__
inline   void   out_32(volatile   unsigned   long   *addr,   unsigned   val)
{
                __asm__   __volatile__( "stw%U0%X0   %1,%0;   eieio "   :   "=m "   (*addr)   :   "r "  
(val));
}

#else
extern   inline   void   out_32(volatile   unsigned   long   *addr,   unsigned   val)
{   *   which   shows   you   how   to   use   PPC   assembler   code   to   ensure   correct   IO  
ordering.

                *addr   =   val   &   0xff;
}
#endif

void     *mapDirectIoRegister(unsigned   long   addr,   size_t   length)
{
void   *map_base,   *   virtAddr;
off_t   target   =   ((unsigned   int)   addr)   &   ~MAP_MASK; //off_t就是int类型;   MAP_MASK=4095UL=>   ~MAP_MASK=0xFFFFF000UL
int   fd;
               
if   ((fd   =   open( "/dev/mem ",   O_RDWR   |   O_SYNC))   ==   -1) //打开内存文件(驱动)
{
printf( "/dev/mem   could   not   be   opened./n ");
exit(1);
}
               
//   Map   one   page
map_base   =   mmap((void   *)target,   length,   PROT_READ   |   PROT_WRITE,   MAP_SHARED,fd,   target);
if(map_base   ==   (void   *)   -1)
{
printf( "Memory   map   failed   for   address   0x%lx/n ",   addr);
return   map_base;
}
               
virtAddr   =   (void   *)   ((unsigned   long)map_base   +   (   (unsigned   long)addr   &   MAP_MASK)); //基地址+偏移量
printf( "Memory   map   0x%lx   ->   %p   offset   0x%lx   virtual   %p/n ",   addr,   map_base,addr   &   MAP_MASK,   virtAddr);
//输出:Memory   map   0xef600700   ->   0x30001000   offset   0x700   virtual   0x30001700
return   virtAddr;
}

int   iounmap(volatile   void   *start,   size_t   length)
{
unsigned   long   ofs_addr;
ofs_addr   =   (unsigned   long)start   &   (getpagesize()-1);
               
 
return   munmap((void*)start-ofs_addr,   length+ofs_addr);
}

void   sysLedSet(unsigned   char   value)
{

*ledRegister   =   ((   unsigned   long   )   ~value   < <23)   ;
out_32(ledRegister,   (   unsigned   long   )   ~value   < <23   );
}

int   main   (int   argc,   char   *argv[])
{
unsigned   char   j;
printf( "%s:   %s   %s/n ",   __FUNCTION__,   __DATE__,   __TIME__   ); //输出main:   Feb     9   2007   18:13:55  
               

ledRegister   =   (unsigned   long   *)mapDirectIoRegister(HCU3_LED_REGISTER,   MAP_SIZE); //MAP_SIZE=4096UL
//上面一行输出:Memory   map   0xef600700   ->   0x30001000   offset   0x700   virtual   0x30001700


//ledRegister[1]     =   0x7ffe0000;  
   



*ledRegister     =     0x7fffffff;
//out_32(ledRegister,   0x7fffffff   );

sleep(1);

*ledRegister     =   0x0;
//out_32(ledRegister,   0x0   );

iounmap((volatile   void   *)HCU3_LED_REGISTER,   MAP_SIZE);
printf( "/n%s:done/n ",   __FUNCTION__); //输出:main:done
return   0;
}

 

以下是dev_gpio.c

#include   "dev_gpio.h "

static   ioport_device_t   gpio_devices[256];

int   __init   gpio_init(void)
{
int   i;
register_chrdev(IOPORT_MAJOR,   "gpiotest ",   &gpio_ctl_fops);
return   0;
}
__initcall(gpio_init);

int   gpio_open(struct   inode   *inode,   struct   file   *filp)
{
int   minor;
minor   =   MINOR(inode-> i_rdev);


*(volatile   unsigned   short*)(0xfff00000+0x962)&=~0x0080;
*(volatile   unsigned   short*)(0xfff00000+0x960)|=0x0080;
gpio_devices[minor]++;
return   0;
}
//__ioremap
int   gpio_release(struct   inode   *inode,   struct   file   *filp)
{
int   minor;
minor   =   MINOR(inode-> i_rdev);
if   (gpio_devices[minor])
gpio_devices[minor]--;
*(volatile   unsigned   short*)(0xfff00000+0x960)&=~0x0080;
*(volatile   unsigned   short*)(0xfff00000+0x962)|=0x0080;
return   0;
}

int   gpio_ctl_ioctl(struct   inode   *inode,struct   file   *flip,unsigned   int   command,unsigned   long   arg)
{
int   err   =   0;
int   minor   =   MINOR(inode-> i_rdev);
switch   (command)
{
case   IOWRITE:
*(volatile   unsigned   short*)(0xfff00000+0x966)&=~0x0080;
return   0;
case   IOCLEAR:
*(volatile   unsigned   short*)(0xfff00000+0x966)|=0x0080;
return   0;
default:
err   =   -EINVAL;
}
return   err;
}

 

 

//以下是dev_gpio.h
#include   <linux/fs.h>
#include   <linux/iobuf.h>
#include   <linux/major.h>
#include   <linux/blkdev.h>
#include   <linux/capability.h>
#include   <linux/smp_lock.h>
#include   <asm/uaccess.h>

#include   <asm/io.h>
#include   <linux/vmalloc.h>

#define   dprintk(x...)
#define   IOPORT_MAJOR   220

typedef   char   ioport_device_t;

int   gpio_open(struct   inode   *,   struct   file   *);
int   gpio_release(struct   inode   *,   struct   file   *);
int   gpio_ctl_ioctl(struct   inode   *,   struct   file   *,   unsigned   int,   unsigned   long);
static   struct   file_operations   gpio_fops   =
{
open:   gpio_open,
release:   gpio_release,
};
static   struct   file_operations   gpio_ctl_fops   =
{
ioctl:   gpio_ctl_ioctl,
open:   gpio_open,
release:   gpio_release,
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值