STM32 CMSIS FreeRTOS:从ISR释放BinrarySemaphore时触发configASSERT

时间:2019-05-04 11:35:42

标签: arm stm32 freertos cmsis

我有一个UART空闲中断,应该通知任务UART上的活动已结束。

为此,我使用的是BinarySemaphore,在这种情况下,它只是最大计数为1的Semaphore。

当我调用信号量释放函数osSemaphoreRelease(semaphore_id_uart4_rx);

由于触发了以下断言,应用程序暂停。

/* Normally a mutex would not be given from an interrupt, especially if
    there is a mutex holder, as priority inheritance makes no sense for an
    interrupts, only tasks. */
    configASSERT( !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->pxMutexHolder != NULL ) ) );

configASSERT扩展为

if ((!( ( pxQueue->pcHead == ((void *)0) ) && ( pxQueue->pcTail != ((void *)0) ) )) == 0) {vPortRaiseBASEPRI(); for( ;; );}

现在pxQueue-> pcHead的值为0,而pxQueue-> pcTail的值为非0。因此,资产被触发。

此断言上方的注释表明,这是为了捕获来自ISR的MUTEX。但是,我没有使用MUTEX,而是使用BinarySemaphore! FreeRTOS FAQ本身鼓励您使用信号量或BinarySemaphores在ISR和Task之间进行同步。这是我在做什么。但是仍然将二进制信号量检测为MUTEX,这会导致此问题。我什至尝试从STM32CubeMX RTOS配置中禁用MUTEX,但仍将其检测为MUTEX并崩溃。

Binary semaphores for FreeRTOS real time embedded software applications

  

二进制信号量和互斥量非常相似,但是有些微妙   差异:互斥包括优先级继承机制,二进制   信号量没有。这使得二进制信号量成为更好的选择   实现同步(任务之间或任务与   中断),并互斥实现简单的更好的选择   互斥。

我正在使用上面装有STM32F429ZIT6的NUCLEO-F429ZI板, CubeMX版本:4.27.0, 固件包名称和版本:STM32Cube FW_F4 V1.21.0

代码:

主要功能:

int main(void)
{
  /* USER CODE BEGIN 1 */

    for(int i=0;i<360;i++) {
        sine_wave_array[i]=sin(i/180.0 * 3.1416)*1900 + 1900 + 100;

        if(sine_wave_array[i]<0) {
            sine_wave_array[i]=0;
        } else if(sine_wave_array[i]>=4096){
            sine_wave_array[i]=4095;
        }
    }

    //Initialize HMI struct
    memset(&hmi,0,sizeof(hmi));


  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART2_UART_Init();
  MX_UART4_Init();
  MX_UART5_Init();
  MX_DAC_Init();
  MX_TIM6_Init();
  MX_SPI1_Init();
  MX_I2C1_Init();
  MX_ADC3_Init();
  MX_USB_OTG_HS_PCD_Init();
  MX_USART3_UART_Init();
  MX_SPI4_Init();
  MX_I2C2_Init();
  MX_CAN1_Init();
  MX_RTC_Init();
  MX_TIM3_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_TIM4_Init();
  /* USER CODE BEGIN 2 */




    HAL_ADC_Start_DMA(&hadc3,adcData,ADC_CHANNEL_COUNT);
    __HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);

    // Setting IRQ priority for UART4
    HAL_NVIC_SetPriority(UART4_IRQn, 15, 15);
    HAL_NVIC_SetPriorityGrouping(0);


  /* USER CODE END 2 */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */


  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  semaphore_id_uart4_rx = osSemaphoreCreate(osSemaphore(semaphore_uart4_rx), 1);
  semaphore_id_uart5_rx = osSemaphoreCreate(osSemaphore(semaphore_uart5_rx), 1);
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* Create the thread(s) */
  /* definition and creation of defaultTask */
  osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  osThreadDef(LWIPTask_, LWIPTask, osPriorityNormal, 0, 1024);
  LWIPTaskHandle = osThreadCreate(osThread(LWIPTask_), NULL);

  osThreadDef(USBTask_, USBTask, osPriorityNormal, 0, 512);
  USBTaskHandle = osThreadCreate(osThread(USBTask_), NULL);


  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */


  /* Start scheduler */
  osKernelStart();

  /* We should never get here as control is now taken by the scheduler */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

ISR:

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
   uint32_t isrflags   = READ_REG(huart->Instance->SR);
   uint32_t cr1its     = READ_REG(huart->Instance->CR1);
   uint32_t cr3its     = READ_REG(huart->Instance->CR3);
   uint32_t errorflags = 0x00U;
   uint32_t dmarequest = 0x00U;

   if ((isrflags & USART_SR_IDLE) != RESET) {
        HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
        volatile uint32_t tmp; /* Must be volatile to prevent optimizations */
        tmp = huart->Instance->SR; /* Read status register */
        tmp = huart->Instance->DR; /* Read data register */
        HAL_UART_IdleCallback(huart);
    }

  /* If no error occurs */
  errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
  if(errorflags == RESET)
  {
    /* UART in mode Receiver -------------------------------------------------*/
    if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
    {
      UART_Receive_IT(huart);
      return;
    }
  }  

  /* If some errors occur */
  if((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
  {
    /* UART parity error interrupt occurred ----------------------------------*/
    if(((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_PE;
    }

    /* UART noise error interrupt occurred -----------------------------------*/
    if(((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_NE;
    }

    /* UART frame error interrupt occurred -----------------------------------*/
    if(((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART_ERROR_FE;
    }

    /* UART Over-Run interrupt occurred --------------------------------------*/
    if(((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    { 
      huart->ErrorCode |= HAL_UART_ERROR_ORE;
    }

    /* Call UART Error Call back function if need be --------------------------*/    
    if(huart->ErrorCode != HAL_UART_ERROR_NONE)
    {
      /* UART in mode Receiver -----------------------------------------------*/
      if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
      {
        UART_Receive_IT(huart);
      }

      /* If Overrun error occurs, or if any error occurs in DMA mode reception,
         consider error as blocking */
      dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
      if(((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
      {
        /* Blocking error : transfer is aborted
           Set the UART state ready to be able to start again the process,
           Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
        UART_EndRxTransfer(huart);

        /* Disable the UART DMA Rx request if enabled */
        if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
        {
          CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);

          /* Abort the UART DMA Rx channel */
          if(huart->hdmarx != NULL)
          {
            /* Set the UART DMA Abort callback : 
               will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
            huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
            if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
            {
              /* Call Directly XferAbortCallback function in case of error */
              huart->hdmarx->XferAbortCallback(huart->hdmarx);
            }
          }
          else
          {
            /* Call user error callback */
            HAL_UART_ErrorCallback(huart);
          }
        }
        else
        {
          /* Call user error callback */
          HAL_UART_ErrorCallback(huart);
        }
      }
      else
      {
        /* Non Blocking error : transfer could go on. 
           Error is notified to user through user error callback */
        HAL_UART_ErrorCallback(huart);
        huart->ErrorCode = HAL_UART_ERROR_NONE;
      }
    }
    return;
  } /* End if some error occurs */

  /* UART in mode Transmitter ------------------------------------------------*/
  if(((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
  {
    UART_Transmit_IT(huart);
    return;
  }

  /* UART in mode Transmitter end --------------------------------------------*/
  if(((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
  {
    UART_EndTransmit_IT(huart);
    return;
  }
}

从ISR调用的功能:

void HAL_UART_IdleCallback(UART_HandleTypeDef *huart) {
    HAL_UART_RxGenericCallback(huart,3);
}

void HAL_UART_RxGenericCallback(UART_HandleTypeDef *huart,int type) {

    if(type ==3) {

        if(UART4 == huart->Instance) {
            end4 = huart->RxXferSize - __HAL_DMA_GET_COUNTER(huart->hdmarx);
            osSemaphoreRelease(semaphore_id_uart4_rx);
        } else if (UART5 == huart->Instance) {
            end5 = huart->RxXferSize - __HAL_DMA_GET_COUNTER(huart->hdmarx);
            osSemaphoreRelease(semaphore_id_uart5_rx);
        }
    }

    return;
}

1 个答案:

答案 0 :(得分:0)

在中断中,您需要使用..FromISR函数或宏,例如

xSemaphoreTakeFromISR()xSemaphoreGiveFromISR()

还需要设置正确的中断优先级,否则将堆积在恒定的停顿和HF中。