SPI
通常会发现 串行外设接口(SPI)器件需要快速的数据传输速率。 SPI非常适合高带宽用例,如外部非易失性存储器和图形显示器。除了 I2C 之外,许多传感器器件都支持SPI。
SPI是同步 串行接口,这意味着它依赖于共享时钟信号来同步器件之间的数据传输。主器件控制时钟信号的触发,所有其他连接的外设称为从站器件。每个设备连接到同一组数据信号以形成总线。
理论上,SPI的数据传输速率仅受主机切换时钟信号的速度的限制。时钟速度通常在16MHz至25MHz范围内。这种高速共享时钟允许SPI外设更快速地传输数据,误码率比 UART 少。
SPI支持全双工 数据传输,意味着主机和从机可以同时交换信息。为了支持全双工传输,总线必须提供以下单独的信号,这使SPI成为最小的4-Wire接口:
- 主机 Out 从机 In (MOSI)
- 主机 In 从机 Out (MISO)
- 共享时钟信号(CLK)
- 公共接地参考(GND)
SPI支持沿同一总线连接的多个从设备。与 I2C 不同,从器件使用硬件进行寻址。每个从器件需要一个外部 芯片选择 信号,以允许主器件将该特定器件寻址作为数据传输目标。如果仅使用单个从器件,则不需要此信号。
管理设备连接
为了打开与特定SPI从站的连接,您需要知道总线的唯一名称。在开发初始阶段,或将应用程序移植到新硬件时,使用 getSpiBusList()
从 PeripheralManagerService
发现所有可用的设备名称:
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模式,定义时钟信号的极性和相位。您选择的模式基于三个属性:
支持以下模式:
MODE0
- 时钟信号空闲低,数据在前沿时钟边沿传输。MODE1
- 时钟信号空闲低,数据在后续时钟边沿传输MODE2
- 时钟信号空闲高,数据在前沿时钟边沿传输MODE3
- 时钟信号空闲高,数据在后续时钟边沿传输
设置以下 SpiDevice
参数:
以下代码配置模式0,16MHz时钟,每字8位,MSB的SPI连接:
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支持半双工和全双工数据传输。大多数应用程序应该使用半双工 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);
...
}