[Embedded] ARM 프로세서의 이해

예빈·2025년 11월 26일

Embedded/Linux

목록 보기
2/21
post-thumbnail


0️⃣ 들어가며

임베디드 시스템의 이해 편을 전부 작성하지 않은 상태인데,
아직 정리가 덜 된 관계로 ARM 프로세서의 이해부터 쓰게 되었다.
다음 주 내로 밀린 것들 싹 정리해서 업데이트하는 게 목표이다.
이번 주에는 STM32 보드를 써서 ARM 프로세서에 관해 알아볼 수 있었다.


1️⃣ 학습 내용

ARM Architecture

ARM Architecture

  • 버전과 패밀리네임

    버전패밀리/코어주요 특징 및 용도
    v1, v2, v3초기 ARM 코어제한적 내장형/교육·연구용
    v4ARM7 (low-end)저가형, 32비트 RISC, 광범위 임베디드
    v5ARM9 (mid)기능/성능 개선, 디지털가전·네트워킹·산업용
    v6ARM11 (high-end)고성능, 스마트폰·고성능 임베디드 타깃
    v7Cortex-A (high-end)모바일·고성능 애플리케이션(스마트폰 등)
    Cortex-R실시간·안전성(자동차·산업 제어)
    Cortex-M (low-end)저가형 MCU, 센서·제어, 하위호환성 낮음
    v8aarch32, aarch6432/64비트, 최신 스마트폰, 고성능·가상화·보안

ARM 레지스터

  • 범용 레지스터(GPR)

    r0~r12는 연산에 사용되는 기본적인 저장 공간

    산술 연산(+, -, & 등), 임시 데이터, 함수 인수 전달 등에 활용함

    ALU와 직접 연결되어 빠른 임시 저장소 역할

  • 특수 목적 레지스터(SPR)

    • r13 (Stack Pointer, SP)

      함수·인터럽트 호출 시 지역 변수를 쌓거나 복귀 주소를 저장하는 공간의 최상단 주소

      스택 포인터가 어디서 데이터를 읽고 쓸지 가리킴 (스택의 꼭대기)

    • r14 (Link Register, LR)

      다른 함수를 호출(BL 명령 등)할 때, 복귀할 PC(프로그램 카운터) 값을 잠깐 저장

      여러 번 함수 호출 시, 이전 LR을 스택에 쌓은 뒤 새 LR값을 사용

    • r15 (Program Counter, PC)

      프로그램이 읽고서 실행할 명령어의 주소를 가리키며 Fetch Unit 소속

      CPU가 다음에 어떤 명령을 가져올지, PC가 항상 현재 읽으려는 위치(주소)를 기억하고 있음

      // 파이프라인 순서
      		IF      ID       IE
      				            BL i5    // 함수 호출 명령어(BL) 실행 시, i5 instruction
      		         i2
      		i3 <- PC가 가리키는 주소
      i4
      i5

      IF (Instruction Fetch): PC가 가리키는 주소(i3)에 있는 명령어를 가져옴

      ID (Instruction Decode): 가져온 명령어 해독

      IE (Instruction Execute): 해독된 명령어 실행

      이처럼 PC(r15)는 늘 다음에 읽을 명령어의 위치를 기억해, 순차적으로 프로그램이 실행됨

  • SFR(Special Function Register)

    CPU 바깥, 각종 장치(주변기기)와 직접 연결된 레지스터

    하드웨어와 소프트웨어의 접점: GPIO(핀 입력/출력 제어), UART(직렬 통신), TIMER(카운터 등)

    C에서 메모리 맵(Address Mapping)을 통해 SFR의 주소에 직접 접근

    register의 값(비트)을 바꾸면 정해진 주소로 접근하여 하드웨어의 모드, 제어, 상태 등이 즉시 바뀜

    • SFR 주요 역할
      1. configuration

        디바이스가 어떻게 동작할지 옵션(모드/기능) 등을 설정

        예: GPIO의 input/output 핀 설정, UART의 속도·동작 방식 등

      2. control

        디바이스의 구동/정지, 동작 방식 전환 등 ON/OFF 결정

        예: 타이머를 켜고 끄기, 통신 모듈 활성화 등

      3. data

        실제 데이터의 입출력

        MCU가 디바이스에서 값을 읽어 오거나, 데이터를 보냄

        예: 센서값 읽기, 액추에이터에 신호 보내기

      4. status

        디바이스의 현재 동작 상태를 확인

        예: 데이터가 준비됐는지(Ready), 에러가 났는지(Flag), 인터럽트 발생 여부 등 확인

    #define GPIO_MODER    (*(volatile unsigned int *)0x40020000) // 모드 설정
    #define GPIO_ODR      (*(volatile unsigned int *)0x40020014) // 출력 데이터
    #define GPIO_IDR      (*(volatile unsigned int *)0x40020010) // 입력 데이터
    #define GPIO_BSRR     (*(volatile unsigned int *)0x40020018) // 비트별 제어
    
    // GPIO를 Output으로 설정
    GPIO_MODER |= (1 << (5 * 2)); // 5번 핀을 Output 모드로
    // GPIO 5번 핀에 High 출력
    GPIO_ODR |= (1 << 5); // 5번 핀 ON
    // GPIO 5번 핀의 입력값 확인
    if (GPIO_IDR & (1 << 5)) { /* 입력 High인 경우 */ }

ARM 주요 명령어 및 특성

  • Instruction

    CPU가 직접 실행할 하나의 최소 단위 명령

    하드웨어(레지스터, 메모리, I/O 등)에 바로 영향을 주는 동작 지정

    ARM에서는 하드웨어 플랫폼이 달라져도 명령어 대부분 그대로 사용 가능(Portable)

    C 코드를 어셈블리로 분석해 보면 하드웨어에서 소스 코드 동작 방식을 익힐 수 있음

    임베디드 디버깅 시 매우 유용

  • 주요 명령어

    분류명령어설명사용 예시
    데이터 이동MOV, MVN레지스터/메모리 간 값 복사, 반전MOV r1, r2 : r1에 r2 복사
    MVN r1, r2 : r2 NOT, r1에 저장
    시스템 레지스터MRS, MSR시스템 상태 레지스터 읽기/쓰기MRS r0, CPSR : r0에 CPSR 값 읽기
    MSR CPSR, r1 : CPSR에 r1 값 쓰기
    비교/비트 연산CMP, BIC두 값 비교(ZF 등 상태 비트 갱신)
    비트 마스크 처리CMP r1, r2 : r1과 r2 비교, 조건 플래그 설정
    BIC r1, r2, r3 : r1 = r2 &~ r3
    산술/논리 연산ADD/SUB/...더하기, 빼기, 곱하기, AND/OR/XORADD r0, r1, r2 : r0 = r1 + r2
    SUB r1, r2, #1 : r1에서 1 빼기
    메모리 연산LDR, STR메모리에서 값 읽고/쓰기LDR r1, [r2] : r2가 가리키는 주소에서 r1로 값 읽기
    STR r1, [r2] : r1값을 r2가 가리키는 주소로 기록
    분기/함수 호출BL, BLX함수 실행 및 복귀주소 저장BL func : func 호출, 복귀주소 LR에 저장
    조건 분기BEQ, BNE조건에 따라 브랜치BEQ label : ZF=1일 때 label로 이동
    BNE label : ZF=0일 때 label 이동
    시스템콜/익셉션SVC운영체제 서비스 호출, 인터럽트 발생SVC #0 : 소프트웨어 인터럽트 호출
    상태 레지스터CPSR, SPSR현재 상태 및 모드 유지/갱신CPSR: 연산 결과 따라 NZCV 플래그, SPSR: 예외 진입 시 이전 CPSR 저장
  • 명령어 사용 예시

    ADD r0, r1, r2 ; r1, r2의 값을 더해서 r0에 저장 (r0 = r1 + r2)
    
    ; r1, r2의 값을 더하고 연산 결과를 플래그에 남긴다 (ADD에 s를 붙임)
    ADDS r0, r1, r2 
    ; r1에 저장된 주소(옵션 더함)에서 값을 읽어서 r0에 복사 (메모리 → 레지스터)
    LDR r0, [r1, #option]
    
    ; r0에 저장된 값을 [r1 + 옵션] 메모리 주소에 저장 (레지스터 → 메모리)
    STR r0, [r1, #option]
    CMP r1, r2 ; r1과 r2를 비교 (동등하면 Z 플래그=1)
    
    BEQ yes ; Z 플래그가 1(같으면) yes 위치로 점프
    BNE no ; Z 플래그가 0(다르면) no 위치로 점프
    
    ; 다양한 조건 접미사: EQ(같음), NE(다름), GT(크다), LT(작다) 등
    BGT bigger   ; r1 > r2이면 bigger로 점프
    BLT lower    ; r1 < r2이면 lower로 점프
  • 조건부 실행과 효율

    명령어에 조건부 접미사를 붙이면 명령어 실행 시점을 컨트롤 가능

    조건부 실행을 사용하면 파이프라인 구조를 깨지않고 효율적인 분기 가능

  • 2바이트, 4바이트 명령어 사용 이유

    ARM 명령어는 기본 4바이트이지만, Thumb 등에서는 2바이트 명령어도 지원

    4바이트 자리에 2바이트 명령어 2개를 저장하면 공간 효율성 높음(코드 압축 효과)

    디코딩이 다소 복잡해질 수 있지만, 메모리 절약·효율 증대 가능

ARM 시스템 모드와 레벨, Cortex-M4 기능 이해

모드와 권한(level, privilege)

  • auth (권한 체계)

    privileged(슈퍼유저/kernel mode): 모든 명령과 장치 제어 가능, 운영체제 핵심(커널 등)이 주로 사용

    non-privileged(user mode): 사용자 프로그램/앱에서 주로 사용, 시스템 핵심 보호

  • mode (실행 모드)

    thread mode: 프로그램 실행시의 일반 모드, 전원을 켜면 전체가 privileged 모드, OS 부팅 후에는 multi-task 기반으로 non-privileged(앱)도 사용됨

    handler mode: 인터럽트 등 시스템 차원에서 동작하는 처리 모드, 항상 privileged

  • stack 종류

    main stack: handler mode와 privileged thread mode에서 사용 (인터럽트, 시스템 함수)

    process stack: non-privileged thread(운영체제 task)에서 사용

시스템 전체 아키텍처 (Cortex-M4 기준)

  • RISC vs CISC

    RISC: 적은 종류의 간단한 명령어로 빠르고 효율적. ARM은 RISC 구조 사용

    CISC: 복잡한 명령어 집합으로 다양한 기능. x86 등에서 사용

  • ARM 프로세서 종류

    Cortex-A: 고성능 애플리케이션 프로세서(스마트폰 등)

    Cortex-R: 실시간 처리용(자동차, 산업)

    Cortex-M: 저전력·소형 MCU(센서, IoT, 임베디드 제어)

  • Cortex-M4 특징

    32비트 RISC, FPU(부동소수점 연산), DSP 명령어, 저전력, 3단계 파이프라인, Thumb/Thumb-2 하이브리드, 하드웨어 디버깅, 실시간 인터럽트, MPU로 메모리 보호 등

  • Execution state

    ARM: 4바이트 명령 실행 (기본)

    Thumb: 2바이트 명령 실행 (공간 절약)

    Thumb-2: ARM+Thumb 혼합

  • 워드(Word)

    한 번에 처리 가능한 데이터의 크기

    Cortex-M4에서는 4바이트

주요 레지스터 및 인터럽트

  • CPSR(Current Program Status Register), SPSR(Stored Program Status Register)

    코드 실행 및 인터럽트 상태, 모드 등 시스템 동작을 실시간으로 저장/관리

    SVC(Supervisor Call) 모드 등 제한된 상황에서만 직접 접근

  • 상태 플래그

    N: 연산 결과 음수

    Z: 연산 결과가 0

    C: 캐리/버로우, 빼기나 더하기시 자리올림/내림 발생

    IF: IRQ/FIQ 인터럽트 발생 여부

하드웨어 제어와 비트 연산

  • 디바이스 접근 방법

    메모리 매핑된 SFR(주소에 직접 접근), C에서 volatile 키워드 사용하여 하드웨어 제어

    어셈블리 언어의 LDR/STR 명령어로 레지스터(메모리) 읽고 쓰기

  • 비트 연산

    하드웨어 레지스터를 비트 단위로 조작할 때 사용

    bit set : 특정 비트를 1로 만듦 (|)

    bit clr : 특정 비트를 0으로 만듦 (&~)

    bit filter : 원하는 비트만 남김 (&)

    bit toggle : 0/1 전환 (^)

  • 비트 마스킹 연산

    레지스터 내부의 특정 비트만 읽거나, 바꾸거나, 필터링할 때 사용

    주로 하드웨어 제어, 플래그 처리, GPIO 핀 제어, 주변장치 설정 등에 자주 활용

    rWDTCON = xxxx:zzxx ; // 레지스터 기존 값
    msk = 0000:1100     ; // 관심 있는 비트 영역 (마스킹)
    ~msk = 1111:0011    ; // 마스크 반전 (NOT)
    rWDTCON & ~msk      ; // 관심 영역만 0으로 클리어 (나머지 비트 유지)
    val = 0000:0100     ; // 원하는 값 (설정)
    rWDTCON | val       ; // 관심 영역에 값 설정(비트 set)
    => xxxx:01xx        ; // 최종적으로, 관심 비트만 원하는 값으로 변경됨
  • 비트 마스킹 연산 예시

    // 관심 비트만 마스킹해서 클리어/셋/필터/토글
    // 클리어하고(특정 비트를 모두 0으로), 원하는 값만 set
    rWDTCON = rWDTCON & ~0x0c;   // 0x0c = 00001100, 관심 영역(비트 2,3)을 모두 0으로 클리어
    rWDTCON = rWDTCON | 0x04;    // 0x04 = 00000100, 비트 2에만 1 set (비트 3은 여전히 0)
    
    rWDTCON &= ~(3<<2);          // 비트 2,3 클리어(3: 11, <<2: 비트 2,3 위치)
    rWDTCON |= (1<<2);           // 비트 2에만 set

GPIO

GPIO 기본 동작 원리

  • GPIO (General Purpose Input Output)

    임베디드 MCU가 외부 핀을 입력(스위치, 센서 등) 또는 출력(LED, 모터 등)으로 자유롭게 제어할 수 있게 해주는 회로/핀

  • Read

    입력모드로 설정 시, 외부에서 신호가 들어오는지 읽음

    (IDR: input data register)

  • Write

    출력모드로 설정 시, 레지스터에 값을 기록해서 전기적 신호를 외부로 전송

    (ODR: output data register 또는 BSRR: bit set/reset register)

    내부 논리회로(P-MOS, N-MOS)를 통해 I/O핀을 직접 제어해 외부 장치(LED/KEY 등)를 구동

    Write → registers → 1 → output control → P-MOS, N-MOS → I/O pin → LED/KEY

    MCU의 코드에서 GPIO에 Write 시도
    → 레지스터(ODR, BSRR 등)에 값 기록
    → 하드웨어 회로(P-MOS 또는 N-MOS)가 해당 신호를 I/O 핀에 내보냄
    → I/O 핀이 LED, 스위치 등 외부 소자를 직접 제어

GPIO 종류 및 입력·출력과 특징

  • Push-pull

    약한 신호(0/1)를 강하게 증폭해서 출력하는 방식

    LED 등 일반 출력에 널리 사용

  • Open-drain

    외부에서 풀업/풀다운 저항 연결

    신호를 0 으로만 직접 만들고, 1 은 외부 회로에서 보조

  • 풀업/풀다운 저항

    눌리지 않을 때/no input일 때 불안정 신호를 방지하고 입력을 안정화

  • Protection diode

    입력 전압이 0~3.3V 같은 허용 범위 내에서만 동작하도록 보호

  • Schmitt trigger

    작은 변동에 흔들리지 않고, 명확한 high(3.3V)/low(0V) 판단

    IH ~ IL 사이의 값으로 측정되는 경우에는 기존의 값을 유지함

  • Alternate function

    GPIO는 필수 외 주변장치(UART, SPI 등) 기능도 담당할 수 있고 핀마다 다름

GPIO 레지스터 구조

  • MODER

    각 핀의 사용 용도를 설정

    (00: 입력, 01: 출력, 10: 대체기능, 11: 아날로그)

  • OTYPER

    push-pull/open-drain 모드 선택

  • IDR/ODR

    입력/출력 데이터 레지스터

  • BSRR

    각 핀 별로 set/reset 명령 빠르게 실행 (LED 켜기/끄기에 자주 활용)

  • PUPDR

    풀업/풀다운 저항 설정

GPIO 사용 실습

  • 타이머 세팅해서 LED 깜빡이기
    int main(void)
    {
      /* MCU Configuration--------------------------------------------------------*/
    
      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();
    
      /* Configure the system clock */
      SystemClock_Config();
    
      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_USART2_UART_Init();
      /* USER CODE BEGIN 2 */
    
    	RCC->AHB1ENR |= (1 << 0); // clock for PA5
    	
    	GPIOA->MODER &= ~(3 << 2*5); // clear 10, 11th bit
    	GPIOA->MODER |= (1 << 2*5); // mode for PA5
    
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
    	while (1)
      {
    		// ODR, BSRR
    		GPIOA->BSRR = (1 << 5); // ODR5 == 1
    		HAL_Delay(500);
    		
    		GPIOA->BSRR = (1 << (5 + 16)); // ODR5 == 0
    		HAL_Delay(500);
    		
        /* USER CODE END WHILE */
      }
    }
  • 스위치 누르면 LED 불 켜기
    int main(void)
    {
      /* MCU Configuration--------------------------------------------------------*/
    
      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();
    
      /* Configure the system clock */
      SystemClock_Config();
    
      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_USART2_UART_Init();
      /* USER CODE BEGIN 2 */
    	
    	GPIOA->MODER &= ~(3 << 2*9); // clear bits
    	GPIOA->MODER |= (1 << 2*9);
    	
    	GPIOC->PUPDR &= ~(3 << 2*7); // no pull-up, no-pull-down
    	GPIOC->PUPDR |= (1 << 2*7);
    
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
    	while (1)
      {
    		if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_7) == 0)
        {
          HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);   // LED OFF
        }
        else
        {
          HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET); // LED ON
        }
    		
    		HAL_Delay(100);
    		
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */
      }
      /* USER CODE END 3 */
    }

인터럽트(Interrupt)

인터럽트와 폴링, DMA

  • 임베디드 시스템의 I/O 및 데이터 흐름

    각 입출력 장치는 자체적으로 작은 내부 버퍼를 갖고 있음

    CPU는 이런 버퍼에서 데이터를 읽어와 더 큰 RAM에 저장해 효율·속도를 맞춤

    폴링, 인터럽트, DMA 등 다양한 데이터 처리(이벤트 응답) 방식이 존재함

    인터럽트란 디바이스가 입력/출력/에러의 상황에 대한 프로세서의 처리를 요구하는 것

  • 폴링(Polling)

    CPU가 주기적으로 장치의 데이터 버퍼를 확인해서 직접 데이터를 읽어오는 방식

    CPU가 다른 작업을 수행 중일 때 데이터를 놓칠 수 있으며, 비효율적

    온도계 등 실시간성이 덜 요구되는 경우 사용

  • 인터럽트(Interrupt)

    장치에 새로운 데이터가 준비되면 CPU에 인터럽트 요청(irqreq)을 보냄

    CPU는 요청을 받으면 지정된 인터럽트 핸들러에서 즉시 데이터를 처리

    효율적이고, 실시간 반응성 보장 (CPU는 평소 자신의 일 하다가 신호 받았을 때만 처리)

    EXTI(외부 인터럽트)·NVIC(인터럽트 관리 컨트롤러) 등으로 관리

  • DMA(Direct Memory Access)

    장치에 새로운 데이터가 준비되면 DMA Request(dmareq)를 보냄

    CPU 대신 DMA라는 전용 장치가 데이터를 직접 옮김

    CPU는 계산 등 본연의 일에 집중, 데이터 복사는 DMA가 전용채널로 수행

ARM 인터럽트 처리 구조

  • 인터럽트 핸들링 과정

    각 디바이스, 센서 등이 인터럽트 요청(IRQ 핀/번호) 발생

    인터럽트 컨트롤러(NVIC)가 우선순위·처리 여부 결정

    GPIO/타이머/UART 등 다양한 인터럽트(WWDG, DMA1_Channel 등) 지원

    EXTI(External Interrupt) 회로는 신호의 변화(에지/레벨 등)를 인식해 소프트웨어/하드웨어적으로 이벤트 발생

    Pending Register가 여러 요청에서 처리 우선순위 정함 (OR/AND 연산)

    NVIC가 적합한 핸들러로 분배 후 처리

  • NVIC (Nested Vectored Interrupt Controller)

    ARM Cortex-M 계열 MCU는 NVIC라는 인터럽트 컨트롤러를 내장

    수십~수백 개의 인터럽트 라인(입력 채널)을 관리하며, 최대 16단계 우선순위 설정이 가능함

    WWDG(윈도우 와치독), EXTI0~4, DMA1_Channel1~7, EXTI15_10, 타이머 등 다양한 라인 관리

    • 주요 기능

      각 인터럽트의 활성화/비활성화

      우선순위 레벨 설정 (중첩 인터럽트가 오면 높은 것부터 처리)

      인터럽트별 핸들러(함수)로 자동 분배

      빠른(저지연) 예외 및 인터럽트 처리

  • EXTI (External Interrupt/Event Controller)

    GPIO에서 들어오는 외부 신호에 대한 에지(Edge, 상승/하강, 변화)를 감지

    • 감지 방식

      edge detect circuit : 입력 신호의 변화(0→1 or 1→0)를 감지

      software interrupt event register : 실제 외부 신호 대신 소프트웨어가 임의로 이벤트 생성 가능

  • 인터럽트 요청 처리 메커니즘

    1. Input line: GPIO 핀 등에서 인터럽트 신호 입력

    2. Edge detect: 변화가 발생(예: 버튼 눌림)하면 감지

    3. OR 연산: 여러 입력이 동시에 올 수 있으니 OR 연산으로 다중 검출

    4. interrupt mask register(IMR): 특정 라인(switch, 센서 등)을 마스킹(허용/차단) 가능, AND 연산으로 선택적 허용

    5. pending request register(PR): 어떤 인터럽트 요청이 대기 중인지 기록, 여러 요청이 쌓이면 우선순위로 정렬

    6. NVIC: 우선순위대로 핸들러로 분배, 실제 인터럽트 핸들링 수행

      Input line → edge detect circuit/software interrupt 
      → OR 연산 → interrupt mask(AND 연산) → pending register → NVIC(우선순위 처리)

타이머(Timer)

타이머의 기본 동작 원리

  • Time-base unit

    MCU 내부의 카운터가 일정 시간마다 숫자를 셈

    타임 베이스 유닛 값을 모니터링하다 필요에 따라 특정 이벤트를 발생시키는 장치

  • 카운터(Counter)

    카운트 업(+) 또는 다운(-) 또는 둘 다(업/다운) 지원

    1초, 1ms 등 원하는 시간 단위 기준으로 인터럽트 등의 이벤트를 생성

  • 핵심 레지스터

    counter register : 현재 카운터 값(몇 번 셌는지 기록)

    prescaler register : 카운트 속도 조절(클럭을 나눠서 처리, 빠르게 또는 느리게)

    auto-reload register : 카운터가 끝까지 세면 자동으로 값 복구하고, 반복 동작

  • 클럭 및 프리스케일러(Prescaler) 설정

    MCU의 클럭(예: 84MHz)에서 프리스케일(default 0~65535 등)을 나눠 속도 조절

    프리스케일 값(PSC)에 83(=84-1)을 넣으면 카운터는 1MHz로 동작

    예: 84MHz / 84 → 1MHz (1초에 100만 번 카운트)

  • counter period(주기) 설정

    카운터 세는 값 한계를 정하고 원하는 시간 단위로 타이머를 반복시킴

    예: 1ms, 50ms, 500ms 등(자동 반복)

  • NVIC Settings 및 인터럽트 핸들러

    NVIC에서 TIM3 global interrupt 활성화

    타이머가 주기마다 자동으로 TIM3_IRQHandler 호출

    handler 내부에서 전역 변수 등으로 플래그 관리(예: 카운트 증가)

    반복 동작, 실시간 이벤트 트리거에 활용

  • 타이머로 LED 조작 실습(delay 구현)

    /* Includes ------------------------------------------------------------------*/
    #include "main.h"
    
    /* Private variables ---------------------------------------------------------*/
    TIM_HandleTypeDef htim3;
    
    UART_HandleTypeDef huart2;
    
    /* Private function prototypes -----------------------------------------------*/
    void SystemClock_Config(void);
    static void MX_GPIO_Init(void);
    static void MX_TIM3_Init(void);
    static void MX_USART2_UART_Init(void);
    
    /* Private user code ---------------------------------------------------------*/
    /* USER CODE BEGIN 0 */
    
    void delay_usec( int us, int loop ) // total delay time = us * loop (usec)
    {
    	while (loop--)
    	{
    		__HAL_TIM_SET_COUNTER(&htim3, 0); // up counter
    		HAL_TIM_Base_Start(&htim3);
    		
    		while (__HAL_TIM_GET_COUNTER(&htim3) < us) ; // delay by while
    		
    		HAL_TIM_Base_Stop(&htim3);
    	}
    }
    
    /* USER CODE END 0 */
    
    int main(void)
    {
      /* MCU Configuration--------------------------------------------------------*/
    
      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();
      
      /* Configure the system clock */
      SystemClock_Config();
    
      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_TIM3_Init();
      MX_USART2_UART_Init();
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
    		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, 1);
    		delay_usec(1000, 1000);
    		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, 0);
    		delay_usec(1000, 1000);
        /* USER CODE END WHILE */
      }
    }

DMA 시스템 구조와 동작 원리

DMA 기본 개념

  • DMA(Direct Memory Access)

    메모리와 외부 장치(Peripheral) 사이의 데이터 전송을 CPU의 개입 없이 전용 DMA 컨트롤러가 직접 처리하는 방식

    CPU의 부담을 덜고, 데이터 이동이 훨씬 빠르고 효율적으로 진행됨

    실무에서는 센서 데이터, 통신, 대용량 데이터 전송 등에 필수 사용

  • DMA 트랜잭션 종류(AHB 버스 기준)

    Peripheral to memory (00) : 센서 등에서 RAM으로 데이터 전달

    Memory to peripheral (01) : RAM에 저장된 데이터를 장치로 전달

    Memory to memory (10) : RAM에서 RAM으로 데이터 복사

  • DMA 요청 흐름

    peripheral → DMAREQ(DMA 요청) → DMA → BUSREQ(버스 사용할 요청) → CPU 
    → BUSACK(버스 사용 허용) → DMA → DMAACK(작동 신호) → peripheral

    Arbiter(중재기): 여러 채널이 동시에 데이터 전송을 요구할 때, 우선순위를 정해서 버스 충돌 방지

DMA 동작 유형

  • DMA 전송 모드

    Peripheral-to-memory, Memory-to-peripheral, Memory-to-memory

  • 필수 설정 항목

    Source(데이터 읽는 쪽), Destination(데이터 쓰는 쪽) 선택

    Flow controller: DMA가 직접 이동 관리하거나, peripheral(장치) 측에서 제어

    Circular mode: 데이터 송수신을 자동 반복할지 여부

    Transfer type: single(데이터 1건씩), burst(여러 건 연속)

    Direct mode, Double buffer mode: 빠른 연속 처리/두 개 버퍼를 번갈아 사용해 끊김 없이 데이터 가능

    • Tranfer type

      버스트(burst): 대용량, 연속 데이터 처리에 적합

      싱글(single): 보통의 단일, 순서 처리

      자동 반복(circular), 더블 버퍼: 실시간 신호처리, 스트리밍 등 정밀 자동화 처리

  • DMA 포인터 증분

    대부분의 DMA 전송은 복사할 때 버퍼 포인터(주소)를 이동시키면서 옮김

    peripheral의 일부 레지스터는 직접 포인터 이동 없이 고정된 주소를 반복해서 읽고, 메모리 쪽 포인터만 증가시켜 복사하기도 함

  • DMA 완료와 인터럽트

    DMA가 작업을 마치면 CPU에 작업 완료 인터럽트로 알림

    에러 상황(데이터 에러, FIFO 에러 등)도 별도 인터럽트로 신호 가능

    실무에서는 DMA가 작업 완료 시 Interrupt Handler에서 후속 작업(버퍼 처리, 상태 업데이트 등)을 관리

  • DMA configurations 요약

    출처 : STM32F401 Reference Manual


2️⃣ 느낀 점

보드를 처음 다뤄보는 거라 많이 낯설고 어려웠다.
이번 주에 배운 내용을 제대로 이해하지 못한 것 같아서 많이 아쉬웠다.
정리는 끝났지만 프로젝트 만들고 이런저런 기능을 더 써 봐야 감이 제대로 잡힐 것 같다.
이론 - 실습 - 이론 다시보기 구조로 배우면 괜찮을까 싶기도 하다.
들어와서 거의 처음으로 나를 의심할 수 있었던 시간이었다...,,!!

0개의 댓글