Android Things物联网开发--外围I/O接口之SPI(六)

SPI接口



SPI(Serial Peripheral Interface )是串行外设接口的缩写。SPI,是一种高速的,全双工,同步的通信总线,经常用于需要高速传输数据的设备。SPI非常适合高带宽的使用场景,比如外部非易失性存储器以及图形显示设备。很多传感器设备除了支持 I2C 之外还支持SPI。

SPI是一个同步串行接口,这意味着它依赖于一个共享时钟信号来同步设备间的数据传输。一个主设备控制时钟信号的触发,所有的连接上的设备都作为从设备。每个设备连接到同一组数据信号以形成总线。

理论上,SPI传输数据的速率仅仅受限于主设备能以多快的速率切换时钟信号。时钟速率的范围一般在16MHZ到25MHZ之间。这种高速时钟信号允许SPI外设更快的传输数据而且还比UART误码率少。
这里写图片描述

SPI支持全双工数据传输,这意味着主设备与从设备之间可以同时交换信息。为了支持全双工传输,总线必须提供如下单独的信号,这使得SPI最少有4根线缆接口:

  • Master Out Slave In (MOSI):主设备输出从设备输入
  • Master In Slave Out (MISO):主设备输入从设备输出
  • Shared clock signal (CLK):共享时钟信号
  • Common ground reference (GND):地线

SPI支持多个从设备连接到同一个总线。不像 I2C 设备需要使用硬件寻址。每个从设备需要一个额外的片选信号,以允许主设备寻址到该特定设备,并将该设备作为数据传输目标。如果仅使用单个从设备,则不需要此信号。

管理设备连接


为了打开一个到特定SPI从设备的连接,你需要知道总线的唯一的名字。在开发的前期阶段,后者移植一个app到一个新设备时,使用PeripheralManagerService getSpiBusList()方法获取所用可用的设备名是很有帮助的。

PeripheralManagerService manager = new PeripheralManagerService();
List<String> deviceList = manager.getSpiBusList();
if (deviceList.isEmpty()) {
    Log.i(TAG, "No SPI bus available on this device.");
} else {
    Log.i(TAG, "List of available devices: " + deviceList);
}

支持多个硬件片选信号的SPI控制器会将每个可用从设备端口报告为单独的设备名称。例如,一个主板上同一个SPI总线上的设备CS0,CS1以及CS2,使用getSpiBusList()方法会获取到类似”SPI0.0”, “SPI0.1”和 “SPI0.2” 的名称。

一旦你知道了目标设备的名称,使用PeripheralManagerService 来连接到该设备。当你完成与外设的通信后,要断开连接释放资源。另外,你不能在同一个设备连接关闭之前再次打开一个新的连接。使用 close() 方法来关闭连接:

public class HomeActivity extends Activity {
    // SPI Device Name
    private static final String SPI_DEVICE_NAME = ...;

    private SpiDevice mDevice;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Attempt to access the SPI device
        try {
            PeripheralManagerService manager = new PeripheralManagerService();
            mDevice = manager.openSpiDevice(SPI_DEVICE_NAME);
        } catch (IOException e) {
             Log.w(TAG, "Unable to access SPI device", e);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (mDevice != null) {
            try {
                mDevice.close();
                mDevice = null;
            } catch (IOException e) {
                Log.w(TAG, "Unable to close SPI device", e);
            }
        }
    }
}

配置时钟和数据模式


当在SPI总线上建立一个连接以后,配置数据传输速率和操作模式来匹配同一个总线上的从设备。要是数据传输成功,总线上的所有设备必须具有相同的时钟和数据传输格式。

注意:一些从设备无法配置他们的SPI操作模式,所以当你选择外设时要查看文档。

  1. 设置SPI模式,模式定义了时钟信号的极性和相位。你选择的模式基于三个属性:
    这里写图片描述

    1. Idle Level:当没有数据传输时,时钟信号的电平(低或高)
    2. Leading Edge:每个时钟脉冲的前沿。
    3. Trailing Edge:每个时钟脉冲与前沿相反的转换。
      支持下面的模式:

      • MODE0–空闲状态时钟信号为低电平,数据在Leading Edge时传输。
      • MODE1–空闲状态时钟信号为低电平,数据在Trailing Edge时传输。
      • MODE0–空闲状态时钟信号为高电平,数据在Leading Edge时传输。
      • MODE0–空闲状态时钟信号为高电平,数据在Leading Edge时传输。
  2. 设置如下SPI设备参数:

    • Frequency (频率)–指定共享时钟信号的频率,单位为HZ。时钟信号功能在不同的设备硬件上有所不同。在设置这个值之前你应该确认你的特定设备支持的频率。
    • Justification (对齐)–指定每个字节中通过总线传输的各个位的顺序。这也被称为字节顺序。默认的,数据将最先发送最高有效位。
    • Bits per Word(一个字对应的位数)–默认一个字为8位。

下面的代码配置了SPI连接的模式为 MODE0,16MHZ时钟,一个字8位,并且是先传输最高有效位。

public void configureSpiDevice(SpiDevice device) throws IOException {
    // Low clock, leading edge transfer
    device.setMode(SpiDevice.MODE0);

    device.setFrequency(16000000);     // 16MHz
    device.setBitsPerWord(8);          // 8 BPW
    device.setBitJustification(false); // MSB first
}

传输数据


SPI支持半双工和全双工数据传输。大多数app应该使用半双工write()或者read()方法来与一个从设备交互数据。

// Half-duplex data transfer
public void sendCommand(SpiDevice device, byte[] buffer) throws IOException {
    // Shift data out to slave
    device.write(buffer, buffer.length);

    // Read the response
    byte[] response = new byte[32];
    device.read(response, response.length);
    ...
}

要执行全双工交互,使用transfer()方法来代替。这个方法接收两个缓冲区来读和写。写缓存包含了要发送给从设备的信息,当读缓冲空时,接收从设备的数据。

数据长度必须小于或等于最小缓冲大小。通常全双工传输缓冲区大小相等。

// Full-duplex data transfer
public void sendCommand(SpiDevice device, byte[] buffer) throws IOException {
    byte[] response = new byte[buffer.length];
    device.transfer(buffer, response, buffer.length);
    ...
}

没有更多推荐了,返回首页