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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天上人间555

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值