any012 发表于 2017-1-20 15:48:54

__HAL_LOCK()这个函数有什么用?

比如串口,串口类型UART_HandleTypeDef的定义有Lock这个变量,其类型是下面这个枚举。
typedef enum
{
HAL_UNLOCKED = 0x00,
HAL_LOCKED   = 0x01
} HAL_LockTypeDef;

串口接收/发送,或者中断模式接收/发送,都是先设置__HAL_LOCK(),然后配置huart,配置完后再__HAL_UNLOCK()。但感觉这个Lock没什么用啊。
接受过程中及中断里都没有涉及到这个变量,也许是我没找到。

zoomdy 发表于 2017-1-20 15:48:55

以STM32F4系列为例
__HAL_LOCK和__HAL_UNLOCK定义在Drivers/STM32F4xx_HAL_driver/Inc/stm32f4xx_hal_def.h头文件中(假设是Cube生成的工程)。
#define __HAL_LOCK(__HANDLE__)                                           \
                              do{                                        \
                                    if((__HANDLE__)->Lock == HAL_LOCKED)   \
                                    {                                    \
                                       return HAL_BUSY;                  \
                                    }                                    \
                                    else                                 \
                                    {                                    \
                                       (__HANDLE__)->Lock = HAL_LOCKED;    \
                                    }                                    \
                                  }while (0)

#define __HAL_UNLOCK(__HANDLE__)                                          \
                                  do{                                       \
                                    (__HANDLE__)->Lock = HAL_UNLOCKED;    \
                                    }while (0)
通过代码可以看出__HAL_LOCK的作用是判断被操作的__HANDLE__是否已经加锁,如果已经加锁那么返回忙,并立即推出函数,如果未加锁,那么执行加锁。__HAL_UNLOCK则是解锁。

举个DMA操作的例子,调用HAL_DMA_Start启动一次DMA传输,在本次传输结束前不允许开始第二次DMA传输,因此HAL_DMA_Start操作执行了__HAL_LOCK进行加锁,在解锁前调用HAL_DMA_Start会返回HAL_BUSY而不会执行DMA操作。接下来调用HAL_DMA_PollForTransfer来轮询DMA是否操作完成,一旦HAL_DMA_PollForTransfer函数检测到DMA操作完成或发生错误,那么会调用__HAL_UNLOCK解锁,解锁之后才能进行下一次DMA请求。
HAL_StatusTypeDef HAL_DMA_Start(...)
{
HAL_StatusTypeDef status = HAL_OK;

/* Check the parameters */
assert_param(IS_DMA_BUFFER_SIZE(DataLength));

/* Process locked */
__HAL_LOCK(hdma);
...
}
调用HAL_DMA_Start会在函数的开头调用__HAL_LOCK,假如DMA已经被开启了,那么这条语句将立即返回HAL_BUSY,否则标记DMA为加锁状态,并继续下面的代码。
HAL_StatusTypeDef HAL_DMA_PollForTransfer(...)
{
...

if(HAL_DMA_STATE_BUSY != hdma->State)
{
    /* No transfer ongoing */
    hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
    __HAL_UNLOCK(hdma);
    return HAL_ERROR;
}

...

while(((tmpisr & mask_cpltlevel) == RESET) && ((hdma->ErrorCode & HAL_DMA_ERROR_TE) == RESET))
{
    /* Check for the Timeout (Not applicable in circular mode)*/
    if(Timeout != HAL_MAX_DELAY)
    {
      if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout))
      {
      /* Update error code */
      hdma->ErrorCode = HAL_DMA_ERROR_TIMEOUT;

      /* Process Unlocked */
      __HAL_UNLOCK(hdma);
      
      /* Change the DMA state */
      hdma->State = HAL_DMA_STATE_READY;
      
      return HAL_TIMEOUT;
      }
    }

...
}

if(hdma->ErrorCode != HAL_DMA_ERROR_NONE)
{
    if((hdma->ErrorCode & HAL_DMA_ERROR_TE) != RESET)
    {
      HAL_DMA_Abort(hdma);
   
      /* Clear the half transfer and transfer complete flags */
      regs->IFCR = (DMA_FLAG_HTIF0_4 | DMA_FLAG_TCIF0_4) << hdma->StreamIndex;
   
      /* Process Unlocked */
      __HAL_UNLOCK(hdma);

      /* Change the DMA state */
      hdma->State= HAL_DMA_STATE_READY;

      return HAL_ERROR;
   }

}

/* Get the level transfer complete flag */
if(CompleteLevel == HAL_DMA_FULL_TRANSFER)
{
    /* Clear the half transfer and transfer complete flags */
    regs->IFCR = (DMA_FLAG_HTIF0_4 | DMA_FLAG_TCIF0_4) << hdma->StreamIndex;
   
    /* Process Unlocked */
    __HAL_UNLOCK(hdma);

    hdma->State = HAL_DMA_STATE_READY;
}
else
{
    /* Clear the half transfer and transfer complete flags */
    regs->IFCR = (DMA_FLAG_HTIF0_4) << hdma->StreamIndex;
}

return status;
}
HAL_DMA_PollForTransfer会根据当前的DMA状态在适当的时机调用__HAL_UNLOCK解锁。

海迹天涯 发表于 2017-1-20 16:03:34

有用的,不知道你用过F0系列没有,F0的HAL库里面调用更新时间函数后时间不更新,就是由于这个锁,我开始还以为是硬件问题呢。应该和RTOS里面的互斥量差不多吧

any012 发表于 2017-1-20 16:23:23

之所以这么问,是之前看到creep大神给的DMA+空闲中断里的空闲回调函数里有个
__HAL_UNLOCK(huart->hdmarx);
之前一直不明白为什么这里有个UNLOCK,而没有找到对应的LOCK。今天修改这部分时,没有加这句,结果接收数组一直是第一次接收的数据。现在想想,应该是后来DMA就没有再使能。
但我没找到根据Lock位做判断的地方。

ts2000 发表于 2017-1-21 08:20:04

估计是一个标志位?停止没完成当前的工作,然后又重复操作?

队长shiwo 发表于 2017-1-21 08:51:52

是一个什么的锁来着吧

any012 发表于 2017-1-21 12:09:51

本帖最后由 any012 于 2017-1-21 12:12 编辑

zoomdy 发表于 2017-1-20 15:48
以STM32F4系列为例
__HAL_LOCK和__HAL_UNLOCK定义在Drivers/STM32F4xx_HAL_driver/Inc/stm32f4xx_hal_def.h ...
能否指明下,__HAL_LOCK()这个函数,在已被锁的情况下被调用后,返回量return HAL_BUSY,这个值,在什么地方被用到?

额,明白了,,__HAL_LOCK()是个宏,如果执行return HAL_BUSY;则直接退出上级函数了。感谢指教。
页: [1]
查看完整版本: __HAL_LOCK()这个函数有什么用?