你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

DMA发送函数只能被调用一次

[复制链接]
Alf·Romeo 提问时间:2024-11-15 15:23 / 已解决

逐步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标志位。 我的问题就是串口中断只能第一次进入,后面就不进入了,所以发送失败。在调试的时候偶尔能发送和接收都正常,各位能帮忙给点建议吗?下面是我的代码:

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART3)
  {
    if (HAL_UARTEx_ReceiveToIdle_DMA(&huart3, usart3RxBuff, MAX_COM3_RXSIZES) == HAL_BUSY) // 接收发生错误后重启
    {
      __HAL_UART_CLEAR_OREFLAG(&huart3);
      huart3.RxState = HAL_UART_STATE_READY;
      huart3.Lock = HAL_UNLOCKED;
      HAL_UARTEx_ReceiveToIdle_DMA(&huart3, usart3RxBuff, MAX_COM3_RXSIZES);
    }
    initSqQueue(&uart[_COM3].Rx, usart3RxBuff, sizeof(usart3RxBuff));
    memset(usart3RxBuff, 0, MAX_COM3_RXSIZES);
    return;
  }
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
  if (huart->Instance == USART3)
  {
    uart[_COM3].Rx.rear = Size; // 写入rear
                                // bleAppConfig.rxAct = 1;
#ifdef _UART3_DEBUG
    uartxEcho(&huart3, &uart3);
#endif
    if (uart[_COM3].rxEnd == true)
    {
      uart[_COM3].rxIdle = false;
      initUartTick(&uart[_COM3], CONST_UART_DLY_TIM);
    }
    else
    {
      uart[_COM3].rxIdle = true;
      initUartTick(&uart[_COM3], CONST_UART_DLY_TIM);
      // MAP_Interrupt_disableSleepOnIsrExit();
    }
    return;
  }
  UNUSED(huart);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART3)
  {
    uart[_COM3].sBusy = false;
#ifdef MAX_COM3_TXSIZES
    memset(usart3TxBuff, 0, MAX_COM3_TXSIZES);
#endif
    return;
  }
  UNUSED(huart);
}

主程序开始调用函数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错误回调。

收藏 评论5 发布时间:2024-11-15 15:23

举报

5个回答
xmshao 最优答案 回答时间:2024-11-18 15:35:02
这个话题说起来有点长。


在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事件的中断,

rrr.png


在相应的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发送函数只能第一次调用有效?

butterflyspring 回答时间:2024-11-15 17:29:45
根据你的描述,可以看看第二次为什么串口中断不执行,看寄存器配置是否被哪里修改了导致中断不能进入。
Alf·Romeo 回答时间:2024-11-22 15:07:24

xmshao 发表于 2024-11-18 15:35
这个话题说起来有点长。</p>
<p>

我后面全部改成了不用DMA的方式了,哈哈哈哈,然后后面想了想我可能知道是哪里的问题了,我是在循环着调用DMA的发送函数,也有发送完成中断的,但是并没有在发送完成中断中将gState改为ready,但是我从代码的执行过程里面看到,他应该不需要自己手动的去设置,因为只要能够进入串口的中断HAL_UART_IRQHandler,在这里面就会调用UART_EndRxTransfer,这个函数就会将gState改为ready,我的问题可能就是没有判断发送是否完成就继续下一次发送了,因为时间问题,我并没有深入去查找,不用DMA现在看来是一切正常了,谢谢你的解释

Alf·Romeo 回答时间:2024-11-22 15:13:46

xmshao 发表于 2024-11-18 15:35
这个话题说起来有点长。</p>
<p>

还有个问题我想请教你一下,就是我使用STM32L431进入STOP1模式,原始功耗为53uA。在进入停止模式之前,我调用HAL_ADC_DeInit(&hadc1)禁用ADC,并在退出STOP1模式后调用MX_ADC1_Init()重新启用ADC。测量的功耗为66uA,大约多出10uA。为什么呢?如果退出STOP1模式后不调用MX_ADC1_Init(),功耗仍为53uA。是因为ADC会产生功耗吗?应该不会的吧。

下面是我的进入和退出STOP模式的函数:

void EnterStop2ModeRTC(void)
{
  HAL_RCCEx_WakeUpStopCLKConfig(RCC_STOP_WAKEUPCLOCK_MSI);
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
  __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF);
  __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG();
  __HAL_RTC_TIMESTAMP_CLEAR_FLAG(&hrtc, RTC_FLAG_TSF);
  __HAL_RTC_TAMPER_TIMESTAMP_EXTI_CLEAR_FLAG();
  HAL_ADC_DeInit(&hadc1);
  HAL_SuspendTick();
  // __HAL_RCC_DMA1_CLK_DISABLE();
  cpuStopFlg = true;
  SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
  __HAL_RCC_PWR_CLK_ENABLE();
  HAL_PWREx_EnterSTOP1Mode(PWR_STOPENTRY_WFI); 
}

void ExitStop2ModeRTC(void)
{
  SystemClock_Config();
  HAL_ResumeTick();
  MX_ADC1_Init();
  cpuStopFlg = false;
}
xmshao 回答时间:2024-11-22 16:59:30

Alf·Romeo 发表于 2024-11-22 15:13
还有个问题我想请教你一下,就是我使用STM32L431进入STOP1模式,原始功耗为53uA。在进入停止模式之前 ...

[md]https://shequ.stmicroelectronics.cn/thread-644680-1-1.html

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版