寒号鸟 发表于 2019-7-19 10:19:29

Freertos 下的__HAL_LOCK(stm32)问题

最近发现一个问题,stm32 的HAL库中有__HAL_LOCK和__HAL_UNLOCK
在串口发送和接受函数中都存在,但是这样一来,串口就无法全双工了
#define __HAL_LOCK(__HANDLE__)                                           \
                              do{                                        \
                                    if((__HANDLE__)->Lock == HAL_LOCKED)   \
                                    {                                    \
                                       return HAL_BUSY;                  \
                                    }                                    \
                                    else                                 \
                                    {                                    \
                                       (__HANDLE__)->Lock = HAL_LOCKED;    \
                                    }                                    \
                                  }while (0U)

#define __HAL_UNLOCK(__HANDLE__)                                          \
                                  do{                                       \
                                    (__HANDLE__)->Lock = HAL_UNLOCKED;    \
                                    }while (0U)

而在LWIP应用中,也有这样的问题,
low_level_output函数调用
HAL_StatusTypeDef HAL_ETH_TransmitFrame(ETH_HandleTypeDef *heth, uint32_t FrameLength)
{
uint32_t bufcount = 0, size = 0, i = 0;

/* Process Locked */
__HAL_LOCK(heth);

这样的话,因为接受数据是在单独的线程中,如果要发送的时候正在接受,那么是不是意味着发送就莫名其妙的失败了,而且不是tcp的话,还不能重发

missfox 发表于 2019-7-19 11:14:55

HAL库的锁机制不支持RTOS,而且不支持嵌套,是在接收的时候直接将其又开锁了。

我分析是这样,楼主看看对不对,以lwip为例
发送:
low_level_output ->HAL_ETH_TransmitFrame

接收接收中断:
HAL_ETH_IRQHandler -> 中断函数里面接收完成回调发送信号量 -> 中断函数结束时直接开锁了->等待信号量函数ethernetif_input ->low_level_input ->low_level_input->HAL_ETH_GetReceivedFrame_IT


由于接收在中断里面强行开启了锁,所以就不存在你说的发送时加上了锁后对接收的影响。




寒号鸟 发表于 2019-7-19 11:46:04

missfox 发表于 2019-7-19 11:14
HAL库的锁机制不支持RTOS,而且不支持嵌套,是在接收的时候直接将其又开锁了。

我分析是这样,楼主看看 ...

还是会存在影响的,接受是在单独的进程里面的
osThreadDef(EthIf, ethernetif_input, osPriorityRealtime, 0, INTERFACE_THREAD_STACK_SIZE);
osThreadCreate (osThread(EthIf), netif);

所以在其他进程里面发送数据,那么HAL_LOCK有被同时调用的风险(并发风险),但接受在一个while函数里面,所以影响不大
for( ;; )
{
    if (osSemaphoreWait( s_xSemaphore, TIME_WAITING_FOR_INPUT)==osOK)
    {
      do
      {   
      p = low_level_input( netif );
      if   (p != NULL)
      {
          if (netif->input( p, netif) != ERR_OK )
          {
            pbuf_free(p);
          }
      }
      } while(p!=NULL);
    }
}

但发送就可能受到影响

missfox 发表于 2019-7-19 12:05:45

寒号鸟 发表于 2019-7-19 11:46
还是会存在影响的,接受是在单独的进程里面的
osThreadDef(EthIf, ethernetif_input, osPriorityRealti ...

这个处理办法就简单很多了,提升接收任务的优先级可解决。

接收任务的优先级高,就不会存在发送被影响的情况。

寒号鸟_SyD58 发表于 2019-7-19 14:37:28

理解了,谢谢

寒号鸟_SyD58 发表于 2019-7-19 14:37:59

missfox 发表于 2019-7-19 12:05
这个处理办法就简单很多了,提升接收任务的优先级可解决。

接收任务的优先级高,就不会存在发送被影响 ...

理解了,谢谢

寒号鸟_SyD58 发表于 2019-7-20 10:09:20

missfox 发表于 2019-7-19 12:05
这个处理办法就简单很多了,提升接收任务的优先级可解决。

接收任务的优先级高,就不会存在发送被影响 ...

我今天思考了一下,发现还是会存在一种情况,您看我的想法是否合理

如果正在发送中(__HAL_locked已经加锁),突然来了一个接受中断(中断里面),
void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
{
osSemaphoreRelease(s_xSemaphore);
}
然后接受函数被运行(接受函数的优先级高)
void ethernetif_input( void const * argument )
{
   。。。。。
    if (osSemaphoreWait( s_xSemaphore, TIME_WAITING_FOR_INPUT)==osOK)
    {
      do
      {
      p = low_level_input( netif );
      if (p != NULL)
      {
          if (netif->input( p, netif) != ERR_OK )
          {
            pbuf_free(p);
          }
      }
      }while(p!=NULL);
    }
}
}
但是这个时候,注意发送函数正在发送(__HAL_LOCKD已经刚刚被发送加锁了),所以low_level_input肯定返回NULL(因为HAL_ETH_GetReceivedFrame_IT的HAL_LOCK返回busy,自然该函数会返回NULL),这样一来本次接收不就失败了嘛,本次的包就没有了

missfox 发表于 2019-7-20 10:12:25

寒号鸟_SyD58 发表于 2019-7-20 10:09
我今天思考了一下,发现还是会存在一种情况,您看我的想法是否合理

如果正在发送中(__HAL_locked已经 ...
二楼已经回复你这种情况,在ETH中断接收处理函数里面已经开锁了。看下中断函数就明白了
页: [1]
查看完整版本: Freertos 下的__HAL_LOCK(stm32)问题