SPI

概述

SPI ( Serial Peripheral Interface, 串行外围设备接口)是一种高速,全双工,同步的通信总线 常规只占用四根线,可节约芯片管脚和 PCB 的布局省空间 常见的集成这种协议的芯片有 EEPROM , FLASH , AD 转换器等

优点:

  • 支持全双工

  • 支持高速

  • 协议支持字长不限于 8bit ,可根据应用特点灵活选择消息字长

  • 硬件连接简单

缺点:

  • 相比 IIC 多两根线

  • 没有寻址机制,只能靠片选选择不同设备

  • 没有从设备接受 ACK ,主设备对于发送成功与否不得而知

  • SPI 传输距离较短

../../_images/SPI_topologies.png

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 作为主机,向从机发送命令或数据,从机端接收主机端发送的数据

../../_images/SPI_framework.png

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 的频率是在 DCORE 主频上分频的,故需要注意 DCORE 的主频必须大于或等于设置的 SPI 频率的四倍,且注意将运行 核频率也适配于设置的 SPI 频率(推荐运行核主频设置成大于或等于设置的 SPI 频率的四倍)。

如果 DCORE 的主频小于设置的 SPI 频率的四倍,则可能出现 SPI CLK 波形异常的问题; 如果运行核频率不适配于设置的 SPI 频率,则可能出现 SPI 大数据包传输时异常终止的问题。

资源依赖

  • SPI

  • DMA

用法流程

注:如果需要 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_dma_callback)(const void *param)

SPI dma done callback func Invoke when dma transfer is done.

Enums

enum WQ_SPI_CLK_MODE

Values:

enumerator WQ_SPI_CLK_MODE_0

Equal to SPI_CPOL_0_CPHA_0

enumerator WQ_SPI_CLK_MODE_1

Equal to SPI_CPOL_0_CPHA_1

enumerator WQ_SPI_CLK_MODE_2

Equal to SPI_CPOL_1_CPHA_0

enumerator WQ_SPI_CLK_MODE_3

Equal to SPI_CPOL_1_CPHA_1

enum WQ_SPI_DFRAME_SIZE

Values:

enumerator WQ_SPI_DFRAME_SIZE_8
enumerator WQ_SPI_DFRAME_SIZE_16

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 frequency of dcore is less than four times that of spi.

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.

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

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.

struct wq_spi_transfer

Public Members

struct wq_spi_transfer *next

SPI link to next block

uint8_t *txbuf

SPI transfer TX buffer

uint32_t txlen

SPI transfer TX buffer length

uint8_t *rxbuf

SPI transfer RX buffer

uint32_t rxlen

SPI transfer RX buffer length