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

在做项目时用到SPI所以这里整理了一下SPI的测试程序以便后用

下面是驱动部分:spi_ker.c

[cpp] view plain copy print ?
  1. /******************************************** 
  2.  *说明:本实验是针对TQ2440的SPI测试程序    * 
  3.  *设备模型:混杂设备                       * 
  4.  *内核选取:linux-2.6.32.2                 * 
  5.  *硬件要求:将MOSI与MISO短结               * 
  6.  *写作时间:2011/12/10                     * 
  7.  *编辑作者:Sheldon Chu                    * 
  8. ********************************************/  
  9.   
  10. #include <linux/miscdevice.h>   
  11. #include <linux/kernel.h>   
  12. #include <linux/module.h>   
  13. #include <linux/init.h>   
  14. #include <linux/fs.h>   
  15. #include <linux/slab.h>   
  16. #include <linux/pci.h>   
  17. #include <asm/uaccess.h>   
  18.    
  19. int loopChar=0x11;  
  20. module_param(loopChar,int,S_IRUGO);  
  21.                                                        
  22. #define DEVICE_NAME "tq2440_spi"   
  23. static void __iomem *base_addr0;  
  24. static void __iomem *base_addr1;  
  25. static void __iomem *base_addr2;  
  26. static void __iomem *base_addr3;  
  27.   
  28. //定义一个测试用的要发送的数据缓存包   
  29. static char *kbuf;  
  30. static int  kbuf_size;  
  31.   
  32. #define S3C2440_CLKCON 0x4c00000c   
  33. #define S3C2440_GPG    0x56000060   
  34. #define S3C2440_GPE    0x56000040   
  35. #define S3C2440_SPI    0x59000000   
  36.   
  37. /*****************************************************/  
  38. //S3C2440_CLKCON 部分   
  39. #define CLKCON      (*(volatile unsigned long *)(base_addr0 + 0x00))   
  40.   
  41. //GPG 控制寄存器部分  GPG2脚对应NSS 端口   
  42. #define GPGCON      (*(volatile unsigned long *)(base_addr1 + 0x00))   
  43. #define GPGDAT      (*(volatile unsigned long *)(base_addr1 + 0x04))   
  44. #define GPGUP       (*(volatile unsigned long *)(base_addr1 + 0x08))   
  45.   
  46. //GPE 控制寄存器部分    
  47. //GPE 11、12、13 脚分别对应SPI的MISO、MOSI、CLK 端口   
  48. #define GPECON      (*(volatile unsigned long *)(base_addr2 + 0x00))   
  49. #define GPEDAT      (*(volatile unsigned long *)(base_addr2 + 0x04))   
  50. #define GPEUP       (*(volatile unsigned long *)(base_addr2 + 0x08))   
  51.   
  52. //SPI 控制寄存器部分   
  53. #define SPCON0      (*(volatile unsigned long *)(base_addr3 + 0x00))   
  54. #define SPSTA0      (*(volatile unsigned long *)(base_addr3 + 0x04))   
  55. #define SPPIN0      (*(volatile char *)(base_addr3 + 0x08))   
  56. #define SPPRE0      (*(volatile char *)(base_addr3 + 0x0C))   
  57. #define SPTDAT0     (*(volatile char *)(base_addr3 + 0x10))   
  58. #define SPRDAT0     (*(volatile char *)(base_addr3 + 0x14))   
  59.   
  60. //SPI 输入输出的判忙状态引脚   
  61. #define SPI_TXRX_READY      (((SPSTA0) & 0x1) == 0x1)   
  62.   
  63. #define  SPNSS0_DISABLE()      (GPEDAT &= ~(0x1 << 2))   
  64. #define  SPNSS0_ENABLE()       (GPEDAT |=  (0x1 << 2))   
  65. /********************************************************/  
  66. static int spi_open(struct inode *inode,struct file *filp)  
  67. {  
  68.     //使能时钟控制寄存器CLKCON 18位使能SPI   
  69.     CLKCON |= (0x01 << 18);//0x40000;   
  70.     printk("s3c2440_clkcon=%08ld\n",CLKCON);  
  71.   
  72.     //使能GPG2 对应的NSS 端口   
  73.     //GPGCON |= (3 << 4);   
  74.     GPGCON &= ~(3 << 4);  
  75.     GPGCON |=  (1 << 4);  
  76.     SPNSS0_ENABLE();  
  77.   
  78.     //使能GPE 11、12、13对应的 MISO0,MOSI0,SCK0 = 11 0x0000FC00*/   
  79.     GPECON &= ~((3 << 22) | (3 << 24) | (3 << 26));  
  80.     GPECON |=  ((2 << 22) | (2 << 24) | (2 << 26));  
  81.       
  82.     //GPEUP 设置;全部disable   
  83.     GPGUP &= ~(0x07 << 2);    
  84.     GPEUP |=  (0x07 << 11);  
  85.   
  86.     /*SPI 寄存器部分*/  
  87.     //SPI 预分频寄存器设置,   
  88.     //Baud Rate=PCLK/2/(Prescaler value+1)   
  89.     SPPRE0 = 0x18;       //freq = 1M   
  90.     printk("SPPRE0=%02X\n",SPPRE0);  
  91.       
  92.     //polling,en-sck,master,low,format A,nomal = 0 | TAGD = 1   
  93.     SPCON0 = (0<<5)|(1<<4)|(1<<3)|(0<<2)|(0<<1)|(0<<0);  
  94.     printk("SPCON1=%02ld\n",SPCON0);  
  95.   
  96.     //多主机错误检测使能   
  97.     SPPIN0 = (0 << 2) | (1 << 1) | (0 << 0);  
  98.     printk("SPPIN1=%02X\n",SPPIN0);  
  99.   
  100.     //初始化程序   
  101.     SPTDAT0 = 0xff;  
  102.     return 0;  
  103. }  
  104.    
  105.    
  106. static int spi_release(struct inode *inode,struct file *filp)  
  107. {  
  108.     //释放掉在写函数操作里面申请的缓存空间   
  109.     kfree(kbuf);  
  110.     //printk("<1>release\n");   
  111.     return 0;  
  112. }  
  113.    
  114. //向SPI寄存器SPI_SPTDAT1中写数据    
  115. static void writeByte(const char data)  
  116. {  
  117.     int j = 0;  
  118.     SPTDAT0 = data;  
  119.     while(!SPI_TXRX_READY)  
  120.         for(j = 0; j < 0xFF; j++);  
  121. }  
  122. //从SPI寄存器SPI_SPRDAT1中读取数据   
  123. static char readByte(const char data)  
  124. {  
  125.     int j = 0;  
  126.     char ch = 0;  
  127.       
  128.     //发送任意数据,如果只是读取的话那   
  129.     //麽仍需向SPTDAT0写数据,来保证SPI的   
  130.     //时钟一直可用   
  131.     SPTDAT0 = data;  
  132.   
  133.     //判忙标志位   
  134.     while(!SPI_TXRX_READY)  
  135.         for(j = 0; j < 0xFF; j++);  
  136.       
  137.     //从寄存器中读取信息   
  138.     ch = SPRDAT0;  
  139.     return ch;  
  140. }  
  141.   
  142. //接收数据并把数据发送到应用空间   
  143. static ssize_t spi_read(struct file *filp,char __user *buf,size_t count,loff_t *f_ops)  
  144. {  
  145. #if 1   
  146.     int   i = 0;  
  147.     char *tab;  
  148.     printk("<1>spi read!\n");  
  149.     tab = kmalloc(kbuf_size,GFP_KERNEL);  
  150.   
  151.     for(; i < kbuf_size; i++){  
  152.         tab[i] = readByte(kbuf[i]);  
  153.         printk("read data tab[%d] = %02X\n",i, tab[i]);  
  154.     }  
  155.     copy_to_user(buf, tab, kbuf_size);  
  156.     kfree(tab);  
  157. #endif   
  158.     return 1;  
  159. }  
  160. //发送数据并把数据从用户空间发送到内核   
  161. static ssize_t spi_write(struct file *filp,const char __user *buf,  
  162.                                             size_t count,loff_t *f_ops)  
  163. {  
  164.     int i;  
  165.     //char *kbuf;   
  166.     kbuf_size = count;  
  167.     printk("<1>spi write!,count=%d\n",count);  
  168.     kbuf = kmalloc(count,GFP_KERNEL);  
  169.       
  170.     //送到发用户空间   
  171.     if(copy_from_user(kbuf,buf,count))  
  172.     {  
  173.         printk("no enough memory!\n");  
  174.         return -1;  
  175.     }  
  176.       
  177.     //循环写入寄存器   
  178. #if 0       
  179.     for(i=0;i<count;i++)  
  180.     {  
  181.         writeByte(kbuf[i]);  
  182.         printk("write 0x%02X!\n",*kbuf);  
  183.     }  
  184.       
  185. #endif   
  186.     return count;  
  187. }  
  188.    
  189.    
  190. /**********************************************************/  
  191. static const struct file_operations spi_fops =  
  192. {  
  193.     .owner=THIS_MODULE,  
  194.     .open=spi_open,  
  195.     .read=spi_read,  
  196.     .release=spi_release,  
  197.     .write=spi_write,  
  198. };  
  199. static struct miscdevice misc = {  
  200.     .minor = MISC_DYNAMIC_MINOR,  
  201.     .name  = DEVICE_NAME,  
  202.     .fops  = &spi_fops,  
  203. };  
  204.   
  205. static int __init spi_init(void)  
  206. {  
  207.     int ret;  
  208.       
  209.     //映射时钟控制寄存器CLKCON    
  210.     base_addr0 = ioremap(S3C2440_CLKCON, 0x04);  
  211.     //映射GPG部分   
  212.     base_addr1 = ioremap(S3C2440_GPG, 0x10);  
  213.     //映射GPE 寄存器地址   
  214.     base_addr2 = ioremap(S3C2440_GPE, 0x10);  
  215.     //映射SPI 寄存器地址   
  216.     base_addr3 = ioremap(S3C2440_SPI, 0x20);  
  217.   
  218.     //复杂设备的注册   
  219.     ret = misc_register(&misc);  
  220.     printk(DEVICE_NAME "\tinitialized\n");  
  221.    
  222.     return ret;  
  223. }  
  224.    
  225.    
  226. static void __exit spi_exit(void)  
  227. {  
  228.     iounmap(base_addr0);  
  229.     iounmap(base_addr1);  
  230.     iounmap(base_addr2);  
  231.     iounmap(base_addr3);  
  232.     misc_deregister(&misc);  
  233.     printk("<1>spi_exit!\n");  
  234. }  
  235.    
  236. module_init(spi_init);  
  237. module_exit(spi_exit);  
  238.    
  239. 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 ?
  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. #include <unistd.h>   
  4. #include <sys/ioctl.h>   
  5. #include <sys/types.h>   
  6. #include <sys/stat.h>   
  7. #include <fcntl.h>   
  8. #define  DATA_SIZE 5    
  9.   
  10. int main(int argc, char **argv)  
  11. {  
  12.     int fd;  
  13.     int count=0;  
  14.     int i = 0;  
  15.     char buf[DATA_SIZE]={0x11,0x22,0x33,0x44,0x55};  
  16.     char tab[DATA_SIZE]={0};  
  17.     fd = open("/dev/tq2440_spi", O_RDWR);  
  18.     if (fd < 0) {  
  19.         perror("open device spi");  
  20.         exit(1);  
  21.     }  
  22. #if 1   
  23.     count=write(fd,buf,sizeof(buf)/sizeof(buf[0]));  
  24.     printf("1--->count= %d\n",count);  
  25.     count=read(fd,tab,sizeof(tab)/sizeof(tab[0]));  
  26.     printf("2--->count= %d\n",count);  
  27. /*   
  28.     for(; i < DATA_SIZE; i++) { 
  29.         count=write(fd,&buf[i],sizeof(buf[i])); 
  30.         count=read(fd,&tab[i],sizeof(tab[i])); 
  31.     } 
  32. */  
  33.     for(i = 0; i < DATA_SIZE; i++){  
  34.         printf("write %d byte is: 0x%02X\n", i, buf[i]);  
  35.         printf("read  %d byte is: 0x%02X\n\n", i, tab[i]);  
  36.     }  
  37. #endif   
  38.   
  39.     printf("-->hello!\n");  
  40.     close(fd);  
  41.     return 0;  
  42. }  
#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 ?
  1. ifneq ($(KERNELRELEASE),)  
  2. obj-m := spi_ker.o  
  3. else  
  4. KDIR := /home/kernel/linux-2.6.32.2  
  5. all:  
  6.     make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-  
  7.     arm-linux-gcc spi_app.c -o spi_app  
  8. clean:  
  9.     rm -f *.ko *.o *.mod.o *.mod.c *symvers modul* spi_app   
  10. endif  
  11.    

你可能感兴趣的:(基于2440的SPI测试驱动程序以及应用程序(实例))