基于2440的SPI测试驱动程序以及应用程序(实例)
在做项目时用到SPI所以这里整理了一下SPI的测试程序以便后用
下面是驱动部分:spi_ker.c
[cpp] view plain copy print ?
- /********************************************
- *说明:本实验是针对TQ2440的SPI测试程序*
- *设备模型:混杂设备*
- *内核选取:linux-2.6.32.2*
- *硬件要求:将MOSI与MISO短结*
- *写作时间:2011/12/10*
- *编辑作者:Sheldon Chu*
- ********************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- 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 intkbuf_size;
- #define S3C2440_CLKCON 0x4c00000c
- #define S3C2440_GPG0x56000060
- #define S3C2440_GPE0x56000040
- #define S3C2440_SPI0x59000000
- /*****************************************************/
- //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)
- #defineSPNSS0_DISABLE()(GPEDAT &= ~(0x1 << 2))
- #defineSPNSS0_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
- inti = 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
- {
- 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");
这是应用程序部分: 【基于2440的SPI测试驱动程序以及应用程序(实例)】
spi_app.c
***********************************************************/
[cpp] view plain copy print ?
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #defineDATA_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
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量