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

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

下面是驱动部分:spi_ker.c

  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");  
/***********************************************************
                                这是应用程序部分:

                                      spi_app.c

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

  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. }  
/***********************************************************
                                这是编译程序部分:

                                         Makefile

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

  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.   
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值