在做项目时用到SPI所以这里整理了一下SPI的测试程序以便后用
下面是驱动部分:spi_ker.c
- /********************************************
- *说明:本实验是针对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");
/********************************************
*说明:本实验是针对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");
/***********************************************************
这是应用程序部分:
spi_app.c
***********************************************************/
- #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
***********************************************************/
- 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
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