在做项目时用到SPI所以这里整理了一下SPI的测试程序以便后用
下面是驱动部分:spi_ker.c
[cpp] view plain copy print ?
-
-
-
-
-
-
-
-
-
- #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
-
-
-
- #define CLKCON (*(volatile unsigned long *)(base_addr0 + 0x00))
-
-
- #define GPGCON (*(volatile unsigned long *)(base_addr1 + 0x00))
- #define GPGDAT (*(volatile unsigned long *)(base_addr1 + 0x04))
- #define GPGUP (*(volatile unsigned long *)(base_addr1 + 0x08))
-
-
-
- #define GPECON (*(volatile unsigned long *)(base_addr2 + 0x00))
- #define GPEDAT (*(volatile unsigned long *)(base_addr2 + 0x04))
- #define GPEUP (*(volatile unsigned long *)(base_addr2 + 0x08))
-
-
- #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))
-
-
- #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 |= (0x01 << 18);
- printk("s3c2440_clkcon=%08ld\n",CLKCON);
-
-
-
- GPGCON &= ~(3 << 4);
- GPGCON |= (1 << 4);
- SPNSS0_ENABLE();
-
-
- GPECON &= ~((3 << 22) | (3 << 24) | (3 << 26));
- GPECON |= ((2 << 22) | (2 << 24) | (2 << 26));
-
-
- GPGUP &= ~(0x07 << 2);
- GPEUP |= (0x07 << 11);
-
-
-
-
- SPPRE0 = 0x18;
- printk("SPPRE0=%02X\n",SPPRE0);
-
-
- 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);
-
- return 0;
- }
-
-
- static void writeByte(const char data)
- {
- int j = 0;
- SPTDAT0 = data;
- while(!SPI_TXRX_READY)
- for(j = 0; j < 0xFF; j++);
- }
-
- static char readByte(const char data)
- {
- int j = 0;
- char ch = 0;
-
-
-
-
- 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;
-
- 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;
-
-
- base_addr0 = ioremap(S3C2440_CLKCON, 0x04);
-
- base_addr1 = ioremap(S3C2440_GPG, 0x10);
-
- base_addr2 = ioremap(S3C2440_GPE, 0x10);
-
- 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
***********************************************************/
[cpp] view plain copy print ?
- #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 = 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 plain copy print ?
- 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
-