• ATMEGA的SPI总线


    转自:

    1. https://www.yiboard.com/thread-782-1-1.html

    2.https://mansfield-devine.com/speculatrix/2018/01/avr-basics-spi-on-the-atmega-part-1/

    当AVR与其他器件进行数据交互时,我们需要选择采用哪种方式。这里可以使用UART、I2C等经典的串口方式,也可以选择串行外设接口(SPI)。我比较喜欢SPI总线方式。那么让我们来聊一聊这种总线形式。

    关系

    在SPI中的一个重要的概念就是主从关系。一个设备作为主机,负责产生时钟信号并启动每次通信。除了时钟之外,其他设备在很多方面都像主机一样操作,而且只有在被呼叫时才会回应。

    一般情况下,SPI总线至少由四条线组成 - 也就是说,它需要每个器件的四个引脚。 他们是:

    ●    MOSI:主机输出,从机输入 - 数据从主机传输到从机。

    ●    MISO:主机输入,从机输出 - 用于从从机到主机的数据传输。

    ●    SCK:时钟线,有时也被标记为CLK。

    ●    SS:从机选择 - 有时也被标记为片选(CS);这根线激活从机并启动通信。

    和其他总线不一样的是,SPI总线总是只有一根MOSI、一根MISO和一根SCK。但是该总线是设计用于连接多个设备。每个总线上只有一个主机设备(不同于提供多主设备模式的I2C)。但是你可以有多个从设备,每个都需要自己的SS线。

    这被认为是SPI的弱势之一,尤其是当您尝试使用GPIO数目较少的微控制器时。它至少需要将四个引脚连接在一个从机设备上,每个附加的从设备需要另一个引脚。但是,这种总线方式非常简单,通讯速度可以很快。

    专用硬件

    谈到GPIO引脚,可以使用任何GPIO引脚来实现一种“软件模拟串行”方式的SPI。事实上,在使用移位寄存器等设备时,我已经做到了这一点。但是,您需要负责切换时钟引脚,以产生必要的脉冲,并将数据移入或移出数据引脚。这并不难,但像AVR微控制器这样的设备已经内置了硬件来为您做所有这些。

    我使用ATMEGA328P进行实验,所以我将指出这一点,但所有这些都应该轻松转移到其他微控制器。我们来看看ATMEG328P的引脚分布。

    <ignore_js_op>

    在右下角你会看到四个粉红色的标签,表明引脚16-19是我们的SPI引脚。当然,它们也是普通的GPIO,但是当启用SPI功能时,它们承担SPI的角色,我们稍后会看到。通过使用这些引脚分配的目的,你需要在代码中做更少的工作。

    不同之处在于SS引脚。说实话,你用这个GPIO是非常随意的。即使启用SPI,您仍然必须将SS引脚设置为输出,并在适当的时刻将其切换为高电平或低电平。如果你想用另一个引脚,可以自己选择。如果你想要连接不止一个从设备,你必须使用其他的GPIO。

    转移数据

    在讨论如何使用SPI之前,让我们花点时间考虑它是如何工作的。

    您可以将每个器件(主器件和从器件)的SPI部分视为一个移位寄存器,在每个时钟脉冲中,一次输入一位和输出一位。

    当时钟滴答时,从主机的移位寄存器发送一位到从机上,其余位移位。从机的移位寄存器有足够的空间来接受这个位,因为在同一个时钟脉冲上,从机已经向主机发送了一位数据,并且也一起移动了。在八个时钟脉冲之后,两个器件已经交换了这些移位寄存器中的全部字节。

    这就是SPI的秘密:每当主机发送数据时,无论数据是否有意义(通常不是),它都会返回。事实上,有很多时候,主机只是想刺激从机放弃一些数据,而这是通过发送任何东西来实现的。它可以是全0或全1,这并不重要 - 这只是让从机发送任何已经准备好的移位寄存器的一种方式。

    启用S​​PI

    像微控制器上的许多事情一样,SPI通过巧妙地使用寄存器来控制。和往常一样,在AVR中,宏(通过avr / io.h)定义了寄存器和其中的位,所以我们可以简单地使用这些名称来处理接口。

    我们不会在这里详细介绍SPI,但是我们将看看能让您获得简单的SPI解决方案的关键要素。我们的重点在于使用AVR作为主设备。

    SPCR - SPI控制寄存器

    SPCR是建立SPI的关键寄存器。所有八位用于配置接口,它们是:

    7
    6
    5
    4
    3
    2
    1
    0
    SPIE
    SPE
    DORD
    MSTR
    CPOL
    CPHA
    SPR1
    SPR0

    根据数据表,当ATMEGA328P上电时,SPCR设置为0。个人而言,我并不介意花费一个或两个时钟周期,在我的SPI设置例程开始时,写到:

    1. 1SPCR = 0;
    复制代码

    那我们来看看这些位的含义:

    ●    SPIE - SPI中断使能。将其设置为1时,只要另一个寄存器中的另一个位(SPSR中的SPIF精确)被置位,就会触发SPI中断。

    ●    SPE - SPI启用。这是至关重要的,因为它有效地打开SPI并使这些引脚承担SPI的角色。

    ●    DORD - 数据顺序。这控制数据是首先发送最高有效位(MSB - 即第7位)还是最低有效位(LSB,第0位)。在默认状态(0)是MSB,这就是我喜欢它。如果您以此方式滚动或者从属设备期望它,则将此设置为1为Little-Endian。

    ●    CPOL、CPHA - 时钟极性和时钟相位。这些需要更多的解释,我们马上就会谈到。

    ●    SPR1、SPR0 - SPI时钟频率。它们与SPSR寄存器中的SPI2X位一起使用来设置时钟速度,从而设置数据移动的速率。这是一个与处理器的振荡器时钟频率(Fosc)相关的预分频器。

    相位和极性

    时钟极性和相位的设置取决于从机的工作方式和期望值。有四种模式:

    SPI模式
    条件
    前边沿
    后边沿
    0(0,0)
    CPOL = 0,CPHA = 0
    采样(上升沿)
    设置(下降沿)
    1(0,1)
    CPOL = 0,CPHA = 1
    设置(上升沿)
    采样(下降沿)
    2(1,0)
    CPOL = 1,CPHA = 0
    采样(下降沿)
    设置(上升沿)
    3(1,1)
    CPOL = 1,CPHA = 1
    设置(下降沿)
    采样(上升沿)

    您需要阅读从设备的数据表以了解其要求。例如,我最近搞砸了一个23LCV512的串行RAM芯片。其数据表说明如下:

    The device is accessed via the SI pin, with data being clocked in on the rising edge of SCK.

    数据在上升沿“锁存”(又称锁存或采样)意味着它必须是上表中的模式0或模式3。这取决于上升沿是被认为是“领先”还是“落后”。你怎么知道的?回到数据表。它应该显示时序图。这里是我们的RAM芯片的例子:

    <ignore_js_op>

    在输入版本中的所有内容开始之前,看看SCK线路是如何变低的?当SCK变高时,'MSB'发生。所以这里的上升沿也是领先的,这意味着我们想要模式0,在很多圈子里也被称为0,0。

    设置速度

    设置SPCR中的SPR0和SPR1位以及SPSR中的SPI2X位可将时钟频率设置为用于运行微控制器(Fosc)的振荡器的特定频率的一小部分。所以,如果你像我一样在16MHz下运行你的处理器,并且设置一个预分频值(比如16),那么SPI总线将以1MHz运行。预分频值越大,SPI总线越慢。

    你可能会认为你想尽可能快地走,但是你可能会遇到问题,特别是如果你的从机的电线很长。正如我在面包板上做了很多这样的事情,我倾向于使用第二个最慢的64位设置,推测我可以随时尝试提高速度。

    SPI2X
    SPR1
    SPR0
    SCK频率
    0
    0
    0
    Fosc / 4
    0
    0
    1
    Fosc / 16
    0
    1
    0
    Fosc / 64
    0
    1
    1
    Fosc / 128
    1
    0
    0
    Fosc / 2
    1
    0
    1
    Fosc / 8
    1
    1
    0
    Fosc / 32
    1
    1
    1
    Fosc / 64

    SPSR - SPI状态寄存器

    在这里我们只关心三个位,如果说实话,我主要关心的只有一个位。

    7
    6
    5
    4
    3
    2
    1
    0
    SPIF
    WCOL
    -
    -
    -
    -
    -
    SPI2X

    ●    SPIF - SPI中断标志。当数据传输和输入完成时自动设置。如果您已经使能了全局中断和SPCR中的SPIE位,则当该标志置位时将触发中断。处理该中断将自动清除该标志,就像读取SPI数据寄存器(SPDR)一样。所以大多数情况下,你只需要读取这个标志就可以了。

    ●    WCOL - 写入碰撞标志。

    ●    SPI2X - 时钟速度设置的一部分。

    准备设置

    在我们检查第三个寄存器之前,让我们来设置SPI。我将假定AVR将作为一个主机,我们不会搞乱中断,数据顺序将是MSB第一。我将要进行通讯的是串行RAM芯片,它的时钟极性(CPOL)为0,时钟相位(CPHA)为0。我将使用处理器速度的1/64作为总线的速度。

    让我们配置SPCR的八位。我将逐一浏览所有八位数据 - 即使是我没有使用的数据 - 你可以看到:

    1. SPCR = 0;                 // just to be sure
    2. // SPCR |= (1 << SPIE);   // not using interrupts, so leaving this at 0
    3. SPCR |= (1 << SPE);       // enable SPI
    4. // SPCR |= (1 << DORD);   // we want to keep the default MSB first, so not using this
    5. SPCR |= (1 << MSTR);      // set master mode
    6. // SPCR |= (1 << CPOL);   // leaving this set to 0
    7. // SPCR |= (1 << CPHA);   // leaving this set to 0
    8. SPCR |= (1 << SPR1);      // using a prescaler setting of 64 (1,0) in this register
    9. // SPCR |= (1 << SPR0);
    复制代码

    这样我们就准备好了。 在第2部分中,我们将开始使用SPI总线。

  • 相关阅读:
    golang/windows如何删除只读属性文件
    golang/TLS 采坑
    gsweb —— 理解HTTP协议
    gsweb —— 自己动手用golang写WEB框架
    Scala冒泡排序、快排、归并
    Hadoop自动化部署脚本
    大数据学习笔记
    vim键盘图
    什么是回调或高级函数?
    使用CSS表达式去除超链接的虚框的一些方法
  • 原文地址:https://www.cnblogs.com/MCSFX/p/10867770.html
Copyright © 2020-2023  润新知