打印
[应用相关]

中断请求的移植与处理(转载)

[复制链接]
689|28
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
labasi|  楼主 | 2019-6-18 13:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本文介绍如何移植STM32的IRQ(中断请求)到自己的系统中,我们以USART1接收中断为例。

    先看启动文件(汇编语言),如下列程序所示,列出了其向量区,USART1的中断向量已用红色标识,当和USART1相关的中断发生时,程序指针(PC)在保护现场后,直接指向到该向量。
__Vectors       DCD     __initial_sp              ; Top of Stack
                DCD     Reset_Handler             ; Reset Handler
                DCD     NMI_Handler               ; NMI Handler
                DCD     HardFault_Handler         ; Hard Fault Handler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     SVC_Handler               ; SVCall Handler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     PendSV_Handler            ; PendSV Handler
                DCD     SysTick_Handler           ; SysTick Handler

                ; External Interrupts
                DCD     WWDG_IRQHandler                ; Window Watchdog
                DCD     PVD_IRQHandler                 ; PVD through EXTI Line detect
                DCD     RTC_IRQHandler                 ; RTC through EXTI Line
                DCD     FLASH_IRQHandler               ; FLASH
                DCD     RCC_CRS_IRQHandler             ; RCC and CRS
                DCD     EXTI0_1_IRQHandler             ; EXTI Line 0 and 1
                DCD     EXTI2_3_IRQHandler             ; EXTI Line 2 and 3
                DCD     EXTI4_15_IRQHandler            ; EXTI Line 4 to 15
                DCD     TSC_IRQHandler                 ; TSC
                DCD     DMA1_Channel1_IRQHandler       ; DMA1 Channel 1
                DCD     DMA1_Channel2_3_IRQHandler     ; DMA1 Channel 2 and Channel 3
                DCD     DMA1_Channel4_5_6_7_IRQHandler ; DMA1 Channel 4, Channel 5, Channel 6 and Channel 7
                DCD     ADC1_COMP_IRQHandler           ; ADC1, COMP1 and COMP2
                DCD     LPTIM1_IRQHandler              ; LPTIM1
                DCD     0                              ; Reserved
                DCD     TIM2_IRQHandler                ; TIM2
                DCD     0                              ; Reserved
                DCD     TIM6_DAC_IRQHandler            ; TIM6 and DAC
                DCD     0                              ; Reserved
                DCD     0                              ; Reserved
                DCD     TIM21_IRQHandler               ; TIM21
                DCD     0                              ; Reserved
                DCD     TIM22_IRQHandler               ; TIM22
                DCD     I2C1_IRQHandler                ; I2C1
                DCD     I2C2_IRQHandler                ; I2C2
                DCD     SPI1_IRQHandler                ; SPI1
                DCD     SPI2_IRQHandler                ; SPI2
                <span style="color:#ff6666;">DCD     USART1_IRQHandler              ; USART1</span>
                DCD     USART2_IRQHandler              ; USART2
                DCD     RNG_LPUART1_IRQHandler         ; RNG and LPUART1
                DCD     LCD_IRQHandler                 ; LCD
                DCD     USB_IRQHandler                 ; USB

__Vectors_End
DCD     USART1_IRQHandler              ; USART1
                DCD     USART2_IRQHandler              ; USART2
                DCD     RNG_LPUART1_IRQHandler         ; RNG and LPUART1
                DCD     LCD_IRQHandler                 ; LCD
                DCD     USB_IRQHandler                 ; USB

__Vectors_End


使用特权

评论回复
沙发
labasi|  楼主 | 2019-6-18 13:00 | 只看该作者
此时,我们需做2件事情,在驱动的头文件中定义该向量的函数原型,在驱动的C文件中完成该向量的函数实现。STM32CubeMX会有相应的中断处理,我们直接调用就好,这个可以参照STM32提供的样例文件,如下列程序所示。

void USART1_IRQHandler(void)
{  
  HAL_UART_IRQHandler(pUART1);
}


使用特权

评论回复
板凳
labasi|  楼主 | 2019-6-18 13:00 | 只看该作者
本帖最后由 labasi 于 2019-6-18 13:03 编辑

后面的事情交由STM32CubeMX提供的驱动函数进行处理,我们慢慢看。HAL_UART_IRQHandler函数对中断进行处理,然后根据相应的中断类型,再调用相关的驱动函数,我们这里就需调用UART_Receive_IT函数,已用红色标识。

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  uint32_t isrflags   = READ_REG(huart->Instance->ISR);
  uint32_t cr1its     = READ_REG(huart->Instance->CR1);
  uint32_t cr3its;
  uint32_t errorflags;

  /* If no error occurs */
  errorflags = (isrflags & (uint32_t)(USART_ISR_PE | USART_ISR_FE | USART_ISR_ORE | USART_ISR_NE));
  if (errorflags == RESET)
  {
    /* UART in mode Receiver ---------------------------------------------------*/
    if(((isrflags & USART_ISR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
    {
      UART_Receive_IT(huart);
      return;
    }
  }  

  /* If some errors occur */
  cr3its = READ_REG(huart->Instance->CR3);
  if(   (errorflags != RESET)
     && (   ((cr3its & USART_CR3_EIE) != RESET)
         || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)) )
  {
    /* UART parity error interrupt occurred -------------------------------------*/
    if(((isrflags & USART_ISR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
    {
      __HAL_UART_CLEAR_IT(huart, UART_CLEAR_PEF);

      huart->ErrorCode |= HAL_UART_ERROR_PE;
    }

    /* UART frame error interrupt occurred --------------------------------------*/
    if(((isrflags & USART_ISR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      __HAL_UART_CLEAR_IT(huart, UART_CLEAR_FEF);

      huart->ErrorCode |= HAL_UART_ERROR_FE;
    }

    /* UART noise error interrupt occurred --------------------------------------*/
    if(((isrflags & USART_ISR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      __HAL_UART_CLEAR_IT(huart, UART_CLEAR_NEF);

      huart->ErrorCode |= HAL_UART_ERROR_NE;
    }

    /* UART Over-Run interrupt occurred -----------------------------------------*/
    if(((isrflags & USART_ISR_ORE) != RESET) &&
       (((cr1its & USART_CR1_RXNEIE) != RESET) || ((cr3its & USART_CR3_EIE) != RESET)))
    {
      __HAL_UART_CLEAR_IT(huart, UART_CLEAR_OREF);

      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_ISR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
      {
        void UART_Receive_IT(huart);
      }

      /* If Overrun error occurs, or if any error occurs in DMA mode reception,
         consider error as blocking */
      if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) ||
          (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))
      {  
        /* 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;

            /* Abort DMA RX */
            if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
            {
              /* Call Directly huart->hdmarx->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 wakeup from Stop mode interrupt occurred ---------------------------*/
  if(((isrflags & USART_ISR_WUF) != RESET) && ((cr3its & USART_CR3_WUFIE) != RESET))
  {
    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_WUF);
    /* Set the UART state ready to be able to start again the process */
    huart->gState  = HAL_UART_STATE_READY;
    huart->RxState = HAL_UART_STATE_READY;
    HAL_UARTEx_WakeupCallback(huart);
    return;
  }

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

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

}HAL_UART_RxCpltCallback(huart);

      return HAL_OK;
    }

    return HAL_OK;
  }
  else
  {
    /* Clear RXNE interrupt flag */
    __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);

    return HAL_BUSY;
  }
}



使用特权

评论回复
地板
labasi|  楼主 | 2019-6-18 13:04 | 只看该作者
总结一下,如何移植和处理中断函数。

    (1)在自己的驱动文件的头文件中,加入需要处理的中断矢量函数的函数原型声明。

    (2)在自己的驱动文件的C文件中,对该函数进行处理,要调用STM32CubeMX提供的驱动文件进行处理。

    (3)在自己的驱动文件的C文件中,直接对相应的回调函数进行处理,加入逻辑即可。


使用特权

评论回复
5
paotangsan| | 2019-7-8 11:39 | 只看该作者

非常感谢楼主分享

使用特权

评论回复
6
renzheshengui| | 2019-7-8 11:43 | 只看该作者

非常感谢楼主分享

使用特权

评论回复
7
wakayi| | 2019-7-8 11:46 | 只看该作者

非常感谢楼主分享

使用特权

评论回复
8
51xlf| | 2019-7-8 21:37 | 只看该作者
这个中断不都是固定的吗?      

使用特权

评论回复
9
i1mcu| | 2019-7-8 21:37 | 只看该作者
labasi 发表于 2019-6-18 13:00
此时,我们需做2件事情,在驱动的头文件中定义该向量的函数原型,在驱动的C文件中完成该向量的函数实现。S ...

驱动函数进行处理就行了。

使用特权

评论回复
10
pmp| | 2019-7-8 21:38 | 只看该作者
官网提供了相关的代码了。     

使用特权

评论回复
11
mmbs| | 2019-7-8 21:38 | 只看该作者
谢谢楼主分享的资料。      

使用特权

评论回复
12
1988020566| | 2019-7-8 21:39 | 只看该作者
STM32中断向量表偏移地址配置?   

使用特权

评论回复
13
lzbf| | 2019-7-8 21:39 | 只看该作者
在汇编启动文件中已经定义好了  

使用特权

评论回复
14
youtome| | 2019-7-8 21:39 | 只看该作者
stm32f1一共有多少中断向量  

使用特权

评论回复
15
cemaj| | 2019-7-8 21:40 | 只看该作者
stm32中断向量表是怎么放在指定的地址的  

使用特权

评论回复
16
cemaj| | 2019-7-8 21:40 | 只看该作者
STM32里面中断向量和中断服务函数是什么联系在一起  

使用特权

评论回复
17
youtome| | 2019-7-8 21:40 | 只看该作者
stm32中断向量表中外部中断的个数为什么是5个  

使用特权

评论回复
18
biechedan| | 2019-7-8 21:40 | 只看该作者
stm32中断向量表怎么重映射        

使用特权

评论回复
19
sanfuzi| | 2019-7-8 21:41 | 只看该作者
stm32看门狗IWDG需要配置中断向量NVIC吗  

使用特权

评论回复
20
1988020566| | 2019-7-8 21:41 | 只看该作者
设置system_stm32f1xx.c文件  #defineVECT_TAB_OFFSET  0x5000
在void SystemInit (void)函数中通过“SCB->VTOR =FLASH_BASE | VECT_TAB_OFFSET”命令实现地址偏移

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

44

主题

3308

帖子

2

粉丝