QQ 24440(s 3 c 2440)ARM開発ボードを応用してMMA 7455加速度計を駆動するlinux設備駆動作成


課題水中ロボットは水中ロボットの姿勢を測定する必要があるため、SPIまたはI 2 CでMCUにデジタル信号を読み取ることができる加速度計MMA 7455を適用した.
駆動MMA 7455はatmega 128で実現されているが、mega 128の速度やリソースなどのボトルネックにより開発継続が制限されているためarmプロセッサに変更されている.
 
armプロセッサ上でlinuxオペレーティングシステムを実行し、MMA 7455加速度計の駆動を完了するにはlinux下のデバイスドライバを理解する必要があるため、対応するデバイスドライバを作成しました.
勉强の过程の中でMakefileの编纂はとても重要で、私のこのような菜鸟にとってmakefileは设备の駆动の一大障害だと感じて、いろいろなmakefileを试して、最后に1つの使いやすいmakefileを発见して、その上通用するようで、そこで记录しました:http://blog.csdn.net/joygo007/article/details/6639368.
私はSPIでMMA 7455を駆動しています.I 2 Cに比べて、SPIは少し簡単だと思いますから.
まずコードを添付し、そこから出会った様々な困難と解決の過程を後でゆっくり共有します.
 
Code 1:linuxでMMA 7455用のSPIデバイスドライバ
 
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/fs.h>//fops
#include <linux/module.h>
#include <linux/init.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/miscdevice.h>
#include <asm/arch/regs-gpio.h>//gpio        
#include <asm/hardware.h>//s3c2410_gpio_setpin   
#include <linux/delay.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/uaccess.h>

#define DEVICE_NAME "spi_gh"	//    
#define SPI_MAJOR_NUM 236	//    

//int whtaever=0;
volatile int *spi_gpecon=NULL;//GPG Part define  
volatile int *spi_gpedat=NULL;
volatile int *spi_gpeup=NULL; 
volatile int *s3c2440_clkcon=NULL;  
volatile int *spi_spcon0=NULL;//SPI Part define  
volatile int *spi_spsta0=NULL;  
volatile int *spi_sppin0=NULL;
volatile int *spi_sppre0=NULL;
volatile int *spi_sptdat0=NULL;  
volatile int *spi_sprdat0=NULL;

#define SPI_TXRX_READY      (((*spi_spsta0)&0x1) == 0x1)  
int loopChar=0x88;  

//  SPI      
static unsigned long spi_pin_tab[]={
	S3C2410_GPE11,
	S3C2410_GPE12,
	S3C2410_GPE13,
	S3C2410_GPG2,

};

//  SPI    
static unsigned long spi_pin_cfg_tab[]={
	S3C2410_GPE11_SPIMISO0,
	S3C2410_GPE12_SPIMOSI0,
	S3C2410_GPE13_SPICLK0,
	S3C2410_GPG2_OUTP,
};
/*======================================
      :__open
    	:        
=======================================*/
static int spi_open(struct inode *inode,struct file *filp)  
{ 
	*s3c2440_clkcon |=0x40000;  
    printk("s3c2440_clkcon=%08X
",*s3c2440_clkcon); *spi_sppre0=0x18; printk("spi_sppre0=%02X
",*spi_sppre0); *spi_spcon0=(0<<6)|(0<<5)|(1<<4)|(1<<3)|(0<<2)|(0<<1)|(0<<0); printk("spi_spcon0=%02X
",*spi_spcon0); *spi_sppin0=(0<<2)|(0<<0); printk("spi_sppin0=%02X
",*spi_sppin0); printk("KKK:OPEN OK
"); return 0; } /*========================================================================== :static void writeByte(const char c) : SPI : : : ==============================================================================*/ static void writeByte(const char c) { int j = 0; *spi_sptdat0 = c; for(j=0;j<0xFF;j++); while(!SPI_TXRX_READY) for(j=0;j<0xFF;j++); } /*========================================================================== :static char readByte(void) : spi : : : ==============================================================================*/ static char readByte(void) { int j = 0; char ch = 0; *spi_sptdat0 = (char)loopChar; for(j=0;j<0xFF;j++); while(!SPI_TXRX_READY) for(j=0;j<0xFF;j++); ch=*spi_sprdat0; return ch; } /*====================================== :ioctl : =======================================*/ static int spi_ioctl( struct inode *inode, struct file *file, unsigned int RdorWr, char * spiBuf ) { char whtevr; char * ch; char * kbuf=&whtevr; switch(RdorWr) { case 0:// spi //printk("<1>spi read!
"); ch=readByte(); copy_to_user(spiBuf,&ch,1); //printk("<1>spi read content:%x
",*spiBuf); return 1; break; case 1:// spi //printk("<1>spi write!
"); copy_from_user(kbuf,spiBuf,1); //printk("<1>copy_from_user OK!
"); writeByte(*kbuf); //printk("<1>spi write content:%x
",*spiBuf); return 1; break; case 3:// SS s3c2410_gpio_setpin(spi_pin_tab[3],0);//nSS0=0 return 0; break; case 4:// SS s3c2410_gpio_setpin(spi_pin_tab[3],1);//nSS0=1 return 0; break; default: return -EINVAL; } } /*====================================== :fops : =======================================*/ static struct file_operations spi_fops = { .open =spi_open, .ioctl = spi_ioctl, }; /*====================================== :__init : =======================================*/ static int __init spi_init(void) { int ret,i; ret=register_chrdev(SPI_MAJOR_NUM,DEVICE_NAME,&spi_fops);// if(ret<0) { printk(DEVICE_NAME" can't register major number
"); return ret; } devfs_mk_cdev(MKDEV(SPI_MAJOR_NUM, 0), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, DEVICE_NAME); // // for(i=0;i<4;i++) { s3c2410_gpio_cfgpin(spi_pin_tab[i],spi_pin_cfg_tab[i]); } s3c2440_clkcon = (int *)ioremap(0x4C00000c,3); //GPIO_E ( SPI_0 ) spi_gpecon = (int *)ioremap (0x56000040,4); //GPeCON ,765 SPI_0 spi_gpedat = (int *)ioremap (0x56000044,2); //GPeDAT spi_gpeup = (int *)ioremap (0x56000048,2); //GPeUP spi_spcon0 = (int *)ioremap(0x59000000,1); //spcon0:spi 0 spi_spsta0 = (int *)ioremap(0x59000004,1); //spsta0:spi 0 spi_sppin0 = (int *)ioremap(0x59000008,1); //sppin0:spi 0 spi_sppre0= (int *)ioremap(0x5900000c,1); //sppre0:spi 0 spi_sptdat0 = (int *)ioremap(0x59000010,1); //sptdat0:spi 0 spi_sprdat0 = (int *)ioremap(0x59000014,1); //sprdat0:spi 0 printk(DEVICE_NAME" initial OK!
"); } /*====================================== :__exit : =======================================*/ static void __exit spi_exit(void) { devfs_remove(DEVICE_NAME); unregister_chrdev(SPI_MAJOR_NUM,DEVICE_NAME); } /*====================================== : =======================================*/ module_init(spi_init); module_exit(spi_exit); //end

Code 2:上記SPIデバイスドライバコードに対するmakefileファイル:
obj-m := spi_MMA7455.o #spi_MMA7455            
ifeq ($(v),arm)
KERNELDIR :=/opt/friendlyARMQQ2440/ghCodes/kernel-2.6.13 #     ARM        
else
KERNELDIR := /lib/modules/$(shell uname -r)/build #   PC       , ARM      ,      PC          
endif 
default: 
	make -C $(KERNELDIR) M=$(shell pwd) modules 
install: 
	insmod spi_MMA7455.ko
uninstall: 
	rmmod spi_MMA7455.ko 
clean: 
	make -C $(KERNELDIR) M=$(shell pwd) clean

このmakefileファイルを実行するときは、コマンドを使用します.
make v=arm

makefileに条件判定ifeq()が設定ためである.
 
Code 3:生成されたドライバをテストするためのテストプログラム
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>

//  SPI          
#define SPI_READFLAG 0// SPI    
#define SPI_WRITEFLAG 1// SPI    

#define SPI_SS_L	3// SS   
#define SPI_SS_H	4// SS   

//              
#define accXreg 0x06
#define accYreg 0x07
#define accZreg	0x08

//           
#define ACC_2G_RANGE 0x05
#define ACC_4G_RANGE 0x09
#define ACC_8G_RANGE 0x01


char Xdata=0,Ydata=0,Zdata=0;
/*==================================
  :	void spiWrite2acc(int fd,unsigned char reg,char data)
  :	SPI   MMA7455        
  :	MMA7455       
   :    
  :
==================================*/
void spiWrite2acc(int fd,unsigned char reg,char data)
{
	char wter=0;
	char *writebuf=&wter;
	*writebuf=((reg&0x3F)<<1)|0x80;
	ioctl(fd, SPI_SS_L);
	ioctl(fd, SPI_WRITEFLAG, writebuf);
	ioctl(fd, SPI_WRITEFLAG, &data);
	ioctl(fd, SPI_SS_H);
}

/*==================================
  :	void spiReadacc(int fd,unsigned char reg,char *rdbuf)
  :	SPI    MMA7455     
  :	MMA7455    
   :          
  :
==================================*/
void spiReadacc(int fd,unsigned char reg,char *rdbuf)
{
	char wter=0;
	char *writebuf=&wter;
	ioctl(fd, SPI_SS_L);
	*writebuf=(reg &0x3F)<<1;//     
	ioctl(fd, SPI_WRITEFLAG, writebuf);//       
	ioctl(fd, SPI_READFLAG, rdbuf);
	ioctl(fd, SPI_SS_H);
}

/*==================================
  :	void readAcc(void)
  :	SPI   
  :	spi      
   :	 
  :
==================================*/
void readAcc(int fd)
{
	spiReadacc(fd,accXreg,&Xdata);	
	spiReadacc(fd,accYreg,&Ydata);	
	spiReadacc(fd,accZreg,&Zdata);	
}

/*==================================
  :	void readAcc(void)
  :	SPI   
  :	spi      
   :	 
  :
==================================*/
void showAcc(void)
{
	printf("%x %x %x",Xdata,Ydata,Zdata);	
}

/*==================================
  :	void acc_init(int fd)
  :	SPI   
  :	spi      
   :	 
  :
==================================*/
void acc_init(int fd)
{
	char ret;
	ioctl(fd, SPI_SS_H);
	spiWrite2acc(fd,0x16,ACC_2G_RANGE);	//    
	spiReadacc(fd,0x16,&ret);			//        
	if(ACC_2G_RANGE!=ret)
		printf("No acceleration!
"); readAcc(fd); } void delay_gh(int time) { int i,j; for(i=0;i<0xffff;i++) for(j=time;j>0;j--); } /*================================== : int main(int argc, char **argv) : : : :spi ==================================*/ int main(int argc, char **argv) { int fd; int on=1; int led_no; char wtevr=0; char whtevr1,whtevr2=0x56; char *redbuf=&whtevr1; char *writebuf=&whtevr2; fd = open("/dev/spi_gh", 0); if (fd < 0) { perror("open device spi_gh"); exit(1); } printf("OPEN OK!
"); acc_init(fd); while(1) { readAcc(fd); printf("%x %x %x
",Xdata,Ydata,Zdata); delay_gh(0x10); } close(fd); return 0; }

このプログラムは基本的なテスト機能を完成することができて、MMA 7455加速度計の値を読み出して、クロスコンパイルを使います:
arm-linux-gcc -o test test.c

 
以上のプログラムのコンパイルが终わった后にARM开発板にダウンロードして、覚えてNFSを使わないでください、间违いが発生することができて、间违いはバージョンの问题を言うようです:
insmod: kernel-module version mismatch         chdev_test.ko was compiled for kernel version         chdev_test.ko was compiled for kernel version
エラーが発生したら、エラーを解決します.方法は、プログラムをダウンロードする方法をftpでダウンロードしたり、Uディスクでダウンロードしたりする方法に変えて、マニュアルを見てみましょう.
 
後で私たちを乗せます.koファイル、マウント方法:
insmod xxxx.ko

xxxxはデバイスドライバのファイル名です
マウント後はmknodは必要ありません.デバイスドライバの初期化にはMKDEPがあります.
devfs_mk_cdev(MKDEV(SPI_MAJOR_NUM, 0), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, DEVICE_NAME);	//                


その後、テストプログラムを実行します.
./test

それからまた間違いました:何のPermission deniedなのか、言って、権限を修正します:
chmod 777 test

そして運転
./test

これでOK!鳥を動かすことができます...
 
その中でN多すぎる问题に出会ったことがあって、私をがっかりさせて长い间、それから少しずつ解决して、今日やっと数を読んで、心の中のあの兴奋...ほほほ