发表于:2007-02-08 19:10:55 楼主
情况是这样的:
我们公司现在在使用PowerPC的CPU,CPU上运行Linux   2.6.13,   现在我想要对GPIO操作,编写了一个程序去写GPIO输出,程序编译是通过了,运行前面的printf之类的语句执行正常,但执行到修改GPIO寄存器 时,出现 "Segmentation   fault "

我估计是操作系统正常运行之后进入保护模式,保护模式下运行的程序无法对CPU的寄存器直接操作,应该怎么办呢?


问题点数:50 回复次数:8 显示所有回复显示星级回复显示楼主回复修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • joyself
  • 独来读网
  • 等级:
  • 可用分等级:小地主
  • 总技术分:6577
  • 总技术分排名:3275

发表于:2007-02-08 19:38:331楼 得分:20
我怀疑你的GPIO寄存器地址不是正确的。需要虚拟地址空间操作。

你在用户空间来操作的?

修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • luchong2000
  • 乐悟
  • 等级:
  • 可用分等级:掌柜
  • 总技术分:983
  • 总技术分排名:19845

发表于:2007-02-08 19:44:252楼 得分:0
GPIO地址情况如下:
1.在开发板提供的.h中:
#define   GPIO_BASE     0xEF600700
#define   GPIO0_OR                               (GPIO_BASE+0x0)

我用的就是GPIO0_OR

2.在程序中:
*(volatile   ulong   *)GPIO0_OR   &=   ~0x00000002;     //就这句出了 "Segmentation   fault "错误

修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • luchong2000
  • 乐悟
  • 等级:
  • 可用分等级:掌柜
  • 总技术分:983
  • 总技术分排名:19845

发表于:2007-02-08 19:45:083楼 得分:0
不知道 "虚拟地址空间操作 "是怎么回事?

修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Sniper167
  • 啥都不会
  • 等级:
  • 可用分等级:富农
  • 总技术分:311
  • 总技术分排名:45700

发表于:2007-02-12 15:50:544楼 得分:10
是在内核空间访问还是用户空间?

修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • jacky_emdoor
  • 浪子
  • 等级:
  • 可用分等级:中农
  • 总技术分:314
  • 总技术分排名:45427

发表于:2007-02-12 17:21:425楼 得分:20
你这段需要在内核空间使用
你如果要在用户空间使用的话,建议使用kiobuf
看来LZ需要补下linux内存管理的基础知识

修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • luchong2000
  • 乐悟
  • 等级:
  • 可用分等级:掌柜
  • 总技术分:983
  • 总技术分排名:19845

发表于:2007-02-26 18:48:086楼 得分:0
是的,终于明白并且实验成功了,在用户空间不能直接访问的,还好开发板提供了一个内存映射的字符设备,我映射到用户空间了.不过将来要做更多事情的话,还得恶补一下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));
}
/*   etc.,   cf   asm/io.h   */
#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);
               
  /*   do   some   cleanup   when   you 're   done   with   it   */
return   munmap((void*)start-ofs_addr,   length+ofs_addr);
}

void   sysLedSet(unsigned   char   value)
{
/*   For   obscure   HW   reasons,   we   have   to   negated   it   and   shift   the   value   23   bits   to   the   left     */
*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  
               
/*   HW   initialisation   */
ledRegister   =   (unsigned   long   *)mapDirectIoRegister(HCU3_LED_REGISTER,   MAP_SIZE); //MAP_SIZE=4096UL
//上面一行输出:Memory   map   0xef600700   ->   0x30001000   offset   0x700   virtual   0x30001700
/*   next   we   set   the   correct   control   mask   in   the   GPIO_TCR   */

//ledRegister[1]     =   0x7ffe0000;   /*   Three   State   Control   */
   
/*   Now   scroll   our   leds   and   pause   a   little   bit   between   */
/*for   (j=0;   j   <   8;   j++)
{
sleep(1);
printf( ". ");
fflush(stdout);
sysLedSet(1   < <   j);
}*/

*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;
}


修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • luchong2000
  • 乐悟
  • 等级:
  • 可用分等级:掌柜
  • 总技术分:983
  • 总技术分排名:19845

发表于:2007-02-26 18:49:367楼 得分:0
以下是dev_gpio.c
/*   src/dev_gpio.c
*
*   This   file   provide   IO   reading   and   writing   from   user   space.
*   Pls   create   some   device   file   in   diretory   /dev/gpiotest   whose   major   is   220.
*   This   driver   support   0-255   devices.   In   user   space   user   can   read   and   write
*   IO   through   open   and   ioctl   function   provided   by   glibc.
*
*/
#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);
/*
*   Open/close   code   for   raw   IO.
*/
int   gpio_open(struct   inode   *inode,   struct   file   *filp)
{
int   minor;
minor   =   MINOR(inode-> i_rdev);

/*   if   (ioport_devices[minor].io_lock)   {
printk( "Device   is   busy\n ");
return   -1;
}*/
*(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;
}
/*
*   Deal   with   ioctls   against   the   raw-device   control   interface,   to   bind
*   and   unbind   other   raw   devices.
*/
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;
}

修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • luchong2000
  • 乐悟
  • 等级:
  • 可用分等级:掌柜
  • 总技术分:983
  • 总技术分排名:19845

发表于:2007-02-26 18:50:098楼 得分:0
//以下是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,
};