為 AW V831 配置 spidev 模塊,使用 py-spidev 進行用戶層的 SPI 通信。


本文目前先記錄一些關鍵詞,因為我還沒來得及整理,但相關的聯系很多,我怕忘了就先記下來。

起因

最近在做 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 . 設備進行 SPI 操作。

這樣的好處就是任何 linux 設備過來都只需要提供相應的 SPI 設備即可,具體引腳定義已經被設備樹確定了。

所以我們現在要為 V831 添加 spidev 設備的定義。

python中的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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM