寫(xiě)在前面的話:由于外設(shè)I/O涉及到GPIO、PWM肥荔、和串行通信三部分绿渣,而串行通信有講了I2C(IIC)、SPI燕耿、UART中符,這樣導(dǎo)致本文的篇幅過(guò)長(zhǎng)不便于閱讀,特此將本文分成幾部分來(lái)方便閱讀
- Android Things 外設(shè)I/O-GPIO
- Android Things 外設(shè)I/O-PWM
- Android Things 外設(shè)I/O-I2C(IIC)
- Android Things 外設(shè)I/O-SPI
- Android Things 外設(shè)I/O-UART
串行通信
使用這些API在連接在同一本地總線上的兩個(gè)或多個(gè)智能設(shè)備之間傳輸更大的數(shù)據(jù)有效負(fù)載缸棵。 下表概述了每個(gè)支持的串行協(xié)議的基本屬性:
協(xié)議 | 傳輸類型 | 電線數(shù)量 | 外圍設(shè)備數(shù)量 | 傳輸速度 |
---|---|---|---|---|
I2C | 同步 | 2 | Up to 127 | Low |
SPI | 同步 | 4+ | Unlimited | High |
UART | 異步 | 2 or 4 | 1 | Medium |
SPI
串行外設(shè)接口(SPI)設(shè)備通常被發(fā)現(xiàn)在需要快速數(shù)據(jù)傳輸速率的地方舟茶。 SPI非常適合高帶寬使用情況,例如外部非易失性存儲(chǔ)器和圖形顯示器堵第。 除了I2C吧凉,許多傳感器器件還支持SPI。
??SPI是同步串行接口踏志,這意味著它依賴于共享時(shí)鐘信號(hào)來(lái)同步設(shè)備之間的數(shù)據(jù)傳輸阀捅。 主器件控制時(shí)鐘信號(hào)的觸發(fā),所有其他連接的外設(shè)稱為從器件针余。 每個(gè)設(shè)備連接到同一組數(shù)據(jù)信號(hào)以形成總線饲鄙。
??理論上,SPI的數(shù)據(jù)傳輸速率僅受主機(jī)切換時(shí)鐘信號(hào)的速度的限制圆雁。 時(shí)鐘速度通常在16MHz至25MHz范圍內(nèi)忍级。 該高速共享時(shí)鐘允許SPI外設(shè)比UART更快速地傳輸數(shù)據(jù)并且具有更少的錯(cuò)誤。
SPI支持全雙工數(shù)據(jù)傳輸伪朽,意味著主站和從站可以同時(shí)交換信息轴咱。 為了支持全雙工傳輸,總線必須提供以下單獨(dú)的信號(hào),這使SPI成為最小的4線接口:
- 主出從入(MOSI)
- 主入從出(MISO)
- 共享時(shí)鐘信號(hào)(CLK)
- 公共接地參考(GND)
SPI支持沿同一總線連接的多個(gè)從器件朴肺。 與I2C不同窖剑,從器件使用硬件尋址。 每個(gè)從設(shè)備需要外部芯片選擇信號(hào)戈稿,以允許主設(shè)備將該特定設(shè)備尋址為數(shù)據(jù)傳輸目標(biāo)西土。 如果只使用一個(gè)從機(jī),則不需要該信號(hào)鞍盗。
管理設(shè)備連接
為了打開(kāi)到特定SPI從器件的連接需了,您需要知道總線的唯一名稱。 在開(kāi)發(fā)的初始階段或?qū)?yīng)用程序移植到新硬件時(shí)橡疼,可以使用getSpiBusList()從PeripheralManagerService找到所有可用的設(shè)備名稱:
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);
}
支持多個(gè)硬件片選的SPI控制器將報(bào)告每個(gè)可用從端口作為單獨(dú)的設(shè)備名稱援所。 例如,在同一SPI總線上支持CS0欣除,CS1和CS2的電路板將返回類似于getSpiBusList()中的“SPI0.0”住拭,“SPI0.1”和“SPI0.2”的名稱。
??一旦知道目標(biāo)名稱历帚,就可以使用PeripheralManagerService連接到該設(shè)備滔岳。 與外圍設(shè)備通信后,記得關(guān)閉連接以釋放資源挽牢。 此外谱煤,在現(xiàn)有連接關(guān)閉之前,無(wú)法打開(kāi)與設(shè)備的新連接禽拔。 要關(guān)閉連接刘离,請(qǐng)使用設(shè)備的close()方法。
public class HomeActivity extends Activity {
// SPI 設(shè)備名稱
private static final String SPI_DEVICE_NAME = ...;
private SpiDevice mDevice;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 嘗試訪問(wèn)SPI設(shè)備
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);
}
}
}
}
配置時(shí)鐘和數(shù)據(jù)模式
在與SPI總線建立連接后睹栖,配置數(shù)據(jù)傳輸速率和操作模式以匹配同一總線上的從器件硫惕。 為了使數(shù)據(jù)傳輸成功,總線上的所有器件都必須具有相同的時(shí)鐘和數(shù)據(jù)格式行為野来。
注:有些從器件不能配置其SPI操作模式恼除,因此在選擇外設(shè)時(shí)請(qǐng)參考硬件文檔。
-
設(shè)置SPI模式曼氛,該模式定義時(shí)鐘信號(hào)的極性和相位豁辉。 您選擇的模式基于三個(gè)屬性:
空閑電平:當(dāng)沒(méi)有數(shù)據(jù)傳輸時(shí),時(shí)鐘信號(hào)的電平(低或高)舀患。
前沿:每個(gè)時(shí)鐘脈沖的前沿徽级。
-
后沿:在每個(gè)時(shí)鐘脈沖中與前沿相反的過(guò)渡。
支持以下模式:- MODE0 - 時(shí)鐘信號(hào)空閑聊浅,數(shù)據(jù)在前沿時(shí)鐘邊沿傳輸
- MODE1 - 時(shí)鐘信號(hào)空閑為低電平餐抢,數(shù)據(jù)在后沿時(shí)鐘邊沿傳輸
- MODE2 - 時(shí)鐘信號(hào)空閑堵幽,數(shù)據(jù)在前沿時(shí)鐘邊沿傳輸
- MODE3 - 時(shí)鐘信號(hào)空閑為高電平,數(shù)據(jù)在后沿時(shí)鐘邊沿傳輸
設(shè)置以下SpiDevice參數(shù):
- 頻率 - 指定以Hz為單位的共享時(shí)鐘信號(hào)弹澎。 時(shí)鐘信號(hào)能力因設(shè)備硬件而異。 在設(shè)置此值之前努咐,應(yīng)驗(yàn)證特定設(shè)備支持的頻率苦蒿。
- 對(duì)齊 - 指定每個(gè)字節(jié)中各個(gè)位在總線上傳輸時(shí)的順序。 這也稱為數(shù)據(jù)的字節(jié)順序渗稍。 默認(rèn)情況下佩迟,數(shù)據(jù)將首先使用最高有效位(MSB)發(fā)送。
- 每位字位 - 配置在切換給定從器件的片選線之間一次傳輸?shù)奈粩?shù)竿屹。 默認(rèn)值為每個(gè)字節(jié)8位报强。
以下代碼使用模式0,16MHz時(shí)鐘拱燃,每字8位和MSB優(yōu)先級(jí)配置SPI連接:
public void configureSpiDevice(SpiDevice device) throws IOException {
// 低時(shí)鐘秉溉,前沿傳輸
device.setMode(SpiDevice.MODE0);
device.setFrequency(16000000); // 16MHz
device.setBitsPerWord(8); // 8 BPW
device.setBitJustification(false); // MSB first
}
傳輸數(shù)據(jù)
SPI支持半雙工和全雙工數(shù)據(jù)傳輸。 大多數(shù)應(yīng)用程序應(yīng)該使用半雙工write()或read()方法與從設(shè)備交換數(shù)據(jù)碗誉。
// 半雙工數(shù)據(jù)傳輸
public void sendCommand(SpiDevice device, byte[] buffer) throws IOException {
// 將數(shù)據(jù)移出到從機(jī)
device.write(buffer, buffer.length);
// 閱讀響應(yīng)
byte[] response = new byte[32];
device.read(response, response.length);
...
}
要執(zhí)行全雙工交換召嘶,請(qǐng)改用transfer()方法。 此方法接受兩個(gè)緩沖區(qū)進(jìn)行讀取和寫(xiě)入哮缺。 寫(xiě)緩沖區(qū)包含要發(fā)送到從設(shè)備的數(shù)據(jù)弄跌,而讀緩沖區(qū)為空并接受來(lái)自從設(shè)備的數(shù)據(jù)。
數(shù)據(jù)長(zhǎng)度必須小于或等于最小緩沖區(qū)大小尝苇。 對(duì)于全雙工傳輸铛只,緩沖區(qū)大小是相等的。
// 全雙工數(shù)據(jù)傳輸
public void sendCommand(SpiDevice device, byte[] buffer) throws IOException {
byte[] response = new byte[buffer.length];
device.transfer(buffer, response, buffer.length);
...
}