逐步debug DMA发送函数,HAL_UART Transmit DMA,发现函数会对串口句柄的一个状态位,gState 进行判断,只有在 huart->gState==HAL UART STATE READY 的时候才会正常进行发送,而第一次发送可以成功,便是因为一开始,gState为HAL_UART_STATE_READY,因此,可以成功发送,而在第一次发送时,HAL_UART_Transmit_DMA 函数会将gState 更改为HAL_UART_STATE_BUSY_TX 状态,gState 位随后一直保持为HAL_UART_STATE_BUSY_TX状态,导致后面的发送无法执行,而gState 状态想要被清除必须要进入串口中断HAL_UART_IRQHandler中的UART_EndTransmit_IT里面,在UART_EndTransmit_IT函数中清除了gState标志位。 我的问题就是串口中断只能第一次进入,后面就不进入了,所以发送失败。在调试的时候偶尔能发送和接收都正常,各位能帮忙给点建议吗?下面是我的代码:
主程序开始调用函数HAL_UARTEx_ReceiveToIdle_DMA(&huart3, usart3RxBuff, MAX_COM3_RXSIZES); 发送调用的函数为HAL_UART_Transmit_DMA(huart, (const uint8_t *)buf, num);调试时buf和num都是正确的,发出去就没有数据。如果不使用DMA发送的话,那么接收的时候就会进入HAL_UART_ErrorCallback错误回调。 |
求教,STM32 LCD驱动段码屏,SEG1-SEG8,可以不连续配置吗?
STM32L431进入STOP1模式后ADC产生多余功耗
STM32L431在去掉注释memcpy后会不断重启
SPI 通信,既有单字节数据传输,又有多字节数据传输,该如正确使用 DMA?
STM32G0B1adc+dma采样数据错位
STM32F4的串口在配置DMA之后,不能使用高波特率吗?
STM32L431在STOP2模式下能否将串口的RX配置成EXTI唤醒呢?为什么我的唤醒不了呢?并且空闲中断也不能用
怎么将HAL库转为LL库。
stm32 DMA串口接收到数组,数组元素顺序错乱怎么办?
STM32L4R9OSPI接口测试
在STM32HAL库里定义很多状态变量,用于对各自外设模块的状态管理,比方ready,busy,idle,timeout,error等,
以便正确使用各个外设,避免使用上的混乱。
以usart为例,库里为USART的发送、接收操作分别定义了两个状态变量,即gState和RxState。其中gState表示USART的发送状态,RxState表述接收时可能的状态。
是ready还是busy或其它出错、超时状态。USART初始化后gState为reddy状态,当要调用UART发送函数时软件将其设置为Busy.
当usart完成发送或中止发送时,软件将gState设置回Ready。
如果说你调用的查询式发送函数,即HAL_UART_Transmit(),则在该函数里查询到数据发送完毕或发生超时都会将gState设置为Ready.
如果说你调用的是中断式发送函数,即HAL_UART_Transmit_IT(),同时你沿用CubeMx创建的中断服务程序代码框架,在相应的发送中断服务程序
里检测到发送完毕时,也会将gState修改为ready为下次发送做准备。 如果说你调用API函数是HAL_UART_Transmit_IT(),而中断服务程序是另外组织的,
要记得在发送完成时将gState改为Ready,不然下次调用HAL_UART_Transmit_IT()函数会因为gstate检查不通过而不能得以执行。
如果说你调用的是DMA方式发送函数,即HAL_UART_Transmit_DMA(),同样,也沿用CubeMx创建的中断服务程序代码框架,且开启了DMA完成中断和UART事件的中断,
在相应的DMA完成中断代码里也会适时地将gState从busy改为ready。如果说,你虽然调用了HAL_UART_Transmit_DMA()函数,但没有开启DMA完成中断,
也没有在适当的位置将gState改为ready,这时就会发生即使你多次调用HAL_UART_Transmit_DMA()函数而只会做一次发送的情形。因为在后续的
HAL_UART_Transmit_DMA()函数里做gState检查发现是busy而强行退出。当然,这时手动将其改为Ready也是可以的,但要保证合适的时间点。
比方,我就是不想开启DMA相关中断,只是想通过DMA方式发送几次字符串而已,像下面这样
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)String1, sizeof(String1));
HAL_Delay(200);
huart2.gState = HAL_UART_STATE_READY;
huart2.hdmatx->State = HAL_DMA_STATE_READY;
__HAL_UNLOCK(huart2.hdmatx);
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)String2, sizeof(String2));
HAL_Delay(200);
huart2.gState = HAL_UART_STATE_READY;
huart2.hdmatx->State = HAL_DMA_STATE_READY;
__HAL_UNLOCK(huart2.hdmatx);
当然,这里还有一种情况,尽管当我们基于中断或DMA方式调用UART发送,也开启了相关中断并沿用库函数的写法,还是可能出现只有第一次发送有效的
情况,比方像下面这样:
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)String1, sizeof(String1));
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)String2, sizeof(String2));
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)String3, sizeof(String3));
这里的三次调用太近了,第一次调用时软件将gstate改为busy,当运行第二个第三个调用时,第一次的uart发送可能根本没有完成,自然也就没法
基于它的完成中断将gstate改为ready,这样导致后续的两次调用都无效了。所以像这种情况,第二次调用前要确保上次传输完成了。
整体上,上面分析了两种可能的情形,请结合你的代码检查下,看看是哪种原因或是还是别的什么原因。
DMA发送函数只能第一次调用有效?
我后面全部改成了不用DMA的方式了,哈哈哈哈,然后后面想了想我可能知道是哪里的问题了,我是在循环着调用DMA的发送函数,也有发送完成中断的,但是并没有在发送完成中断中将gState改为ready,但是我从代码的执行过程里面看到,他应该不需要自己手动的去设置,因为只要能够进入串口的中断
HAL_UART_IRQHandler
,在这里面就会调用UART_EndRxTransfer
,这个函数就会将gState改为ready,我的问题可能就是没有判断发送是否完成就继续下一次发送了,因为时间问题,我并没有深入去查找,不用DMA现在看来是一切正常了,谢谢你的解释还有个问题我想请教你一下,就是我使用STM32L431进入STOP1模式,原始功耗为53uA。在进入停止模式之前,我调用HAL_ADC_DeInit(&hadc1)禁用ADC,并在退出STOP1模式后调用MX_ADC1_Init()重新启用ADC。测量的功耗为66uA,大约多出10uA。为什么呢?如果退出STOP1模式后不调用MX_ADC1_Init(),功耗仍为53uA。是因为ADC会产生功耗吗?应该不会的吧。
下面是我的进入和退出STOP模式的函数:
[md]https://shequ.stmicroelectronics.cn/thread-644680-1-1.html