Search code examples
carmembeddedstm32stm32f4discovery

STM32F429 External Interrupt Edge


I am using the STM32F429I-Discovery board, the board has a pushbutton connected to PA0, which in turn is connected to External Interrupt Line 0 (EXTI0).

Using the HAL Libraries, I can toggle a LED either on the Falling Edge or on the Rising edge using external interrupts. Eg, the LED either changes state as soon as I press the pushbutton, or only once I release the pushbutton.

What I want to do is to Interrupt on the Rising edge, start a timer, and then interrupt on the falling edge again, to stop the timer. I have got no idea how to achieve this?

There is also an option to trigger on both rising and falling edges. I do not know if there should only be one interrupt, and I then figure out if it was a rising or falling edge (probably by accessing the registers directly), or should there be two configured interrupts - One as Rising Edge and one as Falling Edge?

Below are the external interrupt code; firstly to set a GPIO up as an external interrupt, then to detect the interrupt and then to handle the interrupt (callback).

    static void EXTILine0_Config(void)
{
  GPIO_InitTypeDef   GPIO_InitStructure;

  /* Enable GPIOA clock */
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /* Configure PA0 pin as input floating */
  GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStructure.Pull = GPIO_NOPULL;
  GPIO_InitStructure.Pin = GPIO_PIN_0;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Enable and set EXTI Line0 Interrupt to the lowest priority */
  HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
  HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}


/* Clears the interrupt after calling this I think */
void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(KEY_BUTTON_PIN);
}


/**
  * @brief EXTI line detection callbacks
  * @param GPIO_Pin: Specifies the pins connected EXTI line
  * @retval None
  */

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if(GPIO_Pin == KEY_BUTTON_PIN)
  {
    /* Toggle LED3 */
    BSP_LED_Toggle(LED3);
  }
}

Can someone please point out how I can achieve this?


Solution

  • First, you have to setup a timer, e.g.

    TIM_HandleTypeDef htim1;
    
    void TIM1_Init(void)
    {
    
      TIM_ClockConfigTypeDef sClockSourceConfig;
      TIM_MasterConfigTypeDef sMasterConfig;
    
      htim1.Instance = TIM1;
      htim1.Init.Prescaler = 71;
      htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim1.Init.Period = 65535;
      htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      htim1.Init.RepetitionCounter = 0;
      HAL_TIM_Base_Init(&htim1);
    
      sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
      HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig);
    
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
      HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);
    
    }
    

    Code is taken from an STM32F1, so maybe you have to adapt a little, just have a look in the HAL handbook.

    The interrupt for rising and falling edge is the same, so you have to check the state of the pin in your interrupt handler.

    To start the timer

      HAL_TIM_Base_Start(&htim1);
    

    and to stop

      HAL_TIM_Base_Stop(&htim1);
    

    the counter value is stored in

    TIM1->CNT