Chinaunix首页 | 论坛 | 博客
  • 博客访问: 489078
  • 博文数量: 130
  • 博客积分: 2111
  • 博客等级: 大尉
  • 技术积分: 1373
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-28 09:55
个人简介

IT民工

文章分类

全部博文(130)

文章存档

2021年(1)

2019年(1)

2017年(3)

2014年(1)

2013年(3)

2012年(2)

2011年(3)

2010年(2)

2009年(114)

分类: 嵌入式

2009-09-03 13:31:36

SPI驱动流程(S3C2440)
2007-12-27 22:50:25
简单的说就是写几个寄存器,其实非常简单的,呵呵
一、配置IO脚为SPI接口
        我用的是(s3c2440)SPI1通道,所有的IO都在GPG脚上,故配置的是GPGCON,
将对应的位置为SPI
             然后是GPGUP寄存器
二、开始SPI寄存器的配置
       1、SPPRE,设置传送频率,即SPICLK的频率
          SPI_CLK=PCLK/2/(SPPRE+1)
       根据S3C2440的资料,PCLK=48M,我要配置SPI_CLK为  1M,
       1=48/2/(SPPRE+1)=>  SPPRE=23=> SPPRE=0x18
    (个人理解,有错请指出,呵呵)
       2、SPCON 寄存器
          该寄存器有 7 位,对应的控制包括:SPIMOD(6:5),SCK enable (4),master/slave (3),CPOL(2),CPHA(1),TAGD(0).具体怎么设置根据自己的需要设置就OK。
       3、SPPIN 寄存器
        就三个寄存器,都设置好后就可以写和接收数据 啦
          写之前记得要检查SPSTA的 REDY位是否为 1 .
NOTE: 我的配置好IO之后,发现写SPCON寄存器无效,郁闷了两天终于找到原因,就CLKCON寄存器的SPI位没有
激活,所以写寄存器之前记得要检查CLKCON的状态

一点点经验,留个记号,呵呵
代码写的有点乱,测试的时候弄的,不好意思^_^
code :
/************************************************/
#ifndef MODULE
#define MODULE
#endif

#include
#include
#include
#include
#include

#include
/*----------  spi    ---------------*/
/*----------------- addr ----------  note  --------*/
#define GPG_CON   0x56000060     /* port G control */
#define GPG_DAT   0x56000064     /* port G data */
#define GPG_UP    0x56000068     /* pull up port G control */

#define SPCON_1   0x59000020    /*SPI1 control */
#define SPSTA_1   0x59000024    /* SPI1 status */
#define SPPIN_1      0x59000028    /* SPI1 pin control */
#define SPPRE_1   0X5900002C    /* spi1 baud rate prescaler */
#define SPTDAT_1  0x59000030    /* spi1 Tx data */
#define SPRDAT_1  0x59000034    /* spi1 Rx data */

                        /* GPGCON */
#define nSS1            (1<<6  | 1<<7)        /* GPG3 */
#define SPICLK1         (1<<14 | 1<<15)        /* GPG7 */
#define SPIMOSI1        (1<<12 | 1<<13)        /* GPG6 */
#define SPIMISO1        (1<<10 | 1<<11)        /* GPG5 */
#define SPI_USE         (nSS1 | SPICLK1 | SPIMOSI1 |SPIMISO1)


//static int  spi_major;
#define spi_name "S3C2440_SPI"
#define spi_minor       1

#ifdef CONFIG_DEVFS_FS
static devfs_handle_t devfs_spi_dir,devfs_spi_raw;
#endif



MODULE_LICENSE("GPL");

#if 1
#define     SPI_SPPRE1    (*(volatile unsigned long *)SPPRE1)    /* spi1 baud rate prescaler */   
#define     SPI_GPGCON      (*(volatile unsigned long *)GPGCON)     /* port-G control */
#define     SPI_SPCON1     (*(volatile unsigned long *)SPCON1)    /* spi1 control */
#define     SPI_SPSTA1     (*(volatile unsigned long *)SPSTA1)    /* spi1 status */
#define     SPI_SPPIN1     (*(volatile unsigned long *)SPPIN1)    /* spi1 pin control */
#define     SPI_SPTDAT1      (*(volatile unsigned long *)SPTDAT1)    /* spi1 Tx data */
#define     SPI_SPRDAT1      (*(volatile unsigned long *)SPRDAT1)    /* spi1 Rx data */
#define     SPTDAT1_READ    (*(volatile unsigned long *)SPTDAT1)     /* spi1 Tx data */
#define     SPI_GPGDAT    (*(volatile unsigned long *)GPGDAT)    /* port-G data */

#define     CLKCON        (*(volatile unsigned long *)ADDR_CLKCON)

#endif


unsigned long     GPGCON;
unsigned long    GPGDAT;
unsigned long     GPGUP;

unsigned long      SPCON1;
unsigned long      SPSTA1;
unsigned long     SPPIN1;
unsigned long     SPPRE1;
unsigned long    SPTDAT1;
unsigned long     SPRDAT1;
unsigned long   ADDR_CLKCON;
static void get_sys_addr(void)
{
    GPGCON =(unsigned long)ioremap(GPG_CON,4);
    GPGDAT =(unsigned long)ioremap(GPG_DAT,4);
    GPGUP  =(unsigned long)ioremap(GPG_UP,4);
    SPCON1 =(unsigned long)ioremap(SPCON_1,4);
    SPSTA1 =(unsigned long)ioremap(SPSTA_1,4);
    SPPIN1 =(unsigned long)ioremap(SPPIN_1,4);
    SPPRE1 =(unsigned long)ioremap(SPPRE_1,4);
    SPTDAT1=(unsigned long)ioremap(SPTDAT_1,4);
    SPRDAT1=(unsigned long)ioremap(SPRDAT_1,4);
    ADDR_CLKCON=(unsigned long )ioremap(0x4c00000c,4);
}
#if 1

static int spi_open(struct inode *inode,struct file *filp)
{
    unsigned int port_state;
     int i=0;
#if 1
/*===============  start init spi regiser ============*/
    /*  时钟使能  */
    printk("CLKCON: %x \n",(unsigned int )CLKCON);
    if (!(CLKCON&(1<<18)))
        CLKCON|=(1<<18);
    printk("CLKCON: %x \n",(unsigned int )CLKCON);
    /* 配置IO 脚为 SPI  */

    port_state = readl(GPGCON);  
    printk("<1>only read :port_state= %x \n",port_state);
    port_state &= ~SPI_USE;
    port_state |= SPI_USE;
/*    printk("<1>port_state= %x \n",port_state);   */
   
    SPI_GPGCON = port_state;  
//    writel(SPI_USE,GPGCON);
/*    printk("<1> after write :readl(GPGCON)= %x \n",SPI_GPGCON);  */
      /* IO 脚使能  */
    port_state=0x0;
    port_state = readl(GPGUP);   
/*    printk("<1> GPGUP before write: %x \n",port_state);    */
    port_state &=~(1<<3 | 1<<5 | 1<<6 | 1<<7);

    writel(port_state,GPGUP);   
/*    printk("<1>after write :GPGUP= %x \n",readl(GPGUP));    */
#endif

#if 1

    port_state = readl(SPPRE1);

//    writel(value,SPPRE1);    /* if PCLK=50MHz   PCLK/2/(value+1) =SPICLK  */
   
    SPI_SPPRE1=0x18;    /* set Baud rate 1M .get it in net.note: PCLE=48MHz ,SPICLK=48/2/(0x18+1)=1M  */
   
    /*  set spi module  */
/*    printk("<1>before write :readl(SPCON1)=%x \n",readl(SPCON1));     */

    port_state = readl(SPCON1);
    port_state &= ~0x03f;
    port_state |= (0<<0 | 0<<1 | 1<<2 | 1<<3 | 1<<4 | 0<<5 );
    /*  0<<0 normal mode , 0<<1 format A,1<<2 active low ,1<<3 master
     *  1<<4 SCK enable (master only), 0<<5   polling mode
      */       
//    writel(port_state,SPCON1);
    SPI_SPCON1=(0<<0 | 0<<1 | 1<<2 | 1<<3 | 1<<4 | 0<<5 );


    port_state = readl(SPPIN1);
    port_state &= ~(1<<0 | 1<<1 | 1<<2);
    port_state |= (0<<2 | 1<<1 | 0<<0);
    /* 0<<0:release  1<<1:SBO  0<<2:dis-ENMUL*/
//    writel(port_state,SPPIN1);
  
    SPI_SPPIN1=(0<<2 | 1<<1 | 0<<0);
    printk("<1>SPI_SPPIN1 = %x \n",(unsigned int )SPI_SPPIN1);
//    SPI_GPGDAT &= ~1<<3;
    printk("SPSTA1=%x \n",readl(SPSTA1));
/*==================  end init spiregister =========================*/
#if 0   // use for test spi wave ...

    while (1)
    {
//    printk("<1> readl(SPSTA1)&0X01: %x \n",readl(SPSTA1)&0x01);
    if (readl(SPSTA1)&0x01)
    {
    SPTDAT1_READ=0x1234;
//     writel(a,SPTDAT1);
//    SPI_SPTDAT1='a';
    }
    printk("<1>writel \n");
//    printk("<1>readl(SPRDAT1)=%x \n",readl(SPRDAT1));
    printk("<1> readl(SPTDAT1)=%s \n",readl(SPTDAT1));

    i++;
//    printk("<1>readl(SPRDAT1)=%c \n",readl(SPRDAT1));
//    printk("<1> readl(SPTDAT1)=%c \n",readl(SPTDAT1));
    }

#endif // test spi wave
#endif
//    writel(~(1<<4),SPCON1);// dis-SCK
//    printk("<1>is the OPEN   readl(GPGUP)=%x \n",readl(GPGUP));
    return 0;

}

static int spi_release(struct inode *inode,struct file *filp)
{
//    MOD_DEC_USE_COUNT;
    printk("<1> release \n");
    return 0;
}
#endif
#if 1
static ssize_t spi_write(struct file *filp,const char *buf,size_t count,loff_t *f_ops)
{
    int i=0;
//    int config;
    char string;
    char str[20];
    char *txStr,*rxStr;
    volatile char *spiTxStr,*spiRxStr;
    volatile int endSpiTx;
    unsigned int port_state=0;

    endSpiTx=0;
    spiTxStr="spi123456test";
    spiRxStr=str;
    txStr=(char *)spiTxStr;
    rxStr=(char *)spiRxStr;
    /*  Determine SPI clock rate.
 *  Baud rate = PCLK / 2 / (Prescaler value + 1)
 *  Baud rate < 25 M HZ
 *       */
#if 0 // init spi in open ()
    port_state = readl(SPPRE1);
    writel(0x18,SPPRE1);  /*  SPPRE1= 0x18 ,Baud rate = 1MHz */
   
    printk("<1> spi_write\n");
   
    /*  set spi module  */

    port_state = readl(SPCON1);
    port_state &= ~0x07f;
    port_state |= (0<<0 | 0<<1 | 1<<2 | 1<<3 | 1<<4 | 0<<5);
    /*  0<<0 normal mode , 0<<1 format A,1<<2 active low ,1<<3 master
      *  1<<4 SCK enable (master only), 0<<5 | 0<<6  polling mode
      */       
    writel(port_state,SPCON1);
    printk("<1>set SPCON1\n");
    /* SPI : master,nSS pin :multi-master error */
    port_state = readl(SPPIN1);
    port_state &= ~(1<<0 | 1<<1 | 1<<2);
    port_state |= (1<<2 | 0<<1 | 1<<0);
    /* 1<<0: Drive the previous level; 1<<2:Multi master error detect enable*/    writel(port_state,SPPIN1);
    printk("<1>set SPCON1 \n");
#endif // init spi in open()
    while (endSpiTx == 0)
    {
        printk("SPSTA1=%x \n",readl(SPSTA1));
        if((readl(SPSTA1) & 0X01) == 0)
        {
            if (*spiTxStr != '\0')
            {
                writel(*spiTxStr,SPTDAT1);
                string = readl(SPTDAT1);
                spiTxStr++;
            }
            else
            {
                endSpiTx=1;
            }   
            str[i]=readl(SPRDAT1);
            printk("receive char = %c \n",str[i]);
            i++;
        }
    }
    port_state = readl(SPCON1);
    port_state &= ~0x07f;
    port_state |= (0<<1 | 0<<1 | 1<<2 | 0<<4 | 0<<5 );
    writel(port_state,SPCON1);
    *(spiRxStr-1)='\0';
    printk("<1> Tx string : %s \n",txStr);
    printk("<1> Rx string : %s \n",rxStr);
    return 0;
}
#endif

static struct file_operations spi_fops ={
    .owner   = THIS_MODULE,
    .open     = spi_open,
    .release = spi_release,
    .write     = spi_write,
};

static struct miscdevice spi_dev=
{
    123,
    "spi",
    &spi_fops,
};

static int __init spi_init(void)
{
//    unsigned int value;
//    int ret;
    get_sys_addr();

    misc_register(&spi_dev);
#if 0
    ret = register_chrdev(0,spi_name,&spi_fops);
    if(ret<0)
    {
        printk("<1> cannot get major number \n");
        return ret;
    }
    spi_major=ret;
#ifdef CONFIG_DEVFS_FS
    devfs_spi_dir = devfs_mk_dir(NULL,"spi",NULL);
    devfs_spi_raw = devfs_register(devfs_spi_dir,"0",DEVFS_FL_DEFAULT,spi_major,spi_minor,S_IFCHR | S_IRUSR | S_IWUSR,&spi_fops,NULL);
#endif
#endif     
   
    printk(KERN_ALERT "hello,world \n");
    printk("<1> readl(SPTDAT1)=%x ,  SPTDAT1_READ = %x \n",readl(SPTDAT1),(unsigned int)SPTDAT1_READ);

    return 0;
}

static void __exit spi_exit(void)
{
#if 0
#ifdef CONFIG_DEVFS_FS
    devfs_unregister(devfs_spi_raw);
    devfs_unregister(devfs_spi_dir);
#endif
    unregister_chrdev(spi_major,spi_name);
#endif
    misc_deregister(&spi_dev);
    printk(KERN_ALERT "goodbye ,cruel world \n");
}

module_init(spi_init);
module_exit(spi_exit);
阅读(2970) | 评论(5) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-04-22 14:08:02

内容很丰富,真是帮了像我一样的初学者的大忙了,深表谢意!

xujinhui1972010-01-05 17:41:30

请问回环测试的时候,输入口与输出口是不是要接上? 还有,我用你的程序,只能读到输出寄存器的数据,输入的只能读到? 请问这是为什么啊?printk("receive char = %c \n",str[i]); receive char = ff 一直不能白,多谢谢你了, 能不能在你百忙之中给个回复我,万分感谢! 我的邮箱是xujinhui197@163.com

白石2009-12-19 23:05:27

路过,正在写这个驱动,不知道是否有用,先留个脚印,以示谢意。

chinaunix网友2009-11-17 17:46:10

我在写一个驱动和你这个很像,我也是用的1号口,你这个是做的回环测试吧。。我现在碰到一个问题,就是好像SCK一直都没有使能,设置了SPCON寄存器也不行。求高手帮忙~~~我QQ:412985113,求助~~~

chinaunix网友2009-11-17 15:06:27

你好。。能留个联系方式吗?想请教你一下SPI的问题。。