RTOS_SPI使用参考
REVISION HISTORY¶
Revision No. | Description |
Date |
---|---|---|
1.0 | 04/18/2023 | |
1.1 | 04/09/2025 |
1. 概述¶
Serial Peripheral Interface (串行外围设备接口),简称SPI, 是 Motorola 公司推出的一种高速同步串行接口技术,主要应用在EEPROM,Flash,实时时钟(RTC),数模转换器(ADC),数字信号处理器(DSP) 等设备。
MSPI,即Master spi device,是SigmaStar提供的专门作为spi通信主设备的IP,可实现与各种外接的spi slave device通讯,满足绝大部分spi通讯协议设备的需求。
2. 关键字说明¶
-
MISO / SDO:Master input slave output 主机输入,从机输出(数据来自从机)
-
MOSI / SDI:Master output slave input 主机输出,从机输入(数据来自主机)
-
SCLK / SCK : Serial Clock 串行时钟信号,由主机产生发送给从机
-
CS / SS:Slave Select 片选信号,由主机发送,以控制与哪个从机通信,通常是低电平有效信号
-
CPOL / CKP:时钟极性,表示时钟的默认状态下的电平高低状态
-
CPHA / CKE:时钟相位,表示采集数据时是在时钟信号的具体相位
-
SPI Mode :SPI的时钟极性和相位的配置可以输出4种SPI模式
SPI Mode CPOL CPHA 0 [00] 0 0 1 [01] 0 1 2 [10] 1 0 3 [11] 1 1
3. 功能描述¶
-
MSPI(Master SPI)只能作为master device,不能作为slave device
-
硬件支持2组MSPI,支持Motorola SPI标准时序,MSPI的寄存器bank和支持最大软件片选如下:
MSPI Bus bank addr cs_num 0 1110H 2 1 1119H 2 -
FIFO mode下支持全双工读写/半双工读写,DMA mode下仅支持半双工读写
-
支持4线通讯(MISO + MOSI + SCLK + CS)和3线通讯(MOSI + SCLK + CS)
-
8字节读写缓冲区(FIFO mode),字节传输1bit到16bit可配置位宽度
-
Source Clock:12M、104M、108M、144M,实际SPI的通讯频率可选档位则是每种Source Clock分频的8个档位(分频系数为2、4、8、16、32、64、128、256),共计32个档位,因此SPI通讯频率范围是46875HZ~72MHz,目标频率可通过赋值struct mspi_setup结构体中的max_speed_hz变量进行设定;而实际的通讯频率会选择最接近目标频率但小于目标频率的档位。频率档位表如下。
NO. SPI Clock Rate 1 46875 2 93750 3 187500 4 375000 5 421861 6 421875 7 562500 8 750000 9 843723 10 843750 11 1125000 12 1500000 13 1687446 14 1687500 15 2250000 16 3000000 17 3374892 18 3375000 19 4500000 20 6000000 21 6749785 22 6750000 23 9000000 24 13499571 25 13500000 26 18000000 27 26999143 28 27000000 29 36000000 30 53998287 31 54000000 32 72000000
4. 硬件连接介绍¶
MSPI只支持一主多从架构,顾名思义一路总线上面可以只有一个主设备和一个或多个从设备,从设备选择信号线,常称为片选信号线,也称为CS、SS,以下用 SS 表示。 当有多个 SPI 从设备与 SPI 主机相连时,设备的其它信号线 SCLK、MOSI 及 MISO 同时并联到相同的 SPI 总线上,即无论有多少个从设备,都共同只使用这 3 条线;而每个从设备都有独立的这一条 SS 信号线,本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。 SPI 协议中没有设备地址,它使用 SS 信号线来寻址,当主机要选择从设备时,把该从设备的 SS 信号线设置为低电平(默认为低电平),该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI 通讯。所以SPI 通讯以 SS 线置低电平为开始信号,以 SS 线被拉高作为结束信号。

5. RTOS用法介绍¶
MSPI通讯的时候,需要保证基本的如下步骤:
- 硬件设备连接;
- 确认CONFIG_MSPI_SUPPORT是否开启;
- SYSDESC文件配置需求属性;
- PADMUX设定;
- API调用,执行通讯。
5.1 DRIVER PATH¶
sc/driver/sysdriver/mspi/drv/src/drv_mspi.c sc/driver/sysdriver/mspi/hal/pcupid/src/hal_mspi.c sc/driver/sysdriver/mspi/hal/pcupid/inc/hal_mspi.h sc/driver/sysdriver/mspi/hal/pcupid/inc/hal_mspireg.h sc/driver/sysdriver/mspi/hal/pcupid/inc/hal_mspi_cfg.h sc/driver/sysdriver/mspi/os/mspi_os.h sc/driver/sysdriver/mspi/drv/pub/drv_mspi.h sc/driver/sysdriver/mspi/drv/src/drv_mspi_test.c
5.2 CONFIG配置¶
config文件位于mak/defconfigs/
,使能CONFIG_MSPI_SUPPORT
CONFIG_MSPI_SUPPORT = TRUE
5.3 SYSDESC配置¶
chipname.sys文件位于sc/driver/sysdriver/sysdesc/hal/chipname/pub
<mspi0> [reg_u32_u16] 0x2222000 0x200; [interrupts_u8] INT_IRQ_MSPI_0; [camclk_u16] CAMCLK_mspi0; [dma_u8] 1; [cs_num_u8] 2; [cs_ext_u32] PAD_UNKNOWN; [4to3_mode_u8] 0; [clk_out_mode_u32] 0; [padmux_u16] PINMUX_FOR_UNKNOWN_MODE, PINMUX_FOR_UNKNOWN_MODE; [status_u8] 1;
SPI master驱动中支持配置的属性如下表:
属性 | 描述 | 备注 |
---|---|---|
reg_u32_u16 | 用于指定SPI寄存器bank的IO地址 | 不需要修改 |
interrupts_u8 | 用于指定使用的硬件中断号 | 不需要更改 |
camclk_u16 | 用于指定mspi clock | 不需要更改 |
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使用 | 可根据需要修改 |
padmux_u16 | 用于选择mspi的padmux | 可根据需要修改 |
status_u8 | 用于指定是否开启mspi | 可根据需要修改 |
5.3.1 dma mode¶
SigmaStar SPI Master支持两种基本通信模式:fifo mode和dma mode。当SPI Master处于fifo mode工作模式时,SPI Master驱动将需要发送的数据写入SPI Master的发送buffer中,同时将接收到的数据从接收buffer中读出。发送buffer和接收buffer为SPI Master外设中的寄存器,发送buffer和接收buffer的容量为各8bytes。由于SPI Master工作在fifo mode时,需要软件参与发送buffer和接收buffer的操作,所以波形会受到软件调度的影响,在每次发送的之间会产生一定间隔。
当SPI Master处于dma mode工作模式时,驱动只需将需要发送的数据的地址和接收的数据需要存放的地址设置到SPI Master DMA相关的寄存器中后,SPI Master会自动连续发送和接收数据,此过程不需要软件参与。因此当SPI Master工作在dma mode时,SPI的波形连续性较好。
当SPI Master和SPI Device通讯时发送或接收的数据量较少,可以考虑使用fifo mode,工作效率较高。当SPI Master和SPI Device通讯时发送或接收的数据量较大,如接收SPI Sensor数据等等,此类大量数据通讯如果使用fifo mode会使系统的CPU占用率很高,影响系统效率,在大量数据通讯的场景下可以考虑使用dma mode。
[注意] 当前SigmaStar SPI Master dma mode只支持半双工(half-duplex)的工作模式,SPI Master的发送和接收共用同一个dma channel。当设备需要使用全双工(full-duplex)通讯时,只能使用fifo mode的工作模式。dma_u8属性指定的是工作在半双工模式下使用fifo mode或者dma mode,当Device驱动需要使用全双工通讯时,Master驱动会自动切换到fifo mode,可以在dma mode打开时,通过传输的参数来启用全双工,所以如有希望使用全双工模式时,也可以指定dma_u8属性。
5.3.2. cs-num¶
最大值硬件预设的cs数量,cs_num_u8 = n,软件片选号就是MSPI的片选0 ~ n-1;如要使用MSPI软件片选cs0,cs1,需要配置cs_num_u8 = 2。
5.3.3. cs-ext¶
由driver实现的额外添加cs引脚的功能。当硬件预设cs引脚不够用时,可以在dtsi当中配置额外cs引脚来作为扩充,cs_ext_u32片选序号从cs_num_u8的值开始,如cs_ext_u32 = 2,那么第一个cs-ext引脚为cs2。配置额外cs方法为打开dtsi节点下的cs_ext_u32属性并配置所要作为扩充为cs的pad id,同时,建议在xxx-padmux.dtsi当中也把对应的pad配置为GPIO MODE,如下为把PAD_I2C0_SCL作为cs的扩充:
<PAD_GPIOE_14 PINMUX_FOR_MSPI0_MODE_1 MDRV_PUSE_SPI0_CK>, <PAD_GPIOE_16 PINMUX_FOR_MSPI0_MODE_1 MDRV_PUSE_SPI0_DI>, <PAD_GPIOE_17 PINMUX_FOR_MSPI0_MODE_1 MDRV_PUSE_SPI0_DO>, <PAD_GPIOE_15 PINMUX_FOR_MSPI0_MODE_1 MDRV_PUSE_SPI0_CZ>, <PAD_I2C0_SCL PINMUX_FOR_GPIO_MODE MDRV_PUSE_SPI0_CZ2>,
5.3.4. clk-out-mode¶
clk-out-mode为SigmaStar SPI Master所支持的一种特殊模式。当SPI Master处于clk_out_mode_u32时,SPI Master的MOSI和MISO不再按给定的数据发送或接收数据,SPI Master的Clock信号会不断输出方波。此功能的应用场景为使用SPI Master输出的clock作为其他Device的工作Clock。clk_out_mode_u32属性的值用于指定输出clock的频率,配置clk_out_mode_u32只需要在chipname.sys当中把对那个的clk_out_mode_u32属性打开并配置相应要输出的波形频率就可以:
[clk_out_mode_u32] 3750000; //使能clk-out-mode,输出3.75M频率波形
可选的输出频率与MSPI正常工作的频率一样,参考频率档位表。
5.3.5. 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的波形输入,从而达到将四线模式用作三线模式。如果要使用此功能,只要把dtsi节点当中的4to3-mode属性打开就可以,即
[4to3_mode_u8] 1; //使能4to3-mode
注意 : 4to3 mode的MSPI的引脚都不能作为其它mode。 3线模式的MISO可以作为其它功能,前提是mode的优先级比MSPI高,如gpio。
5.4 PADMUX设定¶
CONFIG配置:CONFIG_PADMUX_SUPPORT=TRUE
如果chipname_xxx.sys
文件配置了属性<padmux>
,那么PADMUX的设定直接在此配置:
<padmux> [schematic_u32_u32_u32] PAD_GPIOE_14 PINMUX_FOR_MSPI0_MODE_1 MDRV_PUSE_SPI0_CZ, PAD_GPIOE_16 PINMUX_FOR_MSPI0_MODE_1 MDRV_PUSE_SPI0_CK, PAD_GPIOE_17 PINMUX_FOR_MSPI0_MODE_1 MDRV_PUSE_SPI0_DI, PAD_GPIOE_15 PINMUX_FOR_MSPI0_MODE_1 MDRV_PUSE_SPI0_DO, [status_u8] 1;
第一列为引脚索引号,可以在sc/drivers/sysdriver/gpio/hal/chipname/pub/gpio.h
中查询;
第二列为模式定义,可以在sc/drivers/sysdriver/gpio/hal/chipname/pub/padmux.h
中查询;
第三列为引脚及搭配模式的索引名称,可以在sc/drivers/sysdriver/padmux/drv/pub/drv_puse.h
中查询;
MSPI0硬件组padmux罗列
MSPI Bus | Register addr | Padmod | Pad | Pin Name |
---|---|---|---|---|
0 | bank 103CH offset 6CH bit[6:4] | 1 | MSPI0_CZ0 | PAD_GPIOE_15 |
MSPI0_CK | PAD_GPIOE_14 | |||
MSPI0_DI | PAD_GPIOE_16 | |||
MSPI0_DO | PAD_GPIOE_17 | |||
2 | MSPI0_CZ0 | PAD_GPIOA_12 | ||
MSPI0_CK | PAD_GPIOA_13 | |||
MSPI0_DI | PAD_GPIOA_14 | |||
MSPI0_DO | PAD_GPIOA_15 | |||
3 | MSPI0_CZ0 | PAD_GPIOC_07 | ||
MSPI0_CK | PAD_GPIOC_06 | |||
MSPI0_DI | PAD_GPIOC_04 | |||
MSPI0_DO | PAD_GPIOC_05 | |||
4 | MSPI0_CZ0 | PAD_GPIOE_21 | ||
MSPI0_CK | PAD_GPIOE_22 | |||
MSPI0_DI | PAD_GPIOE_23 | |||
MSPI0_DO | PAD_GPIOE_24 | |||
bank 103CH offset 6CH bit[1:0] | mspi0 cz1 mode 1 | MSPI0_CZ1 | PAD_GPIOE_13 | |
mspi0 cz1 mode 2 | MSPI0_CZ1 | PAD_EMMC_D7 |
5.5 Sample code¶
demo源码位于sc/driver/sysdriver/mspi/drv/src/drv_mspi_test.c
用法举例:
static int spi_ut_test(CLI_t * cli, char * p) { u32 i; s32 ret; u8 argc; u32 port; u32 cs_select; u32 speed; char *cmd; struct mspi_setup setup = {0}; struct mspi_tfr transfers[2] = {0}; argc = CliTokenCount(cli); if (argc != 4) return eCLI_PARSE_INPUT_ERROR; cmd = CliTokenPop(cli); if (CliTokenPopNum(cli, &port, 0) != eCLI_PARSE_OK) { return eCLI_PARSE_INPUT_ERROR; } if (CliTokenPopNum(cli, &cs_select, 0) != eCLI_PARSE_OK) { return eCLI_PARSE_INPUT_ERROR; } if (CliTokenPopNum(cli, &speed, 0) != eCLI_PARSE_OK) { return eCLI_PARSE_INPUT_ERROR; } setup.bus_num = (u8)port; setup.chip_select = (u8)cs_select; setup.max_speed_hz = speed; setup.mode &= ~(MSPI_SETUP_CPHA | MSPI_SETUP_CPOL); //mspi initial configure ret = drv_mspi_setup(&setup); if(ret) { cliPrintf("drv_mspi_setup fail : %d\n", ret); return eCLI_PARSE_UNKNOWN; } //read if (strcmp(cmd, "r") == 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); if (ret) { cliPrintf("drv_mspi_transfer fail : %d\n", ret); return eCLI_PARSE_UNKNOWN; } } //write else if (strcmp(cmd, "w") == 0) { wdata[0] = 0x06; transfers[0].tx_buf = wdata; transfers[0].rx_buf = NULL; transfers[0].len = 1; transfers[0].bits_per_word = 8; ret = drv_mspi_transfer(&setup, transfers, 1); if (ret) { cliPrintf("drv_mspi_transfer fail : %d\n", ret); return eCLI_PARSE_UNKNOWN; } wdata[0] = 0x02; wdata[1] = 0x00; wdata[2] = 0x00; wdata[3] = 0x00; for (i = 0; i < 256; i++) { wdata[i+4] = i; } transfers[0].tx_buf = wdata; transfers[0].rx_buf = NULL; transfers[0].len = 260; transfers[0].bits_per_word = 8; ret = drv_mspi_transfer(&setup, transfers, 1); if (ret) { cliPrintf("drv_mspi_transfer fail : %d\n", ret); return eCLI_PARSE_UNKNOWN; } } ... return eCLI_PARSE_OK; }
当struct mspi_tfr 中.rx_buff不为null,.tx_buff为null时,MSPI Master执行的为半双工读操作;当.rx_buff为null,.tx_buff不为null时,执行的为半双工写操作;当.rx_buff和.tx_buff都不为null时,哪怕dma mode被打开了,执行的也是全双工读写操作。对应的波形示意图如下:

图中MOSI对应的为.tx_buff中的数据,MISO对应的为.rx_buff中的数据。
6. API参考¶
-
头文件位于
sc/driver/sysdriver/mspi/drv/pub/drv_mspi.h
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 */ };
-
该功能模块提供以下接口:
API名称 功能 drv_mspi_setup 设置属性包括模式、频率、片选等。 drv_mspi_transfer 数据传输。
6.1 drv_mspi_setup¶
-
功能
设置属性包括模式、频率、片选等
-
语法
int drv_mspi_setup(struct mspi_setup *setup)
-
参数
参数名称 描述 setup struct mspi_setup 描述通讯的参数配置,参数包含要设定的bus number、cs片选号、通讯频率、mode等 -
返回值
结果 描述 成功 返回0 失败 返回非0值
6.2 drv_mspi_transfer¶
-
功能
数据传输
-
语法
int drv_mspi_transfer(struct mspi_setup *setup, struct mspi_tfr *tfr, u32 length)
-
参数
参数名称 描述 setup mspi参数配置,参数包含要设定的bus number、cs片选号、通讯频率、mode等 tfr struct mspi_tfr 用于描述通讯的信息,包括通讯数据,位宽等 length mspi_tfr的数量 -
返回值
结果 描述 成功 返回0 失败 返回非0值
7. FAQ¶
当出现通讯异常时,可以参考如下方面进行问题调试,提供了几种较为常见的排查方向,另调试过程建议抓取波形方便分析。
排查方向 | 常见问题 |
备注 |
---|---|---|
padmux | 1. 无波形,触发不了 | 可查看寄存器值有没有下下去,padmux设置参考PADMUX章节,或padmux模块说明 |
linux dtsi的配置是否和rtos冲突 | 可能会导致rtos下mspi不生效 | 关闭linux dtsi配置 |
时钟源 | 1. LA抓取数据有误; | 当clock速率设置过高时,比如超过45m有可能会出现这种情况,此时可以调gpio驱动能力 |
cs_ext | 扩展脚功能用不了 | 请确认是否是旧架构,旧架构不支持扩展脚功能,详情参考cs_ext这一小节 |