SPI
概述
SPI ( Serial Peripheral Interface, 串行外围设备接口)是一种高速,全双工,同步的通信总线 常规只占用四根线,可节约芯片管脚和 PCB 的布局省空间 常见的集成这种协议的芯片有 EEPROM , FLASH , AD 转换器等
优点:
支持全双工
支持高速
协议支持字长不限于 8bit ,可根据应用特点灵活选择消息字长
硬件连接简单
缺点:
相比 IIC 多两根线
没有寻址机制,只能靠片选选择不同设备
没有从设备接受 ACK ,主设备对于发送成功与否不得而知
SPI 传输距离较短
SPI 一主多从拓扑结构
SPI 总线包含以下 4 条逻辑线:
SCK : Serial Clock 串行时钟信号,由主机发给从机
MOSI : Master Output Slave Input 主发从收信号
MISO : Master Input Slave Output 主收从发信号
SS/CS : Slave Select 片选信号,由主机发送
WQ7036A/AX 内置两个 SPI master 控制器 WQ7036A/AX 作为主机,向从机发送命令或数据,从机端接收主机端发送的数据
SPI 架构图
功能特性
单收、单发和收发并行模式
四线全双工和三线半双工通信
主机从机模式配置
时钟极性( CPOL )和时钟相位( CPHA )可配
时钟分频倍数可配
传输数据大小可配
SPI DMA 接口支持使用链表收/发数据
SPI 中断接口
工作模式
SPI 支持四种传输模式,可以通过寄存器 SPICR1 中的 CPOL 和 CPHA 位设置:
CPOL , 即 Clock Polarity 时钟极性,决定在总线空闲时, SCK 信号线上的电平为高或低
1 : 时钟低电平时有效, SCK 信号线在空闲时为高电平
0 : 时钟高电平时有效, SCK 信号线在空闲时为低电平
CPHA ,即 Clock Phase 时钟相位,定义 SPI 数据传输的两种基本模式:
1 : 在时钟偶数( 2 , 4 , 6 , ... , 16 )边沿(包括上下边沿)进行数据采样
0 : 在时钟奇数( 1 , 3 , 5 , ... , 15 )边沿(包括上下边沿)进行数据采样
SPI 通讯要求主从设备必须配置相同的传输模式
注意事项一:
当 CPHA = 0 且 CPOL = 0 时, DW_apb_ssi 主设备在开始连续串行传输的每个新数据帧之前切换从选择输出( ss_0_n )
而当 CPHA = 1 且 CPOL = 1 时, DW_apb_ssi 主设备在开始连续串行传输之前拉低从选择输出( ss_0_n )即可
故当用户需要使用 CPHA = 0 且 CPOL = 0 此模式时, 如果用户配置 CS ,交由驱动去控制,那 auto_cs 需设为 false , 如果用户为控制多个 SPI 从设备,那用户需自己手动拉低从选择输出( ss_0_n ), 来保证数据连续传输
注意事项二:
运行核频率需适配设置的 SPI 频率(推荐运行核主频设置为大于或等于设置的 SPI 频率的四倍)
如果运行核频率不适配于设置的 SPI 频率,则可能出现 SPI 大数据包传输时传输波形不连续甚至异常终止的问题
SPI 的时钟是从 DCORE 主频上分出的( SPI FREQ = DCORE FREQ / DIV )
分频系数 DIV 须为非1非3的正整数
如若 DCORE 频率无法整除 SPI 频率或因分频系数限制,分频系数 DIV 默认会向上取整
DCORE 的主频必须大于或等于设置的 SPI 频率的四倍,否则可能出现 SPI CLK 波形异常的问题
如若需要知道 SPI 真实运行频率,可调用 wq_spi_get_frequence 获取 SPI 真实频率信息
如若需要知道切频后 SPI 真实频率,可调用 wq_spi_register_freq_change_cb 注册回调函数,在切频时去获取相应信息
如若需要在切频后修改 SPI 频率,可在 wq_spi_register_freq_change_cb 注册的回调函数中调用 wq_spi_set_frequence 去设置
注意事项三:
因为存在线路延迟,所以 rx 可能需 delay 几个执行核 clk ( ssi_clk )周期。由于用户不一定知道当下执行核的 clk , 但一定知道 SPI CLK ( SCLK ),故在 spi open 配置参数中添加了 rx_sampledly 参数,即延迟 rx_sampledly/1000 个 SPI clk 周期( SCLK )。( rx_sampledly 推荐设置为 500 )
比如 rx_sampledly 设置为 500,即延迟半个 SPI clk 周期, 如若 ssi_clk = 4 * SCLK,则驱动内会配置延迟 2 个执行核 clk 周期; 如若 ssi_clk = 8 * SCLK,则驱动内会配置延迟 4 个执行核 clk 周期; 以此类推。
资源依赖
SPI
DMA
用法流程
初始化
wq_spi_init()配置并打开
wq_spi_open()poll 方式先写后读
wq_spi_poll_transfer()poll 方式双工同时读写
wq_spi_poll_duplex_transfer()DMA 方式先写后读
wq_spi_dma_transfer()DMA 方式双工同时读写
wq_spi_dma_duplex_transfer()
注:如果需要 DMA 方式读写,需要在调用传输函数调用 wq_dma_init()
参考示例
examples/spi_demo
API 介绍
Typedefs
-
typedef struct wq_spi_gpio_cfg wq_spi_gpio_cfg_t
-
typedef struct wq_spi_cfg wq_spi_cfg_t
-
typedef struct wq_spi_transfer wq_spi_transfer_t
-
typedef void (*wq_spi_freq_change_callback)(WQ_SPI_PORT port, uint32_t spi_req_freq, uint32_t spi_set_freq)
SPI frequency change callback func Invoke before and after frequency change.
- Param port:
is the SPI port.
- Param spi_req_freq:
is the SPI request frequency when SPI open.
- Param spi_set_freq:
is the SPI frequency after frequency change.
-
typedef void (*wq_spi_dma_callback)(const void *param)
SPI dma done callback func Invoke when dma transfer is done.
Enums
Functions
-
WQ_RET wq_spi_init(WQ_SPI_PORT port)
This function is to initialize SPI module.
- 参数:
port -- is the SPI port.
- 返回:
WQ_RET_OK Success.
WQ_RET_INVAL Bad param.
WQ_RET_AGAIN Repeated call.
-
WQ_RET wq_spi_deinit(WQ_SPI_PORT port)
This function is to deinitialize SPI module.
- 参数:
port -- is the SPI port.
- 返回:
WQ_RET_OK Success.
WQ_RET_INVAL Bad param.
WQ_RET_BUSY There is a unfinash transmition.
-
WQ_RET wq_spi_open(WQ_SPI_PORT port, const wq_spi_cfg_t *cfg, const wq_spi_gpio_cfg_t *gpio_cfg)
This function is to open SPI.
- 参数:
port -- is the SPI port.
cfg -- is configuration of the SPI.
gpio_cfg -- is configuration of the SPI gpio.
- 返回:
WQ_RET_OK Success.
WQ_RET_INVAL Bad param.
WQ_RET_AGAIN Repeated call.
WQ_RET_NOT_READY spi not init.
WQ_RET_BUSY gpio claim fail. /There is a unfinash transmition.
WQ_RET_NOSUPP spi frequency does not comply with the frequency division coefficient rule.
-
WQ_RET wq_spi_close(WQ_SPI_PORT port)
This function is to close the SPI module.
备注
If this function is called when there is an unfinash dma transfer, then after running this function, even if the return value is WQ_RET_OK, the spi may still be in the stop dma transfer. The spi is not really shut down until the dma stop is complete.
- 参数:
port -- is the SPI port.
- 返回:
WQ_RET_OK Success.
WQ_RET_INVAL spi not open.
WQ_RET_NOT_READY spi cfg frequency is 0.
-
WQ_RET wq_spi_gpio_config(WQ_SPI_PORT port, const wq_spi_gpio_cfg_t *gpio_cfg)
Config spi gpio.
- 参数:
port -- is the SPI port
gpio_cfg -- is the GPIO config
- 返回:
WQ_RET_OK Success.
WQ_RET_INVAL Bad param.
WQ_RET_BUSY gpio claim fail.
-
WQ_RET wq_spi_dma_config(WQ_SPI_PORT port)
Config spi dma.
备注
This function Can be called after wq_spi_init and wq_spi_open and before wq_spi_dma_transfer or wq_spi_dma_duplex_transfer. However, if you do not mind that the time to call this function is extra in wq_spi_dma_transfer or wq_spi_dma_duplex_transfer for the first time after an spi port is open, you do not need to call this function separately in advance.
- 参数:
port -- is the SPI port
- 返回:
WQ_RET_OK Success.
WQ_RET_INVAL Bad param.
WQ_RET_NOT_READY spi not init or not open.
-
WQ_RET wq_spi_poll_transfer(WQ_SPI_PORT port, uint8_t *outbuf, size_t outbuf_len, uint8_t *inbuf, size_t inbuf_len)
This function is to config for using the spi tx and rx by poll mode.(send then receive data)
- 参数:
port -- is the SPI port.
outbuf -- is the data buff need to transfer to the peri.
outbuf_len -- is the out buff length.
inbuf -- is the data buff need to read from the peri.
inbuf_len -- is the in buff length.
- 返回:
WQ_RET_OK Success.
WQ_RET_INVAL Bad param.
WQ_RET_NOT_READY spi not open.
WQ_RET_BUSY spi have a unfinash transfer.
WQ_RET_FAIL spi transfer fail.
-
WQ_RET wq_spi_dma_transfer(WQ_SPI_PORT port, uint8_t *outbuf, size_t outbuf_len, uint8_t *inbuf, size_t inbuf_len, wq_spi_dma_callback cb)
This function is to config for using the spi dma tx and rx.(send then receive data)
- 参数:
port -- is the SPI port.
outbuf -- is the data buff need to transfer to the peri.
outbuf_len -- is the out buff length.
inbuf -- is the data buff need to read from the peri.
inbuf_len -- is the in buff length.
cb -- spi transfer done callback
- 返回:
WQ_RET_OK Success.
WQ_RET_INVAL Bad param.
WQ_RET_NOT_READY spi not open.
WQ_RET_BUSY spi have a unfinash transfer.
WQ_RET_NOMEM no memory to save spi dma transfer cfg.
-
WQ_RET wq_spi_poll_duplex_transfer(WQ_SPI_PORT port, uint8_t *outbuf, size_t outbuf_len, uint8_t *inbuf, size_t inbuf_len)
This function is to config for using the spi tx and rx by poll mode using duplex mode.(send and receive data simultaneously)
- 参数:
port -- is the SPI port.
outbuf -- is the data buff need to transfer to the peri.
outbuf_len -- is the out buff length.
inbuf -- is the data buff need to read from the peri.
inbuf_len -- is the in buff length.
- 返回:
WQ_RET_OK Success.
WQ_RET_INVAL Bad param.
WQ_RET_NOT_READY spi not open.
WQ_RET_BUSY spi have a unfinash transfer.
WQ_RET_FAIL spi transfer fail.
-
WQ_RET wq_spi_dma_duplex_transfer(WQ_SPI_PORT port, uint8_t *outbuf, size_t outbuf_len, uint8_t *inbuf, size_t inbuf_len, wq_spi_dma_callback cb)
This function is to config for using the spi dma tx and rx using duplex mode.(send and receive data simultaneously)
- 参数:
port -- is the SPI port.
outbuf -- is the data buff need to transfer to the peri.
outbuf_len -- is the out buff length.
inbuf -- is the data buff need to read from the peri.
inbuf_len -- is the in buff length.
cb -- spi transfer done callback
- 返回:
WQ_RET_OK Success.
WQ_RET_INVAL Bad param.
WQ_RET_NOT_READY spi not open.
WQ_RET_BUSY spi have a unfinash transfer.
WQ_RET_NOMEM no memory to save spi dma transfer cfg.
-
WQ_RET wq_spi_set_frequence(WQ_SPI_PORT port, uint32_t freq)
This function is to set spi frequency.
- 参数:
port -- is the SPI port.
freq -- is the SPI frequency.
- 返回:
WQ_RET_OK Success.
WQ_RET_INVAL Bad param.
WQ_RET_NOT_READY spi not open.
WQ_RET_BUSY spi have a unfinash transfer.
WQ_RET_NOSUPP spi frequency does not comply with the frequency division coefficient rule.
-
uint32_t wq_spi_get_frequence(WQ_SPI_PORT port)
This function is to get spi frequency.
- 参数:
port -- is the SPI port.
- 返回:
uint32_t is SPI frequency.(0 for error)
-
WQ_RET wq_spi_register_freq_change_cb(WQ_SPI_PORT port, wq_spi_freq_change_callback cb)
This function is to register frequency change callback.
- 参数:
port -- is the SPI port.
cb -- is SPI frequency change callback
- 返回:
WQ_RET_OK Success.
WQ_RET_INVAL Bad param.
-
WQ_RET wq_spi_unregister_freq_change_cb(WQ_SPI_PORT port)
This function is to unregister frequency change callback.
- 参数:
port -- is the SPI port.
- 返回:
WQ_RET_OK Success.
WQ_RET_INVAL Bad param.
-
struct wq_spi_gpio_cfg
Public Members
-
WQ_GPIO_ID clk
SPI clk gpio
-
WQ_GPIO_ID cs
-
WQ_GPIO_ID mosi
SPI mosi gpio
-
WQ_GPIO_ID miso
SPI miso gpio
-
bool auto_cs
Is SPI cs auto, If auto_cs is set to false, driver control cs pin
-
WQ_GPIO_ID clk
-
struct wq_spi_cfg
Public Members
-
WQ_SPI_DFRAME_SIZE dframe_size
SPI dframe size
-
WQ_SPI_CLK_MODE clk_mode
SPI clk mode
-
uint32_t frequency
SPI frequency
备注
The DCORE frequency must be four times greater than this value, The frequency of the running core must also match this value.
-
uint32_t dummy_data
spi sends dummy_data while receiving data:
1) spi transfer data using mode of sending then receiving data and inbuf_len is not 0
2) spi transfer data using mode of sending and receiving data simultaneously and outbuf_len is greater than inbuf_len
备注
When dframe_size = WQ_SPI_DFRAME_SIZE_8, the lower 8 bits of dummy_data are valid. When dframe_size = WQ_SPI_DFRAME_SIZE_16, the lower 16 bits of dummy_data are valid.
-
uint16_t rx_sampledly
the sampling delay to be rx_sampledly/1000 of an SPI clock cycle.
备注
Recommended to be set to 500, which means a delay of half an SPI clock cycle.
-
WQ_SPI_DFRAME_SIZE dframe_size
-
struct wq_spi_transfer