Bare metal C Ch14 EXTI - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki
ํ ์ค ์์ฝ: B1(PC13)์ pollingํ์ง ์๊ณ EXTI13 + NVIC interrupt๋ก ์ฒ๋ฆฌํด LED toggle๊ณผ UART message ์ถ๋ ฅ์ ์ํํ๋ค.
Polling์ CPU๊ฐ ์ํ๋ฅผ ๊ณ์ ๋ฐ๋ณตํด์ ์ฝ๋๋ค. Interrupt ๋ฐฉ์์์๋ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ ๋๋ง CPU๊ฐ ISR๋ก ์ง์ ํ๋ค.
ISR: Interrupt Service Routine
IVT: Interrupt Vector Table
NVIC: Cortex-M interrupt controller
EXTI: STM32 external interrupt/event controller
EXTI๋ pin number ๊ธฐ์ค์ผ๋ก line์ด ์ ํด์ง๋ค.
PA13
PB13
PC13
...
โโ ๋ชจ๋ EXTI13 ํ๋ณด
์ด๋ port์ pin์ EXTI13์ ์ฐ๊ฒฐํ ์ง๋ SYSCFG->EXTICR[]๋ก ์ ํํ๋ค.
Notion ๊ธฐ๋ก์์๋ NUCLEO-F439ZI B1์ active-HIGH๋ก ์ ๋ฆฌํ๋ค.
๋ฒํผ ์ ๋๋ฆ : Low
๋ฒํผ ๋๋ฆ : High
๋ฐ๋ผ์:
Low โ High
= Rising Edge
= EXTI->RTSR
์ ์ฌ์ฉํ๋ค.
Register | ์ญํ -- | -- SYSCFG->EXTICR[3] | EXTI13์ Port C์ ์ฐ๊ฒฐ EXTI->IMR | interrupt mask EXTI->RTSR | rising-edge trigger EXTI->PR | pending flag NVIC | EXTI15_10_IRQn enableEXTI10 ~ EXTI15๋ ํ๋์ EXTI15_10_IRQHandler()๋ฅผ ๊ณต์ ํ๋ฏ๋ก ISR ์์์ PR์ ํ์ธํด์ผ ํ๋ค.
B1 / PC13
โ Rising Edge
โผ
EXTI13
โ
โผ
NVIC
โ
โผ
EXTI15_10_IRQHandler()
โ
โโ PR13 clear
โผ
exti_callback()
โ
โโ UART message
โโ LD1 toggle
Ch14_exti/
โโโ Inc/gpio.h
โโโ Src/gpio.c
โโโ Inc/gpio_exti.h
โโโ Src/gpio_exti.c
โโโ Inc/uart.h
โโโ Src/uart.c
โโโ Src/main.c
syscalls.c,sysmem.c, startup file, linker script, CubeIDE metadata/build output์ Ch04์์ ๋ค๋ฃฌ ๊ณตํต ๊ธฐ๋ฐ์ด๋ฏ๋ก ์ด ํ์ด์ง์์๋ ๋ฐ๋ณตํ์ง ์๋๋ค. ์๋์๋ ์ด chapter ๊ธฐ๋ฅ ๊ตฌํ์ ์ง์ ์ฌ์ฉํ source/header๋ฅผ ์ ๋ถ ๊ธฐ๋กํ๋ค.
#ifndef GPIO_H
#define GPIO_H
#include <stdbool.h>
/* ---- LED (PB0, LD1 ๋
น์) ---- */
void led_init(void);
void led_on(void);
void led_off(void);
/* ---- Push Button (PC13, B1) ---- */
void button_init(void);
bool get_btn_state(void);
void led_toggle(void); /* Ch08์์ ์ถ๊ฐ */
#endif /* GPIO_H */
#include "stm32f4xx.h"
#include "gpio.h"
#define LED_PIN 0U /* PB0 = LD1 (๋
น์) /
#define BTN_PIN 13U / PC13 = B1 */
void led_init(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
GPIOB->MODER &= ~(0x3UL << (LED_PIN * 2));
GPIOB->MODER |= (0x1UL << (LED_PIN * 2));
}
void led_on(void)
{
GPIOB->BSRR = (1UL << LED_PIN); /* Set */
}
void led_off(void)
{
GPIOB->BSRR = (1UL << (LED_PIN + 16)); /* Reset */
}
void button_init(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
GPIOC->MODER &= ~(0x3UL << (BTN_PIN * 2)); /* Input */
GPIOC->PUPDR &= ~(0x3UL << (BTN_PIN * 2)); /* No pull (๋ณด๋๊ฐ ์์ฒด ์ฒ๋ฆฌ) */
}
bool get_btn_state(void)
{
return (GPIOC->IDR & (1UL << BTN_PIN)) != 0U; /* active-HIGH */
}
void led_toggle(void)
{
GPIOB->ODR ^= (1UL << 0); /* PB0 = LD1 */
}
#ifndef GPIO_EXTI_H__
#define GPIO_EXTI_H__
#include <stdint.h>
#include "stm32f4xx.h"
#define LINE13 (1U << 13)
void pc13_exti_init(void);
#endif
#include "gpio_exti.h"
#define GPIOCEN (1U << 2)
#define SYSCFGEN (1U << 14)
void pc13_exti_init(void)
{
__disable_irq();
RCC->AHB1ENR |= GPIOCEN;
GPIOC->MODER &= ~(1U << 26);
GPIOC->MODER &= ~(1U << 27);
RCC->APB2ENR |= SYSCFGEN;
/* EXTI13 -> PORTC */
SYSCFG->EXTICR[3] |= (1U << 5);
EXTI->IMR |= (1U << 13);
/* ์ด ๋ณด๋๋ B1์ด active-HIGH๋ผ Rising-edge (์์๋ FTSR/active-LOW) */
EXTI->RTSR |= (1U << 13);
NVIC_EnableIRQ(EXTI15_10_IRQn);
__enable_irq();
}
#ifndef UART_H
#define UART_H
#include "stm32f4xx.h"
void uart_init(void);
void uart_write_string(const char *s);
int __io_putchar(int ch);
#endif
#include <stdint.h>
#include "uart.h"
#define GPIODEN (1U << 3)
#define USART3EN (1U << 18)
#define DBG_UART_BAUDRATE 115200U
#define SYS_FREQ 16000000U
#define APB1_CLK SYS_FREQ
#define CR1_TE (1U << 3)
#define CR1_UE (1U << 13)
#define SR_TXE (1U << 7)
static void uart_write(int ch);
static uint16_t compute_uart_bd(uint32_t periph_clk, uint32_t baudrate);
static void uart_set_baudrate(uint32_t periph_clk, uint32_t baudrate);
int __io_putchar(int ch)
{
uart_write(ch);
return ch;
}
void uart_init(void)
{
RCC->AHB1ENR |= GPIODEN;
GPIOD->MODER &= ~(0x3UL << (8 * 2));
GPIOD->MODER |= (0x2UL << (8 * 2));
GPIOD->MODER &= ~(0x3UL << (9 * 2));
GPIOD->MODER |= (0x2UL << (9 * 2));
GPIOD->AFR[1] &= ~(0xFUL << 0);
GPIOD->AFR[1] |= (0x7UL << 0); /* PD8 -> AF7 (USART3_TX) */
GPIOD->AFR[1] &= ~(0xFUL << 4);
GPIOD->AFR[1] |= (0x7UL << 4); /* PD9 -> AF7 (USART3_RX) */
RCC->APB1ENR |= USART3EN;
uart_set_baudrate(APB1_CLK, DBG_UART_BAUDRATE);
USART3->CR1 = CR1_TE;
USART3->CR1 |= CR1_UE;
}
static void uart_write(int ch)
{
while (!(USART3->SR & SR_TXE)) { }
USART3->DR = (ch & 0xFF);
}
void uart_write_string(const char *s)
{
while (*s) uart_write((int)*s++);
}
static uint16_t compute_uart_bd(uint32_t periph_clk, uint32_t baudrate)
{
return (uint16_t)((periph_clk + (baudrate / 2U)) / baudrate);
}
static void uart_set_baudrate(uint32_t periph_clk, uint32_t baudrate)
{
USART3->BRR = compute_uart_bd(periph_clk, baudrate);
}
#include <stdio.h>
#include "gpio.h"
#include "gpio_exti.h"
extern void uart_init(void);
int main(void)
{
uart_init();
led_init();
pc13_exti_init();
while (1)
{
/* ์ธํฐ๋ฝํธ๋ง์ผ๋ก ๋์ โ ํด๋ง ์์ */
}
}
static void exti_callback(void)
{
printf("BTN Pressed...\r\n");
led_toggle();
}
void EXTI15_10_IRQHandler(void)
{
if ((EXTI->PR & LINE13) != 0)
{
EXTI->PR |= LINE13;
exti_callback();
}
}
Notion ๊ธฐ๋ก ๊ธฐ์ค ์ค์ ๋ณด๋ ๊ฒ์ฆ ์๋ฃ.
B1์ ๋๋ฅผ ๋๋ง๋ค LD1 toggle
Terminal์
BTN Pressed...์ถ๋ ฅpolling ์์ด interrupt ๊ธฐ๋ฐ์ผ๋ก ๋์
text = 1272 bytes
data = 0 bytes
bss = 2560 bytes
warning ์์
EXTI๋ pin number ๊ธฐ์ค line์ ์ฌ์ฉํ๊ณ port๋ SYSCFG์์ ์ ํํ๋ค.
F439ZI B1์ active-HIGH ๊ธฐ๋ก์ ๋ฐ๋ผ Rising Edge๋ฅผ ์ฌ์ฉํ๋ค.
ISR์์๋ pending flag๋ฅผ ์ฒ๋ฆฌํ๊ณ callback์ผ๋ก ๋์์ ๋ถ๋ฆฌํ๋ค.