NUCLEO-G0B1RE STM32G0B1RET6的学习(3)——SPI从DMA HAL库到应用层回调函数CallBack的定义

三篇初级学习有关Nucleo的板的文章,以下预留跳转其他文章的位置:

NUCLEO-G0B1RE STM32G0B1RET6的学习(1)------STM32CubeIDE的安装、新建工程和配置硬件SPI-CSDN博客

NUCLEO-G0B1RE STM32G0B1RET6的学习(2)------与W25Q32的SPI通信:读取ID、擦除、写和读/解决SPI通信使用模式3的首帧异常的问题-CSDN博客

NUCLEO-G0B1RE STM32G0B1RET6的学习(3)------SPI从DMA HAL库到应用层回调函数CallBack的定义-CSDN博客

本篇介绍SPI从DMA HAL库到应用层回调函数的定义,Los geht's~

目录

分析HAL库的回调函数调用

应用层回调函数CallBack的定义


分析HAL库的回调函数调用

本文所述SPI是有使用DMA的情况下,具体设置IOC可看前两篇博文

在传输完成后,会触发DMA中断,会调用就是以下函数:

void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)

回调的是hdma->XferCpltCallback(hdma);

通过查询功能,搜索XferCpltCallback,可以看到在以下函数定义中进行注册,

HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)

HAL_StatusTypeDef HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)

HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)

总结来说,我们调用HAL_SPI_Transmit_DMA函数,或调用HAL_SPI_Receive_DMA函数,或调用HAL_SPI_TransmitReceive_DMA函数来传输数据,就会把相应的回调函数SPI_DMATransmitCplt、SPI_DMAReceiveCplt、SPI_DMATransmitReceiveCplt的函数指针赋值给XferCpltCallback函数指针,然后在传输完成调用HAL_DMA_IRQHandler中断函数时,调用XferCpltCallback,通过函数指针,实际执行的是相应的回调函数SPI_DMATransmitCplt、SPI_DMAReceiveCplt、SPI_DMATransmitReceiveCplt(具体调用哪个回调函数,看一开始使用哪个传输数据的HAL库函数)

就以我在上两篇博文为例,我使用的是HAL_SPI_TransmitReceive_DMA来进行数据传输

那么对应的是SPI_DMATransmitReceiveCplt函数,在通过搜索该函数,查看其定义:

最终调用的是HAL_SPI_TxRxCallback(hspi);

关系如下:

|-----------------------------------------------------------------|-----------------------------|
| 调用关系(定义中调用) | 注册点(函数指针赋值) |
| HAL_DMA_IRQHandler | |
| ↓ | |
| hdma->XferCpltCallback(只是函数指针) 实际调用 SPI_DMATransmitReceiveCplt | HAL_SPI_TransmitReceive_DMA |
| ↓ | |
| HAL_SPI_TxRxCpltCallback | |

在传输完成后,通过DMA中断的调用,最终运行HAL_SPI_TxRxCallback回调函数定义的程序

所以,通过对使用哪个传输数据的HAL库函数对应的回调函数进行重写就可以做到在传输完成后,运行某一段想要运行的代码,比如SPI用户自定义的状态变化,就可以做超时判断等等,完善代码,不必在while中死等

就以我在上两篇博文为例,我使用的是HAL_SPI_TransmitReceive_DMA来进行数据传输,最终在spi.c中,重写HAL_SPI_TxRxCallback来达到回调的效果,在传输完成后,就会运行HAL_SPI_TxRxCallback函数中定义的程序

应用层回调函数CallBack的定义

spi.c可以说是属于驱动层,在实际使用中,spi调通后,不会动spi.c这一层的程序(这一层一般是初始化、基础的发送接收程序编写等等),会偏向在main.c或其他.c,这一应用层来编写用户自定义的程序,不直接调用HAL库的函数,比如用户的回调函数、发送和接收具体的温度、湿度、压力等等数据,所以会希望main.c中可以定义用户的回调函数。

那么就可以类似HAL库定义和调用回调函数的方法,来写应用层定义和调用回调函数。

关系如下:

|--------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------|
| 调用关系(定义中调用) | 注册点(函数指针赋值) |
| HAL_SPI_TxRxCpltCallback(spi.c中定义的函数) | |
| ↓ | |
| SPI_TxRxCallBack (spi.c中定义的函数指针变量) 实际调用 TxRxCallBack(main.c中定义的函数) | MX_SPI1_Init(spi.c中定义的函数) 实际调用 SPI_TxRxCb(spi.c中定义的函数) (如果简化的话,可以直接MX_SPI1_Init中注册,不必定义SPI_TxRxCb这一函数) |

具体代码(只体现回调函数部分的内容,注意程序要写在提示的USER CODE BEGIN和USER CODE END之间):

spi.c:

cpp 复制代码
static void (*SPI_TxRxCallBack)(SPI_HandleTypeDef* hspi) = NULL;
void SPI_TxRxCb(void(*txrxCallBack)(SPI_HandleTypeDef* hspi));

void MX_SPI1_Init(void)
{

...

  /* USER CODE BEGIN SPI1_Init 2 */

  SPI_TxRxCb(TxRxCallBack);
  /* USER CODE END SPI1_Init 2 */

}

/* USER CODE BEGIN 1 */

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
	if(SPI_TxRxCallBack != NULL)
	{
		SPI_TxRxCallBack(&hspi1);
	}
}

void SPI_TxRxCb(void(*txrxCallBack)(SPI_HandleTypeDef *hspi))
{
	SPI_TxRxCallBack = txrxCallBack;
}

/* USER CODE END 1 */

main.h

cpp 复制代码
void TxRxCallBack(SPI_HandleTypeDef *hspi);

main.c

cpp 复制代码
void TxRxCallBack(SPI_HandleTypeDef *hspi)
{
	//在完成发送生接收后的回调函数,可放应用层调用
	uint8_t a = 0;

	a = 1;
}

最后,在TxRxCallBack函数中增加断点,可以结合逻辑分析仪看,逻辑分析仪只扫描到了一帧数据,断点停在了TxRxCallBack函数中

工程文件(不过还是建议从第一篇博文开始自己搭工程):

https://download.csdn.net/download/dlwlrma_516/92270754

相关推荐
逐步前行5 小时前
STM32_标准库结构
stm32·单片机·嵌入式硬件
Hello_Embed5 小时前
libmodbus STM32 主机实验(USB 串口版)
笔记·stm32·学习·嵌入式·freertos·modbus
不做无法实现的梦~6 小时前
PX4各个模块的作用(3)
linux·stm32·嵌入式硬件·机器人·自动驾驶
不能跑的代码不是好代码6 小时前
STM32独立看门狗(IWDG)知识点及标准库使用指南
stm32·嵌入式硬件
-Springer-7 小时前
STM32 学习 —— 个人学习笔记5(EXTI 外部中断 & 对射式红外传感器及旋转编码器计数)
笔记·stm32·学习
xuxg20051 天前
4G 模组 AT 命令解析框架课程正式发布
stm32·嵌入式·at命令解析框架
CODECOLLECT1 天前
京元 I62D Windows PDA 技术拆解:Windows 10 IoT 兼容 + 硬解码模块,如何降低工业软件迁移成本?
stm32·单片机·嵌入式硬件
BackCatK Chen1 天前
STM32+FreeRTOS:嵌入式开发的黄金搭档,未来十年就靠它了!
stm32·单片机·嵌入式硬件·freertos·低功耗·rtdbs·工业控制
全栈游侠1 天前
STM32F103XX 02-电源与备份寄存器
stm32·单片机·嵌入式硬件
辰哥单片机设计1 天前
STM32项目分享:车辆防盗报警系统
stm32·单片机·嵌入式硬件