【联盛德W806上手笔记】八、SPI及其DMA

目录

  • 高速 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);
}

其他改动

在这里插入图片描述

在这里插入图片描述

实验现象

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/400091.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安装配置 radicale

为什么80%的码农都做不了架构师&#xff1f;>>> 可以直接pip安装,也可以下载源码安装,如果要存储到sql里面,则需要下载源码包,用里面的schema.sql 建表 默认安装后没有相应的配置文件,源码包里面也包含了 logging 和config,放到/etc/radicale 下 安装没什么说的,下…

散分,并如何判断时间段上有重叠冲突。

比如某个会议室的预订信息表 roomBookInfo(id,title,beginTime,endTime), 现在有一个新的预订请求 bTime, eTIme 分别 代表 开始、结束时间。请检查下表中的记录&#xff0c;查看是否有时间上的冲突。create table roomBookInfo (id int auto_increment primary key, title var…

wordpress 根据文章ID获取分类ID和标签ID

//wordpress 根据文章ID获取分类ID $categoryget_the_category( $post_ID ); $catid$category[0]->term_id; //wordpress 根据文章ID获取标签ID $tagswp_get_post_tags( $post_ID ); $tagid$tags[0]->term_id; 查看完整内容&#xff1a;http://web.zhaicool.net/366…

实现复选框的单选效果

<!DOCTYPE><html><head><title>实现复选框的单选效果</title></head><body><form methodpost action""><input type"checkbox" name"aa" οnclick"bb(this)"><input type&q…

【联盛德W806上手笔记】九、DMA

目录DMA 控制器功能概述功能描述DMA 通道DMA 数据流DMA 循环模式DMA 传输模式DMA 外设选择DMA 链表模式DMA 中断中断请求库函数函数参数宏应用Windows 10 20H2 HLK-W806-V1.0-KIT WM_SDK_W806_v0.6.0 摘自《W806 MCU 芯片规格书 V2.0》、《WM_W800_寄存器手册 V2.1》 DMA 控制…

MySql创建一个存储过程

MySQL 存储过程是从 MySQL 5.0 新功能。存储过程的长处有一箩筐。只是最基本的还是运行效率和SQL 代码封装。特别是 SQL 代码封装功能&#xff0c;假设没有存储过程&#xff0c;在外部程序訪问数据库时&#xff08;比如 PHP&#xff09;&#xff0c;要组织非常多 SQL 语句。特别…

attr与prop的区别

我们在获取checked属性值的时候&#xff0c;如果被选中则值为"checked"没选中获取值就是undefined. &#xff08;引述他人&#xff09;因为在有些浏览器中比如说只要写disabled&#xff0c;checked就可以了&#xff0c;而有的要写成disabled "disabled"&a…

定制化WordPress后台的6个技巧

WordPress后台并非千篇一律&#xff0c;你可以通过一些代码定制化一个你喜欢的后台&#xff0c;本文所述代码都应写在主题的functions.PHP中。 移除后台某些菜单 如果你不想客户因为点了错误的菜单选项而删除付费主题&#xff0c;或者搞乱后台的设置&#xff0c;那么把你不希望…

SNF快速开发平台MVC-自由排序组件

1. 自由排序功能使用 在一些需要排序优先级的数据进行调整处理&#xff0c;如民族数据&#xff0c;在北方实施的时候汉族比较多&#xff0c;希望把汉族放在第一位。在蒙古实施项目时&#xff0c;蒙古族人最多把蒙古族放在第一选择位。 1.1. 效果展示 图 1.1 1.2. …

Tip:强制执行exchange DAG节点之间的数据库副本移动

当exchange后端服务器MBX的小版本号不一致&#xff0c;比如都是exchange 2010 SP3 RU8的版本&#xff0c;但是小版本号不一致&#xff0c;这个时候我们去运行平衡exchange DAG分布的脚本的时候&#xff0c;低版本服务器上面的DAG数据库可能无法正常转移到优选节点&#xff0c;这…

系统边界确定

先说说系统边界的确定。这是在工程开发中紧接着需求分析的第二步。顾名思意&#xff0c;这个过程就是要确定我们要开发的系统和外部环境之间的界限&#xff0c;也就是要区分系统本身和它的外部环境。其中的外部环境可能包括用户,其它系统,软硬件条件等。 举个例子&#xff0c;一…

【联盛德W806上手笔记】十、ADC

目录ADCADC 电路设计库函数函数参数宏Demo中的例程main.cwm_hal_msp.cwm_it.cWindows 10 20H2 HLK-W806-V1.0-KIT WM_SDK_W806_v0.6.0 摘自《W806 芯片设计指导书 V1.0》、《W806 MCU 芯片规格书 V2.0》 ADC 基于 Sigma-Delta ADC 的采集模块&#xff0c;集成 4 路 16 比特 AD…

php导入excel到mysql的方法

PhpSpreadsheet 实测 1. https://phpspreadsheet.readthedocs.io/en/latest/ 2 . 查看 phpinfo() 时&#xff0c;发现 php_zip 没有启动 , PHP如何开启自带的ZipArchive类&#xff0c;实现压缩解压功能 [转载]phpspreadsheet开发手记 使用PhpSpreadsheet导入&导出Excel&…

delphi中TStringGrid数据的导出

没什么好说的&#xff0c;就是一个导出Excel的功能&#xff0c;代码如下&#xff1a; function TExportToExcel.Export(SGrid_List: TStringGrid;filename:string;out Errstr:string): Boolean; varexcelapp:Variant;page:Variant;i,j:Integer;savedialog:TSaveDialog;strsavef…

常用插件整理

easydialog&#xff0c;简单易用的模态对话框弹窗 http://www.h-ui.net/easydialog-v2.0/index.html superslide&#xff0c;非常好用的电脑端滚动切换等特效插件 http://www.superslide2.com/ swiper&#xff0c;非常好用且完善的手机端滚动触摸滑动特效插件 http://www.swipe…

【电路补习笔记】8、稳压电路 —— 线性电源及LDO

目录有名的电源芯片品牌DCDC电源分类开关电源vs线性稳压器线性电源参数线性电源工作原理集成稳压器78/79系列&#xff08;固定输出电压&#xff09;正、负对称输出两组电源的稳压电路扩展输出电压扩大输出电流LM317/LM337&#xff08;可调输出电压&#xff09;正、负对称输出两…

ajax代码整理

$.ajax({ type: "post", 【以POST或GET的方式请求。默认GET。PUT和DELETE也可以用&#xff0c;有的浏览器不支持】 url: url, 【请求的目的地址&#xff0c;须是一个字符串。】 contentType: "application/json", 【以哪种数据类型发送请求】 data: data, …

创建一个简单的WCF程序

为了使读者对基于WCF的编程模型有一个直观的映像&#xff0c;我将带领读者一步一步地创建一个完整的WCF应用。本应用功能虽然简单&#xff0c;但它涵盖了一个完整WCF应用的基本结构。对那些对WCF不是很了解的读者来说&#xff0c;这个例子将带领你正式进入WCF的世界。 在这个例…

交换机应用之端口模式(access、trunk和hybird)、是否标记(tag、untag)、端口缺省vlan(pvid、native id)...

一、概述打不打标记Tag&#xff0c;untag以及交换机的各种端口模式是网络工程技术人员调试交换机时接触最多的概念了。标记tag就是指VLAN的标签&#xff0c;数据包属于哪个VLAN的。交换机三种端口模式Access vlan、Trunk vlan和Hybrid vlan三种&#xff0c;即以太网端口有三种链…

深圳IO —— 一个汇编编程小游戏

目录简介数据手册接口简单 I/OXBus简单 I/O 对比 XBus语言参考程序结构注释标签寄存器accdatp0、p1、x0、x1、x2、x3null 伪寄存器指令操作数确保进行足够的睡眠 (slp)&#xff01;基本指令算法指令条件指令隐藏指令游戏界面DIY版本&#xff1a; 简介 以下介绍摘自未来软件园 …