您的位置:首页 > 运维架构 > Linux

基于6467T的linux平台下的SPI驱动编写

2014-11-25 15:32 656 查看

1.  SPI 4线模式

根据6467T的datasheet,SPI4线模式示意图如下图所示:



2.     驱动程序编写

包括必要的头文件

//#include <linux/config.h>

#include <linux/device.h>

#include <linux/spi/spi.h>

#include <linux/compiler.h>

#include <linux/init.h>

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/mm.h>

#include <linux/miscdevice.h>

#include <linux/fs.h>

#include <linux/types.h>

#include <linux/errno.h>

#include <linux/ioctl.h>

#include <linux/cdev.h>

#include <linux/string.h>

#include <linux/list.h>

//#include <linux/devfs_fs_kernel.h>

#include <linux/poll.h>

#include <asm/uaccess.h>

#include <asm/atomic.h>

#include <asm/unistd.h>

#include <asm/io.h>

根据不同的内核版本,头文件稍有差别,我使用的内核版本是2.6.32,有两个文件找不到,因此把他们注释掉。

 

3.     设置SPI的设备名与主设备号以及相关寄存器

注意避开那些已经使用的主设备号

#define DEVICE_NAME "SPI"//设备名

#define SPI_MAJOR 240//主设备号

 

以下设置需要参考6467T的datasheet,不可任意设置

指定SPI寄存器的基地址

#define DAVINCI_SPI_BASE (0x01C66800)

 

定义SPI寄存器结构体

struct davinci_spi_reg {

volatile __u32 __bitwise SPIGCR0;

volatile __u32 __bitwise SPIGCR1;

volatile __u32 __bitwise SPIINT;

volatile __u32 __bitwise SPILVL;

volatile __u32 __bitwise SPIFLG;

volatile __u32 __bitwise SPIPC0;

volatile __u32 __bitwise SPIPC1;

volatile __u32 __bitwise SPIPC2;

volatile __u32 __bitwise SPIPC3;

volatile __u32 __bitwise SPIPC4;

volatile __u32 __bitwise SPIPC5;

volatile __u32 __bitwise SPIPC6;

volatile __u32 __bitwise SPIPC7;

volatile __u32 __bitwise SPIPC8;

volatile __u32 __bitwise SPIDAT0;

volatile __u32 __bitwise SPIDAT1;

volatile __u32 __bitwise SPIBUF;

volatile __u32 __bitwise SPIEMU;

volatile __u32 __bitwise SPIDELAY;

volatile __u32 __bitwise SPIDEF;

volatile __u32 __bitwise SPIFMT[4];

volatile __u32 __bitwise TGINTVEC[2];

volatile __u8 __bitwise RSVD0[8];

volatile __u32 __bitwise MIBSPIE;

};

 

4.     填充file_operations结构体

static struct file_operationsdavinci_z_spi_fops =

{

.owner = THIS_MODULE,

.open = davinci_spi_open,

.write = davinci_spi_write,

.release = davinci_spi_close,

};

分别实现SPI初始化函数open、读写函数write和释放函数release,以及模块初始化函数dev_init和退出函数dev_exit。

 

static int davinci_spi_close(struct inode *inode,struct file *filp)
{
printk("davinci-spi closed\n");
return 0;
}
static int davinci_spi_open(struct inode *inode,struct file *filp)
{
int config;
int value;
int i;

printk("spi open begin..\n");
// 1,Reset SPI
spi_reg_davinci->SPIGCR0 = 0;
for(i=0;i<1000;i++);//进行必要的等待

// 2,Release SPI
spi_reg_davinci->SPIGCR0 = 1;

// 3,master or slave mode setup
spi_reg_davinci->SPIGCR1 = 0
| ( 0 << 24 )
| ( 0 << 16 )//loopback mode default :0 test: 1 //在最初没有从设备的调试阶段,可以设置为 1 。
| ( 1 << 1 )
| ( 1 << 0 );
// 4,Enable the SPI_SIMO, SPI_SOMI, and SPI_CLK pins and the necessary chip select pins
spi_reg_davinci->SPIPC0 = 0
| ( 1 << 11 ) // DI
| ( 1 << 10 ) // DO
| ( 1 << 9 ) // CLK
| ( 0 << 1 ) // EN1
| ( 0 << 0 ); // EN0
// 5,Configure the desired data format
spi_reg_davinci->SPIFMT[0] = 0
| ( 0 << 20 ) // SHIFTDIR MSB
| ( 0 << 17 ) // Polarity
| ( 1 << 16 ) // Phase
| ( 50 << 8 ) // Prescale
| ( 8 << 0 ); // Char Len
//6,Select the preconfigured data format
//7,using SPI in 4-pin mode with SPI_CS,configue hold time,default chip select pin value
//8,4-pin mode with spi_en
//9,5-pin mode
spidat1 = 0
| ( 1 << 28 ) // CSHOLD
| ( 0 << 24 ) // Format [0]
| ( 3 << 16 ) // CSNR [0 both, 1 CS1, 2 only CS0 enbled , 3 none]
| ( 0 << 0 ); //
spi_reg_davinci->SPIDAT1 = spidat1;
spi_reg_davinci->SPIDELAY = 0
| ( 8 << 24 ) // C2TDELAY
| ( 8 << 16 ); // T2CDELAY
spi_reg_davinci->SPIDEF = 0
| ( 1 << 1 ) // EN1 inactive high
| ( 1 << 0 ); // EN0 inactive high
//10. Enable the desired interrupts
spi_reg_davinci->SPIINT = 0
| ( 0 << 16 ) //
| ( 0 << 8 ) //
| ( 0 << 6 ) //
| ( 0 << 4 ); //
//11,select interrupt level
spi_reg_davinci->SPILVL = 0
| ( 0 << 8 ) // EN0
| ( 0 << 6 ) // EN0
| ( 0 << 4 ); // EN0

//12, Enable SPI
spi_reg_davinci->SPIGCR1 |= ( 1 << 24 );
//13. If using the EDMA to perform the transfers, setup and enable the EDMA channels for transmit or receive and then set the DMAREQEN bit in SPIINT.
//14. Data is ready to be transferred using the CPU or EDMA by writing to SPIDAT1.
printk("Open spi successfully\n");
return 0;

}


static ssize_t davinci_spi_write(struct file *filp, char __user *buf,size_t count,loff_t *f_ops)
{
//	int spcon;
char i=0;
//	char len=0;

//printk("in davinci_spi_write: count is %d\n",count);
//将用户空间的数据搬移到内核空间
copy_from_user(dataTx,buf,count);//sizeof(dataTx));

//dataTx[0]=0x85;//just for test
// Clear any old data
spi_reg_davinci->SPIBUF;
// SPI access cycle
// Wait for transmit ready
while ( spi_reg_davinci->SPIBUF & 0x10000000 );

//发送一字节
spi_reg_davinci->SPIDAT1 = spidat1 | (int)(dataTx[i]);

// Wait for receive data ready
while ( spi_reg_davinci->SPIBUF & 0x80000000 );
// Read 1 byte
dataRx[i] = (spi_reg_davinci->SPIBUF)&0xff;

copy_to_user(buf,dataRx,count);//sizeof(dataTx));
//printk("copy_to_user is %d\n",dataRx[0]);
return 0;
}

static int __init dev_init(void)
{
int ret;

spi_reg_davinci = (struct davinci_spi_reg *)ioremap( DAVINCI_SPI_BASE ,200);

ret = register_chrdev(SPI_MAJOR,DEVICE_NAME,&davinci_z_spi_fops);//设备注册
if(ret < 0)
{
printk(DEVICE_NAME "can't get major number\n");
return ret;
}
//	devfs_mk_cdev(MKDEV(SPI_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,DEVICE_NAME);
printk (DEVICE_NAME"\tinitialized\n");
return 0;
}
static void __exit dev_exit(void)
{
//	devfs_remove(DEVICE_NAME);
unregister_chrdev(SPI_MAJOR, DEVICE_NAME);
printk("Good-bye, SPI module was removed!\n");
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("surui");


5.     编写Makefile

ifeq ($(KERNELRELEASE),)

DIROBJ	= ./

SRC = spi_master_mod.c

OBJ = ${SRC:%.c=$(DIROBJ)/%.o}

CSTOOL_DIR=/opt/arm-2009q1

CSTOOL_PREFIX=$(CSTOOL_DIR)/bin/arm-none-linux-gnueabi-

MVTOOL_DIR=$(CSTOOL_DIR)

MVTOOL_PREFIX=$(CSTOOL_PREFIX)

KERNELDIR = /opt/dvsdk/git_dm6467t

# The current directory is passed to sub-makes as argument

PWD := $(shell pwd)

modules:

@echo "before modules"

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

@echo "modules"

modules_install:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

@echo "modules_install"

clean:

rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

@echo "clean"

.PHONY: modules modules_install clean

else

# called from kernel build system: just declare what our modules are

obj-m := spi_master_mod.o

#echo "else"

endif


6.     编译调试

l  分别编译

配置好内核路径,以及交叉编译器路径,几次make即可。

l  加载模块

insmodspi_master_mod.ko

l  创建设备节点

mknod /dev/SPIc 240 1

l  open设备,操作

进入运行路径,执行应用程序,./spi

 

7.     上电测试

在没有从设备时要进行初步的测试,可以启动spi的环路测试模式,即自发自收,这样发出的数据就是接收的数据,对应的寄存器是 spi_reg_davinci->SPIGCR1。

 

附录

源代码下载:

http://download.csdn.net/detail/surui_555/8244591
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: