目录
- 高速 SPI 设备控制器
- 库函数
- 函数
- 参数
- 宏
- 应用示例
- 初始化
- 引脚复用
- 中断相关
- 使用
- 注意事项
- DataAlignment
- Direction
- 测试
- 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);
//初始化SPI的工作模式和速率等HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi);
//将初始化之后的SPI接口恢复成默认的状态–各个寄存器复位时的值void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi);
//用于启用SPI时钟,引脚复用,配置DMA及中断优先级等void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi);
//用于禁用SPI时钟,将对应引脚恢复成默认的状态HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size, uint32_t Timeout);
//SPI发送数据,使用超时管理机制
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size, uint32_t Timeout);
//SPI接收数据,使用超时管理机制
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint32_t Size,uint32_t Timeout);
//SPI收发数据,使用超时管理机制 HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size);
//SPI中断模式发送
HAL_StatusTypeDef HAL_SPI_Receive_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size);
//SPI中断模式接收
HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,uint32_t Size);
//SPI中断模式收发HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size);
//SPI DMA模式发送
HAL_StatusTypeDef HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size);
//SPI DMA模式接收
HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,uint32_t Size);
//SPI DMA模式收发HAL_StatusTypeDef HAL_SPI_DMAPause(SPI_HandleTypeDef *hspi);
//SPI DMA传输暂停
HAL_StatusTypeDef HAL_SPI_DMAResume(SPI_HandleTypeDef *hspi);
//SPI DMA传输恢复
HAL_StatusTypeDef HAL_SPI_DMAStop(SPI_HandleTypeDef *hspi);
//SPI DMA传输停止void HAL_SPI_IRQHandler(SPI_HandleTypeDef *hspi);
//SPI 中断服务函数
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi);
//SPI 发送完毕回调函数
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi);
//SPI 接收完毕回调函数
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi);
//SPI 收发完毕回调函数
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);
//获取SPI传输状态
uint32_t HAL_SPI_GetError(SPI_HandleTypeDef *hspi);
参数
结构体和枚举类型
typedef struct
{uint32_t Mode; /*!< Specifies the SPI operating mode.This parameter can be a value of @ref SPI_Mode */uint32_t CLKPolarity; /*!< Specifies the serial clock steady state.This parameter can be a value of @ref SPI_Clock_Polarity */uint32_t CLKPhase; /*!< Specifies the clock active edge for the bit capture.This parameter can be a value of @ref SPI_Clock_Phase */uint32_t NSS; /*!< Specifies whether the NSS signal is managed byhardware (NSS pin) or by software using the SSI bit.This parameter can be a value of @ref SPI_Slave_Select_management */uint32_t BaudRatePrescaler; /*!< Specifies the Baud Rate prescaler value which will beused to configure the transmit and receive SCK clock.This parameter can be a value of @ref SPI_BaudRate_Prescaler@note The communication clock is derived from the masterclock. The slave clock does not need to be set. */uint32_t FirstByte; /* Specifies whether data transfers start from high byte or low byte.This parameter can be a value of @ref SPI_HBYTE_LBYTE_transmission */} SPI_InitTypeDef;typedef enum
{HAL_SPI_STATE_RESET = 0x00U, /*!< Peripheral not Initialized */HAL_SPI_STATE_READY = 0x01U, /*!< Peripheral Initialized and ready for use */HAL_SPI_STATE_BUSY = 0x02U, /*!< an internal process is ongoing */HAL_SPI_STATE_BUSY_TX = 0x03U, /*!< Data Transmission process is ongoing */HAL_SPI_STATE_BUSY_RX = 0x04U, /*!< Data Reception process is ongoing */HAL_SPI_STATE_BUSY_TX_RX = 0x05U, /*!< Data Transmission and Reception process is ongoing */HAL_SPI_STATE_ERROR = 0x06U, /*!< SPI error state */HAL_SPI_STATE_ABORT = 0x07U /*!< SPI abort is ongoing */
} HAL_SPI_StateTypeDef;typedef struct __SPI_HandleTypeDef
{SPI_TypeDef *Instance; /*!< SPI registers base address */SPI_InitTypeDef Init; /*!< SPI communication parameters */uint8_t *pTxBuffPtr; /*!< Pointer to SPI Tx transfer Buffer */uint32_t TxXferSize; /*!< SPI Tx Transfer size */__IO uint32_t TxXferCount; /*!< SPI Tx Transfer Counter */uint8_t *pRxBuffPtr; /*!< Pointer to SPI Rx transfer Buffer */uint32_t RxXferSize; /*!< SPI Rx Transfer size */__IO uint32_t RxXferCount; /*!< SPI Rx Transfer Counter */DMA_HandleTypeDef *hdmatx; /*!< SPI Tx DMA Handle parameters */DMA_HandleTypeDef *hdmarx; /*!< SPI Rx DMA Handle parameters */HAL_LockTypeDef Lock; /*!< Locking object */__IO HAL_SPI_StateTypeDef State; /*!< SPI communication state */__IO uint32_t ErrorCode; /*!< SPI Error code */} SPI_HandleTypeDef;
宏参数
#define SPI ((SPI_TypeDef *)SPI_BASE)#define HAL_SPI_ERROR_NONE (0x00000000U) /*!< No error */
#define HAL_SPI_ERROR_TXERR (0x00000001U) /*!< Tx error */
#define HAL_SPI_ERROR_RXERR (0x00000002U) /*!< Rx error */
#define HAL_SPI_ERROR_DMA (0x00000010U) /*!< DMA transfer error */// SPI_Mode
#define SPI_MODE_SLAVE (0x00000000U)
#define SPI_MODE_MASTER (SPI_SPI_CFG_MASTER)// SPI_Clock_Polarity
#define SPI_POLARITY_LOW (0x00000000U)
#define SPI_POLARITY_HIGH SPI_SPI_CFG_CPOL// SPI_Clock_Phase
#define SPI_PHASE_1EDGE (0x00000000U)
#define SPI_PHASE_2EDGE SPI_SPI_CFG_CPHA// SPI_Slave_Select_management
#define SPI_NSS_HARD (0x00000000U)
#define SPI_NSS_SOFT SPI_CH_CFG_CSSEL// SPI_HBYTE_LBYTE_transmission
#define SPI_LITTLEENDIAN (0x00000000U)
#define SPI_BIGENDIAN SPI_SPI_CFG_BIGENDIAN// fclk = 40MHz / (2 * (div + 1))
#define SPI_BAUDRATEPRESCALER_2 (0x00000000U) // 40M / 2 = 20M
#define SPI_BAUDRATEPRESCALER_4 (0x00000001U) // 40M / 4 = 10M
#define SPI_BAUDRATEPRESCALER_8 (0x00000003U) // 40M / 8 = 5M
#define SPI_BAUDRATEPRESCALER_10 (0x00000004U) // 40M / 10 = 4M
#define SPI_BAUDRATEPRESCALER_20 (0x00000009U) // 40M / 20 = 2M
#define SPI_BAUDRATEPRESCALER_40 (0x00000013U) // 40M / 40 = 1M#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; //分频系数 其中SPI时钟为40MHzhspi.Init.FirstByte = SPI_LITTLEENDIAN; //控制数据 MSB或LSBif (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(); //启用SPI时钟__HAL_AFIO_REMAP_SPI_CS(GPIOB, GPIO_PIN_4); //SPI引脚复用__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; //使用的DMA通道hdma_spi_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; //DMA传输方向 这里疑似有问题,见后文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; //DMA工作模式hdma_spi_tx.Init.RequestSourceSel = DMA_REQUEST_SOURCE_SPI_TX; //DMA请求源__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_BYTE;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);
}
其他改动
实验现象