目录
- 高速 SPI 设备控制器
- 库函数
-
- 注意事项
-
- 测试
- main.c
- wm_hal_msp.c
- wm_it.c
- 其他改动
- 实验现象
Windows 10 20H2
HLK-W806-V1.0-KIT
WM_SDK_W806_v0.6.0
摘自《W806 芯片设计指导书 V1.0》、《W806 MCU 芯片规格书 V2.0》、《WM_W800_寄存器手册 V2.1》
高速 SPI 设备控制器
兼容通用 SPI 物理层协议,通过约定与主机交互的数据格式,主机对设备的高速访问,最高支持工作频率为50Mbps。
兼容通用 SPI 协议
可选择的电平中断信号
最高支持 50Mbps 速率
简单的帧格式,全硬件解析与 DMA
库函数
函数
HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi);
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi);
void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint32_t Size,
uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size);
HAL_StatusTypeDef HAL_SPI_Receive_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size);
HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,
uint32_t Size);
HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size);
HAL_StatusTypeDef HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size);
HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,
uint32_t Size);
HAL_StatusTypeDef HAL_SPI_DMAPause(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DMAResume(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_DMAStop(SPI_HandleTypeDef *hspi);
void HAL_SPI_IRQHandler(SPI_HandleTypeDef *hspi);
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_TxRxHalfCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi);
HAL_SPI_StateTypeDef HAL_SPI_GetState(SPI_HandleTypeDef *hspi);
uint32_t HAL_SPI_GetError(SPI_HandleTypeDef *hspi);
参数
结构体和枚举类型
typedef struct
{
uint32_t Mode;
uint32_t CLKPolarity;
uint32_t CLKPhase;
uint32_t NSS;
uint32_t BaudRatePrescaler;
uint32_t FirstByte;
} SPI_InitTypeDef;
typedef enum
{
HAL_SPI_STATE_RESET = 0x00U,
HAL_SPI_STATE_READY = 0x01U,
HAL_SPI_STATE_BUSY = 0x02U,
HAL_SPI_STATE_BUSY_TX = 0x03U,
HAL_SPI_STATE_BUSY_RX = 0x04U,
HAL_SPI_STATE_BUSY_TX_RX = 0x05U,
HAL_SPI_STATE_ERROR = 0x06U,
HAL_SPI_STATE_ABORT = 0x07U
} HAL_SPI_StateTypeDef;
typedef struct __SPI_HandleTypeDef
{
SPI_TypeDef *Instance;
SPI_InitTypeDef Init;
uint8_t *pTxBuffPtr;
uint32_t TxXferSize;
__IO uint32_t TxXferCount;
uint8_t *pRxBuffPtr;
uint32_t RxXferSize;
__IO uint32_t RxXferCount;
DMA_HandleTypeDef *hdmatx;
DMA_HandleTypeDef *hdmarx;
HAL_LockTypeDef Lock;
__IO HAL_SPI_StateTypeDef State;
__IO uint32_t ErrorCode;
} SPI_HandleTypeDef;
宏参数
#define SPI ((SPI_TypeDef *)SPI_BASE)
#define HAL_SPI_ERROR_NONE (0x00000000U)
#define HAL_SPI_ERROR_TXERR (0x00000001U)
#define HAL_SPI_ERROR_RXERR (0x00000002U)
#define HAL_SPI_ERROR_DMA (0x00000010U)
#define SPI_MODE_SLAVE (0x00000000U)
#define SPI_MODE_MASTER (SPI_SPI_CFG_MASTER)
#define SPI_POLARITY_LOW (0x00000000U)
#define SPI_POLARITY_HIGH SPI_SPI_CFG_CPOL
#define SPI_PHASE_1EDGE (0x00000000U)
#define SPI_PHASE_2EDGE SPI_SPI_CFG_CPHA
#define SPI_NSS_HARD (0x00000000U)
#define SPI_NSS_SOFT SPI_CH_CFG_CSSEL
#define SPI_LITTLEENDIAN (0x00000000U)
#define SPI_BIGENDIAN SPI_SPI_CFG_BIGENDIAN
#define SPI_BAUDRATEPRESCALER_2 (0x00000000U)
#define SPI_BAUDRATEPRESCALER_4 (0x00000001U)
#define SPI_BAUDRATEPRESCALER_8 (0x00000003U)
#define SPI_BAUDRATEPRESCALER_10 (0x00000004U)
#define SPI_BAUDRATEPRESCALER_20 (0x00000009U)
#define SPI_BAUDRATEPRESCALER_40 (0x00000013U)
#define BLOCK_SIZE (8 * 1024 - 8)
宏
#define IS_SPI_ALL_INSTANCE(INSTANCE) ((INSTANCE) == SPI1)
#define IS_SPI_MODE(__MODE__) ((__MODE__) == SPI_MODE_MASTER)
#define IS_SPI_NSS(__NSS__) (((__NSS__) == SPI_NSS_SOFT) || \
((__NSS__) == SPI_NSS_HARD_INPUT) || \
((__NSS__) == SPI_NSS_HARD_OUTPUT))
#define IS_SPI_BIG_OR_LITTLE(__ENDIAN__) (((__ENDIAN__) == SPI_LITTLEENDIAN) || \
((__ENDIAN__) == SPI_BIGENDIAN))
#define IS_SPI_DMA_HANDLE(__HANDLE__) ((__HANDLE__) != NULL)
#define __HAL_SPI_ENABLE_TX(__HANDLE__) SET_BIT((__HANDLE__)->Instance->CH_CFG, SPI_CH_CFG_TXON)
#define __HAL_SPI_DISABLE_TX(__HANDLE__) CLEAR_BIT((__HANDLE__)->Instance->CH_CFG, SPI_CH_CFG_TXON)
#define __HAL_SPI_ENABLE_RX(__HANDLE__) SET_BIT((__HANDLE__)->Instance->CH_CFG, SPI_CH_CFG_RXON)
#define __HAL_SPI_DISABLE_RX(__HANDLE__) CLEAR_BIT((__HANDLE__)->Instance->CH_CFG, SPI_CH_CFG_RXON)
#define __HAL_SPI_ENABLE_TXRX(__HANDLE__) SET_BIT((__HANDLE__)->Instance->CH_CFG, (SPI_CH_CFG_RXON | SPI_CH_CFG_TXON))
#define __HAL_SPI_DISABLE_TXRX(__HANDLE__) CLEAR_BIT((__HANDLE__)->Instance->CH_CFG, (SPI_CH_CFG_RXON | SPI_CH_CFG_TXON))
#define __HAL_SPI_CLEAR_FIFO(__HANDLE__) do{SET_BIT((__HANDLE__)->Instance->CH_CFG, SPI_CH_CFG_CLEARFIFOS);\
while(READ_BIT((__HANDLE__)->Instance->CH_CFG, SPI_CH_CFG_CLEARFIFOS));}while(0U);
#define __HAL_SPI_GET_TXFIFO(__HANDLE__) (((__HANDLE__)->Instance->STATUS) & SPI_STATUS_TXFIFO)
#define __HAL_SPI_GET_RXFIFO(__HANDLE__) ((((__HANDLE__)->Instance->STATUS) & SPI_STATUS_RXFIFO) >> SPI_STATUS_RXFIFO_Pos)
#define __HAL_SPI_SET_CLK_NUM(__HANDLE__, NUM) (MODIFY_REG((__HANDLE__)->Instance->CH_CFG, SPI_CH_CFG_LEN, NUM << SPI_CH_CFG_LEN_Pos))
#define __HAL_SPI_SET_START(__HANDLE__) SET_BIT((__HANDLE__)->Instance->CH_CFG, SPI_CH_CFG_START)
#define __HAL_SPI_GET_BUSY_STATUS(__HANDLE__) (READ_BIT((__HANDLE__)->Instance->STATUS, SPI_STATUS_BUSY))
#define __HAL_SPI_SET_CS_LOW(__HANDLE__) CLEAR_BIT((__HANDLE__)->Instance->CH_CFG, SPI_CH_CFG_CSLEVEL)
#define __HAL_SPI_SET_CS_HIGH(__HANDLE__) SET_BIT((__HANDLE__)->Instance->CH_CFG, SPI_CH_CFG_CSLEVEL)
#define __HAL_SPI_GET_FLAG(__HANDLE__, FLAG) READ_BIT((__HANDLE__)->Instance->INT_SRC, FLAG)
#define __HAL_SPI_CLEAR_FLAG(__HANDLE__, FLAG) SET_BIT((__HANDLE__)->Instance->INT_SRC, FLAG)
#define __HAL_SPI_ENABLE_IT(__HANDLE__, IT) CLEAR_BIT((__HANDLE__)->Instance->INT_MASK, IT)
#define __HAL_SPI_DISABLE_IT(__HANDLE__, IT) SET_BIT((__HANDLE__)->Instance->INT_MASK, IT)
应用示例
摘自spi例程
初始化
在main.c中
SPI_HandleTypeDef hspi;
DMA_HandleTypeDef hdma_spi_tx;
DMA_HandleTypeDef hdma_spi_rx;
static void SPI_Init(void);
static void DMA_Init(void);
static void SPI_Init(void)
{
hspi.Instance = SPI;
hspi.Init.Mode = SPI_MODE_MASTER;
hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi.Init.NSS = SPI_NSS_SOFT;
hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_20;
hspi.Init.FirstByte = SPI_LITTLEENDIAN;
if (HAL_SPI_Init(&hspi) != HAL_OK)
{
Error_Handler();
}
}
static void DMA_Init(void)
{
__HAL_RCC_DMA_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA_Channel0_IRQn, 0);
HAL_NVIC_EnableIRQ(DMA_Channel0_IRQn);
HAL_NVIC_SetPriority(DMA_Channel1_IRQn, 0);
HAL_NVIC_EnableIRQ(DMA_Channel1_IRQn);
}
引脚复用
在wm_hal_msp.c中
extern DMA_HandleTypeDef hdma_spi_tx;
extern DMA_HandleTypeDef hdma_spi_rx;
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
__HAL_RCC_SPI_CLK_ENABLE();
__HAL_AFIO_REMAP_SPI_CS(GPIOB, GPIO_PIN_4);
__HAL_AFIO_REMAP_SPI_CLK(GPIOB, GPIO_PIN_2);
__HAL_AFIO_REMAP_SPI_MISO(GPIOB, GPIO_PIN_3);
__HAL_AFIO_REMAP_SPI_MOSI(GPIOB, GPIO_PIN_5);
hdma_spi_tx.Instance = DMA_Channel0;
hdma_spi_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi_tx.Init.DestInc = DMA_DINC_DISABLE;
hdma_spi_tx.Init.SrcInc = DMA_SINC_ENABLE;
hdma_spi_tx.Init.DataAlignment = DMA_DATAALIGN_WORD;
hdma_spi_tx.Init.Mode = DMA_MODE_NORMAL_SINGLE;
hdma_spi_tx.Init.RequestSourceSel = DMA_REQUEST_SOURCE_SPI_TX;
__HAL_LINKDMA(hspi, hdmatx, hdma_spi_tx);
if (HAL_DMA_Init(&hdma_spi_tx) != HAL_OK)
{
Error_Handler();
}
hdma_spi_rx.Instance = DMA_Channel1;
hdma_spi_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi_rx.Init.DestInc = DMA_DINC_ENABLE;
hdma_spi_rx.Init.SrcInc = DMA_SINC_DISABLE;
hdma_spi_rx.Init.DataAlignment = DMA_DATAALIGN_WORD;
hdma_spi_rx.Init.Mode = DMA_MODE_NORMAL_SINGLE;
hdma_spi_rx.Init.RequestSourceSel = DMA_REQUEST_SOURCE_SPI_RX;
__HAL_LINKDMA(hspi, hdmarx, hdma_spi_rx);
if (HAL_DMA_Init(&hdma_spi_rx) != HAL_OK)
{
Error_Handler();
}
HAL_NVIC_SetPriority(SPI_LS_IRQn, 1);
HAL_NVIC_EnableIRQ(SPI_LS_IRQn);
}
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{
__HAL_RCC_SPI_CLK_DISABLE();
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);
}
中断相关
在wm_it.c中
extern SPI_HandleTypeDef hspi;
extern DMA_HandleTypeDef hdma_spi_tx;
extern DMA_HandleTypeDef hdma_spi_rx;
__attribute__((isr)) void SPI_LS_IRQHandler(void)
{
HAL_SPI_IRQHandler(&hspi);
}
__attribute__((isr)) void DMA_Channel0_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_spi_tx);
}
__attribute__((isr)) void DMA_Channel1_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_spi_rx);
}
使用
DMA_Init();
SPI_Init();
__HAL_SPI_SET_CS_LOW(&hspi);
HAL_SPI_Transmit_DMA(&hspi, 数据首地址, 数据长度);
__HAL_SPI_SET_CS_LOW(&hspi);
HAL_SPI_Receive_DMA(&hspi, 缓冲区首地址, 数据长度);
注意事项
DataAlignment
在WM_SDK_W806_v0.6.0中,DMA的数据对齐方式DataAlignment和STM32的效果完全相反,不知道是否是有意为之:
所传数据为
当hdma_spi_tx.Init.DataAlignment = DMA_DATAALIGN_WORD时
波形正确
使用硬件I2C+DMA驱动相同的屏幕,在STM32中则为
若改为hdma_spi_tx.Init.DataAlignment = DMA_DATAALIGN_BYTE;
则波形错误
Direction
在WM_SDK_W806_v0.6.0中,外设到内存的宏和内存到外设的宏是一样的,有点奇怪
在STM32中则是不一样的:
测试
这里的测试程序见【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结
main.c
#include <stdio.h>
#include "wm_hal.h"
#include "oled.h"
SPI_HandleTypeDef hspi;
DMA_HandleTypeDef hdma_spi_tx;
void Error_Handler(void);
static void SPI_Init(void);
static void GPIO_Init(void);
static void DMA_Init(void);
uint16_t FPS = 0, FPS_Count = 0;
int main(void)
{
SystemClock_Config(CPU_CLK_240M);
GPIO_Init();
DMA_Init();
SPI_Init();
printf("enter main\r\n");
uint8_t i;
OLED_Init();
OLED_Clear();
OLED_Display_On();
OLED_ShowString(0, 0, " W806 OLED", 16, 0);
OLED_ShowString(0, 2, " 2022-01-25", 6, 0);
for(i = 0; i < 7; ++i)
OLED_ShowChinese(8 + 16 * i, 6, i, 1);
OLED_Refresh_Gram();
while (1)
{
++FPS_Count;
OLED_ShowString(0, 4, "FPS: ", 16, 0);
OLED_ShowNum(32, 4, FPS, 7, 16, 0);
OLED_Refresh_Gram();
}
}
static void SPI_Init(void)
{
hspi.Instance = SPI;
hspi.Init.Mode = SPI_MODE_MASTER;
hspi.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi.Init.NSS = SPI_NSS_SOFT;
hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi.Init.FirstByte = SPI_LITTLEENDIAN;
if (HAL_SPI_Init(&hspi) != HAL_OK)
{
Error_Handler();
}
}
static void GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = SSD1306_RES_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(SSD1306_RES_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = SSD1306_DC_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(SSD1306_DC_PORT, &GPIO_InitStruct);
}
static void DMA_Init(void)
{
__HAL_RCC_DMA_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA_Channel0_IRQn, 0);
HAL_NVIC_EnableIRQ(DMA_Channel0_IRQn);
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
}
void Error_Handler(void)
{
while (1)
{
}
}
void assert_failed(uint8_t *file, uint32_t line)
{
printf("Wrong parameters value: file %s on line %d\r\n", file, line);
}
wm_hal_msp.c
#include "wm_hal.h"
#include "oled.h"
extern DMA_HandleTypeDef hdma_spi_tx;
void Error_Handler(void);
void HAL_MspInit(void)
{
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
__HAL_RCC_SPI_CLK_ENABLE();
__HAL_AFIO_REMAP_SPI_CS(SSD1306_CS_PORT, SSD1306_CS_PIN);
__HAL_AFIO_REMAP_SPI_CLK(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
__HAL_AFIO_REMAP_SPI_MOSI(SSD1306_MOSI_PORT, SSD1306_MOSI_PIN);
hdma_spi_tx.Instance = DMA_Channel0;
hdma_spi_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi_tx.Init.DestInc = DMA_DINC_DISABLE;
hdma_spi_tx.Init.SrcInc = DMA_SINC_ENABLE;
hdma_spi_tx.Init.DataAlignment = DMA_DATAALIGN_WORD;
hdma_spi_tx.Init.Mode = DMA_MODE_NORMAL_SINGLE;
hdma_spi_tx.Init.RequestSourceSel = DMA_REQUEST_SOURCE_SPI_TX;
__HAL_LINKDMA(hspi, hdmatx, hdma_spi_tx);
if (HAL_DMA_Init(&hdma_spi_tx) != HAL_OK)
{
Error_Handler();
}
HAL_NVIC_SetPriority(SPI_LS_IRQn, 1);
HAL_NVIC_EnableIRQ(SPI_LS_IRQn);
}
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{
__HAL_RCC_SPI_CLK_DISABLE();
HAL_GPIO_DeInit(SSD1306_CS_PORT, SSD1306_CS_PIN);
HAL_GPIO_DeInit(SSD1306_SCK_PORT, SSD1306_SCK_PIN);
HAL_GPIO_DeInit(SSD1306_MOSI_PORT, SSD1306_MOSI_PIN);
}
wm_it.c
#include "wm_hal.h"
extern uint16_t FPS, FPS_Count;
extern SPI_HandleTypeDef hspi;
extern DMA_HandleTypeDef hdma_spi_tx;
#define readl(addr) ({unsigned int __v = (*(volatile unsigned int *) (addr)); __v;})
__attribute__((isr)) void CORET_IRQHandler(void)
{
static uint16_t ms_Count = 0;
readl(0xE000E010);
HAL_IncTick();
if(++ms_Count >= 1000)
{
ms_Count = 0;
FPS = FPS_Count;
FPS_Count = 0;
}
}
__attribute__((isr)) void SPI_LS_IRQHandler(void)
{
HAL_SPI_IRQHandler(&hspi);
}
__attribute__((isr)) void DMA_Channel0_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_spi_tx);
}
其他改动
实验现象
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)