์์ํ๊ธฐ ์
์ ์๊ฐ์์๋ ๋ ์ง์คํฐ ๊ฐ์ ์ด๋ป๊ฒ ๋ฐ๊พธ๋ ์ง ์์๋ณด์์ต๋๋ค. ์ด๋ฒ ์๊ฐ์๋ UART ํต์ ์ผ๋ก ์ถ๋ ฅ๊ณผ ์ ๋ ฅ์ ๋ฐฐ์ ๋ณผ ์์ ์ ๋๋ค (์ฝ๋ ์ ๋ง์)
5.1 UART (from GPT)
UART(๋ฒ์ฉ ๋น๋๊ธฐ ์ก์์ ๊ธฐ)๋ ๋ ์ฅ์น ๊ฐ์ ํด๋ญ ์ ํธ ์์ด ๋น๋๊ธฐ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ง๋ ฌ๋ก ์ ์กํ๋ ๊ธฐ์ ์ด๋ค. ์์ ๋นํธ์ ์ ์ง ๋นํธ๋ฅผ ์ฌ์ฉํด ๋ฐ์ดํฐ ํ๋ ์์ ๊ตฌ๋ถํ๋ฉฐ, ์ค๋ฅ ๊ฒ์ถ์ ์ํ ํจ๋ฆฌํฐ ๋นํธ๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ์ฃผ๋ก ๋ง์ดํฌ๋ก์ปจํธ๋กค๋ฌ์ ์ปดํจํฐ ๊ฐ์ ํต์ ์ ๋ง์ด ์ฌ์ฉ๋๋ค.
UART๋ ์ฃผ๋ก ์ฝ์ ์ ์ถ๋ ฅ์ฉ์ผ๋ก ์ฌ์ฉ๋๋ค. UART๋ฅผ ์ฌ์ฉํ ๋ UART ํ๋์จ์ด์ ๋ ์ง์คํฐ๋ฅผ ์ฝ๋๋ก ๊ฐ์ง๊ณ ์์ผ๋ฉด ๋ฐ๋ก UART๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
์คํ์ ์ด 0x00์ธ UARTDR์ UART Data Register์ ์ฝ์ 0 ~ 7๋ฒ ๋นํธ๊น์ง ์ ์ถ๋ ฅ์ ๋ด๋นํฉ๋๋ค. ํ๋ฒ์ 1byte๋ฅผ ํต์ ํ ์ ์๋ค 8 ~ 11๋ฒ ๋นํธ๊น์ง๋ ์ข ๋ฅ๋ณ๋ก ์ ์๋ ์๋ฌ์ด๋ค. ํ๋ ์์๋ฌ, ํจ๋ฆฌํฐ ์๋ฌ, ๋ธ๋ ์ดํฌ ์๋ฌ, ์ค๋ฒ๋ฐ ์๋ฌ ๋ฑ ์ด๋ฆ์ด ๋ถ์ด์๋ค. ์ค๋ช ์ ๋ถํฉํ๋ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด ํด๋น ๋นํธ ๊ฐ์ด 1์ด ๋๋ค.
5-2 ๊ทธ๋ฆผ
5-2 ๊ทธ๋ฆผ์ ์ฝ๋๋ก ์ฎ๊ธฐ๋ ๋ฐฉ๋ฒ์ 1. C์ธ์ด ๋งคํฌ๋ก๋ฅผ ํตํด ์ ์๋ฅผ ํ๊ฑฐ๋, 2. ๊ตฌ์กฐ์ฒด๋ฅผ ์ด์ฉํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.` ์ฐ๋ฆฌ๋ ๊ตฌ์กฐ์ฒด๋ฅผ ์ด์ฉํ ๊ฒ์ด๋ค.
๊ตฌ์กฐ์ฒด ์ฌ์ฉ ์ฝ๋ ์์
/*
* Uart.h
*
* Created on: Sep 8, 2018
* Author: maanu
*/
#ifndef HAL_RVPB_UART_H_
#define HAL_RVPB_UART_H_
typedef union UARTDR_t
{
uint32_t all;
struct {
uint32_t DATA:8; // 7:0
uint32_t FE:1; // 8
uint32_t PE:1; // 9
uint32_t BE:1; // 10
uint32_t OE:1; // 11
uint32_t reserved:20;
} bits;
} UARTDR_t;
typedef union UARTRSR_t
{
uint32_t all;
struct {
uint32_t FE:1; // 0
uint32_t PE:1; // 1
uint32_t BE:1; // 2
uint32_t OE:1; // 3
uint32_t reserved:28;
} bits;
} UARTRSR_t;
typedef union UARTFR_t
{
uint32_t all;
struct {
uint32_t CTS:1; // 0
uint32_t DSR:1; // 1
uint32_t DCD:1; // 2
uint32_t BUSY:1; // 3
uint32_t RXFE:1; // 4
uint32_t TXFF:1; // 5
uint32_t RXFF:1; // 6
uint32_t TXFE:1; // 7
uint32_t RI:1; // 8
uint32_t reserved:23;
} bits;
} UARTFR_t;
typedef union UARTILPR_t
{
uint32_t all;
struct {
uint32_t ILPDVSR:8; // 7:0
uint32_t reserved:24;
} bits;
} UARTILPR_t;
typedef union UARTIBRD_t
{
uint32_t all;
struct {
uint32_t BAUDDIVINT:16; // 15:0
uint32_t reserved:16;
} bits;
} UARTIBRD_t;
typedef union UARTFBRD_t
{
uint32_t all;
struct {
uint32_t BAUDDIVFRAC:6; // 5:0
uint32_t reserved:26;
} bits;
} UARTFBRD_t;
typedef union UARTLCR_H_t
{
uint32_t all;
struct {
uint32_t BRK:1; // 0
uint32_t PEN:1; // 1
uint32_t EPS:1; // 2
uint32_t STP2:1; // 3
uint32_t FEN:1; // 4
uint32_t WLEN:2; // 6:5
uint32_t SPS:1; // 7
uint32_t reserved:24;
} bits;
} UARTLCR_H_t;
typedef union UARTCR_t
{
uint32_t all;
struct {
uint32_t UARTEN:1; // 0
uint32_t SIREN:1; // 1
uint32_t SIRLP:1; // 2
uint32_t Reserved1:4; // 6:3
uint32_t LBE:1; // 7
uint32_t TXE:1; // 8
uint32_t RXE:1; // 9
uint32_t DTR:1; // 10
uint32_t RTS:1; // 11
uint32_t Out1:1; // 12
uint32_t Out2:1; // 13
uint32_t RTSEn:1; // 14
uint32_t CTSEn:1; // 15
uint32_t reserved2:16;
} bits;
} UARTCR_t;
typedef union UARTIFLS_t
{
uint32_t all;
struct {
uint32_t TXIFLSEL:3; // 2:0
uint32_t RXIFLSEL:3; // 5:3
uint32_t reserved:26;
} bits;
} UARTIFLS_t;
typedef union UARTIMSC_t
{
uint32_t all;
struct {
uint32_t RIMIM:1; // 0
uint32_t CTSMIM:1; // 1
uint32_t DCDMIM:1; // 2
uint32_t DSRMIM:1; // 3
uint32_t RXIM:1; // 4
uint32_t TXIM:1; // 5
uint32_t RTIM:1; // 6
uint32_t FEIM:1; // 7
uint32_t PEIM:1; // 8
uint32_t BEIM:1; // 9
uint32_t OEIM:1; // 10
uint32_t reserved:21;
} bits;
} UARTIMSC_t;
typedef union UARTRIS_t
{
uint32_t all;
struct {
uint32_t RIRMIS:1; // 0
uint32_t CTSRMIS:1; // 1
uint32_t DCDRMIS:1; // 2
uint32_t DSRRMIS:1; // 3
uint32_t RXRIS:1; // 4
uint32_t TXRIS:1; // 5
uint32_t RTRIS:1; // 6
uint32_t FERIS:1; // 7
uint32_t PERIS:1; // 8
uint32_t BERIS:1; // 9
uint32_t OERIS:1; // 10
uint32_t reserved:21;
} bits;
} UARTRIS_t;
typedef union UARTMIS_t
{
uint32_t all;
struct {
uint32_t RIMMIS:1; // 0
uint32_t CTSMMIS:1; // 1
uint32_t DCDMMIS:1; // 2
uint32_t DSRMMIS:1; // 3
uint32_t RXMIS:1; // 4
uint32_t TXMIS:1; // 5
uint32_t RTMIS:1; // 6
uint32_t FEMIS:1; // 7
uint32_t PEMIS:1; // 8
uint32_t BEMIS:1; // 9
uint32_t OEMIS:1; // 10
uint32_t reserved:21;
} bits;
} UARTMIS_t;
typedef union UARTICR_t
{
uint32_t all;
struct {
uint32_t RIMIC:1; // 0
uint32_t CTSMIC:1; // 1
uint32_t DCDMIC:1; // 2
uint32_t DSRMIC:1; // 3
uint32_t RXIC:1; // 4
uint32_t TXIC:1; // 5
uint32_t RTIC:1; // 6
uint32_t FEIC:1; // 7
uint32_t PEIC:1; // 8
uint32_t BEIC:1; // 9
uint32_t OEIC:1; // 10
uint32_t reserved:21;
} bits;
} UARTICR_t;
typedef union UARTDMACR_t
{
uint32_t all;
struct {
uint32_t RXDMAE:1; // 0
uint32_t TXDMAE:1; // 1
uint32_t DMAONERR:1;// 2
uint32_t reserved:29;
} bits;
} UARTDMACR_t;
typedef struct PL011_t
{
UARTDR_t uartdr; //0x000
UARTRSR_t uartrsr; //0x004
uint32_t reserved0[4]; //0x008-0x014
UARTFR_t uartfr; //0x018
uint32_t reserved1; //0x01C
UARTILPR_t uartilpr; //0x020
UARTIBRD_t uartibrd; //0x024
UARTFBRD_t uartfbrd; //0x028
UARTLCR_H_t uartlcr_h; //0x02C
UARTCR_t uartcr; //0x030
UARTIFLS_t uartifls; //0x034
UARTIMSC_t uartimsc; //0x038
UARTRIS_t uartris; //0x03C
UARTMIS_t uartmis; //0x040
UARTICR_t uarticr; //0x044
UARTDMACR_t uartdmacr; //0x048
} PL011_t;
#define UART_BASE_ADDRESS0 0x10009000
#define UART_INTERRUPT0 44
#endif /* HAL_RVPB_UART_H_ */
UART ํ๋์จ์ด๋ฅผ ์ ์ด ํ ์ ์๋ ๋ณ์๋ฅผ ์ ์ธํ๊ธฐ ์ํด์ Regs.c ํ์ผ์ ์์ฑ
Regs.c
/*
* Regs.c
*
* Created on: Sep 8, 2018
* Author: maanu
*/
#include "stdint.h"
#include "Uart.h"
volatile PL011_t* Uart = (PL011_t*)UART_BASE_ADDRESS0;
PLUS HAL
HAL(Hardware Abstraction Layer)์ ์ด์ ์ฒด์ ์ ํ๋์จ์ด ๊ฐ์ ์ค์ฌ ์ญํ ์ ํ๋ ์ํํธ์จ์ด ๊ณ์ธต์ผ๋ก, ๋ค์ํ ํ๋์จ์ด๋ฅผ ์ถ์ํํ์ฌ ์ผ๊ด๋ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ค. ์ด๋ฅผ ํตํด ๊ฐ๋ฐ์๋ ํ๋์จ์ด์ ์ธ๋ถ ์ฌํญ์ ๊ตฌ์ ๋ฐ์ง ์๊ณ ์์ฉ ํ๋ก๊ทธ๋จ์ ๊ฐ๋ฐํ ์ ์์ผ๋ฉฐ, ์์คํ ์ ์ด์์ฑ๊ณผ ํธํ์ฑ์ ๋์ผ ์ ์๋ค. HAL์ ํนํ ๋๋ผ์ด๋ฒ ๊ฐ๋ฐ๊ณผ ์์คํ ์์ ์ฑ ์ ์ง์ ์ค์ํ ์ญํ ์ ํ๋ค.
ํ์ฌ ํ์ผ๊ตฌ์กฐ
--boot
| |--Entry.S
| |--Main.c
|
--hal
| |--HalUart.h
| |--rvpb
| |--Uart.h
|
--include
| |--ARMv7AR.h
| |--MemoryMap.h
| |--stdint.h
|
--Makefile
--navilos
--README.md
HARUART.h ํ์ผ์ ์์ฑํฉ๋๋ค.
HALUART.h ์ฝ๋
/*
* HalUart.h
*
* Created on: Sep 8, 2018
* Author: maanu
*/
#ifndef HAL_HALUART_H_
#define HAL_HALUART_H_
void Hal_uart_init(void);
void Hal_uart_put_char(uint8_t ch);
#endif /* HAL_HALUART_H_ */
UART ๊ณต์ฉ API๋ฅผ ์ค๊ณํ์ต๋๋ค. ํด๋น API๋ฅผ ๋ง์กฑํ๋ ์ฝ๋๋ฅผ ๋ง๋ค๊ธฐ ์ํด Uart.c ํ์ผ์ ์ฌ๊ตฌ์ฑํด์ผํฉ๋๋ค.
Uart.c ์ฝ๋
/*
* Uart.c
*
* Created on: Sep 8, 2018
* Author: maanu
*/
#include "stdint.h" // ํ์ค ์ ์ ํ์
์ ์๋ฅผ ํฌํจํ๋ ํค๋ ํ์ผ
#include "Uart.h" // UART ๊ด๋ จ ํค๋ ํ์ผ
#include "HalUart.h" // HAL (Hardware Abstraction Layer) UART ๊ด๋ จ ํค๋ ํ์ผ
// ์ธ๋ถ์์ ์ ์ธ๋ volatile ํ์
์ PL011_t ๊ตฌ์กฐ์ฒด ํฌ์ธํฐ ๋ณ์ Uart
extern volatile PL011_t* Uart;
/*
* Hal_uart_init
* UART๋ฅผ ์ด๊ธฐํํ๋ ํจ์
*/
void Hal_uart_init(void)
{
// UART๋ฅผ ๋นํ์ฑํ
Uart->uartcr.bits.UARTEN = 0;
// ์ก์ (TX)์ ํ์ฑํ
Uart->uartcr.bits.TXE = 1;
// ์์ (RX)์ ํ์ฑํ
Uart->uartcr.bits.RXE = 1;
// UART๋ฅผ ํ์ฑํ
Uart->uartcr.bits.UARTEN = 1;
}
์ฝ๋๊ฐ ์ ์์ ์ผ๋ก ์๋๋๋ค๋ฉด ์คํ๋๋ ์๊ฐ UART๋ฅผ ํตํด์๋ฐ์ดํฐ๊ฐ ํธ์คํธ๋ก ์ ์ก๋ฉ๋๋ค.
Main.c ์ฝ๋
#include "stdint.h" // ํ์ค ์ ์ ํ์
์ ์๋ฅผ ํฌํจํ๋ ํค๋ ํ์ผ
#include "HalUart.h" // HAL (Hardware Abstraction Layer) UART ๊ด๋ จ ํค๋ ํ์ผ
#include "stdio.h" // ํ์ค ์
์ถ๋ ฅ ํจ์๋ค์ ํฌํจํ๋ ํค๋ ํ์ผ
static void Hw_init(void); // ํ๋์จ์ด ์ด๊ธฐํ ํจ์์ ์ ์ ์ ์ธ
void main(void) // ๋ฉ์ธ ํจ์์ ์ ์
{
Hw_init(); // ํ๋์จ์ด ์ด๊ธฐํ ํจ์ ํธ์ถ
uint32_t i = 100; // ์นด์ดํฐ ๋ณ์ ์ด๊ธฐํ
while(i--) // ์นด์ดํฐ๊ฐ 0์ด ๋ ๋๊น์ง ๋ฐ๋ณต
{
Hal_uart_put_char('N'); // UART๋ก ๋ฌธ์ 'N'์ ์ ์ก
}
}
static void Hw_init(void) // ํ๋์จ์ด ์ด๊ธฐํ ํจ์์ ์ ์
{
Hal_uart_init(); // UART ์ด๊ธฐํ ํจ์ ํธ์ถ
}
makefile์ ๊ตฌ์ฑ ํ ๋ค์์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํด๋ด ์๋ค.
Makefile
ARCH = armv7-a # ์ํคํ
์ฒ ์ค์
MCPU = cortex-a8 # CPU ์ค์
CC = arm-none-eabi-gcc # C ์ปดํ์ผ๋ฌ ์ค์
AS = arm-none-eabi-as # ์ด์
๋ธ๋ฌ ์ค์
LD = arm-none-eabi-ld # ๋ง์ปค ์ค์
OC = arm-none-eabi-objcopy # ์ค๋ธ์ ํธ ๋ณต์ฌ๊ธฐ ์ค์
LINKER_SCRIPT = ./navilos.ld # ๋ง์ปค ์คํฌ๋ฆฝํธ ํ์ผ ๊ฒฝ๋ก
MAP_FILE = build/navilos.map # ๋งต ํ์ผ ๊ฒฝ๋ก
ASM_SRCS = $(wildcard boot/*.S) # ์ด์
๋ธ๋ฆฌ ์์ค ํ์ผ ๋ชฉ๋ก
ASM_OBJS = $(patsubst boot/%.S, build/%.os, $(ASM_SRCS)) # ์ด์
๋ธ๋ฆฌ ์ค๋ธ์ ํธ ํ์ผ ๋ชฉ๋ก
C_SRCS = $(wildcard boot/*.c) # C ์์ค ํ์ผ ๋ชฉ๋ก
C_OBJS = $(patsubst boot/%.c, build/%.o, $(C_SRCS)) # C ์ค๋ธ์ ํธ ํ์ผ ๋ชฉ๋ก
INC_DIRS = -I include # ํฌํจ ๋๋ ํ ๋ฆฌ ์ค์
navilos = build/navilos.axf # ์์ฑ๋ ์คํ ํ์ผ ๊ฒฝ๋ก
navilos_bin = build/navilos.bin # ์์ฑ๋ ๋ฐ์ด๋๋ฆฌ ํ์ผ ๊ฒฝ๋ก
.PHONY: all clean run debug gdb # ๊ฐ์ ํ๊ฒ ์ค์
all: $(navilos) # ๊ธฐ๋ณธ ํ๊ฒ ์ค์
clean: # ๋น๋ ๋๋ ํ ๋ฆฌ ์ ๋ฆฌ ํ๊ฒ
@rm -fr build
run: $(navilos) # ์คํ ํ๊ฒ
qemu-system-arm -M realview-pb-a8 -kernel $(navilos)
debug: $(navilos) # ๋๋ฒ๊ทธ ํ๊ฒ
qemu-system-arm -M realview-pb-a8 -kernel $(navilos) -S -gdb tcp::1234,ipv4
gdb: # GDB ์คํ ํ๊ฒ
arm-none-eabi-gdb
$(navilos): $(ASM_OBJS) $(C_OBJS) $(LINKER_SCRIPT) # ์คํ ํ์ผ ์์ฑ ํ๊ฒ
$(LD) -n -T $(LINKER_SCRIPT) -o $(navilos) $(ASM_OBJS) $(C_OBJS) -Map=$(MAP_FILE)
$(OC) -O binary $(navilos) $(navilos_bin)
build/%.os: $(ASM_SRCS) # ์ด์
๋ธ๋ฆฌ ์ค๋ธ์ ํธ ํ์ผ ์์ฑ ํ๊ฒ
mkdir -p $(shell dirname $@)
$(CC) -march=$(ARCH) -mcpu=$(MCPU) $(INC_DIRS) -c -g -o $@ $<
build/%.o: $(C_SRCS) # C ์ค๋ธ์ ํธ ํ์ผ ์์ฑ ํ๊ฒ
mkdir -p $(shell dirname $@)
$(CC) -march=$(ARCH) -mcpu=$(MCPU) $(INC_DIRS) -c -g -o $@ $<
make run

N์ด 100๋ฒ ์ถ๋ ฅ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
ํ์ง๋ง ๋ฆฌ๋ ์ค ํฐ๋ฏธ๋์ ์ ๋ ฅ์ด QEMU์์ฐ๊ฒฐ๋์ด ์์ด Ctrl + C๋ก ์ข ๋ฃํ ์ ์๋ค. ๋ณ๊ฐ์ ํฐ๋ฏธ๋๋ก kill ๋ช ๋ น์ด๋ฅผ ํตํด QEMU ๋ฅผ ์ข ๋ฃ ์ํฌ ์ ์๋ค.
5.2 ์๋ ์ธ์!
ํ์ ์ฝ๋ฉ์ ์์ํ ๋ ๊ฐ์ฅ ๋จผ์ ๋ณด์ฌ์ฃผ๋ ์์ ๋ printf("Hello world"); ์
๋๋ค. python, C๋ฅผ ๋ฐฐ์ธ๋๋ ๊ทธ๋ฅ ์จ๋ ๋์์ง๋ง,
ํ์จ์ด์์๋ printf()๋ฅผ ์ง์ ๋ง๋ค์ด์ผํ๋ค.
๊ทธ๋ฌ๋ฏ๋ก stdio.h, stdio.c ํ์ผ์ ๋ง๋ค ๊ฒ์ด๋ค.
stdio.h
/*
* stdio.h
*
* Created on: Sep 17, 2018
* Author: maanu
*/
#ifndef LIB_STDIO_H_
#define LIB_STDIO_H_
uint32_t putstr(const char* s);
#endif /* LIB_STDIO_H_ */
stdio.c
/*
* stdio.c
*
* Created on: Sep 17, 2018
* Author: maanu
*/
#include "stdint.h"
#include "HalUart.h"
#include "stdio.h"
uint32_t putstr(const char* s)
{
uint32_t c = 0;
while(*s)
{
Hal_uart_put_char(*s++);
c++;
}
return c;
}
์ด์ hello world๋ฅผ ์ถ๋ ฅํ ์ ์๋๋ก main.c ํ์ผ์ putchr ํจ์๋ฅผ ๋ฃ์ด์ค์๋ค.
Main.c
#include "stdint.h"
#include "HalUart.h"
#include "stdio.h"
static void Hw_init(void);
void main(void)
{
Hw_init();
uint32_t i = 100;
while(i--)
{
Hal_uart_put_char('N');
}
Hal_uart_put_char('\n');
putstr("Hello World!\n");
}
static void Hw_init(void)
{
Hal_uart_init();
}
make run

Hello World! ๊ฐ ์ ์ถ๋ ฅ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
5.3 UART๋ก ์ ๋ ฅ๋ฐ๊ธฐ
์ด์ UART๋ก ์ถ๋ ฅ์ ํด๋ณด์์ผ๋ ์ ๋ ฅ ๋ํ ๊ตฌํํด๋ณด๊ฒ ์ต๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ถ๋ ฅ์ ํ ๋์๋
- ๋ณด๋ด๊ธฐ ๋ฒํผ๊ฐ ๋น์๋์ง, ๋น์ด์์ผ๋ฉด
- ๋ฐ์ดํฐ ๋ ์ง์คํฐ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๊ธฐ ๋ฒํผ๋ก ๋ณด๋ด๊ณ ,
- ํ๋์จ์ด๊ฐ ์์์ ๋๋จธ์ง ์์ ์ ์ฒ๋ฆฌํด์ฃผ๊ณ
- ํ๋์จ์ด์ ์ฐ๊ฒฐ๋ ์ฝ์์ ๋ฐ์ดํฐ๊ฐ ๋ํ๋ฉ๋๋ค.
์ ๋ ฅ์ ๊ทธ์ ๋ฐ๋๋ก
- ๋ฐ๊ธฐ ๋ฒํผ๊ฐ ์ฑ์์ ธ์๋์ง ํ์ธํ๊ณ , ์ฑ์์ ธ ์๋ค๋ฉด
- ๋ฐ์ดํฐ ๋ ์ง์คํฐ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ค๋ฉด ๋ฉ๋๋ค.
์ ๋ ฅ๋ฐ๋ ํจ์๋ ์ฝ๋ ๊ตฌ์ฑ์ ๋ฐ๋ผ ์ฑ๋ฅ์ด ํฌ๊ฒ ๋ฌ๋ผ์ง๊ฒ ๋ฉ๋๋ค. ์ ๋ ๋ฐ๋ก ์ต์ ํ ์ฝ๋๋ก ๊ตฌ์ฑํ๊ฒ ์ต๋๋ค.
Hal_uart_get_char() - [Uart.c]
uint8_t Hal_uart_get_char(void)
{
uint32_t data;
while(Uart->uartfr.bits.RXFE);
data = Uart->uartdr.all;
// Check for an error flag
if (data & 0xFFFFFF00)
{
// Clear the error
Uart->uartrsr.all = 0xFF;
return 0;
}
return (uint8_t)(data & 0xFF);
}

์ต์ ํ๊ฐ ๋์ง ์์ ์ฝ๋๋ ์ฝ 340๋ฐ์ดํธ๊ฐ ์์ฑ๋์ง๋ง ์ด ์ฝ๋๋ ์ด 200๋ฐ์ดํธ์ง๋ฆฌ ๋ฐ์ด๋๋ฆฌ๊ฐ ์์ฑ๋ฉ๋๋ค.
๋ง๋ ํจ์๋ฅผ Main.c์ ๋ฃ์ด๋ด ์๋ค
Main.c
#include "stdint.h"
#include "HalUart.h"
#include "stdio.h"
static void Hw_init(void);
void main(void)
{
Hw_init();
uint32_t i = 100;
while(i--)
{
Hal_uart_put_char('N');
}
Hal_uart_put_char('\n');
putstr("Hello World!\n");
i = 100;
while(i--)
{
uint8_t ch = Hal_uart_get_char();
Hal_uart_put_char(ch);
}
}
static void Hw_init(void)
{
Hal_uart_init();
}

์ ์ ๋ ฅ๋๋ ๊ฑธ ํ์ธ ํ ์ ์์ต๋๋ค.
5.4 printf ๋ง๋ค๊ธฐ
์ฐ๋ฆฌ๊ฐ ์ฐ๋ printf์ ์ค์ printf์ ์ฐจ์ด์ ์ ํฌ๋งท์ ์ธ ์ ์๋, ์๋ ์
๋๋ค. ํฌ๋งท์ %s, %d ๊ฐ์ด ๋ฐ์ดํฐ๋ฅผ ์ถ๋ ฅํ๋ ํ์์ ์ง์ ํ ์ ์๋ค๋ ๊ฒ์
๋๋ค. ๋ค๋ฅธ ๊ธฐ๋ฅ๋ค์ด ๋ง์ง๋ง ์ฐ๋ฆฌ๋ ํ์ํ ๊ธฐ๋ฅ๋ง ๋ง๋ค์ด ๋ณผ ๊ฒ์
๋๋ค. ์ฐ๋ฆฌ๋ debug_printf()๋ฅผ ๋ง๋ค ๊ฒ ์
๋๋ค.
debug_printf() ์ ์ธ
uint32_t debug_printf(const char* format, ...)
{
va_list args;
va_start(args, format);
vsprintf(printf_buf, format, args);
va_end(args);
return putstr(printf_buf);
}
์ฝ๋๊ฐ ์๊ฐ๋ณด๋ค ๊ฐ๋จํฉ๋๋ค. ๋ค์์ผ๋ก stdarg.h ์ฝ๋๋ฅผ ์์ฑํด๋ณด๊ฒ ์ต๋๋ค.
stdarg.h
/*
* stdarg.h
*
* Created on: Sep 19, 2018
* Author: maanu
*/
#ifndef INCLUDE_STDARG_H_
#define INCLUDE_STDARG_H_
typedef __builtin_va_list va_list;
#define va_start(v,l) __builtin_va_start(v,l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v,l) __builtin_va_arg(v,l)
#endif /* INCLUDE_STDARG_H_ */
GCC ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ธฐ์กด stdarg.h ํ์ผ์ ๋ ๋ณต์กํฉ๋๋ค. ๊ทธ๋์ ํ์ํ ๋ถ๋ถ๋ง ๋ณต์ฌํด์ ์ฌ์ฉํฉ๋๋ค.
stdio.h ํ์ผ์์ include๋ง ์ฌ์ฉํ๋ฉด, va_list, va_start, va_end๋ฅผ ์ฌ์ฉ ํ ์ ์๊ฒ ๋ฉ๋๋ค.
stdio.h
/*
* stdio.h
*
* Created on: Sep 17, 2018
* Author: maanu
*/
#ifndef LIB_STDIO_H_
#define LIB_STDIO_H_
#include "stdarg.h"
typedef enum utoa_t
{
utoa_dec = 10,
utoa_hex = 16,
} utoa_t;
uint32_t putstr(const char* s);
uint32_t debug_printf(const char* format, ...);
uint32_t vsprintf(char* buf, const char* format, va_list arg);
uint32_t utoa(char* buf, uint32_t val, utoa_t base);
#endif /* LIB_STDIO_H_ */
stdio.h์ stdarg.hํ์ผ์ ๋ถ๋ฌ์ต๋๋ค
vsprintf() ํจ์
uint32_t vsprintf(char* buf, const char* format, va_list arg)
{
uint32_t c = 0;
char ch;
char* str;
uint32_t uint;
uint32_t hex;
for (uint32_t i = 0 ; format[i] ; i++)
{
if (format[i] == '%')
{
i++;
switch(format[i])
{
case 'c':
ch = (char)va_arg(arg, int32_t);
buf[c++] = ch;
break;
case 's':
str = (char*)va_arg(arg, char*);
if (str == NULL)
{
str = "(null)";
}
while(*str)
{
buf[c++] = (*str++);
}
break;
case 'u':
uint = (uint32_t)va_arg(arg, uint32_t);
c += utoa(&buf[c], uint, utoa_dec);
break;
case 'x':
hex = (uint32_t)va_arg(arg, uint32_t);
c += utoa(&buf[c], hex, utoa_hex);
break;
}
}
else
{
buf[c++] = format[i];
}
}
if (c >= PRINTF_BUF_LEN)
{
buf[0] = '\0';
return 0;
}
buf[c] = '\0';
return c;
}
์ต์ํ์ ๊ธฐ๋ฅ๋ง ๊ตฌํํ vsprintf() ์ฝ๋์ ๋๋ค.
stdio.h
/*
* stdio.h
*
* Created on: Sep 17, 2018
* Author: maanu
*/
#ifndef LIB_STDIO_H_
#define LIB_STDIO_H_
#include "stdarg.h"
typedef enum utoa_t
{
utoa_dec = 10,
utoa_hex = 16,
} utoa_t;
uint32_t putstr(const char* s);
uint32_t debug_printf(const char* format, ...);
uint32_t vsprintf(char* buf, const char* format, va_list arg);
uint32_t utoa(char* buf, uint32_t val, utoa_t base);
#endif /* LIB_STDIO_H_ */
utoa ํจ์๋ฅผ ์ ์ธํฉ๋๋ค.
stdio.c
uint32_t utoa(char* buf, uint32_t val, utoa_t base)
{
const char asciibase = 'a';
uint32_t c = 0;
int32_t idx = 0;
char tmp[11]; // It is enough for 32 bit int
do {
uint32_t t = val % (uint32_t)base;
if (t >= 10)
{
t += asciibase - '0' - 10;
}
tmp[idx] = (t + '0');
val /= base;
idx++;
} while(val);
// reverse
idx--;
while (idx >= 0)
{
buf[c++] = tmp[idx];
idx--;
}
return c;
}
utoa ํจ์๋ฅผ ๊ตฌํํฉ๋๋ค.
main.c์ printf()ํจ์๋ฅผ ์ถ๊ฐํ๊ฒ ์ต๋๋ค
Main.c
#include "stdint.h"
#include "HalUart.h"
#include "stdio.h"
static void Hw_init(void);
static void Printf_test(void);
void main(void)
{
Hw_init();
uint32_t i = 100;
while(i--)
{
Hal_uart_put_char('N');
}
Hal_uart_put_char('\n');
putstr("Hello World!\n");
Printf_test();
i = 100;
while(i--)
{
uint8_t ch = Hal_uart_get_char();
Hal_uart_put_char(ch);
}
}
static void Hw_init(void)
{
Hal_uart_init();
}
static void Printf_test(void)
{
char* str = "printf pointer test";
char* nullptr = 0;
uint32_t i = 5;
debug_printf("%s\n", "Hello printf");
debug_printf("output string pointer: %s\n", str);
debug_printf("%s is null pointer, %u number\n", nullptr, 10);
debug_printf("%u = 5\n", i);
debug_printf("dec=%u hex=%x\n", 0xff, 0xff);
}
์ดํ make run์ ๋์์ํค๋ฉด ์๋ฌ๊ฐ ๋ฐ ๊ฒ์ ๋๋ค. ์๋๋ฉด utoa()์์๋ ๋๋จธ์ง, ๋๋๊ธฐ ์ฐ์ฐ์ด ์ฐ์ด์ง๋ง ARM์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋๋จธ์ง, ๋๋๊ธฐ ์ฐ์ฐ์ ์ง์ํ๋ ํ๋์จ์ด๊ฐ ์๋ค๊ณ ๊ฐ์ฃผํฉ๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก GCC๊ฐ ์ด๋ฅผ ์ํํธ์จ์ด๋ก ๊ตฌํํด๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํจ์๋ก ์๋์ผ๋ก ๋งํนํด์ผ ํฉ๋๋ค.
์ฆ makefile์ ์กฐ๊ธ ์์ ํ๊ฒ ์ต๋๋ค.
Makefile
ARCH = armv7-a
MCPU = cortex-a8
TARGET = rvpb
CC = arm-none-eabi-gcc
AS = arm-none-eabi-as
LD = arm-none-eabi-gcc
OC = arm-none-eabi-objcopy
LINKER_SCRIPT = ./navilos.ld
MAP_FILE = build/navilos.map
ASM_SRCS = $(wildcard boot/*.S)
ASM_OBJS = $(patsubst boot/%.S, build/%.os, $(ASM_SRCS))
VPATH = boot \
hal/$(TARGET) \
lib
C_SRCS = $(notdir $(wildcard boot/*.c))
C_SRCS += $(notdir $(wildcard hal/$(TARGET)/*.c))
C_SRCS += $(notdir $(wildcard lib/*.c))
C_OBJS = $(patsubst %.c, build/%.o, $(C_SRCS))
INC_DIRS = -I include \
-I hal \
-I hal/$(TARGET) \
-I lib
CFLAGS = -c -g -std=c11 -mthumb-interwork
LDFLAGS = -nostartfiles -nostdlib -nodefaultlibs -static -lgcc
navilos = build/navilos.axf
navilos_bin = build/navilos.bin
.PHONY: all clean run debug gdb
all: $(navilos)
clean:
@rm -fr build
run: $(navilos)
qemu-system-arm -M realview-pb-a8 -kernel $(navilos) -nographic
debug: $(navilos)
qemu-system-arm -M realview-pb-a8 -kernel $(navilos) -S -gdb tcp::1234,ipv4
gdb:
arm-none-eabi-gdb
kill:
kill -9 `ps aux | grep 'qemu' | awk 'NR==1{print $$2}'`
$(navilos): $(ASM_OBJS) $(C_OBJS) $(LINKER_SCRIPT)
$(LD) -n -T $(LINKER_SCRIPT) -o $(navilos) $(ASM_OBJS) $(C_OBJS) -Wl,-Map=$(MAP_FILE) $(LDFLAGS)
$(OC) -O binary $(navilos) $(navilos_bin)
build/%.os: %.S
mkdir -p $(shell dirname $@)
$(CC) -march=$(ARCH) -mcpu=$(MCPU) -marm $(INC_DIRS) $(CFLAGS) -o $@ $<
build/%.o: %.c
mkdir -p $(shell dirname $@)
$(CC) -march=$(ARCH) -mcpu=$(MCPU) -marm $(INC_DIRS) $(CFLAGS) -o $@ $<
make run

๊ตณ๊ตณ
์ง๊ธ๊น์ง ํ์ผ๊ตฌ์กฐ ์ ๋๋ค
.
โโโ ARMv7AR.h
โโโ Makefile
โโโ MemoryMap.h
โโโ boot
โย ย โโโ Entry.S
โย ย โโโ Entry.bin
โย ย โโโ Entry.o
โย ย โโโ Main.c
โโโ build
โย ย โโโ Entry.os
โย ย โโโ Main.o
โย ย โโโ Regs.o
โย ย โโโ Uart.o
โย ย โโโ navilos.axf
โย ย โโโ navilos.bin
โย ย โโโ navilos.map
โย ย โโโ stdio.o
โโโ em.em
โโโ hal
โย ย โโโ HalUart.h
โย ย โโโ rvpb
โย ย โโโ Regs.c
โย ย โโโ Uart.c
โย ย โโโ Uart.h
โย ย โโโ Uart.o
โโโ hello.txt
โโโ include
โย ย โโโ ARMv7AR.h
โย ย โโโ MemoryMap.h
โย ย โโโ stdarg.h
โย ย โโโ stdint.h
โโโ lib
โย ย โโโ stdio.c
โย ย โโโ stdio.h
โโโ navilos.axf
โโโ navilos.ld
โโโ temp
โโโ SYS_ID_analysis.py
