精华内容
下载资源
问答
  • SPI接口

    2019-12-26 00:40:14
    SPI接口简介: 1.定义 SPI:串行外设接口(Serial Penpheral interface)——由摩托罗拉率先在其MC68HCXX系列处理器上定义。 2.特点 高速的、全双工、同步的通信总线 占用四根线 注解 全双工: ⇄发送接收是...

    SPI接口简介:

    1.定义

        SPI:串行外设接口(Serial Penpheral interface)——由摩托罗拉率先在其MC68HCXX系列处理器上定义。

    2.特点

    1. 高速的、全双工同步的通信总线
    2. 占用四根线
    • 注解
      • 全双工: ⇄  发送接收是独立的单元
      • 同步:信号在时钟的控制下来传输
      • 四根线:
        • 全双工:发送接收(2根)
        • 同步时钟信号:1根
        • 片选:1根
          • SPI接口在链接设备的时候通信口(全双工)、同步时钟信号口可以多设备共用
          • 每个SPI设备要单独接一个片选引脚,低电平工作,高电平挂起

    3.主要应用

         EEPROM、FLASH、实时时钟、AD转换器、数字信号处理器、数字信号解码器

    4.原理

         

    •  MISO(master input slave output)主设备数据输入,从设备数据输入
    •  MOSI(master output slave input)主设备数据输入,从设备数据输出
    •  SCLK时钟信号,由主设备产生
    •  CS从设备片选信号,由主设备控制

     

     
    展开全文
  • SPI 接口

    2017-07-19 15:52:22
    SPI 接口的全称是“Serial Peripheral Interface”意为串行外围接口,是 Motorola 首先在其 MC68HCxx 系列处理器上定义的。SPI 接口主要应用于 EEPROM、FLASH、实时时钟、AD转换器,还有数字信号处理器和数字信号...

    SPI 接口的全称是“Serial Peripheral Interface”意为串行外围接口,是 Motorola 首先在其 MC68HCxx 系列处理器上定义的。SPI 接口主要应用于 EEPROM、FLASH、实时时钟、AD转换器,还有数字信号处理器和数字信号解码器之间。
    SPI 接口是在 CPU 和外围低速器件之间进行同步串行数据传输,在主器件的位移脉冲下,数据按位传输,高位在前、低位在后,为全双工通信,数据传输速度总体来说比 I2C 总线要快。

    SPI 接口经常被称为 4 线串行总线,以主/从方式工作,数据传输过程由主机初始化,使用的 4 条信号线分别是:
    1. SCLK:串行时钟,用来同步数据传输,由主机输出。
    2. MOSI:主机输出从机输入数据线
    3. MISO:主机输入从机输出数据线
    4. CS:片选线、低电平有效由主机输出

    在 SPI 总线上,某一时刻可以出现多个从机,但只能有一个主机,主机通过片选线来确定要通信的主机,这就要求从机的 MISO 口具有三态状态,使得该线在器件未被选通时表现为高阻抗。
    在点对点的通信中,SPI 接口不需要进行寻址操作,且为全双工通信,显得简单高效,在多个从器件的系统中,每个从器件需要独立的使能信号,硬件上比 I2C 系统要稍微复杂一些。

    优点:
    1. 支持全双工操作
    2. 操作简单
    3. 数据传输速率较高
    缺点:
    1. 只支持单个主机(SPI 是单主设备通信协议,这意味着总线中只有一只中心设备能发起通信)
    2. 需占用主机较多的口线(每个从机都需要一根片选线)
    这里写图片描述

    展开全文
  • SPI接口详细介绍

    万次阅读 多人点赞 2018-10-16 20:02:45
    SPI = Serial Peripheral Interface,是串行外围设备接口,是一种高速,全双工,同步的通信总线。常规只占用四根线,节约了芯片管脚,PCB的布局省空间。现在越来越多的芯片集成了这种通信协议,常见的有EEPROM、...

    1. 概述

    SPI = Serial Peripheral Interface,是串行外围设备接口,是一种高速,全双工,同步的通信总线。常规只占用四根线,节约了芯片管脚,PCB的布局省空间。现在越来越多的芯片集成了这种通信协议,常见的有EEPROM、FLASH、AD转换器等。

    • 优点:

    支持全双工,push-pull的驱动性能相比open-drain信号完整性更好

    支持高速(100MHz以上);

    协议支持字长不限于8bits,可根据应用特点灵活选择消息字长;

    硬件连接简单;

    • 缺点:

    相比IIC多两根线;

    没有寻址机制,只能靠片选选择不同设备;

    没有从设备接受ACK,主设备对于发送成功与否不得而知;

    典型应用只支持单主控;

    相比RS232 RS485和CAN总线,SPI传输距离短;

     

    2. 硬件结构

    SPI总线定义两个及以上设备间的数据通信,提供时钟的设备为主设备Master,接收时钟的设备为从设备Slave;

    • 信号定义如下:

    SCK : Serial Clock 串行时钟

    MOSI : Master Output, Slave Input 主发从收信号

    MISO : Master Input, Slave Output 主收从发信号

    SS/CS : Slave Select 片选信号

    • 电路连接如下:

    单个主设备和单个从设备:

    单个主设备和多个从设备,通过多个片选信号或者菊花链方式实现:

    3. 寄存器类型

    Motorola定义的SPI寄存器包括:

    SPI Control Register 1 (SPICR1)    控制寄存器1

    SPI Control Register 2 (SPICR2)    控制寄存器2

    SPI Baud Rate Register (SPIBR)    波特率寄存器

    SPI Status Register (SPISR)            状态寄存器  (只读   其余均可读可写)

    SPI Data Register (SPIDR)              数据寄存器

    通过往寄存器中写入不同的值,设置SPI模块的不同属性。

     

    4. SPI传输模式

    通过设置控制寄存器SPICR1中的CPOLCPHA位,将SPI可以分成四种传输模式。

    CPOL,即Clock Polarity,决定时钟空闲时的电平为高或低。对于SPI数据传输格式没有显著影响。

    1 = 时钟低电平时有效,空闲时为高

    0 = 时钟高电平时有效,空闲时为低

    CPHA,即Clock Phase,定义SPI数据传输的两种基本模式。

    1 = 数据采样发生在时钟(SCK)偶数(2,4,6,...,16)边沿(包括上下边沿)

    0 = 数据采样发生在时钟(SCK)奇数(1,3,5,...,15)边沿(包括上下边沿)

     

    四种模式如下图所示:

    先看第一列两张图(CPHA = 0),采样发生在第一个时钟跳变沿,即数据采样发生在SCK奇数边沿;再看第二列(CPHA =1),采样发生在第二个时钟跳变沿,即数据采样发生在SCK偶数边沿

    第一行两张图,第二行两张图(CPOL = 1),SCK空闲状态为高电平。

    主从设备进行SPI通讯时,要确保它们的传输模式设置相同。

    其中mode0mode3最为常见,SPI接口的flash中均会有标注。

    5. 读写操作

    • 标准SPI读写为例

    片选---读指令---地址---数据读出

     

    片选---写指令---地址---数据写入

     

    • Dual I/O Fast Read Sequence Diagram  双路IO

    • Quad I/O Fast Read Sequence Diagram  四路IO

    与IIC一样,是一种最常见的板内芯片间的串行接口。

    欢迎加入硬件QQ群:1018083751,一起讨论硬件问题,分享调试心得,共同成长。

     

    展开全文
  • spi接口

    2012-04-21 22:55:34
    SPI接口四条线,一个时钟CLK,一个片选CE,以及两数据线MOSI和MISO(主出从入和主入从出)。由于这里的SPI时序等都已经由SPI控制器做好了,所以我要做的就是读些那些控制器上的寄存器来控制读些flash,这个控制器的...

        SPI接口四条线,一个时钟CLK,一个片选CE,以及两数据线MOSI和MISO(主出从入和主入从出)。由于这里的SPI时序等都已经由SPI控制器做好了,所以我要做的就是读些那些控制器上的寄存器来控制读些flash,这个控制器的型号我不知道,是intel,貌似有点类似ICH系列的, flash是SST25VF016B的。

    1、 SPI读Flash。

        i)往地址寄存器中写入addr。

        ii)设置好下一条执行命令,要读的数据个数,是否采用ACS(Atomic cycle Sequence,读书据时我没用这个,如设置它需设置好pre 命令),这些都可通过控制寄存器设置。

        iii)清调状态寄存器的CDS等标志,然后读取SCIP标志确认设备空闲后,将控制寄存器在ii)的基础上置SCG0标志,这样SPI控制器将会启动一个读flash的过程。

       iv)读取状态寄存器,确认读取过程后,从数据寄存器读取出数据。

    2、SPI写Flash。整个流程与1类似,只是在i)中加入往数据寄存器中写入要发的数据,在iii)中需启动acs使flash写使能。但需要注意的是由于flash的只可1变0,而不可直接0写变成1,在写之前一般要将flash相关区域擦除下,而且flash本身的写保护以及主控端的BIOS写保护都得关掉,具体可参看手册。

    3、整个驱动是字符类型的,遵循一般的linux字符驱动编写流程,只是配置信息是从PCI桥接设备的寄存器中读出的。

    4、说明。写flash要写擦flash,但写时,很难判断当前flash 是否已擦除,所以我把擦flash独立到了ioctl操作中,而写flash就只管写了,这也符合功能独立的原则。

    5、写驱动,如果对并发同步效率的要求不高的话,基本上就只剩下读写寄存器操作了。读写寄存器虽然机械,但一定要小心,因为寄存器之间是有耦合的,在操作某个寄存器时,一定也要检查相关的寄存器是否已正确设置,不要想当然。我当初就是忘了自己已经使能了BIOS写保护,而导致一个上午没写成功flash。

    6、驱动是细心活。建议先单元测试,再集成测试。一下子就来集成测试问题可能有一大堆,会打击信心的~

    最后贴上整个驱动的源码,没什么注释,大家将就下。相应的用户空间程序,见零一篇文章《读写SPI FLASH--应用程序部分》

    /*****************************spi.h*************************************/

    #ifndef _SPI_H_
    #define _SPI_H_

    #include <linux/cdev.h>
    #include <linux/types.h>

    #define DRIVERNAME "spi_char"
    #define MAJOR_NO 252
    #define MINOR_NO 0
    /* #define SPI_DEBUG */

    /* pci configuration */
    #define SPI_VENDOR_ID 0x8086
    #define SPI_DEVICE_ID 0x5031

    /* spi space */
    #define CRBA_BAR 0xF0
    #define BIOS_CTRL 0xDC
    #define SPI_BAR_OFFSET 0x3020
    #define SPI_MEM_SIZE 112
    #define SPI_FLASH_SIZE 2048*1024
    #define SPI_FLASH_SECTOR_BIT 12
    #define SPI_FLASH_SECTOR_SIZE 0x1000

    /* spi registers */
    #define SPI_STATUS 0x00
    #define SPI_CTRL 0x02
    #define SPI_ADDR 0x04
    #define SPI_DATA0 0x08
    #define SPI_OPTYPE 0x56
    #define SPI_OPMENU 0x58
    #define SPI_PREOP 0x54
    #define SPI_BBAR 0x50
    #define SPI_PBAR0 0x60


    /* spi opcode */
    #define SPI_WR_STATUS 0x01
    #define SPI_RD_STATUS 0x05
    #define SPI_WR_DATA 0x02
    #define SPI_RD_DATA 0x03
    #define SPI_WR_ENABLE 0x06
    #define SPI_WSR_ENABLE 0x50
    #define SPI_4K_ERASE 0x20
    #define SPI_WR_DISABLE 0x04
    #define SPI_CHIP_ERASE 0x60


    /* spi opcode type */
    #define SPI_OPTYPE_WIDTH 0x02
    #define SPI_RD_NOADDR 0x00
    #define SPI_WR_NOADDR 0x01
    #define SPI_RD_ADDR 0x02
    #define SPI_WR_ADDR 0x03


    /* bit definition */
    #define SPI_STATUS_SCIP  0x01
    #define SPI_STATUS_CDS 0x04
    #define SPI_STATUS_BAS 0x08
    #define SPI_STATUS_CFG_LOCK 0x8000

    #define SPI_CTRL_SCGO 0x02
    #define SPI_CTRL_ACS 0x04
    #define SPI_CTRL_SPOP 0x08
    #define SPI_CTRL_COP 0x70
    #define SPI_CTRL_COP_SHIFT 0x4
    #define SPI_CTRL_DC 0x4000
    #define SPI_CTRL_DBC 0x3f00
    #define SPI_CTRL_DBC_SHIFT 0x8

    #define SPI_CTRL_OPMENU_RD 0x00
    #define SPI_CTRL_OPMENU_RDSR 0x01
    #define SPI_CTRL_OPMENU_WR 0x02
    #define SPI_CTRL_OPMENU_WRSR 0x03
    #define SPI_CTRL_OPMENU_4KERASE 0x04
    #define SPI_CTRL_OPMENU_CHIPERASE 0x05

    #define SPI_FLASH_PROTECTION 0x3C
    #define BIOS_NOPROTECTION 0x01


    #define SPI_IOCTL_BASE 0xDE
    #define IOCTL_ERASE_CHIP _IOWR(SPI_IOCTL_BASE, 0, ioctl_arg_t)  
    #define IOCTL_ERASE_BLOCK _IOWR(SPI_IOCTL_BASE, 1, ioctl_arg_t)



    #define BUF_SIZE 512

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

      Description:
         This structure contains data that is used for most driver operations.

    *****************************************************************************/
    typedef struct _spi_char
    {
        dev_t dev;
        struct cdev cdev;
        uint32_t bios_ctrl_addr;
        void *mem_virt; /* base virtual address  */
        uint32_t mem_base;
        uint32_t mem_size;
        uint32_t mem_ready; /* ioremap successfully? */
        uint8_t iomem_ready;
        uint32_t fp; /* file pointer */
    } spi_char_t;

    typedef struct _ioctl_arg
    {
        uint32_t type;
        union
        {
            struct
            {
                uint32_t start;
                uint32_t end;
            }erase_range;
        }data;  
    }ioctl_arg_t;


    #ifdef SPI_DEBUG
    #define SPI_DBG(args...) printk(KERN_DEBUG "SPI: " args)
    #else
    #define SPI_DBG(args...)
    #endif

    #define SPI_ERR(args...) printk(KERN_ERR "SPI: " args)

    #endif /* _SPI_H_ */

    /*****************************spi.c*************************************/

    #include <linux/types.h>
    #include <linux/fs.h>
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/pci.h>
    #include <asm/uaccess.h>
    #include <linux/ioport.h>
    #include <linux/delay.h>
    #include <linux/ioctl.h>
    #include <linux/cdev.h>
    #include "spi.h"

    static spi_char_t spi_char;
    MODULE_LICENSE("Dual BSD/GPL");

    static uint8_t get_flash_status(void);
    static uint8_t set_flash_status(uint8_t value);

    static int  is_flash_protection(void);
    static int disable_flash_protection(void);
    static int is_bios_protection(void);
    static int disable_bios_protection(void);

    static int erase_4K_sector(unsigned int idx);
    static int erase_chip(void);
    static uint8_t read_byte(uint32_t addr);
    static int write_byte(uint32_t addr, uint8_t byte);


    /*****************************************************************************
      Description:
        This function is called when the driver is unloaded from memory.   

      Parameters:
        none

      Returns:
          none
    ******************************************************************************/
    void spi_cleanup(void)
    {
        //remove cdev struct from system
        cdev_del(&spi_char.cdev);

        //unregister driver module
        unregister_chrdev_region(spi_char.dev, 1);

        //release the reserved IO memory space
        if ( spi_char.mem_ready )
        {
              iounmap(spi_char.mem_virt);
        }
        if(spi_char.iomem_ready)
        {
             release_mem_region(spi_char.mem_base, SPI_MEM_SIZE);
        }

        SPI_DBG("%s:spi_cleanup-Driver unload complete/n", DRIVERNAME);
    }


    /*****************************************************************************
      Description:
        This function is called when the driver interface is opened    

      Parameters:
        none

      Returns:
          0 => success
        < 0 => error
    ******************************************************************************/
    int spi_open(struct inode *inode, struct file *filp)
    {
        SPI_DBG("%s:spi_open-module opened/n", DRIVERNAME);
        spi_char.fp = 0;
        SPI_DBG("spi_char.fp = %08x/n", spi_char.fp);
        return 0;
    }

    /*****************************************************************************
      Description:
        This function is called when the driver interface is closed   

      Parameters:
        none

      Returns:
          0 => success
        < 0 => error

    ******************************************************************************/
    int spi_release(struct inode *inode, struct file *filp)
    {
        spi_char.fp = 0;
        SPI_DBG("spi_char.fp = %08x/n", spi_char.fp);
        SPI_DBG("%s:spi_release-module released/n", DRIVERNAME);
        return 0;
    }



    int spi_read (struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
    {
        int i;
        uint32_t addr, val;
        uint16_t word;
        unsigned char data[BUF_SIZE];
        ssize_t retval = 0;
       
        /* print some information for debug */
        SPI_DBG("start spi_read/n");
        val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
        SPI_DBG("status=%08x/n", val);
        val = readw((void *)(spi_char.mem_virt+SPI_CTRL));
        SPI_DBG("ctrl=%08x/n", val);
        val = readw((void *)(spi_char.mem_virt+SPI_ADDR));
        SPI_DBG("addr=%08x/n", val);
        val = readl((void *)(spi_char.mem_virt+SPI_DATA0));
        SPI_DBG("data0.0=%08x/n", val);
        val = readl((void *)(spi_char.mem_virt+SPI_DATA0+4));
        SPI_DBG("data0.1=%08x/n", val);
       
        /* check count */
        if(count > BUF_SIZE)
        {
            count = BUF_SIZE;
        }
        if(spi_char.fp+count > SPI_FLASH_SIZE)
        {
            count = SPI_FLASH_SIZE-spi_char.fp;
        }
       
       
        SPI_DBG("spi_char.fp = %08x/n", spi_char.fp);
        addr = spi_char.fp;
        SPI_DBG("spi_read: addr = %08x/n", addr);
        for(i = 0; i < count; i++)
        {
            data[i] = read_byte(addr+i);
        }
       
        if(copy_to_user(buf, data, count))
        {
            SPI_ERR("spi_read::copty_to_user eror/n");
            return (-EFAULT);
        }
        spi_char.fp += count;
        SPI_DBG("leave spi_read, count=%d/n", count);
        
        return (count);
    }
      

    int spi_write (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
    {
        int i;
        uint32_t addr, val;
        uint16_t word;
        unsigned char data[BUF_SIZE];
        ssize_t retval = 0;
       
        /* print some information for debug */
        SPI_DBG("start spi_write/n");
        val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
        SPI_DBG("status=%08x/n", val);
        val = readw((void *)(spi_char.mem_virt+SPI_CTRL));
        SPI_DBG("ctrl=%08x/n", val);
        val = readw((void *)(spi_char.mem_virt+SPI_ADDR));
        SPI_DBG("addr=%08x/n", val);
        val = readl((void *)(spi_char.mem_virt+SPI_DATA0));
        SPI_DBG("data0.0=%08x/n", val);
        val = readl((void *)(spi_char.mem_virt+SPI_DATA0+4));
        SPI_DBG("data0.1=%08x/n", val);
        val = readl((void *)(spi_char.mem_virt+SPI_BBAR));
        SPI_DBG("BBAR=%08x/n", val);
        val = readl((void *)(spi_char.mem_virt+SPI_PBAR0));
        SPI_DBG("PBAR0=%08x/n", val);
      
        /* check count */
        if(count > BUF_SIZE)
        {
            count = BUF_SIZE;
        }
        if(spi_char.fp+count > SPI_FLASH_SIZE)
        {
            count = SPI_FLASH_SIZE-spi_char.fp;
        }
       
        if(copy_from_user(data, buf, count))
        {
             SPI_ERR("spi_read::copy_from_user error/n");
             return(-EFAULT);
        }
       
        /* disable flash protection */
        if(is_flash_protection())
        {
            if(!disable_flash_protection())
            {
                SPI_ERR("can't disable flash protection/n");
                return(-EFAULT);
            }
        }
       
        addr = spi_char.fp;
        for(i = 0; i < count; i++)
        {
            if(!write_byte(addr+i, data[i]))
            {
                SPI_ERR("spi_write error/n");
            }
            
             /* print some information for debug */
             val = readl((void *)(spi_char.mem_virt+SPI_DATA0));
             SPI_DBG("after write, data=%08x/n", val);
             val = readw((void *)(spi_char.mem_virt+SPI_CTRL));
             SPI_DBG("after write, ctrl=%08x/n", val);
             val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
             SPI_DBG("after write, status=%08x/n", val);
             word = readw((void *)(spi_char.mem_virt+SPI_STATUS));
             word |= SPI_STATUS_CDS;
             word |= SPI_STATUS_BAS;
             writew(word, (void *)(spi_char.mem_virt+SPI_STATUS));
             val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
             SPI_DBG("after write1, status=%08x/n", val);
        }
       
        spi_char.fp += count;
        SPI_DBG("leave spi_write, count=%d/n", count);
        return (count);
    }


    /*****************************************************************************
      Description:
        This function is the ioctl interface to the driver.   

      Parameters:
        inode  ptr to inode
        filp   ptr to file struct
        cmd    ioctl command
        arg    passed in argument

      Returns:
          0 => success
        < 0 => error
    ******************************************************************************/
    int spi_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                    unsigned long arg)
    {
        ioctl_arg_t info;
        unsigned int start, end;
        int i;
       
        switch(cmd)
        {
            case IOCTL_ERASE_CHIP:
                if( !erase_chip())
                {
                    return (-EFAULT);
                }
                break;
            
            case IOCTL_ERASE_BLOCK:
                if((void *)arg == NULL)
                {
                    return(-EINVAL);
                }
                //get the ioctl struct passed in by user
           if ( copy_from_user(&info, (ioctl_arg_t*)arg, sizeof(ioctl_arg_t)) )
           {
               SPI_ERR("%s:spi_ioctl::copy_from_user error./n", DRIVERNAME);
               return -EFAULT;
               }
               
                 /* sector & address index start from 0 */
                start = (info.data.erase_range.start) >> SPI_FLASH_SECTOR_BIT;
                end = (info.data.erase_range.end) >> SPI_FLASH_SECTOR_BIT;
                /* start = (info.data.erase_range.start + SPI_FLASH_SECTOR_SIZE -1) >> SPI_FLASH_SECTOR_BIT;
                end = (info.data.erase_range.end + SPI_FLASH_SECTOR_SIZE -1) >> SPI_FLASH_SECTOR_BIT;
                start--;
                end--; */
                if(start > end || start < 0 || end >= SPI_FLASH_SIZE/SPI_FLASH_SECTOR_SIZE)
                {
                    return (-EINVAL);
                }
              
                    SPI_DBG("start=%d,end=%d/n", start, end);               

                for(i = start; i <= end; i++)
                {
                    if(!erase_4K_sector(i))
                    {
                        return (-EFAULT);
                    }
                }
                break;
               
                default:
                    return (-EINVAL);
                        break;
        }
               
      
        return 0;
    }



    void EP80579_spi_init(uint32_t base)
    {
        uint8_t byte;
        uint16_t word;
        uint32_t dword,val;
        uint64_t qword;
        uint32_t addr;
           
        /* print some information for debug */
        val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
        SPI_DBG("status=%08x/n", val);
        val = readw((void *)(spi_char.mem_virt+SPI_CTRL));
        SPI_DBG("ctrl=%08x/n", val);
        val = readl((void *)(spi_char.mem_virt+SPI_ADDR));
        SPI_DBG("addr=%08x/n", val);
        val = readl((void *)(spi_char.mem_virt+SPI_DATA0));
        SPI_DBG("data0=%08x/n", val);
        val = readl((void *)(spi_char.mem_virt+SPI_BBAR));
        SPI_DBG("BBAR=%08x/n", val);
        val = readl((void *)(spi_char.mem_virt+SPI_PBAR0));
        SPI_DBG("PBAR0=%08x/n", val);

        /* enable configuration */
        addr = base + SPI_STATUS;
        word = readw((void *)addr);
        word &= ~SPI_STATUS_CFG_LOCK;
        writew(word, (void *)addr);
       
        /* fill opcode */
        addr = base + SPI_OPMENU;
        val = readl((void *)(spi_char.mem_virt+SPI_OPMENU));
        SPI_DBG("before init, SPI_OPMENU.0=%08x/n", val);
        val = readl((void *)(spi_char.mem_virt+SPI_OPMENU+4));
        SPI_DBG("before init, SPI_OPMENU.1=%08x/n", val);
        dword = SPI_RD_DATA + (SPI_RD_STATUS<<8) + (SPI_WR_DATA<<16) + (SPI_WR_STATUS<<24);
        writel(dword, (void *)addr);
        dword = (SPI_4K_ERASE)+(SPI_CHIP_ERASE<<8);
        writel(dword, (void *)(addr+4));
        val = readl((void *)(spi_char.mem_virt+SPI_OPMENU));
        SPI_DBG("after init, SPI_OPMENU.0=%08x/n", val);
        val = readl((void *)(spi_char.mem_virt+SPI_OPMENU+4));
        SPI_DBG("after init, SPI_OPMENU.1=%08x/n", val);
       
        /* fill opcode type */
        val = readw((void *)(spi_char.mem_virt+SPI_OPTYPE));
        SPI_DBG("before init, SPI_OPTTYPE=%08x/n", val);
        val &= 0x0000;
        val = val |SPI_RD_ADDR|(SPI_RD_NOADDR<<SPI_OPTYPE_WIDTH)|(SPI_WR_ADDR<<SPI_OPTYPE_WIDTH*2)
                  |(SPI_WR_NOADDR<<SPI_OPTYPE_WIDTH*3)|(SPI_WR_ADDR<<SPI_OPTYPE_WIDTH*4)|(SPI_WR_NOADDR<<SPI_OPTYPE_WIDTH*5);
        writew(val, (void *)(spi_char.mem_virt+SPI_OPTYPE));
        val = readw((void *)(spi_char.mem_virt+SPI_OPTYPE));/* check the status */
        SPI_DBG("after init, SPI_OPTTYPE=%08x/n", val);

       /* fill pre opcode */
        addr = base + SPI_PREOP;
        val = readw((void *)(spi_char.mem_virt+SPI_PREOP));
        SPI_DBG("before init, SPI_PREOOP=%08x/n", val);
        val = SPI_WR_ENABLE | (SPI_WSR_ENABLE << 8);
        writew(val, (void *)addr);
        val = readw((void *)(spi_char.mem_virt+SPI_PREOP));
        SPI_DBG("after init, SPI_PREOP=%08x/n", val);
      
       
        /* disable Atomic Cycle Sequence */
        val = readw((void *)(spi_char.mem_virt+SPI_CTRL));
        val &= ~SPI_CTRL_ACS;
        val &= ~SPI_CTRL_SPOP;
        writew(val, (void*)(spi_char.mem_virt+SPI_CTRL));
    }


    loff_t spi_lseek(struct file *filp, loff_t off, int whence)
    {
        loff_t newpos;
       
        switch (whence)
        {
            case 0: /* SEEK_SET */
                newpos = off;
                break;
            
            case 1: /* SEEK_CUR */
                newpos = spi_char.fp + off;
                break;
               
            case 2: /* SEEK_END */
                newpos = spi_char.fp + off;
                break;
            
             default: /* cant't happen */
                return (-EINVAL);
                break;
         }
        
         if(newpos < 0 || newpos >= SPI_FLASH_SIZE)
         {
            return (-EINVAL);
         }
        
         spi_char.fp = newpos;
         return (newpos);
    }

    // Linux file operations
    struct file_operations file_ops =
    {
        .owner =     THIS_MODULE,
        .read =      spi_read,
        .write =     spi_write,
        .llseek = spi_lseek,
         .open =        spi_open,
         .release =   spi_release,
         .ioctl    = spi_ioctl,
    };





    /*****************************************************************************
      Description:
        Entry point for the driver.   

      Parameters:
        none

      Returns:
          0 => success
        < 0 => error
    ******************************************************************************/
    int spi_init(void)
    {
        int ret;
        dev_t devno;
        struct pci_dev *pdev = NULL;
       
        spi_char.mem_base = 0;
        spi_char.mem_ready = 0;

        //request and reserve a device number
       /* ret = alloc_chrdev_region(&spi_char.dev, 0, 1, DRIVERNAME);

        if ( ret < 0)
        {
            SPI_ERR("%s:spi_init-Could not register module/n", DRIVERNAME);
            return ret;
        } */

        //init cdev struct for adding device to kernel
        cdev_init(&spi_char.cdev, &file_ops);
        spi_char.cdev.owner = THIS_MODULE;
        spi_char.cdev.ops = &file_ops;
        spi_char.mem_size = SPI_FLASH_SIZE;
         
        //devno = MKDEV(MAJOR(spi_char.dev), 0);
        devno = MKDEV(MAJOR_NO, MINOR_NO);
        SPI_DBG("major id:%d, minor id:%d/n", MAJOR(devno), MINOR(devno));
        if(cdev_add(&spi_char.cdev, devno, 1))
        {
            SPI_ERR("%s:spi_init-cdev_add failed/n", DRIVERNAME);
            goto Exit_Error;
        }
       

        //Get dev struct for the LPC device. The GPIO BAR is located in the
        //LPC device config space
        pdev = pci_get_device(SPI_VENDOR_ID, SPI_DEVICE_ID, NULL);
        if ( !pdev )
        {
            SPI_ERR("%s:spi_char_init-Could not find pci device/n", DRIVERNAME);
            goto Exit_Error;
        }
           
        //Get base address from the LPC configuration space.
        pci_read_config_dword(pdev, CRBA_BAR, &(spi_char.mem_base));
        SPI_DBG("base addr1 %08x/n", spi_char.mem_base);
        //Get BIOS Contrl address
        pci_read_config_byte(pdev, BIOS_CTRL, &(spi_char.bios_ctrl_addr));
        SPI_DBG("bios ctrl addr %08x/n", spi_char.bios_ctrl_addr);

        /* Get own base address */
        spi_char.mem_base &= 0xFFFFC000;
        SPI_DBG("base addr11 %08x/n", spi_char.mem_base);
        spi_char.mem_base += SPI_BAR_OFFSET;
        SPI_DBG("base addr21 %08x/n", spi_char.mem_base);

        //release reference to device
        pci_dev_put(pdev);


        //obtain memory space
        if ( !request_mem_region(spi_char.mem_base, SPI_MEM_SIZE, DRIVERNAME) )
        {
            spi_char.iomem_ready = 0;
            SPI_ERR("%s:spi_init-IO memory region has been reserved?/n", DRIVERNAME);
        }
        else
        {
            spi_char.iomem_ready = 1;
        }
        spi_char.mem_virt = ioremap(spi_char.mem_base, SPI_MEM_SIZE);
        SPI_DBG("virtual addr %08x/n", spi_char.mem_virt);
        //indicate memory space reserved
        spi_char.mem_ready = 1;
       
       
        //do some special initiation
        EP80579_spi_init(spi_char.mem_virt);
       

        goto Exit;

    Exit_Error:
        SPI_ERR("%s:spi_init-Initialization failed/n", DRIVERNAME);
        spi_cleanup();
        return -ENODEV;
       
    Exit:
        SPI_DBG("%s:spi_init-Initialization complete/n", DRIVERNAME);
        return 0;
    }

    module_init(spi_init);
    module_exit(spi_cleanup);



    static uint8_t get_flash_status(void)
    {
        uint32_t word, val;
        uint8_t ret;
       
         word = readw((void *)(spi_char.mem_virt+SPI_CTRL));
         word |= SPI_CTRL_SCGO; /* set cycle */
         word |= SPI_CTRL_ACS; /* Enable Atomic Cycle Sequence */
         word |= SPI_CTRL_SPOP;
         word &= ~SPI_CTRL_COP;    
         word = word | SPI_CTRL_OPMENU_RDSR<<SPI_CTRL_COP_SHIFT; /* read */
         word &= ~SPI_CTRL_DBC;    
         word = word | 0x00<<SPI_CTRL_DBC_SHIFT; /* read count=1 */
         word |= SPI_CTRL_DC;
        
          /* check the status */
         val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         while(val & SPI_STATUS_SCIP)
         {
                val = readw((void *)(spi_char.mem_virt+SPI_STATUS));/* check the status */
         }
            
         writew(word, (void *)(spi_char.mem_virt+SPI_CTRL));
            
         /* check the status */
         val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         while(val & SPI_STATUS_SCIP)
         {
            val = readw((void *)(spi_char.mem_virt+SPI_STATUS));/* check the status */
         }
           
         val = readl((void *)(spi_char.mem_virt+SPI_DATA0));
         SPI_DBG("get_flash_status:%08x/n", val);    
         ret = (val&0xFF);
        
         word = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         word |= SPI_STATUS_CDS; /* clear Cycle Done Status flag */
         word |= SPI_STATUS_BAS;  /* clear blocked flag */
         writew(word, (void *)(spi_char.mem_virt+SPI_STATUS));
            
         return (ret);
    }

    static uint8_t set_flash_status(uint8_t value)
    {
         uint32_t word, var, val;
       
         var = value;
         writel(var, (void *)(spi_char.mem_virt+SPI_DATA0));
         word = readw((void *)(spi_char.mem_virt+SPI_CTRL));
         word |= SPI_CTRL_SCGO; /* set cycle */
         word |= SPI_CTRL_ACS; /* Enable Atomic Cycle Sequence */
         word |= SPI_CTRL_SPOP;
         word &= ~SPI_CTRL_COP;    
         word = word | SPI_CTRL_OPMENU_WRSR<<SPI_CTRL_COP_SHIFT; /* read */
         word &= ~SPI_CTRL_DBC;    
         word = word | 0x00<<SPI_CTRL_DBC_SHIFT; /* write count=1 */
         word |= SPI_CTRL_DC;
        
          /* check the status */
         val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         while(val & SPI_STATUS_SCIP)
         {
                val = readw((void *)(spi_char.mem_virt+SPI_STATUS));/* check the status */
         }
            
         writew(word, (void *)(spi_char.mem_virt+SPI_CTRL));
            
         /* check the status */
         val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         while(val & SPI_STATUS_SCIP)
         {
            val = readw((void *)(spi_char.mem_virt+SPI_STATUS));/* check the status */
         }
         word = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         word |= SPI_STATUS_CDS; /* clear Cycle Done Status flag */
         word |= SPI_STATUS_BAS;  /* clear blocked flag */
         writew(word, (void *)(spi_char.mem_virt+SPI_STATUS));
        
         var = get_flash_status();
         return (var);
    }

    static int is_bios_protection(void)
    {
        unsigned int ret;
       
        ret = spi_char.bios_ctrl_addr & BIOS_NOPROTECTION;
       
        return (!ret);
    }

    static  int disable_bios_protection(void)
    {
        unsigned int temp;
        struct pci_dev *pdev = NULL;
       
        if(is_bios_protection())
        {
            temp = spi_char.bios_ctrl_addr | BIOS_NOPROTECTION;
            pdev = pci_get_device(SPI_VENDOR_ID, SPI_DEVICE_ID, NULL);
            if ( !pdev )
            {
                SPI_ERR("%s:spi_char_init-Could not find pci device/n", DRIVERNAME);
                return (0);
             }
            pci_write_config_byte(pdev, BIOS_CTRL, temp);
            spi_char.bios_ctrl_addr = temp;
        //release reference to device
        pci_dev_put(pdev);
        }
       
        return (1);
    }


    static int  is_flash_protection(void)
    {
        unsigned int var;
       
        var = get_flash_status();
        var &= SPI_FLASH_PROTECTION;
        if(var || is_bios_protection())
        {
            return (1);
        }
        return (0);
    }


    static int disable_flash_protection(void)
    {
        uint32_t word, var;
        uint8_t ret1, ret2;
       
        var = get_flash_status();
        var &= ~SPI_FLASH_PROTECTION;
        ret1 = set_flash_status(var);
       
        ret2 = disable_bios_protection();
       
        if(ret1 != var || !ret2)
        {
            return 0;
        }
       
        return (1);
    }


    static int write_byte(uint32_t addr, uint8_t byte)
    {
        uint32_t word, var, val;
       
        var = byte;
        writel(var, (void *)(spi_char.mem_virt+SPI_DATA0));
        writel(addr, (void*)(spi_char.mem_virt+SPI_ADDR));
        word = readw((void *)(spi_char.mem_virt+SPI_CTRL));
        word |= SPI_CTRL_SCGO; /* set cycle */
        word |= SPI_CTRL_ACS; /* Enable Atomic Cycle Sequence */
        word &= ~SPI_CTRL_SPOP;
        word &= ~SPI_CTRL_COP;    
        word = word | SPI_CTRL_OPMENU_WR<<SPI_CTRL_COP_SHIFT; /* write */
        word &= ~SPI_CTRL_DBC;    
        word = word | 0x00<<SPI_CTRL_DBC_SHIFT; /* write count=1 */
        word |= SPI_CTRL_DC;
        
         /* check the status */
         val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         while(val & SPI_STATUS_SCIP)
         {
                val = readw((void *)(spi_char.mem_virt+SPI_STATUS));/* check the status */
         }
            
         writew(word, (void *)(spi_char.mem_virt+SPI_CTRL));
            
         /* check the status */
         val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         while(val & SPI_STATUS_SCIP)
         {
            val = readw((void *)(spi_char.mem_virt+SPI_STATUS));/* check the status */
         }
        
         word = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         word |= SPI_STATUS_CDS; /* clear Cycle Done Status flag */
         word |= SPI_STATUS_BAS;  /* clear blocked flag */
         writew(word, (void *)(spi_char.mem_virt+SPI_STATUS));
        
        return (1);
    }


    static uint8_t read_byte(uint32_t addr)
    {
        uint32_t word, var, val;
        uint8_t ret;
       
         word = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         word |= SPI_STATUS_CDS; /* clear Cycle Done Status flag */
         word |= SPI_STATUS_BAS;  /* clear blocked flag */
         writew(word, (void *)(spi_char.mem_virt+SPI_STATUS));
        writel(addr, (void*)(spi_char.mem_virt+SPI_ADDR));
        word = readw((void *)(spi_char.mem_virt+SPI_CTRL));
        word |= SPI_CTRL_SCGO; /* set cycle */
        word &= ~SPI_CTRL_ACS; /* Diable Atomic Cycle Sequence */
        //word &= ~SPI_CTRL_SPOP;
        word &= ~SPI_CTRL_COP;    
        word = word | SPI_CTRL_OPMENU_RD<<SPI_CTRL_COP_SHIFT; /* read */
        word &= ~SPI_CTRL_DBC;    
        word = word | 0x00<<SPI_CTRL_DBC_SHIFT; /* read count=1 */
        word |= SPI_CTRL_DC;
        
         /* check the status */
          val = readw((void *)(spi_char.mem_virt+SPI_STATUS));/* check the status */
         while(val & SPI_STATUS_SCIP)
         {
              val = readw((void *)(spi_char.mem_virt+SPI_STATUS));/* check the status */
         }
            
         writew(word, (void *)(spi_char.mem_virt+SPI_CTRL));
         SPI_DBG("read_byte: ctrl=%08x/n", word);
            
         /* check the status */
         val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         while(val & SPI_STATUS_SCIP)
         {
            val = readw((void *)(spi_char.mem_virt+SPI_STATUS));/* check the status */
         }
         var = readl((void *)(spi_char.mem_virt+SPI_DATA0));
         SPI_DBG("read_byte: data=%08x", var);
         ret = var & 0xFF;
       
         word = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         word |= SPI_STATUS_CDS; /* clear Cycle Done Status flag */
         word |= SPI_STATUS_BAS;  /* clear blocked flag */
         writew(word, (void *)(spi_char.mem_virt+SPI_STATUS));
        
        return (ret);
    }

    static int erase_chip(void)
    {
         uint32_t word, var, val;
        
        /* disable flash protection */
        if(is_flash_protection())
        {
            if(!disable_flash_protection())
            {
                SPI_ERR("can't disable flash protection/n");
                return (0);
            }
            SPI_DBG("erase_chip is_flash_protection/n") ;
        }
      
        word = readw((void *)(spi_char.mem_virt+SPI_CTRL));
        word |= SPI_CTRL_SCGO; /* set cycle */
        word |= SPI_CTRL_ACS; /* Enable Atomic Cycle Sequence */
        word &= ~SPI_CTRL_SPOP;
        word &= ~SPI_CTRL_COP;    
        word = word | SPI_CTRL_OPMENU_CHIPERASE<<SPI_CTRL_COP_SHIFT; /* write */
        word &= ~SPI_CTRL_DBC;    
        word = word | 0x00<<SPI_CTRL_DBC_SHIFT; /* write count=1 */
        word &= ~SPI_CTRL_DC;
        
         /* check the status */
         val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         while(val & SPI_STATUS_SCIP)
         {
                val = readw((void *)(spi_char.mem_virt+SPI_STATUS));/* check the status */
         }
            
         writew(word, (void *)(spi_char.mem_virt+SPI_CTRL));
            
         /* check the status */
         val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         while(val & SPI_STATUS_SCIP)
         {
            val = readw((void *)(spi_char.mem_virt+SPI_STATUS));/* check the status */
         }
        
         word = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         word |= SPI_STATUS_CDS; /* clear Cycle Done Status flag */
         word |= SPI_STATUS_BAS;  /* clear blocked flag */
         writew(word, (void *)(spi_char.mem_virt+SPI_STATUS));
         SPI_DBG("erase_chip() end/n");
        
         return (1);
    }

    static int erase_4K_sector(unsigned int idx)
    {
        uint32_t addr;
        uint32_t word, var, val;
       
        if(((idx+1)<< SPI_FLASH_SECTOR_BIT) > SPI_FLASH_SIZE)
        {
            return (1);
        }
       
         /* disable flash protection */
        if(is_flash_protection())
        {
            if(!disable_flash_protection())
            {
                SPI_ERR("can't disable flash protection/n");
                return (0);
            }
        }
       
        addr = idx<<SPI_FLASH_SECTOR_BIT;
        writel(addr, (void*)(spi_char.mem_virt+SPI_ADDR));
        word = readw((void *)(spi_char.mem_virt+SPI_CTRL));
        word |= SPI_CTRL_SCGO; /* set cycle */
        word |= SPI_CTRL_ACS; /* Enable Atomic Cycle Sequence */
        word &= ~SPI_CTRL_SPOP;
        word &= ~SPI_CTRL_COP;    
        word = word | SPI_CTRL_OPMENU_4KERASE<<SPI_CTRL_COP_SHIFT; /* write */
        word &= ~SPI_CTRL_DBC;    
        word = word | 0x00<<SPI_CTRL_DBC_SHIFT; /* write count=1 */
        word &= ~SPI_CTRL_DC;
        
         /* check the status */
         val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         while(val & SPI_STATUS_SCIP)
         {
             val = readw((void *)(spi_char.mem_virt+SPI_STATUS));/* check the status */
         }
            
         writew(word, (void *)(spi_char.mem_virt+SPI_CTRL));
            
         /* check the status */
         val = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         while(val & SPI_STATUS_SCIP)
         {
            val = readw((void *)(spi_char.mem_virt+SPI_STATUS));/* check the status */
         }
        
         word = readw((void *)(spi_char.mem_virt+SPI_STATUS));
         word |= SPI_STATUS_CDS; /* clear Cycle Done Status flag */
         word |= SPI_STATUS_BAS;  /* clear blocked flag */
         writew(word, (void *)(spi_char.mem_virt+SPI_STATUS));

         SPI_DBG("spi_4kerase end/n");
        
        return (1);
    }

    展开全文
  • SPI接口

    2012-10-10 14:41:01
      【SPI总线的系统】 MOTOROLA公司的SPI总线的基本信号线为3根传输线 ,即SI、SO、SCK ...传输的速率由时钟信号SCK决定,SI为...采用SPI总线的系统如上图所示,它包含了一个主片和多个从片,主片通过发出片选...
  • AVR-SPI接口与NOKIA5110-显示器:项目包括SPI接口与NOKIA5110显示器
  • MSP430 SPI接口程序

    2021-01-28 14:30:21
    MSP430 SPI接口程序,芯片用MSP430F2xxx系列,硬件SPI. MSP430 SPI接口程序,芯片用MSP430F2xxx系列,硬件SPI.
  • 本文主要介绍SPI接口的一些基础知识,后续文章会用DAC芯片81416的配置为例来具体说明SPI接口的具体FPGA实现。 1.SPI基本结构 SPI的全称是Serial Peripheral 目录 1.SPI基本结构 Interface,直译过来就是串行...
  • 1.学习SPI的基本工作原理 2.通过实验加深对STM32SPI的理解 3. 利用STM32的SPI11和SPI接口的flash芯片进行通信,读写测试,并将测试结果用串口打印出来
  • SPI接口 HDL Verilog

    2019-01-20 15:21:29
    SPI接口verilog代码,自己编写的接口代码,主模块,已实验过可以读取spi flash的数据,可供参考
  • 摘要: 本文主要介绍STM32的SPI接口、cubeMX软件配置SPI接口和分析SPI相关代码。STM32之SPI简介:(1)SPI协议【Serial Peripheral Interface】 串行外围设备接口,是一种高速全双工的通信总线。主要用在MCU与...
  • SPI接口简介

    2019-07-31 10:58:28
    本文先简要说明SPI接口,然后介绍ADI公司支持SPI的模拟开关与多路转换器,以及它们如何帮助减少系统电路板设计中的数字GPIO数量。 SPI是一种同步、全双工、主从式接口。来自主机或从机的数据在时钟上升沿或下降沿...
  • spi接口简介

    2019-08-07 15:32:17
    本文先简要说明SPI接口,然后介绍ADI公司支持SPI的模拟开关与多路转换器,以及它们如何帮助减少系统电路板设计中的数字GPIO数量。 SPI是一种同步、全双工、主从式接口。来自主机或从机的数据在时钟上升沿或下降沿...
  • SPI接口arduino连接方式

    2018-10-18 17:38:22
    SPI接口arduino连接方式,压缩包的形式上传,分享欢迎交流
  • SPI接口屏幕

    千次阅读 2019-04-06 15:21:25
    在小分辨率(不高于qvga(320*240))的设备中,使用的是spi接口的屏幕,比如gc9306和st7789等。有两种类型的屏幕: 3线屏(3线1data或 3线2data),有接口1和接口2之分,接口1收发数据在一根数字线中,接口2收发两根线。 ...
  • 但是现有文献和设计多数仅实现了SPI接口的基本发送和接收功能,对SPI接口的时序控制没有进行深入的研究。全功能SPI接口应具有四种不同的时钟模式,以适应具有不同时序要求的从控制器。文中主要研究SPI接口的时钟时序...
  • FPGA实现SPI接口控制

    2019-12-14 22:44:14
    用FPGA实现SPI接口,可以实现8位、16位,速度可达100M以上,可以根据不同场景进行修改应用,相对来说比较方便。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,837
精华内容 3,934
关键字:

spi接口