您的位置:首页 > 其它

基于2440的SPI测试驱动程序以及应用程序(实例)

2012-05-25 18:16 477 查看
在做项目时用到SPI所以这里整理了一下SPI的测试程序以便后用

下面是驱动部分:spi_ker.c

[cpp]
view plaincopyprint?

/********************************************
*说明:本实验是针对TQ2440的SPI测试程序 *
*设备模型:混杂设备 *
*内核选取:linux-2.6.32.2 *
*硬件要求:将MOSI与MISO短结 *
*写作时间:2011/12/10 *
*编辑作者:Sheldon Chu *
********************************************/

#include <linux/miscdevice.h>

#include <linux/kernel.h>

#include <linux/module.h>
#include <linux/init.h>

#include <linux/fs.h>
#include <linux/slab.h>

#include <linux/pci.h>
#include <asm/uaccess.h>

int loopChar=0x11;
module_param(loopChar,int,S_IRUGO);

#define DEVICE_NAME "tq2440_spi"

static void __iomem *base_addr0;
static void __iomem *base_addr1;
static void __iomem *base_addr2;
static void __iomem *base_addr3;

//定义一个测试用的要发送的数据缓存包
static char *kbuf;
static int kbuf_size;

#define S3C2440_CLKCON 0x4c00000c

#define S3C2440_GPG 0x56000060

#define S3C2440_GPE 0x56000040

#define S3C2440_SPI 0x59000000

/*****************************************************/
//S3C2440_CLKCON 部分
#define CLKCON (*(volatile unsigned long *)(base_addr0 + 0x00))

//GPG 控制寄存器部分 GPG2脚对应NSS 端口

#define GPGCON (*(volatile unsigned long *)(base_addr1 + 0x00))

#define GPGDAT (*(volatile unsigned long *)(base_addr1 + 0x04))

#define GPGUP (*(volatile unsigned long *)(base_addr1 + 0x08))

//GPE 控制寄存器部分
//GPE 11、12、13 脚分别对应SPI的MISO、MOSI、CLK 端口

#define GPECON (*(volatile unsigned long *)(base_addr2 + 0x00))

#define GPEDAT (*(volatile unsigned long *)(base_addr2 + 0x04))

#define GPEUP (*(volatile unsigned long *)(base_addr2 + 0x08))

//SPI 控制寄存器部分
#define SPCON0 (*(volatile unsigned long *)(base_addr3 + 0x00))

#define SPSTA0 (*(volatile unsigned long *)(base_addr3 + 0x04))

#define SPPIN0 (*(volatile char *)(base_addr3 + 0x08))

#define SPPRE0 (*(volatile char *)(base_addr3 + 0x0C))

#define SPTDAT0 (*(volatile char *)(base_addr3 + 0x10))

#define SPRDAT0 (*(volatile char *)(base_addr3 + 0x14))

//SPI 输入输出的判忙状态引脚
#define SPI_TXRX_READY (((SPSTA0) & 0x1) == 0x1)

#define SPNSS0_DISABLE() (GPEDAT &= ~(0x1 << 2))

#define SPNSS0_ENABLE() (GPEDAT |= (0x1 << 2))

/********************************************************/
static int spi_open(struct inode *inode,struct file *filp)
{
//使能时钟控制寄存器CLKCON 18位使能SPI
CLKCON |= (0x01 << 18);//0x40000;

printk("s3c2440_clkcon=%08ld\n",CLKCON);

//使能GPG2 对应的NSS 端口
//GPGCON |= (3 << 4);

GPGCON &= ~(3 << 4);
GPGCON |= (1 << 4);
SPNSS0_ENABLE();

//使能GPE 11、12、13对应的 MISO0,MOSI0,SCK0 = 11 0x0000FC00*/

GPECON &= ~((3 << 22) | (3 << 24) | (3 << 26));
GPECON |= ((2 << 22) | (2 << 24) | (2 << 26));

//GPEUP 设置;全部disable
GPGUP &= ~(0x07 << 2);
GPEUP |= (0x07 << 11);

/*SPI 寄存器部分*/
//SPI 预分频寄存器设置,
//Baud Rate=PCLK/2/(Prescaler value+1)

SPPRE0 = 0x18; //freq = 1M

printk("SPPRE0=%02X\n",SPPRE0);

//polling,en-sck,master,low,format A,nomal = 0 | TAGD = 1

SPCON0 = (0<<5)|(1<<4)|(1<<3)|(0<<2)|(0<<1)|(0<<0);
printk("SPCON1=%02ld\n",SPCON0);

//多主机错误检测使能
SPPIN0 = (0 << 2) | (1 << 1) | (0 << 0);
printk("SPPIN1=%02X\n",SPPIN0);

//初始化程序
SPTDAT0 = 0xff;
return 0;
}

static int spi_release(struct inode *inode,struct file *filp)
{
//释放掉在写函数操作里面申请的缓存空间
kfree(kbuf);
//printk("<1>release\n");
return 0;
}

//向SPI寄存器SPI_SPTDAT1中写数据
static void writeByte(const char data)
{
int j = 0;
SPTDAT0 = data;
while(!SPI_TXRX_READY)
for(j = 0; j < 0xFF; j++);
}
//从SPI寄存器SPI_SPRDAT1中读取数据
static char readByte(const char data)
{
int j = 0;
char ch = 0;

//发送任意数据,如果只是读取的话那
//麽仍需向SPTDAT0写数据,来保证SPI的

//时钟一直可用
SPTDAT0 = data;

//判忙标志位
while(!SPI_TXRX_READY)
for(j = 0; j < 0xFF; j++);

//从寄存器中读取信息
ch = SPRDAT0;
return ch;
}

//接收数据并把数据发送到应用空间
static ssize_t spi_read(struct file *filp,char __user *buf,size_t count,loff_t *f_ops)
{
#if 1
int i = 0;
char *tab;
printk("<1>spi read!\n");
tab = kmalloc(kbuf_size,GFP_KERNEL);

for(; i < kbuf_size; i++){
tab[i] = readByte(kbuf[i]);
printk("read data tab[%d] = %02X\n",i, tab[i]);
}
copy_to_user(buf, tab, kbuf_size);
kfree(tab);
#endif
return 1;
}
//发送数据并把数据从用户空间发送到内核
static ssize_t spi_write(struct file *filp,const char __user *buf,
size_t count,loff_t *f_ops)
{
int i;
//char *kbuf;
kbuf_size = count;
printk("<1>spi write!,count=%d\n",count);
kbuf = kmalloc(count,GFP_KERNEL);

//送到发用户空间
if(copy_from_user(kbuf,buf,count))
{
printk("no enough memory!\n");
return -1;
}

//循环写入寄存器
#if 0
for(i=0;i<count;i++)
{
writeByte(kbuf[i]);
printk("write 0x%02X!\n",*kbuf);
}

#endif
return count;
}

/**********************************************************/
static const struct file_operations spi_fops =
{
.owner=THIS_MODULE,
.open=spi_open,
.read=spi_read,
.release=spi_release,
.write=spi_write,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &spi_fops,
};

static int __init spi_init(void)
{
int ret;

//映射时钟控制寄存器CLKCON

base_addr0 = ioremap(S3C2440_CLKCON, 0x04);
//映射GPG部分
base_addr1 = ioremap(S3C2440_GPG, 0x10);
//映射GPE 寄存器地址
base_addr2 = ioremap(S3C2440_GPE, 0x10);
//映射SPI 寄存器地址
base_addr3 = ioremap(S3C2440_SPI, 0x20);

//复杂设备的注册
ret = misc_register(&misc);
printk(DEVICE_NAME "\tinitialized\n");

return ret;
}

static void __exit spi_exit(void)
{
iounmap(base_addr0);
iounmap(base_addr1);
iounmap(base_addr2);
iounmap(base_addr3);
misc_deregister(&misc);
printk("<1>spi_exit!\n");
}

module_init(spi_init);
module_exit(spi_exit);

MODULE_LICENSE("GPL");

[cpp]
view plaincopyprint?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/ioctl.h>
#include <sys/types.h>

#include <sys/stat.h>
#include <fcntl.h>

#define  DATA_SIZE 5

int main(int argc, char **argv)
{
int fd;
int count=0;
int i = 0;
char buf[DATA_SIZE]={0x11,0x22,0x33,0x44,0x55};
char tab[DATA_SIZE]={0};
fd = open("/dev/tq2440_spi", O_RDWR);
if (fd < 0) {
perror("open device spi");
exit(1);
}
#if 1
count=write(fd,buf,sizeof(buf)/sizeof(buf[0]));
printf("1--->count= %d\n",count);
count=read(fd,tab,sizeof(tab)/sizeof(tab[0]));
printf("2--->count= %d\n",count);
/*
for(; i < DATA_SIZE; i++) {
count=write(fd,&buf[i],sizeof(buf[i]));
count=read(fd,&tab[i],sizeof(tab[i]));
}
*/
for(i = 0; i < DATA_SIZE; i++){
printf("write %d byte is: 0x%02X\n", i, buf[i]);
printf("read  %d byte is: 0x%02X\n\n", i, tab[i]);
}
#endif

printf("-->hello!\n");
close(fd);
return 0;
}

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define  DATA_SIZE 5

int main(int argc, char **argv)
{
int fd;
int count=0;
int i = 0;
char buf[DATA_SIZE]={0x11,0x22,0x33,0x44,0x55};
char tab[DATA_SIZE]={0};
fd = open("/dev/tq2440_spi", O_RDWR);
if (fd < 0) {
perror("open device spi");
exit(1);
}
#if 1
count=write(fd,buf,sizeof(buf)/sizeof(buf[0]));
printf("1--->count= %d\n",count);
count=read(fd,tab,sizeof(tab)/sizeof(tab[0]));
printf("2--->count= %d\n",count);
/*
for(; i < DATA_SIZE; i++) {
count=write(fd,&buf[i],sizeof(buf[i]));
count=read(fd,&tab[i],sizeof(tab[i]));
}
*/
for(i = 0; i < DATA_SIZE; i++){
printf("write %d byte is: 0x%02X\n", i, buf[i]);
printf("read  %d byte is: 0x%02X\n\n", i, tab[i]);
}
#endif

printf("-->hello!\n");
close(fd);
return 0;
}
/***********************************************************

这是编译程序部分:

Makefile

***********************************************************/

[cpp]
view plaincopyprint?

ifneq ($(KERNELRELEASE),)
obj-m := spi_ker.o
else
KDIR := /home/kernel/linux-2.6.32.2
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
arm-linux-gcc spi_app.c -o spi_app
clean:
rm -f *.ko *.o *.mod.o *.mod.c *symvers modul* spi_app
endif
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐