zoukankan      html  css  js  c++  java
  • 【笔记】NIOS II spi详解

    NIOS II spi详解

    1、说明

    本文是依据笔者阅读《Embedded Peripherals (ver 9.0, Mar 2009, 4 MB).pdf》参考文档所作的个人理解,可以看做是笔记吧。

    本文只讲NIOS II嵌入式外设SPI的原理与使用,关于IP-CORE的使用,请读者参考   SPI Slave JTAG to Avalon Master.pdf》。

    在下一篇文章中将用实例说明如何用SPI驱动ADS1256

    2、功能描述

    Spi通讯包括两条数据线(进、出)、一条同步时钟线和一条控制线。

    1Master Out Slave In (mosi)—主设备输入数据到从设备的数据线。

    2Master In Slave Out (miso)—从设备输出数据到主设备的数据线。

    3Serial Clock (sclk)—主设备驱动从设备的同步时钟。

    4Slave Select (ss_n)—主设备驱动,用于选择从设备。置低时有效。最多可以设置32个从设备。

                     
                SclkAvalonMM是同步的。当配置为主设备,spi-coreAvalonMM的时钟分频得到sclk。若配置为从设备,接收逻辑是与sclk的输入同步的。

    3、发送逻辑

    发送逻辑包含发送保持寄存器(txdata)和发送移位寄存器,各有n位宽度,可配置1~32位。当某主外设写txdata,值会自动被复制到移位寄存器,并在下个操作开始时传输。

    Txdata和移位寄存器提供两个存储空间。当有数据在移位寄存器传输时,可以往txdata中写入数据,并且在移位寄存器处理完当前数据时会自动加载txdata中数据,并发送。

    在主设备模式传输移位寄存器直接驱动mosi,在从设备模式,传输移位寄存器直接驱动miso

    数据传输时,LSB或者MSB在前,由配置时用户指定。指定之后,不可软件更改。

    4、接收逻辑

    接收逻辑包含接收保持寄存器(rxdata)和接收移位寄存器,各有n位宽度,可配置1~16位。在接收移位寄存器捕获满n位数据后,主外设可以从rxdata中读取接收到的数据。

    同发送逻辑类似,接收逻辑同样具有提供两个存储空间的功能。Rxdata可以保持前一个接收到的数据,同时接收移位寄存器亦在接收数据。当一个传输完毕时,接收逻辑自动将接收移位寄存器的数据更新至rxdata

    在主设备模数时,接收移位寄存器直接受miso驱动。在从设备模式 ,受mosi驱动。同样,数据传输时,LSB或者MSB在前,由配置时用户指定。指定之后,不可软件更改。

    5、在SOPC中安装SPI-CORE

    5.1 主从设置

    用户可以选择主设备模式或者从设备模式。当选择主设备模式时,下面的选择是有效的:Number of select (SS_n) signalsSPI clock rate Specify delay.

    1Number of Select (SS_n) Signals

    设置从设备的个数。取值范围是1~32。该选择会在生成NIOS II时产生nSS_n引脚,用于片选。

     

    2SPI Clock (sclk) Rate

    该时钟是有Avalon-MM分频产生,其数学关系是:

    <Avalon-MM system clock frequency> / [2, 4, 6, 8, ...]

    SOPC设置时,可以输入所需要的时钟,软件会自动选择一个低于或者等于所输入时钟的最近符合值。

    时钟的设置注意结合从设备的要求。

    3Specify Delay

    该延时是指片选信号有效(置低)之后,需要多长的时间才能对从设备发起操作。

          

    5.2 数据寄存器设置

    该设置影响数据寄存器的大小和行为特性。

    1Width—设置txdatarxdata、发送移位寄存器、接收移位寄存器的大小,可设置为1~32位。

    2Shift direction指定数据传输时LSB或者MSB在前。用户需了解从设备所需的模式。

    5.3 时序设定

    该设定涉及ss_n, sclk, mosi miso 信号的设置。共有两处设定,可设定4种模式。

    1Clock polarity设置为0时,sclk空闲时为低;设置为1时,sclk空闲时为高。

    2Clock phase设置为0时,数据在sclk的上升沿锁存;设置为1时,数据在sclk的下降沿锁存。

    具体见如下时序图:

           1. Clock Polarity = 0, Clock Phase = 0



          2. Clock Polarity = 0, Clock Phase = 1

     
                            

                3. Clock Polarity = 1, Clock Phase = 0

                     
          
                 4. Clock Polarity = 1, Clock Phase = 1

            

    6NIOS II软件驱动模块

    有两种方式:

    1.              使用有Altera提供的alt_avalon_spi_command()函数,使用非常简单。具体可见笔者下一篇驱动实例。

    2.              读者自己编写。

    这里先将读者自己DIY的驱动编写方法。

    6.1 驱动方式一

    必须包含:

    #include "altera_avalon_spi.h"

    #include "altera_avalon_pio_regs.h"

    这两个头文件。

    文件中包含有寄存器地址与API函数。

    IOWR_ALTERA_AVALON_SPI_SLAVE_SEL();    //从设备选择

    IOWR_ALTERA_AVALON_SPI_CONTROL(base, data); //控制寄存器

    IORD_ALTERA_AVALON_SPI_RXDATA(base);                  //读接收寄存器

    IOWR_ALTERA_AVALON_SPI_TXDATA(base, data);       //写发送寄存器

    IORD_ALTERA_AVALON_SPI_STATUS(base);          //读状态寄存器

    为了准确实现方式,首先列出SPI寄存器映射图 

     

     (1)若rxdatatxdata少于16位,则[31:16]位无效;

    2)写status会清除ROETOEE位;

    3ss0只在作为主设备时有效;用来启动发送或者接受数据。例如:

    // Force SS_n active:
    na_spi_0-> np_spicontrol |= np_spicontrol_sso_mask;
    for (i = 0; i < 3++i)
    {
    // Transmit a byte:
    while (!(na_spi_0->np_spistatus & np_spistatus_trdy_mask));
    na_spi_0
    ->np_spitxdata = data[i];
    // Read and throw away the received data:
    while (!(na_spi_0->np_spistatus & np_spistatus_rrdy_mask));
    na_spi_0
    ->np_spirxdata;
    }
    // Wait until the last byte is transmitted:
    while (!(na_spi_0->np_spistatus & np_spistatus_tmt_mask));
    // Release SS_n:
    na_spi_0-> np_spicontrol &=~np_spicontrol_sso_mask;


        (4rxdata

             a)当接收寄存器接收到所设置的n位且将数据移入rxdata后,status中的RRDY设为1;软件可设查询此位来判断是否有新数据接收。如:

    while(IORD_ALTERA_AVALON_SPI_STATUS(base) & ALTERA_AVALON_SPI_STATUS_RRDY_MSK == 1);

                       b)读rxdata会自动清除RRDY位;

                       c)新数据总是不断读入rxdata,若RRDY=1; rxdata的数据未读出时,有新的数据传入rxdata,则ROE=1;此时,rxdata存储的数据未定义。

             5txdata

                       a)当TRDY=1时,表示发送寄存器准备好接受下一个发送数据。如:

    while(IORD_ALTERA_AVALON_SPI_STATUS(base) & ALTERA_AVALON_SPI_STATUS_TRDY_MSK == 1);

                       b)写入rxdata使TRDY=0;

                       c)当txdata中的数据传入发送寄存器时,TRDY=1;

                       d)若TRDY=0时写入数据至txdata会导致TOE=1;此时新数据被忽略。

    6.2驱动方式二

    该方式使用官方的函数:(下篇文章使用的是该方式。)

    int alt_avalon_spi_command(alt_u32 base, alt_u32 slave,

    alt_u32 write_length,

    const alt_u8* wdata,

    alt_u32 read_length,

    alt_u8* read_data,

    alt_u32 flags)

    该函数不支持8位或者8位以上的传输。但是,可以调用多次实现高于8位的传输。该函数源码位于“<安装路径>/altera/81/ip/altera/sopc_builder_ip/altera_avalon_spi/HAL/src”

    alt_u32 base, alt_u32 slave,   //选择从设备

    alt_u32 write_length, //设置写入长度。8位为一个长度。

    const alt_u8* wdata,                //将要写入数据的数组地址。该函数自动将数组中的数据依次发出直到发出所设定的write_length长度。

    alt_u32 read_length,                //设置读出长度。8位为一个长度

    alt_u8* read_data,                  //将读出的数据存储到数组中,直到存满所设定的read_length长度

    alt_u32 flags                        //如果flag=ALT_AVALON_SPI_COMMAND_MERGE,则访问完从设备之后不会释放从设备,一般用于需多次访问的情况。如果flag=0,则每次访问完从设备都会释放从设备,即当读取read_length个字节数,或者写完write_length个字节数,会释放从设备。

    7、总结

    笔者测试使用环境均为8.1版本。

    使用器件为CYCLONE II EP2C8Q208C8N

     

  • 相关阅读:
    BadUSB 利用
    java 将函数作为参数传递
    odoo12 修行提升篇之 常用的高阶函数 (二)
    odoo12 修行提升篇之 异步定时任务 (一)
    odoo12 修行基础篇之 利用kanban做分析 点击跳转分析模型列表 (九)
    odoo12 修行基础篇之 kanban (八)
    odoo12 修行基础篇之 记录批处理 (七)
    odoo12 修行基础篇之 列表的筛选和分组 (六)
    odoo12 修行基础篇之 添加记录编码 (五)
    odoo12 修行基础篇之 添加工作流和操作记录 (四)
  • 原文地址:https://www.cnblogs.com/oneseven/p/1543909.html
Copyright © 2011-2022 走看看