本文目前先記錄一些關鍵詞,因為我還沒來得及整理,但相關的聯系很多,我怕忘了就先記下來。
起因
最近在做 MaixPy3 的開發中適配 Linux V831 的外設驅動接口,從 MCU 的思維去是希望直接在 Python 就可以使用 SPI 的驅動來調試外設。
現狀
截止(2021-01-28)提供的 Sipeed MaixII Dock (V831) 鏡像基於 linux 4.9 的版本,並在設備樹描述中還未提供 spidev 設備結點(/dev/spidev
所以根據原理圖補一下 spidev 的定義,然后通過 spidev_test 測試該設備,最后再通過 py-spidev 去訪問即可完成本功能。
Python 示例
使用 py-spidev 完成 SPI 接口的 Python 代碼。
import spidev
spi = spidev.SpiDev()
spi.open(bus, device)
to_send = [0x01, 0x02, 0x03]
spi.xfer(to_send)
- open(bus, device)
Connects to the specified SPI device, opening /dev/spidev
從 open 接口可以得知我們需要 linux 為它提供 /dev/spidev
這樣的好處就是任何 linux 設備過來都只需要提供相應的 SPI 設備即可,具體引腳定義已經被設備樹確定了。
所以我們現在要為 V831 添加 spidev 設備的定義。
加載 spidev 模塊(.ko)
先在 kernel_menuconfig 中選中 spidev.c 的驅動。
在 arch/arm/configs/xxx_defconfig中添加CONFIG_SPI_SPIDEV=y那么就會編譯drivers/spi/spidev.c文件,該文件的內容是注冊一個spidev驅動。該驅動是一個字符設備驅動。
make kernel_menuconfig
Device Drivers --->
SPI support --->
<*> User mode SPI device driver support
模塊本身沒有什么好說明的,加載上就行,補充一下可以參考的 spidev_test 測試用法。
在設備樹添加 spi 結點
如果沒有相應的設備樹定義,雖然可以加載 spidev.ko 模塊,但你是看不到類似 /dev/spidev1.0 的設備出現的。
那么怎么做呢?
由於每個芯片的設備樹都有些許出入,所以要先從原理圖下手,確定好引腳資源后,再從官方 bsp 的設備樹中提取設備的定義,再給其到綁定相應的驅動模塊。
首先 MaixII dock 的給用戶使用的 SPI 引腳定義如下圖。
所以我們確定這組引腳可以被定義為某一個 spi1 設備(假設的),也就是期望可以出現一個 /dev/spidev1.0 設備,如下圖。
先確定 V831 芯片的類型為 sun8iw19p1,所以找到源頭 lichee/linux-4.9/arch/arm/boot/dts/sun8iw19p1.dtsi 獲取關於芯片的定義,我們可以確保自己的定義不會與官方的有所出入,可以看到我提取了 spi1 的定義。
spi1: spi@05011000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "allwinner,sun8i-spi";
device_type = "spi1";
reg = <0x0 0x05011000 0x0 0x1000>;
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_pll_periph0>, <&clk_spi1>;
clock-frequency = <200000000>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&spi1_pins_a &spi1_pins_b>;
pinctrl-1 = <&spi1_pins_c>;
spi1_cs_number = <2>;
spi1_cs_bitmap = <3>;
status = "disabled";
};
然后這個定義要被修改到適合當前版型的硬件:
spi1_pins_a: spi1@0 {
allwinner,pins = "PH0", "PH1", "PH2";
allwinner,pname = "spi1_sclk", "spi1_mosi",
"spi1_miso";
allwinner,function = "spi1";
allwinner,muxsel = <4>;
allwinner,drive = <1>;
allwinner,pull = <0>;
};
spi1_pins_b: spi1@1 {
allwinner,pins = "PH3";
allwinner,pname = "spi1_cs0";
allwinner,function = "spi1";
allwinner,muxsel = <4>;
allwinner,drive = <1>;
allwinner,pull = <1>; // only CS should be pulled up
};
spi1_pins_c: spi1@2 {
allwinner,pins = "PH0", "PH1", "PH2", "PH3";
allwinner,function = "io_disabled";
allwinner,muxsel = <7>;
allwinner,drive = <1>;
allwinner,pull = <0>;
};
spi@05011000 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0x0 0x05011000 0x0 0x1000>;
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_pll_periph0>, <&clk_spi1>;
clock-frequency = <200000000>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&spi1_pins_a &spi1_pins_b>;
pinctrl-1 = <&spi1_pins_c>;
spi1_cs_number = <2>;
spi1_cs_bitmap = <3>;
status = "okay";
spi_board1 {
device_type = "spi_board1";
compatible = "spidev";
spi-max-frequency = <0x5f5e100>;
reg = <0x0>;
spi-rx-bus-width = <0x1>;
spi-tx-bus-width = <0x1>;
};
};
注意的地方有 spi1_pins_xxx 的引腳映射,這是與原理圖對應的,最后在這個結點添加一個 spi_board1 為 compatible = "spidev"; 這時系統就會自行加載 /dev/spidev1.0 設備了。
其中:
- spi_cs_bitmap,由於 SPI 控制器支持多個 CS,這一個參數表示 CS 的掩碼;
- spi_cs0、spi_sclk、spi_mosi 和 spi_miso 用於配置相應的 GPIO。
至於想要添加多個片選的設備定義我還沒測試和整理,這個問題留給之后有需要的時候再來補充。
感興趣的同學可以參考這幾篇,都是全志芯片系列的文檔。
測試 SPI 功能和最終效果
現在確保你系統已經有 /dev/spidevX.X 設備,然后准備一下 spidev_test -D /dev/spidevX.X 測試程序。
如果未短接 MOSI MISO 兩個引腳就會全為 0xFF (不要在這里跟我說原理圖引腳沒對好),如果短接了,就按 spidev_test 定義字符串進行數據的回環。
uint8_t default_tx[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF0, 0x0D,
};
root@sipeed:/# spidev_test -D /dev/spidev1.0
spi mode: 0x0
bits per word: 8
max speed: 500000 Hz (500 KHz)
RX | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................................
跳線帽短接一下。
現在結果如下:
root@sipeed:/# spidev_test -D /dev/spidev1.0
spi mode: 0x0
bits per word: 8
max speed: 500000 Hz (500 KHz)
RX | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................................
root@sipeed:/# spidev_test -D /dev/spidev1.0
spi mode: 0x0
bits per word: 8
max speed: 500000 Hz (500 KHz)
RX | FF FF FF FF FF FF 40 00 00 00 00 95 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 0D | ......@....�..................�.
root@sipeed:/#
現在內部測試完成,拿到邏輯分析儀來驗證一遍,因為這個時鍾有點不太確定,量一下具體的數據信號確認事實。
現在確定了數據符合預期,但時鍾為 400hz ,說明 spidev_test 測試時的時鍾是不對的,只是軟件上的主觀配置(最好多測幾種頻率,不過我還沒測)。
后記
本次記錄是怕自己關了所有窗口就什么都不剩而做的記錄。
2021年01月28日 junhuanchen