S3C2440 spi驱动简单测试 (转)
来源:互联网 发布:幼儿园淘宝节活动流程 编辑:程序博客网 时间:2024/05/29 03:55
这两天参考网上的资料,自己写了个SPI的驱动,并实际测试通过。
硬件平台:mini2440 用的是S3C2440 的SPI1(共有2个SPI模块)
操作系统:linux-2.6.32.2
测试方法:将SPI的MISO与MOSI管脚短路,这样读数据的时候第一个发出的dummy字节即为收到的字节。
下面是驱动的源代码(mini2440_spi.c):
/***************************************************/
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <linux/spinlock.h>
#include <asm/system.h>
#include <asm/uaccess.h>
int
loopChar=0x88;
module_param(loopChar,
int
,S_IRUGO);
static
int
spi_major = 55;
#define spi_name "mini2440_spi"
struct
cdev spiCdev;
/*****************************************************/
static
int
spi_open(
struct
inode *,
struct
file *);
static
int
spi_release(
struct
inode *,
struct
file *);
static
ssize_t spi_write(
struct
file *filp,
const
char
*buf,
size_t
count,loff_t *f_ops);
static
ssize_t spi_read(
struct
file *filp,
char
*buf,
size_t
count,loff_t *f_ops);
static
ssize_t spi_ioctl(
struct
inode *inode,
struct
file *filp,unsigned
int
cmd,unsigned
long
data);
volatile
int
*spi_gpfcon=NULL;
//GPF Part define
volatile
int
*spi_gpfdat=NULL;
volatile
int
*spi_gpfup=NULL;
volatile
int
*spi_gpgcon=NULL;
//GPG Part define
volatile
int
*spi_gpgdat=NULL;
volatile
int
*spi_gpgup=NULL;
volatile
int
*s3c2440_clkcon;
volatile
int
*spi_spcon1;
//SPI Part define
volatile
int
*spi_spsta1;
volatile
int
*spi_sppin1;
volatile
int
*spi_sppre1;
volatile
int
*spi_sptdat1;
volatile
int
*spi_sprdat1;
#define SPI_TXRX_READY (((*spi_spsta1)&0x1) == 0x1)
/**********************************************************/
static
const
struct
file_operations spi_fops =
{
.owner=THIS_MODULE,
.open=spi_open,
.read=spi_read,
.ioctl=spi_ioctl,
.release=spi_release,
.write=spi_write,
};
/********************************************************/
static
int
spi_open(
struct
inode *inode,
struct
file *filp)
{
filp->private_data =&spiCdev;
/***********************************************
*PCLK
************************************************/
/*control PCLK into spi block*/
*s3c2440_clkcon |=0x40000;
printk(
"s3c2440_clkcon=%08X/n"
,*s3c2440_clkcon);
/***********************************************
*GPG PORTS
************************************************/
/*config SCK1,MOSI1,MISO1 = 11*/
*spi_gpgcon |=0x0000FC00;
/*poll up MISO1 MOSI1,SCK1*/
*spi_gpgup &=0xFF1F;
*spi_gpgup |=0x0060;
/***********************************************
*GPF PORTS
************************************************/
*spi_gpfcon &= 0xFCF3;
*spi_gpfcon |= 0x0108;
*spi_gpfup &= 0xED;
*spi_gpfdat |= 0x10;
/***********************************************
*SPI REGS
************************************************/
//SPI Baud Rate Prescaler Register,Baud Rate=PCLK/2/(Prescaler value+1)
*spi_sppre1=0x18;
//freq = 1M
printk(
"spi_sppre1=%02X/n"
,*spi_sppre1);
//polling,en-sck,master,low,format A,nomal = 0 | TAGD = 1
*spi_spcon1=(0<<6)|(0<<5)|(1<<4)|(1<<3)|(0<<2)|(0<<1)|(0<<0);
printk(
"spi_spcon1=%02X/n"
,*spi_spcon1);
//Multi Master error detect disable,reserved,rech=*spi_sprdat0;lease
*spi_sppin1=(0<<2)|(0<<0);
printk(
"spi_sppin1=%02X/n"
,*spi_sppin1);
return
0;
}
static
int
spi_release(
struct
inode *inode,
struct
file *filp)
{
//free irq
free_irq(IRQ_EINT1, NULL);
printk(
"<1>release/n"
);
return
0;
}
static
void
writeByte(
const
char
c)
{
int
j = 0;
*spi_sptdat1 = c;
for
(j=0;j<0xFF;j++);
while
(!SPI_TXRX_READY)
for
(j=0;j<0xFF;j++);
}
static
char
readByte(
void
)
{
int
j = 0;
char
ch = 0;
*spi_sptdat1 = (
char
)loopChar;
for
(j=0;j<0xFF;j++);
while
(!SPI_TXRX_READY)
for
(j=0;j<0xFF;j++);
ch=*spi_sprdat1;
return
ch;
}
static
ssize_t spi_read(
struct
file *filp,
char
__user *buf,
size_t
count,loff_t *f_ops)
{
//int len=0;
char
ch;
printk(
"<1>spi read!/n"
);
ch=readByte();
copy_to_user(buf,&ch,1);
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;
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;
}
for
(i=0;i<count;i++)
{
writeByte(*kbuf);
printk(
"write 0x%02X!/n"
,*kbuf);
kbuf++;
}
return
count;
}
static
ssize_t spi_ioctl(
struct
inode *inode,
struct
file *filp,unsigned
int
cmd,unsigned
long
data)
{
return
0;
}
static
int
__init spi_init(
void
)
{
int
result;
dev_t devno = MKDEV(spi_major, 0);
/**/
if
(spi_major)
result = register_chrdev_region(devno, 1, spi_name);
else
/**/
{
result = alloc_chrdev_region(&devno, 0, 1, spi_name);
spi_major = MAJOR(devno);
}
if
(result < 0)
return
result;
cdev_init(&spiCdev, &spi_fops);
spiCdev.owner = THIS_MODULE;
spiCdev.ops = &spi_fops;
if
(cdev_add(&spiCdev, devno, 1))
printk(KERN_NOTICE
"Error adding spi %d"
, 0);
s3c2440_clkcon = (
int
*)ioremap(0x4C00000c,3);
spi_gpgcon = (
int
*)ioremap (0x56000060,4);
spi_gpgdat = (
int
*)ioremap (0x56000064,2);
spi_gpgup = (
int
*)ioremap (0x56000068,2);
spi_gpfcon = (
int
*)ioremap (0x56000050,2);
spi_gpfdat = (
int
*)ioremap (0x56000054,1);
spi_gpfup = (
int
*)ioremap (0x56000058,1);
spi_spcon1 = (
int
*)ioremap(0x59000020,1);
spi_spsta1 = (
int
*)ioremap(0x59000024,1);
spi_sppin1 = (
int
*)ioremap(0x59000028,1);
spi_sppre1 = (
int
*)ioremap(0x5900002c,1);
spi_sptdat1 = (
int
*)ioremap(0x59000030,1);
spi_sprdat1 = (
int
*)ioremap(0x59000034,1);
printk(
"Init spi success!/n"
);
return
result;
}
static
void
__exit spi_exit(
void
)
{
cdev_del(&spiCdev);
unregister_chrdev_region(MKDEV(spi_major, 0), 1);
printk(
"<1>spi_exit!/n"
);
}
module_init(spi_init);
module_exit(spi_exit);
MODULE_LICENSE(
"GPL"
);
MODULE_AUTHOR(
"nkzc"
);
MODULE_DESCRIPTION(
"SPI driver for S3C2440"
);
几点需要注意的地方:
1.一开始在spi_exit()函数中使用了void unregister_chrdev(unsigned int major, const char *name)函数来注销设备,但再次insmod驱动的时候提示"Device or resource busy",改为unregister_chrdev_region()后一切正常,说明即使只注册了一个设备,register_chrdev_region()和unregister_chrdev_region()也要配套使用。
2.定义spi_spcon1等寄存器变量时前面要加上volatile关键字,这样每次访问该变量时cpu会从实际内存中读取该值而不是使用寄存器中的值。尤其是spi_spsta1变量,它的最低位代表了spi发送接收是否ready,如果没有volatile,可能会在readByte()或writeByte()函数中导致死循环。
3.使用了module_param()宏向驱动传递参数,这里定义了一个int型的loopChar参数,加载模块时使用insmod mini2440_spi.ko loopChar=123 来设置loopChar的值。
测试程序:spi_test.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int
main(
int
argc,
char
**argv)
{
int
fd;
int
count=0;
char
buf[]={0x11,0x22,0x33,0x44,0x55};
fd = open(
"/dev/mini2440_spi"
, O_RDWR);
if
(fd < 0) {
perror
(
"open device spi"
);
exit
(1);
}
count=write(fd,buf,
sizeof
(buf)/
sizeof
(buf[0]));
read(fd,buf,1);
printf
(
"read byte is: 0x%02X/n"
,buf[0]);
close(fd);
return
0;
}
很简单的一个程序,分别调用了open,write,read,close函数,可以观察输出结果,验证驱动程序是否正确,read的输出即为loopChar的值。
注意:open的时候要注意第二个参数flag,只有当flag为O_RDWR时,驱动中的相应的spi_read,spi_write函数才会被调用。
- S3C2440 spi驱动简单测试 (转)
- S3C2440 spi驱动简单测试
- S3C2440 spi驱动简单测试
- S3C2440 SPI驱动简单测试
- S3C2440 SPI驱动简单测试
- linux S3C2440 spi 驱动简单测试 (基于简单字符驱动)
- linux S3C2440 spi 驱动简单测试 (基于简单字符驱动)
- SPI驱动流程(S3C2440)
- linux-2.6.26下SPI1(3) S3C2440 spi驱动简单测试
- linux-2.6.26下SPI1(4) S3C2440 spi驱动简单测试
- 基于S3C2440的SPI驱动的开发和测试
- SPI设备驱动简单测试例子
- S3C2440 Linux驱动移植——SPI
- S3C2440驱动移植——SPI
- S3C2440驱动移植——SPI .
- s3c2440 spi驱动DMA模式
- s3c2440 spi驱动DMA模式
- S3C2440 Linux驱动移植——SPI
- 数据库异库操作(SQL2000)_数据库开发_web应用开发
- suse安装小小输入法
- nohup 研究
- 优秀的人必备的素质之一:细心
- 信息系统项目管理系列之四:项目可行性研究与评估
- S3C2440 spi驱动简单测试 (转)
- 小画面选择数据后传给父页面数据(2)
- 函数指针 与 类
- 数据库异库操作(SQL2000)_数据库开发_web应用开发
- 索引组织表(IOT)和堆组织表的性能对比测试
- 欧几里德算法和扩展欧几里德算法
- 大端与小端
- WPARAM 和 LPARAM,消息响应机制
- 我都做了些什么