Bare metal C Ch10 UART - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki

Ch10. UART (Universal Asynchronous Receiver/Transmitter)

ํ•œ ์ค„ ์š”์•ฝ: NUCLEO-F439ZI์˜ ST-LINK VCP์— ์—ฐ๊ฒฐ๋œ USART3๋ฅผ 115200 bps๋กœ ์„ค์ •ํ•˜๊ณ , 1์ดˆ๋งˆ๋‹ค ๋ฌธ์ž์—ด์„ PC ํ„ฐ๋ฏธ๋„๋กœ ์ถœ๋ ฅํ•œ๋‹ค.

1. ํ•ต์‹ฌ ์ด๋ก 

UART๋Š” ๋ณ„๋„์˜ clock line ์—†์ด TX/RX ์„ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ๋น„๋™๊ธฐ ์ง๋ ฌ ํ†ต์‹ ์ด๋‹ค. ์–‘์ชฝ ์žฅ์น˜๊ฐ€ ๊ฐ™์€ baud rate๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋ฏ€๋กœ baud-rate ์„ค์ •์ด ์ค‘์š”ํ•˜๋‹ค.

์›์„œ ๋ณด๋“œ์™€ F439ZI์˜ ์ฐจ์ด

ํ•ญ๋ชฉ | ์›์„œ NUCLEO-F411 | NUCLEO-F439ZI ์‹ค์Šต -- | -- | -- ST-LINK VCP | USART2 | USART3 TX | PA2 | PD8 RX | PA3 | PD9 Clock enable | USART2EN | USART3EN, APB1ENR bit18 Alternate Function | AF7 | AF7 AFR | PA2/3 โ†’ AFR[0] | PD8/9 โ†’ AFR[1]

Baud rate

Notion๊ณผ ์‹ค์ œ ์ฝ”๋“œ์—์„œ๋Š”:

(periph_clk + baudrate / 2U) / baudrate

ํ˜•ํƒœ๋กœ ์ •์ˆ˜ ๋‚˜๋ˆ—์…ˆ์˜ ๋ฐ˜์˜ฌ๋ฆผ์„ ๊ตฌํ˜„ํ•œ๋‹ค.

APB1 clock = 16 MHz
baud       = 115200
BRR        โ‰ˆ 139

Polling ์†ก์‹ 

while (!(USART3->SR & SR_TXE)) { }
USART3->DR = data;

CPU๊ฐ€ TXE๊ฐ€ set๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ ๋’ค ๋‹ค์Œ byte๋ฅผ DR์— ์“ด๋‹ค.

2. ๋™์ž‘ ํ๋ฆ„

GPIOD clock enable
      โ”‚
      โ–ผ
PD8 / PD9 โ†’ Alternate Function
      โ”‚
      โ–ผ
AF7 โ†’ USART3
      โ”‚
      โ–ผ
USART3 clock enable
      โ”‚
      โ–ผ
BRR = 115200 bps ์„ค์ •
      โ”‚
      โ–ผ
TE + UE enable
      โ”‚
      โ–ผ
TXE polling
      โ”‚
      โ–ผ
DR write
      โ”‚
      โ–ผ
ST-LINK VCP โ†’ PC terminal

3. ์‹ค์ œ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ


Ch10_uart/

โ”œโ”€โ”€ Inc/gpio.h

โ”œโ”€โ”€ Src/gpio.c

โ”œโ”€โ”€ Inc/systick.h

โ”œโ”€โ”€ Src/systick.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๋ฅผ ์ „๋ถ€ ๊ธฐ๋กํ•œ๋‹ค.

4. ์ „์ฒด ์ฝ”๋“œ

Inc/gpio.h

#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 */

Src/gpio.c

#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-&gt;MODER &amp;= ~(0x3UL &lt;&lt; (LED_PIN * 2));
GPIOB-&gt;MODER |=  (0x1UL &lt;&lt; (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-&gt;MODER &amp;= ~(0x3UL &lt;&lt; (BTN_PIN * 2));  /* Input */
GPIOC-&gt;PUPDR &amp;= ~(0x3UL &lt;&lt; (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 */ }

Inc/systick.h

#ifndef SYSTICK_H_
#define SYSTICK_H_

#include <stdint.h> #include "stm32f4xx.h"

void systick_msec_delay(uint32_t delay);

#endif /* SYSTICK_H_ */

Src/systick.c

#include "systick.h"

#define CTRL_ENABLE (1UL << 0) #define CTRL_CLKSRC (1UL << 2) #define CTRL_COUNTFLAG (1UL << 16)

/* ์ฝ”์–ดํด๋Ÿญ 16MHz(๊ธฐ๋ณธ HSI) ๊ธฐ์ค€ 1ms๋‹น ํด๋Ÿญ ์‚ฌ์ดํด ์ˆ˜ */ #define ONE_MSEC_LOAD 16000UL

void systick_msec_delay(uint32_t delay) { SysTick->LOAD = ONE_MSEC_LOAD - 1UL; SysTick->VAL = 0UL; SysTick->CTRL = CTRL_CLKSRC; SysTick->CTRL |= CTRL_ENABLE;

for (uint32_t i = 0; i &lt; delay; i++)
{
    while ((SysTick-&gt;CTRL &amp; CTRL_COUNTFLAG) == 0UL) { }
}

SysTick-&gt;CTRL = 0UL;

}

Inc/uart.h

#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

Src/uart.c

#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-&gt;MODER &amp;= ~(0x3UL &lt;&lt; (8 * 2));
GPIOD-&gt;MODER |=  (0x2UL &lt;&lt; (8 * 2));
GPIOD-&gt;MODER &amp;= ~(0x3UL &lt;&lt; (9 * 2));
GPIOD-&gt;MODER |=  (0x2UL &lt;&lt; (9 * 2));

GPIOD-&gt;AFR[1] &amp;= ~(0xFUL &lt;&lt; 0);
GPIOD-&gt;AFR[1] |=  (0x7UL &lt;&lt; 0);   /* PD8 -&gt; AF7 (USART3_TX) */
GPIOD-&gt;AFR[1] &amp;= ~(0xFUL &lt;&lt; 4);
GPIOD-&gt;AFR[1] |=  (0x7UL &lt;&lt; 4);   /* PD9 -&gt; AF7 (USART3_RX) */

RCC-&gt;APB1ENR |= USART3EN;

uart_set_baudrate(APB1_CLK, DBG_UART_BAUDRATE);

USART3-&gt;CR1 = CR1_TE;
USART3-&gt;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); }

Src/main.c

#include "gpio.h"
#include "systick.h"
#include "uart.h"

int main(void) { led_init(); uart_init();

while (1)
{
    uart_write_string("Hello from NUCLEO-F439ZI! (USART3, 115200bps)\r\n");
    led_toggle();
    systick_msec_delay(1000);
}

}

5. ์‹ค์Šต ๊ฒฐ๊ณผ

Notion ๊ธฐ๋ก ๊ธฐ์ค€ ์‹ค์ œ ๋ณด๋“œ ๊ฒ€์ฆ ์™„๋ฃŒ.

  • STM32CubeIDE build/download/run ์™„๋ฃŒ

  • VCP๋ฅผ 115200-8-N-1๋กœ ์—ด์–ด ๋ฌธ์ž์—ด ์ถœ๋ ฅ ํ™•์ธ

  • 1์ดˆ๋งˆ๋‹ค ๋ฌธ์ž์—ด ์ถœ๋ ฅ๊ณผ LD1 toggle ํ™•์ธ

text = 1168 bytes
data = 0 bytes
bss  = 2560 bytes
warning ์—†์Œ

6. ํ•ต์‹ฌ ์ •๋ฆฌ

  • F439ZI VCP๋Š” USART3 PD8/PD9๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

  • GPIO Alternate Function ์„ค์ • ํ›„ USART clock/BRR/TE/UE๋ฅผ ์„ค์ •ํ•œ๋‹ค.

  • TXE polling ํ›„ DR์— byte๋ฅผ ๊ธฐ๋กํ•œ๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ