• 为 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

  • 相关阅读:
    英文句子相似性判断
    机器学习(一)特征工程基本流程
    经典卷积神经网络(LeNet、AlexNet、VGG、GoogleNet、ResNet)的实现(MXNet版本)
    Google免费GPU使用教程(亲测可用)
    XGBoost、LightGBM的详细对比介绍
    终身机器学习:一种可持续学习的范式
    机器学习中安全与隐私问题(对抗性攻击)
    频繁模式挖掘中Apriori、FP-Growth和Eclat算法的实现和对比(Python实现)
    Webpack教程,更新中
    @babel/plugin-transform-runtime
  • 原文地址:https://www.cnblogs.com/juwan/p/14341406.html
Copyright © 2020-2023  润新知