Alternative Function

๐Ÿ“˜ ์ „์ฒด ๊ตฌ์กฐ ๊ฐœ์š”

  • ์ด ํšŒ๋กœ๋Š” ์ž…๋ ฅ๊ณผ ์ถœ๋ ฅ ๋ชจ๋‘ ๊ฐ€๋Šฅํ•œ I/O ํ•€์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.
  • ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ๋‹ค์–‘ํ•œ ๋ ˆ์ง€์Šคํ„ฐ์™€ ๋“œ๋ผ์ด๋ฒ„ ํšŒ๋กœ, ์Šˆ๋ฏธํŠธ ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฐ ๊ธฐ๋Šฅ์€ STM32์˜ GPIOx_MODER, GPIOx_IDR, GPIOx_ODR, GPIOx_AFR, ๊ทธ๋ฆฌ๊ณ  PUPDR ๊ฐ™์€ ๋ ˆ์ง€์Šคํ„ฐ๋กœ ์ œ์–ด๋ฉ๋‹ˆ๋‹ค.

๐Ÿ”น ์ฃผ์š” ๋ธ”๋ก ์„ค๋ช… (โ†’ ๊ด€๋ จ ๋ ˆ์ง€์Šคํ„ฐ ์—ฐ๊ฒฐ ํฌํ•จ)

โ‘  Input Path (์ž…๋ ฅ ๊ฒฝ๋กœ)

  • TTL Schmitt Trigger: ๋””์ง€ํ„ธ ์ž…๋ ฅ ์‹ ํ˜ธ๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํžˆ์Šคํ…Œ๋ฆฌ์‹œ์Šค ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ๋น„๊ต๊ธฐ์ž…๋‹ˆ๋‹ค.
  • ์—ฐ๊ฒฐ๋œ ๋ ˆ์ง€์Šคํ„ฐ:

    โœ… GPIOx_IDR

    • ์™ธ๋ถ€ I/O ํ•€์—์„œ ๋“ค์–ด์˜จ ์‹ ํ˜ธ๋Š” TTL ์Šˆ๋ฏธํŠธ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ๊ฑฐ์ณ Input data register๋กœ ์ „๋‹ฌ๋˜๊ณ , ์†Œํ”„ํŠธ์›จ์–ด์—์„œ GPIOx_IDR์„ ์ฝ์œผ๋ฉด ํ˜„์žฌ ํ•€ ์ƒํƒœ๋ฅผ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โ‘ก Output Path (์ถœ๋ ฅ ๊ฒฝ๋กœ)

  • Output control ๋ธ”๋ก์€ P-MOS, N-MOS๋ฅผ ์ œ์–ดํ•˜์—ฌ ํ•€์— ์ถœ๋ ฅ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค.
  • ์—ฐ๊ฒฐ๋œ ๋ ˆ์ง€์Šคํ„ฐ:

    โœ… GPIOx_ODR

    โœ… GPIOx_BSRR / GPIOx_BRR (๋น„ํŠธ ์„ธํŠธ/๋ฆฌ์…‹์šฉ)

    • ์†Œํ”„ํŠธ์›จ์–ด์—์„œ GPIOx_ODR ๋˜๋Š” BSRR/BRR์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•€์„ High/Low๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

โ‘ข Alternate Function (๋Œ€์ฒด ๊ธฐ๋Šฅ ๊ฒฝ๋กœ)

  • ์™ธ๋ถ€ ์žฅ์น˜(UART, SPI, PWM ๋“ฑ)์™€ ์—ฐ๊ฒฐ ์‹œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ์—ฐ๊ฒฐ๋œ ๋ ˆ์ง€์Šคํ„ฐ:

    โœ… GPIOx_AFR[0/1] (Alternate Function Low/High Register)

    โœ… GPIOx_MODER: ํ•ด๋‹น ํ•€์„ alternate ๊ธฐ๋Šฅ์œผ๋กœ ์„ค์ •

    • MODER์—์„œ ํŠน์ • ํ•€์„ Alternate ๋ชจ๋“œ(10)๋กœ ์„ค์ •ํ•˜๋ฉด ์ด ๊ฒฝ๋กœ๊ฐ€ ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค.
    • ์ดํ›„ AFRL/AFRH๋ฅผ ํ†ตํ•ด ์–ด๋–ค ์ฃผ๋ณ€ ๊ธฐ๋Šฅ(UART, SPI ๋“ฑ)์— ์—ฐ๊ฒฐํ• ์ง€ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

โ‘ฃ Pull-up / Pull-down ์ œ์–ด

  • ๋‚ด๋ถ€ ํ’€์—…/ํ’€๋‹ค์šด ์ €ํ•ญ์„ ์—ฐ๊ฒฐํ•˜์—ฌ ์ž…๋ ฅ ์•ˆ์ •ํ™” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • ์—ฐ๊ฒฐ๋œ ๋ ˆ์ง€์Šคํ„ฐ:

    โœ… GPIOx_PUPDR

    • ๊ฐ ํ•€๋งˆ๋‹ค 2๋น„ํŠธ์”ฉ ์„ค์ •:

      00: ์—†์Œ, 01: Pull-up, 10: Pull-down, 11: ์˜ˆ์•ฝ


โ‘ค Protection Diodes (๋ณดํ˜ธ ๋‹ค์ด์˜ค๋“œ)

  • ESD(์ •์ „๊ธฐ)๋‚˜ ๊ณผ์ „์•• ๋ณดํ˜ธ๋ฅผ ์œ„ํ•ด VDD, VSS์™€ ์—ฐ๊ฒฐ๋œ ๋ณดํ˜ธ ๋‹ค์ด์˜ค๋“œ.
  • ํ•˜๋“œ์›จ์–ด์  ๋ณดํ˜ธ์žฅ์น˜๋กœ, ๋ ˆ์ง€์Šคํ„ฐ์™€ ์ง์ ‘ ์—ฐ๊ฒฐ๋˜์ง€๋Š” ์•Š์ง€๋งŒ, ์™ธ๋ถ€ ์ „์•• ์ธ๊ฐ€ ์‹œ ์ค‘์š” ์—ญํ• .

๐Ÿ“Š ์š”์•ฝ: ์ฃผ์š” ๋ ˆ์ง€์Šคํ„ฐ ์ •๋ฆฌ

๊ธฐ๋Šฅ ๊ด€๋ จ ๋ ˆ์ง€์Šคํ„ฐ ์„ค๋ช…
์ž…์ถœ๋ ฅ ๋ชจ๋“œ ์„ค์ • GPIOx_MODER 00: ์ž…๋ ฅ, 01: ์ถœ๋ ฅ, 10: AF, 11: ์•„๋‚ ๋กœ๊ทธ
์ž…๋ ฅ ๊ฐ’ ์ฝ๊ธฐ GPIOx_IDR ์ž…๋ ฅ๋œ High/Low ์ƒํƒœ ํ™•์ธ
์ถœ๋ ฅ ๊ฐ’ ์„ค์ • GPIOx_ODR, BSRR, BRR ํ•€์„ High/Low๋กœ ์„ค์ •
Pull-up/down ์ €ํ•ญ ์„ค์ • GPIOx_PUPDR ๋‚ด๋ถ€ ํ’€์—…/ํ’€๋‹ค์šด ์ €ํ•ญ ์„ค์ •
Alternate Function ์„ค์ • GPIOx_AFR[0/1] ์ฃผ๋ณ€ ์žฅ์น˜์™€ ์—ฐ๊ฒฐ ์„ค์ •

image.png

image.png

#define RCC_APB1ENR ((volatile uint32_t)0x40023840) โ‡’ 0x 40023800 + 0x40

image.png

RCC_APB1ENR |= (1 << 17);

image.png

image.png

โœ… 1. USART2 ๊ธฐ๋ณธ ์ •๋ณด

ํ•ญ๋ชฉ ๋‚ด์šฉ
TX ํ•€ PA2 (AF7)
ํด๋Ÿญ APB1 (RCC_APB1ENR)
USART2 ๋ฒ ์ด์Šค ์ฃผ์†Œ 0x4000 4400

image.png

๐Ÿ“˜ USART_SR (Status Register) ๋น„ํŠธ ์„ค๋ช…

๋น„ํŠธ ์ด๋ฆ„ ์†์„ฑ ์˜๋ฏธ
15 Reserved ์‚ฌ์šฉ๋˜์ง€ ์•Š์Œ
14 Reserved ์‚ฌ์šฉ๋˜์ง€ ์•Š์Œ
13 CTS (Clear To Send) rc_w0 ํ•˜๋“œ์›จ์–ด ํ๋ฆ„์ œ์–ด์—์„œ CTS ํ•€ ์ƒํƒœ CTS ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์‹œ 1๋กœ ์„ค์ •๋จ
12 LBD (LIN Break Detection) rc_w0 LIN ํ”„๋กœํ† ์ฝœ์—์„œ Break ๊ฐ์ง€ ์‹œ 1๋กœ ์„ค์ •๋จ
11 TXE (Transmit Data Register Empty) r TX ๋ฒ„ํผ๊ฐ€ ๋น„์—ˆ์Œ์„ ๋‚˜ํƒ€๋ƒ„1์ด๋ฉด ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ์“ธ ์ˆ˜ ์žˆ์Œ
10 TC (Transmission Complete) rc_w0 ์ „์†ก ์™„๋ฃŒ (shift register๊นŒ์ง€ ์ „๋ถ€ ์ „์†ก ์™„๋ฃŒ๋จ)
9 RXNE (Read Data Register Not Empty) rc_w0 ์ˆ˜์‹ ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ DR์— ๋„์ฐฉํ•จ์ฝ์„ ์ค€๋น„๊ฐ€ ๋˜์—ˆ์Œ์„ ์˜๋ฏธ
8 IDLE r IDLE ์ƒํƒœ ๊ฐ์ง€ (์ผ์ • ์‹œ๊ฐ„ ์ˆ˜์‹  ์—†์Œ)
7 ORE (Overrun Error) r ์ˆ˜์‹  ๋ฒ„ํผ ์˜ค๋ฒ„๋Ÿฐ ๋ฐœ์ƒ ์‹œ 1 (๋ฐ์ดํ„ฐ ์†์‹ค)
6 NF (Noise Flag) r ์ˆ˜์‹  ์ค‘ ๋…ธ์ด์ฆˆ ๊ฐ์ง€๋จ
5 FE (Framing Error) r Start/Stop ๋น„ํŠธ ์˜ค๋ฅ˜
4 PE (Parity Error) r ํŒจ๋ฆฌํ‹ฐ ์˜ค๋ฅ˜ ๋ฐœ์ƒ (ํŒจ๋ฆฌํ‹ฐ ๋น„ํŠธ ์„ค์ • ์‹œ)
3~0 Reserved ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ (0์œผ๋กœ ์œ ์ง€)

๐Ÿ“Œ ์ฃผ์š” ๋น„ํŠธ ์š”์•ฝ (์‹ค์ œ ์‚ฌ์šฉ์—์„œ ์ค‘์š”ํ•œ ๊ฒƒ)

๋น„ํŠธ ์ด๋ฆ„ ์–ธ์ œ ํ™•์ธ? ๋™์ž‘
TXE ์ „์†ก ์ค€๋น„ ์†ก์‹ ํ•˜๊ธฐ ์ „ 1์ด๋ฉด USART_DR์— ๋ฐ์ดํ„ฐ ์จ๋„ ๋จ
TC ์ „์†ก ์™„๋ฃŒ ์†ก์‹  ํ›„ ์ „์ฒด ์™„๋ฃŒ ํ™•์ธ ์‹œ 1์ด๋ฉด ๋ชจ๋‘ ์ „์†ก ์™„๋ฃŒ
RXNE ์ˆ˜์‹  ์ค€๋น„ ๋ฐ์ดํ„ฐ ์ˆ˜์‹  ์‹œ 1์ด๋ฉด USART_DR์—์„œ ์ฝ๊ธฐ
ORE ์˜ค๋ฅ˜ ์ˆ˜์‹  ์‹œ ์ฒ˜๋ฆฌ ์ง€์—ฐ๋˜๋ฉด ๋ฐœ์ƒ RXNE๋ฅผ ์•ˆ ์ฝ์–ด์„œ ๋ฐ์ดํ„ฐ ์œ ์‹ค
PE ์˜ค๋ฅ˜ ํŒจ๋ฆฌํ‹ฐ ์„ค์ •ํ•œ ๊ฒฝ์šฐ ์ž˜๋ชป๋œ ํŒจ๋ฆฌํ‹ฐ ์ˆ˜์‹ 
FE ์˜ค๋ฅ˜ ์ž˜๋ชป๋œ Stop bit ์ˆ˜์‹  framing error

๐Ÿ›  rc_w0 ๋œป?

์†์„ฑ ์˜๋ฏธ
r Read-only
rc_w0 ์ฝ๊ธฐ ๊ฐ€๋Šฅ, “1”์„ ์จ์•ผ ํด๋ฆฌ์–ด๋จ (write 0 has no effect)

์ฆ‰, ์˜ค๋ฅ˜ ๋น„ํŠธ๋‚˜ ์ƒํƒœ ํ”Œ๋ž˜๊ทธ๋Š” ‘์ฝ๊ธฐ’ + ‘1 ์“ฐ๊ธฐ’๋กœ ํด๋ฆฌ์–ด ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

c
๋ณต์‚ฌํŽธ์ง‘
USART2->SR &= ~(1 << 5);   // โŒ ์ž‘๋™์•ˆํ•จ
USART2->SR = ~(1 << 5);    // โŒ ์ž‘๋™์•ˆํ•จ

// ์ •์„: SR์€ ์ฝ๊ณ  DR๋„ ์ฝ์–ด์•ผ ํด๋ฆฌ์–ด๋จ (RXNE ๋“ฑ)
uint8_t dummy = USART2->DR;


โœ… ์‹ค์ œ ์†ก์‹  ๋ฃจํ‹ด ์˜ˆ์‹œ

c
๋ณต์‚ฌํŽธ์ง‘
// ์ „์†ก ์ค€๋น„๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
while (!(USART2->SR & (1 << 7))); // TXE

// ๋ฐ์ดํ„ฐ ์ „์†ก
USART2->DR = 'A';

// ์ „์†ก ์™„๋ฃŒ๊นŒ์ง€ ๋Œ€๊ธฐ (์˜ต์…˜)
while (!(USART2->SR & (1 << 6))); // TC


โœ… ์‹ค์ œ ์ˆ˜์‹  ๋ฃจํ‹ด ์˜ˆ์‹œ

c
๋ณต์‚ฌํŽธ์ง‘
// ์ˆ˜์‹  ๋ฐ์ดํ„ฐ ๋„์ฐฉ ๋Œ€๊ธฐ
while (!(USART2->SR & (1 << 5))); // RXNE

// ์ˆ˜์‹  ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ
char data = USART2->DR;

// RCC ๋ฐ GPIO ๊ด€๋ จ ๋ ˆ์ง€์Šคํ„ฐ ์ •์˜
#define RCC_AHB1ENR     (*(volatile uint32_t*)0x40023830) // AHB1 ํด๋Ÿญ (GPIO์šฉ)
#define RCC_APB1ENR     (*(volatile uint32_t*)0x40023840) // APB1 ํด๋Ÿญ (USART2์šฉ)

#define GPIOA_MODER     (*(volatile uint32_t*)0x40020000) // GPIOA ๋ชจ๋“œ ์„ค์ •
#define GPIOA_AFRL      (*(volatile uint32_t*)0x40020020) // GPIOA์˜ AFR[7:0] (PA0 ~ PA7)

#define USART2_BASE     0x40004400                         // USART2 ๋ฒ ์ด์Šค ์ฃผ์†Œ
#define USART2_SR       (*(volatile uint32_t*)(USART2_BASE + 0x00)) // ์ƒํƒœ ๋ ˆ์ง€์Šคํ„ฐ
#define USART2_DR       (*(volatile uint32_t*)(USART2_BASE + 0x04)) // ๋ฐ์ดํ„ฐ ๋ ˆ์ง€์Šคํ„ฐ
#define USART2_BRR      (*(volatile uint32_t*)(USART2_BASE + 0x08)) // ๋ณด๋ ˆ์ดํŠธ ์„ค์ •
#define USART2_CR1      (*(volatile uint32_t*)(USART2_BASE + 0x0C)) // ์ œ์–ด ๋ ˆ์ง€์Šคํ„ฐ 1

// USART2 ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜
void usart2_init() {
    // 1. ํด๋Ÿญ ์ธ๊ฐ€
    RCC_AHB1ENR |= (1 << 0);       // GPIOA ํด๋Ÿญ ์ธ๊ฐ€
    RCC_APB1ENR |= (1 << 17);      // USART2 ํด๋Ÿญ ์ธ๊ฐ€

    // 2. GPIO ์„ค์ • (PA2๋ฅผ USART2 TX๋กœ ์„ค์ •)
    GPIOA_MODER &= ~(3 << (2 * 2));      // MODER2 ํด๋ฆฌ์–ด
    GPIOA_MODER |=  (2 << (2 * 2));      // MODER2 = 10 (AF ๋ชจ๋“œ)

    GPIOA_AFRL &= ~(0xF << (4 * 2));     // AFRL2 ํด๋ฆฌ์–ด
    GPIOA_AFRL |=  (7 << (4 * 2));       // AFRL2 = 0111 (AF7: USART2)

    // 3. USART ์„ค์ • (9600 bps @ 16 MHz)
    USART2_BRR = 0x0683; // 9600bps ์„ค์ •

    // 4. USART ๋ฐ ์†ก์‹  ๊ธฐ๋Šฅ ํ™œ์„ฑํ™”
    USART2_CR1 |= (1 << 13);  // UE (USART Enable)
    USART2_CR1 |= (1 << 3);   // TE (Transmitter Enable)
}

// USART2๋ฅผ ํ†ตํ•ด ๋ฌธ์ž 1๊ฐœ ์†ก์‹ 
void usart2_write(char ch) {
    while (!(USART2_SR & (1 << 7)));  // TXE ๋Œ€๊ธฐ
    USART2_DR = ch;                   // ๋ฐ์ดํ„ฐ ์ „์†ก
}

int main(void) {
    usart2_init(); // USART2 ์ดˆ๊ธฐํ™”

    while (1) {
        usart2_write('A'); // ๋ฌธ์ž ์ „์†ก
        for (volatile int i = 0; i < 100000; ++i); // ๋”œ๋ ˆ์ด
    }
}

๐Ÿง  ์ด ์ฝ”๋“œ์˜ ํ•ต์‹ฌ ํฌ์ธํŠธ

  • GPIOA ํด๋Ÿญ, USART2 ํด๋Ÿญ, GPIO ํ•€ ๋ชจ๋“œ ์„ค์ •, AF ์„ค์ •, ๋ณด๋ ˆ์ดํŠธ ๊ณ„์‚ฐ, TX enable, TXE ์ƒํƒœ ์ฒดํฌ๊นŒ์ง€ ์ „๋ถ€ ๋ ˆ์ง€์Šคํ„ฐ๋กœ ์ฒ˜๋ฆฌ
  • HAL, CMSIS, StdPeriph ๋“ฑ ์–ด๋–ค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ
  • while (!(USART2_SR & (1 << 7)))๋Š” TX ๋ฒ„ํผ๊ฐ€ ๋น„์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ์ฝ”๋“œ

โœ… ์‹œ์Šคํ…œ ๊ตฌ์„ฑ

ํ•ญ๋ชฉ ๋‚ด์šฉ
MCU STM32F401
TX ํ•€ PA2 (AF7)
USART2 TX ์‚ฌ์šฉ
DMA DMA1, Stream 6, Channel 4 (USART2_TX ์ „์šฉ)

โœ… ์ „์ฒด ํ๋ฆ„

  1. RCC๋กœ USART2 / DMA1 / GPIOA ํด๋Ÿญ ์ธ๊ฐ€
  2. PA2๋ฅผ Alternate Function (AF7)๋กœ ์„ค์ •
  3. USART2 ๋ณด๋ ˆ์ดํŠธ ์„ค์ •, TE ํ™œ์„ฑํ™”
  4. DMA1_Stream6 ์„ค์ • (๋ฉ”๋ชจ๋ฆฌ โ†’ ์ฃผ๋ณ€์žฅ์น˜, ์ „์†ก ํฌ๊ธฐ ๋“ฑ)
  5. USART2์— DMA TX ์š”์ฒญ ํ—ˆ์šฉ
  6. DMA Enable โ†’ ์ž๋™ ์†ก์‹  ์‹œ์ž‘
#include <stdint.h>

// RCC
#define RCC_AHB1ENR      (*(volatile uint32_t*)0x40023830)
#define RCC_APB1ENR      (*(volatile uint32_t*)0x40023840)

// GPIO
#define GPIOA_MODER      (*(volatile uint32_t*)0x40020000)
#define GPIOA_AFRL       (*(volatile uint32_t*)0x40020020)

// USART2
#define USART2_BASE      0x40004400
#define USART2_SR        (*(volatile uint32_t*)(USART2_BASE + 0x00))
#define USART2_DR        (*(volatile uint32_t*)(USART2_BASE + 0x04))
#define USART2_BRR       (*(volatile uint32_t*)(USART2_BASE + 0x08))
#define USART2_CR1       (*(volatile uint32_t*)(USART2_BASE + 0x0C))
#define USART2_CR3       (*(volatile uint32_t*)(USART2_BASE + 0x14))

// DMA1 (USART2_TX โ†’ Stream 6, Channel 4)
#define DMA1_BASE        0x40026000
#define DMA1_Stream6_CR  (*(volatile uint32_t*)(DMA1_BASE + 0x118))
#define DMA1_Stream6_NDTR (*(volatile uint32_t*)(DMA1_BASE + 0x11C))
#define DMA1_Stream6_PAR (*(volatile uint32_t*)(DMA1_BASE + 0x120))
#define DMA1_Stream6_M0AR (*(volatile uint32_t*)(DMA1_BASE + 0x124))
#define DMA1_HIFCR        (*(volatile uint32_t*)(DMA1_BASE + 0x0A8)) // DMA Clear Interrupt Flags

void dma_usart2_init(const char* data, uint32_t len) {
    // 1. ํด๋Ÿญ ์ธ๊ฐ€
    RCC_AHB1ENR |= (1 << 0);     // GPIOA
    RCC_AHB1ENR |= (1 << 21);    // DMA1
    RCC_APB1ENR |= (1 << 17);    // USART2

    // 2. GPIO ์„ค์ • (PA2 -> AF7)
    GPIOA_MODER &= ~(3 << (2 * 2));
    GPIOA_MODER |=  (2 << (2 * 2));        // AF ๋ชจ๋“œ
    GPIOA_AFRL &= ~(0xF << (4 * 2));
    GPIOA_AFRL |=  (7 << (4 * 2));         // AF7: USART2

    // 3. USART2 ๋ณด๋ ˆ์ดํŠธ ๋ฐ ํ™œ์„ฑํ™”
    USART2_BRR = 0x0683;                   // 9600bps @ 16MHz
    USART2_CR3 |= (1 << 7);                // DMAT ํ™œ์„ฑํ™” (DMA enable transmitter)
    USART2_CR1 |= (1 << 13) | (1 << 3);    // USART Enable + Transmitter Enable

    // 4. DMA ์„ค์ • (Stream6, Channel 4)
    DMA1_Stream6_CR &= ~(1 << 0);          // Stream disable
    while (DMA1_Stream6_CR & 1);           // Stream์ด ์™„์ „ํžˆ ๊บผ์งˆ ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ

    DMA1_HIFCR |= (0x3D << 16);            // ๋ชจ๋“  ์ธํ„ฐ๋ŸฝํŠธ ํ”Œ๋ž˜๊ทธ ํด๋ฆฌ์–ด

    DMA1_Stream6_CR &= ~(7 << 25);         // CHSEL[2:0] ํด๋ฆฌ์–ด
    DMA1_Stream6_CR |=  (4 << 25);         // Channel 4 ์„ ํƒ (USART2_TX)

    DMA1_Stream6_CR &= ~(3 << 6);          // DIR = 01 (Memory โ†’ Peripheral)
    DMA1_Stream6_CR |=  (1 << 6);

    DMA1_Stream6_CR &= ~(1 << 10);         // Peripheral increment disable
    DMA1_Stream6_CR |=  (1 << 10);         // Memory increment enable

    DMA1_Stream6_CR &= ~(3 << 13);         // Memory data size = 8-bit
    DMA1_Stream6_CR &= ~(3 << 11);         // Peripheral data size = 8-bit

    DMA1_Stream6_PAR  = (uint32_t)&USART2_DR; // ๋ชฉ์ ์ง€ ์ฃผ์†Œ: USART2_DR
    DMA1_Stream6_M0AR = (uint32_t)data;       // ์†Œ์Šค ์ฃผ์†Œ: ๋ฌธ์ž์—ด
    DMA1_Stream6_NDTR = len;                  // ์ „์†กํ•  ๋ฐ”์ดํŠธ ์ˆ˜

    DMA1_Stream6_CR |= (1 << 0);              // DMA Stream Enable
}

int main(void) {
    const char msg[] = "Hello DMA USART2!\\r\\n";
    dma_usart2_init(msg, sizeof(msg) - 1);

    while (1); // ์ „์†ก ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
}

โœ… ํ•ต์‹ฌ ์š”์•ฝ

ํ•ญ๋ชฉ ์„ค๋ช…
DMA ์ฑ„๋„ DMA1 Stream6, Channel 4 (USART2_TX)
๋ฐ์ดํ„ฐ ํ๋ฆ„ Memory โ†’ USART2_DR
์žฅ์  CPU ๊ฐœ์ž… ์—†์ด ๋ฌธ์ž์—ด ์ „์†ก ๊ฐ€๋Šฅ
DMA ์ข…๋ฃŒ ์ฒ˜๋ฆฌ DMA๋Š” ์ž๋™ ์ข…๋ฃŒ, ์ˆ˜๋™ ํด๋ฆฌ์–ด ๊ฐ€๋Šฅ
๋””๋ฒ„๊น… ๋ฐฉ๋ฒ• ์˜ค์‹ค๋กœ์Šค์ฝ”ํ”„๋‚˜ UART ๋ชจ๋‹ˆํ„ฐ๋กœ ํ™•์ธ

โœ… ์‹œ์Šคํ…œ ๊ตฌ์„ฑ

ํ•ญ๋ชฉ ๋‚ด์šฉ
MCU STM32F401
TX ํ•€ PA2 (AF7)
USART2 TX ์‚ฌ์šฉ
DMA DMA1, Stream 6, Channel 4 (USART2_TX ์ „์šฉ)

โœ… ์ „์ฒด ํ๋ฆ„

  1. RCC๋กœ USART2 / DMA1 / GPIOA ํด๋Ÿญ ์ธ๊ฐ€
  2. PA2๋ฅผ Alternate Function (AF7)๋กœ ์„ค์ •
  3. USART2 ๋ณด๋ ˆ์ดํŠธ ์„ค์ •, TE ํ™œ์„ฑํ™”
  4. DMA1_Stream6 ์„ค์ • (๋ฉ”๋ชจ๋ฆฌ โ†’ ์ฃผ๋ณ€์žฅ์น˜, ์ „์†ก ํฌ๊ธฐ ๋“ฑ)
  5. USART2์— DMA TX ์š”์ฒญ ํ—ˆ์šฉ
  6. DMA Enable โ†’ ์ž๋™ ์†ก์‹  ์‹œ์ž‘

#include <stdint.h>

// RCC
#define RCC_AHB1ENR      (*(volatile uint32_t*)0x40023830)
#define RCC_APB1ENR      (*(volatile uint32_t*)0x40023840)

// GPIO
#define GPIOA_MODER      (*(volatile uint32_t*)0x40020000)
#define GPIOA_AFRL       (*(volatile uint32_t*)0x40020020)

// USART2
#define USART2_BASE      0x40004400
#define USART2_SR        (*(volatile uint32_t*)(USART2_BASE + 0x00))
#define USART2_DR        (*(volatile uint32_t*)(USART2_BASE + 0x04))
#define USART2_BRR       (*(volatile uint32_t*)(USART2_BASE + 0x08))
#define USART2_CR1       (*(volatile uint32_t*)(USART2_BASE + 0x0C))
#define USART2_CR3       (*(volatile uint32_t*)(USART2_BASE + 0x14))

// DMA1 Stream6 for USART2_TX
#define DMA1_BASE        0x40026000
#define DMA1_Stream6_CR  (*(volatile uint32_t*)(DMA1_BASE + 0x118))
#define DMA1_Stream6_NDTR (*(volatile uint32_t*)(DMA1_BASE + 0x11C))
#define DMA1_Stream6_PAR (*(volatile uint32_t*)(DMA1_BASE + 0x120))
#define DMA1_Stream6_M0AR (*(volatile uint32_t*)(DMA1_BASE + 0x124))
#define DMA1_HIFCR        (*(volatile uint32_t*)(DMA1_BASE + 0x0A8))

// NVIC
#define NVIC_ISER1       (*(volatile uint32_t*)0xE000E104)

volatile char rx_data = 0;

void dma_usart2_tx(const char* data, uint32_t len) {
    DMA1_Stream6_CR &= ~(1 << 0);          // Disable DMA stream
    while (DMA1_Stream6_CR & 1);

    DMA1_HIFCR |= (0x3D << 16);            // Clear all DMA interrupt flags

    DMA1_Stream6_CR &= ~(7 << 25);         // CHSEL = 4
    DMA1_Stream6_CR |=  (4 << 25);

    DMA1_Stream6_CR &= ~(3 << 6);
    DMA1_Stream6_CR |=  (1 << 6);          // Memory to Peripheral

    DMA1_Stream6_CR &= ~(1 << 10);         // Peripheral increment disable
    DMA1_Stream6_CR |=  (1 << 10);         // Memory increment enable

    DMA1_Stream6_CR &= ~(3 << 13);         // 8-bit mem
    DMA1_Stream6_CR &= ~(3 << 11);         // 8-bit periph

    DMA1_Stream6_PAR  = (uint32_t)&USART2_DR;
    DMA1_Stream6_M0AR = (uint32_t)data;
    DMA1_Stream6_NDTR = len;

    DMA1_Stream6_CR |= (1 << 0);           // Enable DMA stream
}

void usart2_init_dma_rx(void) {
    // Enable clocks
    RCC_AHB1ENR |= (1 << 0) | (1 << 21); // GPIOA, DMA1
    RCC_APB1ENR |= (1 << 17);            // USART2

    // GPIOA2 = TX, A3 = RX
    GPIOA_MODER &= ~((3 << (2 * 2)) | (3 << (3 * 2)));
    GPIOA_MODER |=  ((2 << (2 * 2)) | (2 << (3 * 2))); // AF mode

    GPIOA_AFRL &= ~((0xF << (4 * 2)) | (0xF << (4 * 3)));
    GPIOA_AFRL |=  ((7 << (4 * 2)) | (7 << (4 * 3))); // AF7

    USART2_BRR = 0x0683;                   // 9600 bps
    USART2_CR3 |= (1 << 7);                // DMAT enable
    USART2_CR1 |= (1 << 13) | (1 << 3) | (1 << 2) | (1 << 5); // UE, TE, RE, RXNEIE

    NVIC_ISER1 |= (1 << (USART2_IRQn - 32)); // USART2 interrupt enable
}

void USART2_IRQHandler(void) {
    if (USART2_SR & (1 << 5)) { // RXNE
        rx_data = USART2_DR;    // Read to clear RXNE
        // echo back
        dma_usart2_tx(&rx_data, 1);
    }
}

int main(void) {
    usart2_init_dma_rx();

    const char* msg = "USART2 DMA TX + RX interrupt ready\\r\\n";
    dma_usart2_tx(msg, 34);

    while (1);
}

clock_source.png

USART2๋ฅผ ํ†ตํ•ด DMA๋กœ ๋ฌธ์ž์—ด์„ ์†ก์‹ ํ•˜๊ณ , ์ˆ˜์‹ ๋œ ๋ฌธ์ž๋ฅผ ์ธํ„ฐ๋ŸฝํŠธ์—์„œ ๋ฐ›์•„ ์ฆ‰์‹œ DMA๋กœ ๋‹ค์‹œ ์†ก์‹ (์—์ฝ”)ํ•˜๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

๋‹ค์šด๋กœ๋“œ.gif

Posted in ์ „๋ฌธ๊ธฐ์ˆ ์„œ์ .

๋‹ต๊ธ€ ๋‚จ๊ธฐ๊ธฐ

์ด๋ฉ”์ผ ์ฃผ์†Œ๋Š” ๊ณต๊ฐœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•„์ˆ˜ ํ•„๋“œ๋Š” *๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค