基于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");
这是编译程序部分:
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
下面是驱动部分: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
相关文章推荐
- 基于2440的SPI测试驱动程序以及应用程序(实例)
- 基于2440的SPI测试驱动程序以及应用程序(实例)
- 【ARM&Linux】基于c3c2440 Linux SPI驱动程序移植与测试
- 如何编写Linux设备驱动程序以及测试详细流程(附实例)
- 基于Linux的S3C6410模拟SPI的外围设备驱动程序、Makefile及测试程序的实现
- 基于AMF协议的Flex应用程序-性能测试
- Linux管理工作,实例讲解工作中使用ssh证书登录的实际流程,讲解ssh证书登录的配置原理,基于配置原理,解决实际工作中,windows下使用SecureCRT证书登录的各种问题,以及实现hadoo
- 基于java的串口通讯(附带实例+说明文档+测试工具)
- linux下基于S3C2440的PWM蜂鸣器移植以及驱动程序分析
- 基于dwr2.0的Push推送技术详细解析以及实例
- 使用Spring TestContext 测试框架,完美测试基于Spring的应用程序
- Python测试用例生成脚本(合并相应单元格以及写入单行数据)代码实例
- python基于mysql实现的简单队列以及跨进程锁实例详解
- Android驱动程序开发实例精讲-0_Android系统HAL驱动开发经典案例详解(基于Android4.0)
- 【原】基于vc 6.0开发dll动态链接库和测试实例--串口操作
- 基于Windows CE的SPI驱动程序设计
- Java Web应用程序认证 -- 基于JDK7的License开发应用以及认证
- 基于dwr2.0的Push推送技术详细解析以及实例
- 非常实用的Junit3与Junit4 测试 以及两者平滑过渡(高兼容性)实例代码