KIT STM32F4 Discovery – Bài 4: Ngắt ngoài (EXTI)

1
1643

Trên vi điều khiển STM32F407VG có một bộ điều khiển ngắt/sự kiện ngoại gọi tắt là EXTI (External interrupt/event controller). EXTI bao gồm 23 bộ phát hiện sự kiện, từ đó khởi tạo nên các yêu cầu ngắt. Mỗi đường đầu vào có thể được cấu hình độc lập để lựa chọn kiểu là interrupt hay event và trigger event tương ứng (rising, falling hoặc cả 2). Mỗi đường ngắt cũng có thể được che một cách độc lập.

EXTI được kết nối với bộ xử lý ngắt lồng nhau NVIC như sau:

Bộ xử lý ngắt lồng nhau NVIC

NVIC (Nested Vector Interrupt Controller) là khối quản lý ngắt trên các dòng vi điều khiển dựa trên lõi ARM Cortex M4. Khi có một sự kiện và sự kiện đó được cấu hình ngắt, thì tất cả ngắt sẽ được đưa vào khối NVIC, và dựa trên nhiều yếu tố mà NVIC sẽ quyết định xem ngắt nào sẽ được thực thi để đưa CPU vào Interrupt Service Routine.

Bộ điều khiển ngắt ngoại EXTI xử lý tất cả các tín hiệu yêu cầu ngắt đến từ tất cả các chân của vi điều khiển. Ngoài ra nó còn xử lý các yêu cầu ngắt đến từ các nguồn khác. Các yêu cầu ngắt được phân thành 23 đường ngắt khác nhau, trong đó các yêu cầu đến từ chân 0 của tất cả các port được xử lý trên line 0, các yêu cầu đến từ chân 1 của tất cả các port được xử lý trên line 1 v.v.. như mô tả ở hình dưới.

Các đường ngắt khác nhau trên STM32F4 Discovery

7 đường ngắt EXTI còn lại được nối như sau:

• EXTI line 16 được nối vào PVD output

• EXTI line 17 được nối vào RTC Alarm event

• EXTI line 18 được nối vào USB OTG FS Wakeup event

• EXTI line 19 được nối vào Ethernet Wakeup event

• EXTI line 20 được nối vào USB OTG HS (configured in FS) Wakeup event

• EXTI line 21 được nối vào RTC Tamper and TimeStamp events

• EXTI line 22 được nối vào RTC Wakeup event

Yêu cầu ngắt trên line n với n nhận giá trị từ 0 đến 4 được xử lý trong chương trình con xử lý ngắt có tên:

void EXTIn_IRQHandler(void)

Các yêu cầu ngắt trên các line từ 5 đến 9 được xử lý chung trong chương trình con xử lý ngắt: void EXTI9_5_IRQHandler(void).

Các yêu cầu ngắt trên các line từ 10 đến 15 được xử lý chung trong chương trình con xử lý ngắt:

void EXTI15_10_IRQHandler(void).

Tín hiệu ngắt có thể được phân ra thành FALLING, RISING hoặc cả 2, tùy thuộc vào sự thay đổi mức hiệu điện thế.

Các ngắt có thể có độ ưu tiên khác nhau. Khi một ngắt có độ ưu tiên cao hơn đang được xử lý thì các ngắt khác phải chờ. Ta gọi các ngắt đang chờ là PENDING INTERRUPT.

IrqHandlerDescription
EXTI0_IRQnEXTI0_IRQHandlerHandler for pins connected to line 0
EXTI1_IRQnEXTI1_IRQHandlerHandler for pins connected to line 1
EXTI2_IRQnEXTI2_IRQHandlerHandler for pins connected to line 2
EXTI3_IRQnEXTI3_IRQHandlerHandler for pins connected to line 3
EXTI4_IRQnEXTI4_IRQHandlerHandler for pins connected to line 4
EXTI9_5_IRQnEXTI9_5_IRQHandlerHandler for pins connected to line 5 to 9
EXTI15_10_IRQnEXTI15_10_IRQHandlerHandler for pins connected to line 10 to 15
Các chương trình con xử lý ngắt trên STM32F4 Discovery

Mức ưu tiên ngắt

NVIC trên chip ARM được dùng cho STM32F4 hỗ trợ cài đặt 16 mức độ ưu tiên của các ngắt:

Chế độ chọn nhóm ngắt NVIC

Số n quyết định có bao nhiêu mức cấu hình ngắt cho Mức độ ưu tiên (Preemption Priority) và Sub-priority.

Quy tắc hoạt động của mức độ ưu tiên ngắt như sau:

1. Khi cả hai ngắt có cùng mức độ ưu tiên

Ngắt nào xảy ra trước sẽ được thực thi trước.

2. Hai ngắt khác Mức độ ưu tiên (Preemption Priority)

Mức độ ưu tiên quyết định ngắt A có được phép thực thi khi ngắt B đang hoạt động hay không.
Nếu ngắt A có Mức độ ưu tiên lớn hơn B, thì nó sẽ được NVIC ưu tiên hơn so với ngắt B trong mọi trường hợp, nghĩa là ngắt B đang hoạt động, nhưng ngắt A yêu cầu thực thi thì NVIC sẽ cho phép dừng ngắt B, thực thi ngắt A trước và sau đó về thực thi tiếp ngắt B.

3. Hai ngắt khác Sub-priority

Khi có một ngắt A đang được thực thi (với Mức độ ưu tiên lớn hơn B, C), cùng lúc đó hai ngắt B và C có cờ báo cần thực thi, thì sub-priority sẽ quyết định 2 ngắt đang chờ này cái nào sẽ được thực thi trước

Để lập trình sử dụng ngắt ngoại, ta phải include các file sau từ thư viện CMSIS: stm32f4xx_syscfg.h, stm32f4xx_exti.h và misc.h. Việc cấu hình phải gồm 3 bước:

  • Bật syscfg clock và kết nối tới line yêu cầu ngắt
  • Cấu hình cho exti
  • Cấu hình cho NVIC

Để hiểu các dùng ngắt ngoại ta xem ví dụ sau:

Ví dụ 1:

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include "stm32f4xx_syscfg.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_exti.h"
#include "misc.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void EXTILine0_Config(void);
void LEDInit(void);
/* Private functions ---------------------------------------------------------*/

/**
  * @brief  EXTI Example program
  * @param  None
  * @retval None
  */
void main(void)
{
  /*!< At this stage the microcontroller clock setting is already configured,
       this is done through SystemInit() function which is called from startup
       file (startup_stm32f4xx.s) before to branch to application main.
       To reconfigure the default setting of SystemInit() function, refer to
        system_stm32f4xx.c file
     */

  /* Initialize LED4 mounted on STM32F4-Discovery board */
  LEDInit();

  /* Configure EXTI Line0 (connected to PA0 pin) in interrupt mode */
  EXTILine0_Config();

  /* Generate software interrupt: simulate a rising edge applied on EXTI0 line */
  EXTI_GenerateSWInterrupt(EXTI_Line0);

  while (1)
  {
  }
}

/**
  * @brief  Configures LED GPIO.
  * @param  None
  * @retval None
  */
void LEDInit()
{
  GPIO_InitTypeDef  GPIO_InitStructure;

  /* Enable the GPIO_LED Clock */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

  /* Configure the GPIO_LED pin */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
}

/**
  * @brief  Configures EXTI Line0 (connected to PA0 pin) in interrupt mode
  * @param  None
  * @retval None
  */
void EXTILine0_Config(void)
{

  GPIO_InitTypeDef   GPIO_InitStructure;
  EXTI_InitTypeDef   EXTI_InitStructure;
  NVIC_InitTypeDef   NVIC_InitStructure;

  /* Enable GPIOA clock */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  /* Enable SYSCFG clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

  /* Configure PA0 pin as input floating */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Connect EXTI Line0 to PA0 pin */
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);

  /* Configure EXTI Line0 */
  EXTI_InitStructure.EXTI_Line = EXTI_Line0;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

  /* Enable and set EXTI Line0 Interrupt to the lowest priority */
  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

/**
  * @brief  This function handles External line 0 interrupt request.
  * @param  None
  * @retval None
  */
void EXTI0_IRQHandler(void)
{
  if(EXTI_GetITStatus(EXTI_Line0) != RESET)
  {
    /* Toggle LED1 */
    GPIO_ToggleBits(GPIOD, GPIO_Pin_12);

    /* Clear the EXTI line 0 pending bit */
    EXTI_ClearITPendingBit(EXTI_Line0);
  }
}

Ví dụ 2:

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include "stm32f4xx_syscfg.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_exti.h"
#include "misc.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void EXTILine7_Config(void);
void LEDInit(void);
/* Private functions ---------------------------------------------------------*/

/**
 * @brief  EXTI Example program
 * @param  None
 * @retval None
 */
void main(void)
{
	/*!< At this stage the microcontroller clock setting is already configured,
       this is done through SystemInit() function which is called from startup
       file (startup_stm32f4xx.s) before to branch to application main.
       To reconfigure the default setting of SystemInit() function, refer to
        system_stm32f4xx.c file
	 */

	/* Initialize LED4 mounted on STM32F4-Discovery board */
	LEDInit();

	/* Configure EXTI Line0 (connected to PA0 pin) in interrupt mode */
	EXTILine7_Config();

	/* Generate software interrupt: simulate a rising edge applied on EXTI0 line */
	EXTI_GenerateSWInterrupt(EXTI_Line7);

	while (1)
	{
	}
}

/**
 * @brief  Configures LED GPIO.
 * @param  None
 * @retval None
 */
void LEDInit()
{
	GPIO_InitTypeDef  GPIO_InitStructure;

	/* Enable the GPIO_LED Clock */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

	/* Configure the GPIO_LED pin */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
}

/**
 * @brief  Configures EXTI Line0 (connected to PA0 pin) in interrupt mode
 * @param  None
 * @retval None
 */
void EXTILine7_Config(void)
{

	GPIO_InitTypeDef   GPIO_InitStructure;
	EXTI_InitTypeDef   EXTI_InitStructure;
	NVIC_InitTypeDef   NVIC_InitStructure;

	/* Enable GPIOA clock */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	/* Enable SYSCFG clock */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

	/* Configure PA0 pin as input floating */
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	/* Connect EXTI Line0 to PA0 pin */
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource7);

	/* Configure EXTI Line0 */
	EXTI_InitStructure.EXTI_Line = EXTI_Line7;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);

	/* Enable and set EXTI Line0 Interrupt to the lowest priority */
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

/**
 * @brief  This function handles External line 0 interrupt request.
 * @param  None
 * @retval None
 */
void EXTI9_5_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line7) != RESET)
	{
		/* Toggle LED1 */
		GPIO_ToggleBits(GPIOD, GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);

		/* Clear the EXTI line 0 pending bit */
		EXTI_ClearITPendingBit(EXTI_Line7);
	}
}

1 COMMENT

  1. Magnificent beat ! I wish to apprentice while you amend your web site, how could i subscribe for a blog
    website? The account aided me a acceptable deal. I had been tiny bit acquainted of this your
    broadcast offered bright clear concept

LEAVE A REPLY

Please enter your comment!
Please enter your name here