RISCV_SPI使用参考


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 11/14/2022

    1. 概述

    1.1. 概述

    SPI是一个同步串行接口,可以连接各种外部设备。硬件组如下表:

    MSPI Bus bank addr cs_num
    0 1110H 2
    1 1111H 2

    1.2. 功能支持

    1. mspi只能作为master device,不能作为slave device。

    2. 支持Motorola SPI兼容时序(CPHA / CPOL)。

    3. MSPI(Master SPI)在FIFO mode下支持全双工读写,也支持半双工读写;DMA模式只能在半双工读写的时候使用。使用DMA模式,需要先在sysDesc节点中先设定DMA enable。

      另外,在开启DMA使能的情况下,也可以使用全双工。驱动中,分辨使用全双工和半双工,是通过通讯调用时传下去的*tx_buf*rx_buf指针是否为0来判断的,当DMA enable,且*rx_buf*tx_buf有1个为0,此时的半双工通讯会启用DMA;而当*rx_buf*tx_buf都不为0时,哪怕我们预先设定了DMA enable,此时驱动也会自动判定走全双工模式。

    4. 支持三线模式,即3-wire mode。

    5. 8字节读写缓冲区(FIFO mode);字节传输1bit到15bit可配置位宽度。

    6. 通讯频率满足从50K-72MHz,分档,根据要求设定的频率选择比它小的最大值设定。设定方法为通过调用参数的struct spi_ioc_transfer当中的speed_hz变量修改设定,可参考用户态读写章节。分档如下:

      档位 频率(Hz)
      1 46875
      2 93750
      3 187500
      4 210937
      5 375000
      6 406250
      7 421875
      8 562500
      9 750000
      10 812500
      11 843750
      12 1125000
      13 1500000
      14 1625000
      15 1687500
      16 2250000
      17 3000000
      18 3250000
      19 3375000
      20 4500000
      21 6000000
      22 6500000
      23 6750000
      24 9000000
      25 13000000
      26 13500000
      27 18000000
      28 26000000
      29 27000000
      30 36000000
      31 52000000
      32 54000000
      33 72000000
    7. 硬件预设多片选设定,mspi0预设2路cs,mspi1预设2路。driver当中提供额外cs扩展,需要从dtsi当中添加,详细方法见cs-ext章节。


    1.3. driver

    sc/driver/sysdriver/mspi/drv/src/drv_mspi.c

    sc/driver/sysdriver/mspi/hal/pioneer5/src/hal_mspi.c

    sc/driver/sysdriver/mspi/hal/pioneer5/inc/hal_mspi.h

    sc/driver/sysdriver/mspi/hal/pioneer5/inc/hal_mspireg.h

    sc/driver/sysdriver/mspi/hal/pioneer5/inc/hal_mspi_cfg.h

    sc/driver/sysdriver/mspi/os/mspi_os.h

    1.4. public file

    sc/driver/sysdriver/mspi/drv/pub/drv_mspi.h

    1.5. demo

    sc/driver/sysdriver/mspi/drv/src/drv_mspi_test.c


    2. 功能使用与配置

    2.1. 引脚复用关系

    2.1.1. padmux与pad对应关系

    MSPI Bus Register addr Padmod Pad Pin Name
    0 bank 103CH offset 68H bit[1:0] 1 PAD_SD0_D1 SPI0_CZ
    PAD_SD0_D0 SPI0_CK
    PAD_SD0_CLK SPI0_DI
    PAD_SD_CMD SPI0_DO
    2 PAD_SAR_ADC20 SPI0_CZ
    PAD_SAR_ADC21 SPI0_CK
    PAD_SAR_ADC22 SPI0_DI
    PAD_SAR_ADC23 SPI0_DO
    3 PAD_OUTN_TX0_CH_4 SPI0_CZ
    PAD_OUTP_TX1_CH_0 SPI0_CK
    PAD_OUTN_TX1_CH_0 SPI0_DI
    PAD_OUTP_TX1_CH_1 SPI0_DO
    bank 103CH offset 70H bit[5:4] mspi0 cz1 mode 1 PAD_SD0_CDZ SPI0_CZ1
    mspi0 cz1 mode 2 PAD_SAR_ADC_19 SPI0_CZ1
    mspi0 cz1 mode 3 PAD_OUTP_TX0_CH_4 SPI0_CZ1
    1 bank 103CH offset 68H bit[5:3] 1 PAD_SAR_ADC_4 SPI1_CZ
    PAD_SAR_ADC_5 SPI1_CK
    PAD_SAR_ADC_6 SPI1_DI
    PAD_SAR_ADC_7 SPI1_DO
    2 PAD_RGMII0_RXD2 SPI1_CZ
    PAD_RGMII0_RXD3 SPI1_CK
    PAD_RGMII0_TXD2 SPI1_DI
    PAD_RGMII0_TXD3 SPI1_DO
    3 PAD_EMMC_D4 SPI1_CZ
    PAD_EMMC_D5 SPI1_CK
    PAD_EMMC_D6 SPI1_DI
    PAD_EMMC_D7 SPI1_DO
    4 PAD_SAR_ADC_10 SPI1_CZ
    PAD_SAR_ADC_11 SPI1_CK
    PAD_SAR_ADC_12 SPI1_DI
    PAD_SAR_ADC_13 SPI1_DO
    bank 103CH offset 68 bit[7:6] mspi1 cz1 mode 1 PAD_RGMII0_TXCLK SPI1_CZ1
    mspi1 cz1 mode 2 PAD_EMMC_DS SPI1_CZ1

    2.1.2. 使用方式

    注意:当确定某一路mspi要在RISCV下使用时,linux kernel下对应的dtsi中的设备节点,status状态应为disabled,同时xxx-padmux.dtsi当中也不应该再对这路mspi配置padmux。

    RISCV mspi driver中,对于mspi的padmux,共有三种配置方法,三种情况只会使用一种,当前默认使用sysDesc配置方法。三种如下:

    1. sysDesc配置

      配置文件在 sc/driver/sysdriver/sysdesc/hal/pioneer5/pub/pioneer5-default.sys

      在.sys文件的[padmux]节点中,添加或修改对应padmux,例如要使用mspi0 padmod1,则添加如下修改,宏定义的参考文件在:

      sc\driver\sysdriver\gpio\hal\pioneer5\pub\gpio.h

      sc\driver\sysdriver\gpio\hal\pioneer5\pub\padmux.h

      sc\driver\sysdriver\padmux\drv\pub\mdrv_puse.h

      1. `padmux`
      2.     [schematic_u32_u32_u32]
      3.     PAD_PM_GPIO0 PINMUX_FOR_PM_UART1_MODE_1 MDRV_PUSE_PM_UART_RX,
      4.     PAD_PM_GPIO1 PINMUX_FOR_PM_UART1_MODE_1 MDRV_PUSE_PM_UART_TX,
      5.     PAD_SD0_D1   PINMUX_FOR_SPI0_MODE_1      MDRV_PUSE_SPI0_CZ,
      6.     PAD_SD0_D0   PINMUX_FOR_SPI0_MODE_1      MDRV_PUSE_SPI0_CK,
      7.     PAD_SD0_CLK  PINMUX_FOR_SPI0_MODE_1      MDRV_PUSE_SPI0_DI,
      8.     PAD_SD0_CMD  PINMUX_FOR_SPI0_MODE_1      MDRV_PUSE_SPI0_DO;
      9.     [status_u8] 1;
      
    2. padmux driver文件中配置

      配置文件在 sc/driver/sysdriver/padmux/hal/pioneer5/src/pioneer5-riscv-padmux.c

      在文件的结构体数组变量schematic当中,依照格式添加对应的pad id、mode、puse

      10. typedef struct
      11. {
      12.     U32         u32PadId;
      13.     U32         u32Mode;
      14.     U32         u32Puse;
      15. }
      16.
      17. pad_info_t schematic[] =
      18. {
      19.     {PAD_SAR_ADC_20,    PINMUX_FOR_SPI0_MODE_2,    MDRV_PUSE_SPI0_CZ},
      20.     {PAD_SAR_ADC_21,    PINMUX_FOR_SPI0_MODE_2,    MDRV_PUSE_SPI0_CK},
      21.     {PAD_SAR_ADC_22,    PINMUX_FOR_SPI0_MODE_2,    MDRV_PUSE_SPI0_DI},
      22.     {PAD_SAR_ADC_23,    PINMUX_FOR_SPI0_MODE_2,    MDRV_PUSE_SPI0_DO},
      23. }
      
    3. mspi_cfg配置

      配置文件在 sc/driver/sysdriver/mspi/hal/pioneer5/inc/hal_mspi_cfg.h

      在如下结构体数组的对应元素的padmod项修改所需的padmode

      24. struct mspi_cfg_t mspi_cfg[] =
      25. {
      26.     // mspi0
      27.     [0] =
      28.     {
      29.      ……
      30. #ifndef CONFIG_PADMUX_SUPPORT
      31. #ifdef CONFIG_GPIO_SUPPORT
      32.         .padmod = PINMUX_FOR_SPI0_MODE_2,
      33. #else
      34.         .padmod = 2,
      35. #endif
      36. #endif
      37.       ……
      38. }
      

    2.2. sysDesc节点说明

    1. <mspi0>
    2. [reg_u32_u16] 0x2222000 0x200;
    3. [interrupts_u8] INT_IRQ_MSPI_0;
    4. [camclk_u16] CAMCLK_mspi0;
    5. [dma_u8] 1;
    6. [cs_num_u8] 2;
    7. [cs_ext_u32] PAD_UNKNOWN;
    8. [pad_mux_u16] 1;
    9. [4to3_mode_u8] 0;
    10. [clk_out_mode_u32] 0;
    

    SPI master驱动中支持配置的属性如下表:

    属性 描述 备注
    reg_u32_u16 用于指定SPI寄存器bank的IO地址 不需要修改
    interrupts_u8 用于指定使用的硬件中断号 不需要更改
    dma_u8 用于指定是否使能DMA模式 可根据需要修改
    clk-out-mode_u32 用于指定是否开启clk-out-mode 可根据需要修改
    cs_num_u8 用于指定Engine自带的cs pad的数量 和cs-ext_u32配合使用
    cs_ext_u32 用于指定除Engine自带的cs外要使用的pad index 可根据需要修改
    4to3_mode_u8 用于指定是否开启4Wires作为3Wires使用 可根据需要修改
    pad_mux_u16 用于选择mspi的padmux 可根据需要修改

    说明:当配置了padmux节点之后,上面的[pad_mux_u16]不需要再做配置。


    2.3. dma mode

    SigmaStar SPI Master支持两种基本通信模式:buffer mode和dma mode。当SPI Master处于buffer mode工作模式时,SPI Master驱动将需要发送的数据写入SPI Master的发送buffer中,同时将接收到的数据从接收buffer中读出。发送buffer和接收buffer为SPI Master外设中的寄存器,发送buffer和接收buffer的容量为各8 * 2-bytes。由于SPI Master工作在buffer mode时,需要软件参与发送buffer和接收buffer的操作,所以波形会受到软件调度的影响,在每次发送的之间会产生一定间隔。

    当SPI Master处于dma mode工作模式时,驱动只需将需要发送的数据的地址和接收的数据需要存放的地址设置到SPI Master DMA相关的寄存器中后,SPI Master会自动连续发送和接收数据,此过程不需要软件参与。因此当SPI Master工作在dma mode时,SPI的波形连续性较好。

    当SPI Master和SPI Device通讯时发送或接收的数据量较少,可以考虑使用buffer mode,工作效率较高。当SPI Master和SPI Device通讯时发送或接收的数据量较大,如接收SPI Sensor数据等等,此类大量数据通讯如果使用buffer mode会使系统的CPU占用率很高,影响系统效率,在大量数据通讯的场景下可以考虑使用dma mode。

    [注意] 当前SigmaStar SPI Master dma mode只支持半双工(half-duplex)的工作模式,SPI Master的发送和接收共用同一个dma channel。当设备需要使用全双工(full-duplex)通讯时,只能使用buffer mode的工作模式。use-dma属性指定的是工作在半双工模式下使用buffer mode或者dma mode,当Device驱动需要使用全双工通讯时,Master驱动会自动切换到buffer mode,可以在dma mode打开时,通过传输的参数来启用全双工,所以如有希望使用全双工模式时,也可以指定use-dma属性。

    2.4. cs-num

    硬件预设的cs数量。

    2.5. cs-ext

    由driver实现的额外添加cs引脚的功能。当硬件预设cs引脚不够用时,我们可以在sysDesc对应节点当中配置额外cs引脚来作为扩充,配置方法为sysDesc对应节点下的cs_ext_u32属性并配置所要作为扩充为cs的pad id。

    2.6. clk-out-mode

    clk-out-mode为SigmaStar SPI Master所支持的一种特殊模式。当SPI Master处于clk-out-mode时,SPI Master的MOSI和MISO不再按给定的数据发送或接收数据,SPI Master的Clock信号会不断输出方波。此功能的应用场景为使用SPI Master输出的clock作为其他Device的工作Clock。clk-out-mode属性的值用于指定输出clock的频率,配置clk-out-mode只需要在dtsi当中把对那个的clk-out-mode属性打开并配置相应要输出的波形频率就可以。

    2.7. 3-wire mode

    mspi支持三线模式,即通讯只需采用CZ/CK/DI(即MOSI)三根引脚,其中CZ作为片选和CK作为时钟引脚不变,DI引脚既作为输出引脚,也作为输入引脚,意味着此时的mspi只能采用半双工通讯,同时dma可以使用。硬件连接也需要从设备支持三线模式,把对应引脚接入即可。

    2.8. 4 to 3 mode

    某些平台的SPI Master 3-wires mode不支持dma mode,如果此时有3-wires dma mode的通讯需求时可以开启4 to 3 mode模式。硬件上将Master的MOSI和MISO短接并连接至Device的SDAT,如下图:

    当驱动在读数据时,会将MOSI自动切换为GPIO Input Mode从而不干扰MISO的波形输入,从而达到将四线模式用作三线模式。如果要使用此功能,只要把sysDesc节点当中的4to3-mode属性设1就可以。


    3. 驱动使用

    3.1. 驱动支持的模式

    当前驱动中支持的模式如下表:

    模式 描述 备注
    SPI_CPHA 用于和SPI_CPOL配合组成4种通讯时序
    SPI_CPOL 用于和SPI_CPHA配合组成4种通讯时序
    SPI_CS_HIGH 用于指定CS高有效
    SPI_LSB_FIRST 用于指定通讯序列为LSB(默认为MSB)
    SPI_3WIRE 用于指定使用三线模式

    3.2. 使用mspi

    参考文件:

    sc/driver/sysdriver/mspi/drv/src/drv_mspi_test.c

    调用流程:

    1) drv_mspi_setup(struct spi_setup *setup)

    mspi的初始化配置,参数包含要设定的bus number、cs片选号、通讯频率、mode

    struct mspi_setup
    {
        u8  bus_num;                        /* mspi bus number */
        u32 max_speed_hz;                   /* transfer speed */
        u8  chip_select;
        u32 mode;                           /* define below */
    #define SPI_CPHA        0x01            /* clock phase */
    #define SPI_CPOL        0x02            /* clock polarity */
    #define SPI_MODE_0      (0|0)           /* (original MicroWire) */
    #define SPI_MODE_1      (0|SPI_CPHA)
    #define SPI_MODE_2      (SPI_CPOL|0)
    #define SPI_MODE_3      (SPI_CPOL|SPI_CPHA)
    #define SPI_CS_HIGH     0x04            /* chipselect active high? */
    #define SPI_LSB_FIRST   0x08            /* per-word bits-on-wire */
    #define SPI_3WIRE       0x10            /* SI/SO signals shared */
    #define SPI_LOOP        0x20            /* loopback mode */
    #define SPI_NO_CS       0x40            /* 1 dev/bus, no chipselect */
    #define SPI_READY       0x80            /* slave pulls low to pause */
    #define SPI_TX_DUAL     0x100           /* transmit with 2 wires */
    #define SPI_TX_QUAD     0x200           /* transmit with 4 wires */
    #define SPI_RX_DUAL     0x400           /* receive with 2 wires */
    #define SPI_RX_QUAD     0x800           /* receive with 4 wires */
    #define SPI_CS_WORD     0x1000          /* toggle cs after each word */
    #define SPI_TX_OCTAL    0x2000          /* transmit with 8 wires */
    #define SPI_RX_OCTAL    0x4000          /* receive with 8 wires */
    #define SPI_3WIRE_HIZ   0x8000          /* high impedance turnaround */
    };
    ……
    struct mspi_setup setup;
    setup.bus_num = (u8)port;
    setup.chip_select = (u8)cs_select;
    setup.max_speed_hz = speed;
    //setup.mode = SPI_CPHA | SPI_CPOL; //如果默认0,可不赋值
    
    ret = drv_mspi_setup(&setup);
    

    2) drv_mspi_transfer(struct spi_setup *setup, struct spi_tfr *tfr, u32 length)

    struct mspi_tfr
    {
        const u8 *tx_buf;  /* transfer send data load */
        u8 *      rx_buf;  /* transfer recv data save */
        u32       len;     /* transfer length */
        u8        cs_change;
        u16       delay_usecs;
        u8        bits_per_word;
    };
    static u8 rdata[512];
    static u8 wdata[512];
    struct mspi_tfr transfers[2] = {0};
    wdata[0] = 0x03;
    wdata[1] = 0x00;
    wdata[2] = 0x00;
    wdata[3] = 0x00;
    transfers[0].tx_buf = wdata;
    transfers[0].rx_buf = NULL;
    transfers[0].len = 4;
    transfers[0].bits_per_word = 8;
    transfers[1].tx_buf = NULL;
    transfers[1].rx_buf = rdata;
    transfers[1].len = 256;
    transfers[1].bits_per_word = 8;
    ret = drv_mspi_transfer(&setup, transfers, 2);//一次半双工写,一次半双工读