RISCV_SPI使用参考
REVISION HISTORY¶
Revision No. | Description |
Date |
---|---|---|
1.0 | 11/14/2022 |
1. 概述¶
1.1. 概述¶
SPI是一个同步串行接口,可以连接各种外部设备。硬件组如下表:
MSPI Bus | bank addr | cs_num |
---|---|---|
0 | 1110H | 2 |
1 | 1111H | 2 |
1.2. 功能支持¶
-
mspi只能作为master device,不能作为slave device。
-
支持Motorola SPI兼容时序(CPHA / CPOL)。
-
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,此时驱动也会自动判定走全双工模式。 -
支持三线模式,即3-wire mode。
-
8字节读写缓冲区(FIFO mode);字节传输1bit到15bit可配置位宽度。
-
通讯频率满足从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 -
硬件预设多片选设定,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配置方法。三种如下:
-
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;
-
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. }
-
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);//一次半双工写,一次半双工读