基于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. #include
  10. #include
  11. #include
  12. #include
  13. #include
  14. #include
  15. #include
  16. #include
  17. int loopChar=0x11;
  18. module_param(loopChar,int,S_IRUGO);
  19. #define DEVICE_NAME "tq2440_spi"
  20. static void __iomem *base_addr0;
  21. static void __iomem *base_addr1;
  22. static void __iomem *base_addr2;
  23. static void __iomem *base_addr3;
  24. //定义一个测试用的要发送的数据缓存包
  25. static char *kbuf;
  26. static intkbuf_size;
  27. #define S3C2440_CLKCON 0x4c00000c
  28. #define S3C2440_GPG0x56000060
  29. #define S3C2440_GPE0x56000040
  30. #define S3C2440_SPI0x59000000
  31. /*****************************************************/
  32. //S3C2440_CLKCON 部分
  33. #define CLKCON(*(volatile unsigned long *)(base_addr0 + 0x00))
  34. //GPG 控制寄存器部分GPG2脚对应NSS 端口
  35. #define GPGCON(*(volatile unsigned long *)(base_addr1 + 0x00))
  36. #define GPGDAT(*(volatile unsigned long *)(base_addr1 + 0x04))
  37. #define GPGUP(*(volatile unsigned long *)(base_addr1 + 0x08))
  38. //GPE 控制寄存器部分
  39. //GPE 11、12、13 脚分别对应SPI的MISO、MOSI、CLK 端口
  40. #define GPECON(*(volatile unsigned long *)(base_addr2 + 0x00))
  41. #define GPEDAT(*(volatile unsigned long *)(base_addr2 + 0x04))
  42. #define GPEUP(*(volatile unsigned long *)(base_addr2 + 0x08))
  43. //SPI 控制寄存器部分
  44. #define SPCON0(*(volatile unsigned long *)(base_addr3 + 0x00))
  45. #define SPSTA0(*(volatile unsigned long *)(base_addr3 + 0x04))
  46. #define SPPIN0(*(volatile char *)(base_addr3 + 0x08))
  47. #define SPPRE0(*(volatile char *)(base_addr3 + 0x0C))
  48. #define SPTDAT0(*(volatile char *)(base_addr3 + 0x10))
  49. #define SPRDAT0(*(volatile char *)(base_addr3 + 0x14))
  50. //SPI 输入输出的判忙状态引脚
  51. #define SPI_TXRX_READY(((SPSTA0) & 0x1) == 0x1)
  52. #defineSPNSS0_DISABLE()(GPEDAT &= ~(0x1 << 2))
  53. #defineSPNSS0_ENABLE()(GPEDAT |=(0x1 << 2))
  54. /********************************************************/
  55. static int spi_open(struct inode *inode,struct file *filp)
  56. {
  57. //使能时钟控制寄存器CLKCON 18位使能SPI
  58. CLKCON |= (0x01 << 18); //0x40000;
  59. printk("s3c2440_clkcon=%08ld\n",CLKCON);
  60. //使能GPG2 对应的NSS 端口
  61. //GPGCON |= (3 << 4);
  62. GPGCON &= ~(3 << 4);
  63. GPGCON |=(1 << 4);
  64. SPNSS0_ENABLE();
  65. //使能GPE 11、12、13对应的 MISO0,MOSI0,SCK0 = 11 0x0000FC00*/
  66. GPECON &= ~((3 << 22) | (3 << 24) | (3 << 26));
  67. GPECON |=((2 << 22) | (2 << 24) | (2 << 26));
  68. //GPEUP 设置; 全部disable
  69. GPGUP &= ~(0x07 << 2);
  70. GPEUP |=(0x07 << 11);
  71. /*SPI 寄存器部分*/
  72. //SPI 预分频寄存器设置,
  73. //Baud Rate=PCLK/2/(Prescaler value+1)
  74. SPPRE0 = 0x18; //freq = 1M
  75. printk("SPPRE0=%02X\n",SPPRE0);
  76. //polling,en-sck,master,low,format A,nomal = 0 | TAGD = 1
  77. SPCON0 = (0<<5)|(1<<4)|(1<<3)|(0<<2)|(0<<1)|(0<<0);
  78. printk("SPCON1=%02ld\n",SPCON0);
  79. //多主机错误检测使能
  80. SPPIN0 = (0 << 2) | (1 << 1) | (0 << 0);
  81. printk("SPPIN1=%02X\n",SPPIN0);
  82. //初始化程序
  83. SPTDAT0 = 0xff;
  84. return 0;
  85. }
  86. static int spi_release(struct inode *inode,struct file *filp)
  87. {
  88. //释放掉在写函数操作里面申请的缓存空间
  89. kfree(kbuf);
  90. //printk("<1>release\n");
  91. return 0;
  92. }
  93. //向SPI寄存器SPI_SPTDAT1中写数据
  94. static void writeByte(const char data)
  95. {
  96. int j = 0;
  97. SPTDAT0 = data;
  98. while(!SPI_TXRX_READY)
  99. for(j = 0; j < 0xFF; j++);
  100. }
  101. //从SPI寄存器SPI_SPRDAT1中读取数据
  102. static char readByte(const char data)
  103. {
  104. int j = 0;
  105. char ch = 0;
  106. //发送任意数据,如果只是读取的话那
  107. //麽仍需向SPTDAT0写数据,来保证SPI的
  108. //时钟一直可用
  109. SPTDAT0 = data;
  110. //判忙标志位
  111. while(!SPI_TXRX_READY)
  112. for(j = 0; j < 0xFF; j++);
  113. //从寄存器中读取信息
  114. ch = SPRDAT0;
  115. return ch;
  116. }
  117. //接收数据并把数据发送到应用空间
  118. static ssize_t spi_read(struct file *filp,char __user *buf,size_t count,loff_t *f_ops)
  119. {
  120. #if 1
  121. inti = 0;
  122. char *tab;
  123. printk("<1>spi read!\n");
  124. tab = kmalloc(kbuf_size,GFP_KERNEL);
  125. for(; i < kbuf_size; i++){
  126. tab[i] = readByte(kbuf[i]);
  127. printk("read data tab[%d] = %02X\n",i, tab[i]);
  128. }
  129. copy_to_user(buf, tab, kbuf_size);
  130. kfree(tab);
  131. #endif
  132. return 1;
  133. }
  134. //发送数据并把数据从用户空间发送到内核
  135. static ssize_t spi_write(struct file *filp,const char __user *buf,
  136. size_t count,loff_t *f_ops)
  137. {
  138. int i;
  139. //char *kbuf;
  140. kbuf_size = count;
  141. printk("<1>spi write!,count=%d\n",count);
  142. kbuf = kmalloc(count,GFP_KERNEL);
  143. //送到发用户空间
  144. if(copy_from_user(kbuf,buf,count))
  145. {
  146. printk("no enough memory!\n");
  147. return -1;
  148. }
  149. //循环写入寄存器
  150. #if 0
  151. for(i=0; i
  152. {
  153. writeByte(kbuf[i]);
  154. printk("write 0x%02X!\n",*kbuf);
  155. }
  156. #endif
  157. return count;
  158. }
  159. /**********************************************************/
  160. static const struct file_operations spi_fops =
  161. {
  162. .owner=THIS_MODULE,
  163. .open=spi_open,
  164. .read=spi_read,
  165. .release=spi_release,
  166. .write=spi_write,
  167. };
  168. static struct miscdevice misc = {
  169. .minor = MISC_DYNAMIC_MINOR,
  170. .name= DEVICE_NAME,
  171. .fops= &spi_fops,
  172. };
  173. static int __init spi_init(void)
  174. {
  175. int ret;
  176. //映射时钟控制寄存器CLKCON
  177. base_addr0 = ioremap(S3C2440_CLKCON, 0x04);
  178. //映射GPG部分
  179. base_addr1 = ioremap(S3C2440_GPG, 0x10);
  180. //映射GPE 寄存器地址
  181. base_addr2 = ioremap(S3C2440_GPE, 0x10);
  182. //映射SPI 寄存器地址
  183. base_addr3 = ioremap(S3C2440_SPI, 0x20);
  184. //复杂设备的注册
  185. ret = misc_register(&misc);
  186. printk(DEVICE_NAME "\tinitialized\n");
  187. return ret;
  188. }
  189. static void __exit spi_exit(void)
  190. {
  191. iounmap(base_addr0);
  192. iounmap(base_addr1);
  193. iounmap(base_addr2);
  194. iounmap(base_addr3);
  195. misc_deregister(&misc);
  196. printk("<1>spi_exit!\n");
  197. }
  198. module_init(spi_init);
  199. module_exit(spi_exit);
  200. MODULE_LICENSE("GPL");
/******************************************** *说明:本实验是针对TQ2440的SPI测试程序 * *设备模型:混杂设备 * *内核选取:linux-2.6.32.2 * *硬件要求:将MOSI与MISO短结 * *写作时间:2011/12/10 * *编辑作者:Sheldon Chu * ********************************************/ #include #include #include #include #include #include #include #includeint 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; ispi_exit!\n"); } module_init(spi_init); module_exit(spi_exit); MODULE_LICENSE("GPL"); /***********************************************************
这是应用程序部分: 【基于2440的SPI测试驱动程序以及应用程序(实例)】
spi_app.c
***********************************************************/

[cpp] view plain copy print ?
  1. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. #include
  8. #defineDATA_SIZE 5
  9. int main(int argc, char **argv)
  10. {
  11. int fd;
  12. int count=0;
  13. int i = 0;
  14. char buf[DATA_SIZE]={0x11,0x22,0x33,0x44,0x55};
  15. char tab[DATA_SIZE]={0};
  16. fd = open("/dev/tq2440_spi", O_RDWR);
  17. if (fd < 0) {
  18. perror("open device spi");
  19. exit(1);
  20. }
  21. #if 1
  22. count=write(fd,buf,sizeof(buf)/sizeof(buf[0]));
  23. printf("1--->count= %d\n",count);
  24. count=read(fd,tab,sizeof(tab)/sizeof(tab[0]));
  25. printf("2--->count= %d\n",count);
  26. /*
  27. for(; i < DATA_SIZE; i++) {
  28. count=write(fd,&buf[i],sizeof(buf[i]));
  29. count=read(fd,&tab[i],sizeof(tab[i]));
  30. }
  31. */
  32. for(i = 0; i < DATA_SIZE; i++){
  33. printf("write %d byte is: 0x%02X\n", i, buf[i]);
  34. printf("read%d byte is: 0x%02X\n\n", i, tab[i]);
  35. }
  36. #endif
  37. printf("-->hello!\n");
  38. close(fd);
  39. return 0;
  40. }
#include#include#include #include#include#include#include #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

    推荐阅读