9. SoC Prgraming using C

9์žฅ SoC Programming using C ๊ฐœ์š”

์ž„๋ฒ ๋””๋“œ SoC ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ C ์–ธ์–ด๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ธฐ๋ณธ ๋ฐฉ์‹. Memory-mapped I/O๋ฅผ ํ†ตํ•œ peripheral ์ ‘๊ทผ, pointer manipulation, volatile keyword, bit operation, startup sequence, linker script ๋“ฑ์„ ๋‹ค๋ฃฌ๋‹ค.

Memory-Mapped I/O

ARM Cortex-M์—์„œ๋Š” ๋ชจ๋“  peripheral์ด ํŠน์ • ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ์— ๋งคํ•‘๋˜์–ด ์žˆ์Œ. Register์— ์ ‘๊ทผ = ํ•ด๋‹น ์ฃผ์†Œ์— read/write.

#define GPIO_ODR (*(volatile uint32_t *)0x40020014)

GPIO_ODR = 0x01;   // GPIO ์ถœ๋ ฅ ์„ค์ •
uint32_t val = GPIO_ODR;  // ํ˜„์žฌ ์ƒํƒœ ์ฝ๊ธฐ

volatile Keyword

  • Compiler ์ตœ์ ํ™” ๋ฐฉ์ง€ (์˜ˆ: ๊ฐ™์€ ์ฃผ์†Œ๋ฅผ ๋‘ ๋ฒˆ ์ฝ์„ ๋•Œ ์ƒ๋žต ๊ธˆ์ง€)
  • Hardware register๋Š” ์™ธ๋ถ€์—์„œ ๋ฐ”๋€” ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ฐ˜๋“œ์‹œ volatile
volatile uint32_t *GPIO_IDR = (volatile uint32_t *)0x40020010;
while (!(*GPIO_IDR & 0x1)) ;  // ๋ฒ„ํŠผ ๋ˆŒ๋ฆด ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ

volatile์ด ์—†์œผ๋ฉด compiler๊ฐ€ loop ์ตœ์ ํ™”๋กœ ๋ฌดํ•œ ๋Œ€๊ธฐ ๋ฐœ์ƒ.

Struct ๊ธฐ๋ฐ˜ Register ์ ‘๊ทผ

๋Œ€๊ทœ๋ชจ peripheral์€ struct๋กœ ์ •์˜ (CMSIS style):

typedef struct {
    volatile uint32_t MODER;    // 0x00
    volatile uint32_t OTYPER;   // 0x04
    volatile uint32_t OSPEEDR;  // 0x08
    volatile uint32_t PUPDR;    // 0x0C
    volatile uint32_t IDR;      // 0x10
    volatile uint32_t ODR;      // 0x14
    // ...
} GPIO_TypeDef;

#define GPIOA ((GPIO_TypeDef *)0x40020000)

GPIOA->ODR = 0x01;

Bit Operation

Bit Set

GPIOA->ODR |= (1 << 5);    // 5๋ฒˆ bit๋ฅผ 1๋กœ

Bit Clear

GPIOA->ODR &= ~(1 << 5);   // 5๋ฒˆ bit๋ฅผ 0์œผ๋กœ

Bit Toggle

GPIOA->ODR ^= (1 << 5);    // 5๋ฒˆ bit ๋ฐ˜์ „

Bit Check

if (GPIOA->IDR & (1 << 5)) { /* bit 5 is 1 */ }

Multi-bit Field

2-bit field๋ฅผ ๊ฐ’ val๋กœ ์„ค์ •:

GPIOA->MODER &= ~(0x3 << (pin * 2));    // clear 2 bits
GPIOA->MODER |= (val << (pin * 2));     // set value

Memory-mapped I/O ๋ฐ Bit Op

Startup Sequence

Reset ์‹œ ํ”„๋กœ์„ธ์„œ๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ์ดˆ๊ธฐํ™”:

  1. R13 โ† Initial SP (Vector table offset 0x00)
  2. PC โ† Reset handler (offset 0x04)
  3. Reset handler: - .data section์„ Flash์—์„œ RAM์œผ๋กœ copy - .bss section์„ 0์œผ๋กœ ์ดˆ๊ธฐํ™” - SystemInit() ํ˜ธ์ถœ (clock, PLL ์„ค์ •) - main() ํ˜ธ์ถœ
void Reset_Handler(void) {
    // Copy .data from Flash to RAM
    extern uint32_t _sdata, _edata, _sidata;
    uint32_t *src = &_sidata;
    uint32_t *dst = &_sdata;
    while (dst < &_edata) *dst++ = *src++;

    // Zero-init .bss
    extern uint32_t _sbss, _ebss;
    dst = &_sbss;
    while (dst < &_ebss) *dst++ = 0;

    SystemInit();
    main();
    while(1);
}

Linker Script

Memory layout ์ •์˜:

MEMORY {
    FLASH (rx) : ORIGIN <mark class="highlight"><strong><u> 0x08000000, LENGTH </u></strong></mark> 128K
    RAM (rwx)  : ORIGIN <mark class="highlight"><strong><u> 0x20000000, LENGTH </u></strong></mark> 20K
}

SECTIONS {
    .isr_vector : {
        KEEP(*(.isr_vector))
    } > FLASH

    .text : {
        *(.text*)
        *(.rodata*)
    } > FLASH

    .data : AT(_sidata) {
        _sdata = .;
        *(.data*)
        _edata = .;
    } > RAM

    .bss : {
        _sbss = .;
        *(.bss*)
        _ebss = .;
    } > RAM
}

Startup Code ๋ฐ Linker Script

CMSIS (Cortex Microcontroller Software Interface Standard)

ARM ํ‘œ์ค€ SW interface:

  • Core peripheral access (NVIC, SysTick, SCB)
  • Vendor-specific register definitions
  • DSP, NN library (option)

์˜ˆ:

#include "stm32f10x.h"    // CMSIS device header

int main(void) {
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;   // GPIOC clock enable
    GPIOC->CRH = 0x00300000;              // PC13 output

    while (1) {
        GPIOC->ODR ^= (1 << 13);          // toggle LED
        for (volatile int i = 0; i < 100000; i++);  // delay
    }
}

Interrupt Handler

CMSIS๋Š” vector table์„ ์ž๋™ ์ƒ์„ฑ. Handler๋ฅผ ์ž‘์„ฑ๋งŒ ํ•˜๋ฉด ์—ฐ๊ฒฐ:

void TIM2_IRQHandler(void) {
    if (TIM2->SR & TIM_SR_UIF) {
        TIM2->SR = ~TIM_SR_UIF;    // clear flag
        GPIOC->ODR ^= (1 << 13);   // toggle LED
    }
}

Linker script์—์„œ TIM2_IRQHandler์˜ ์ฃผ์†Œ๊ฐ€ vector table์˜ ํ•ด๋‹น offset์— ๋“ฑ๋ก๋จ.

Clock ์„ค์ •

SoC์˜ clock ์‹œ์Šคํ…œ์€ ๋ณต์žก (HSI, HSE, PLL, AHB/APB prescaler).

void SystemInit(void) {
    // Enable HSE
    RCC->CR |= RCC_CR_HSEON;
    while (!(RCC->CR & RCC_CR_HSERDY));

    // Configure PLL
    RCC->CFGR = RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9;
    RCC->CR |= RCC_CR_PLLON;
    while (!(RCC->CR & RCC_CR_PLLRDY));

    // Switch SYSCLK to PLL
    RCC->CFGR |= RCC_CFGR_SW_PLL;
}

CMSIS ๋ฐ Clock ์„ค์ •

Debugging Tools

  • printf via UART: syscalls.c์—์„œ _write() ์žฌ์ •์˜
  • Semihosting: ARM debugger๋ฅผ ํ†ตํ•ด stdout
  • SWD (Serial Wire Debug): breakpoint, watchpoint, live register view
  • ITM (Instrumentation Trace Macrocell): ๊ณ ์† trace

์ตœ์ ํ™” Tips

  • Inline: ์งง์€ ํ•จ์ˆ˜๋Š” static inline์œผ๋กœ
  • volatile์€ ๊ผญ ํ•„์š”ํ•œ ๊ณณ์—๋งŒ (์ตœ์ ํ™” ๋ฐฉํ•ด)
  • Cache alignment: DMA buffer๋Š” cache line์— ์ •๋ ฌ
  • -O2 / -Os: gcc ์ตœ์ ํ™” ๋ ˆ๋ฒจ, ์ž„๋ฒ ๋””๋“œ๋Š” ํฌ๊ธฐ ์ค‘์š”

Debugging ๋ฐ ์ตœ์ ํ™”

์ •๋ฆฌ

๊ฐœ๋… ํ•ต์‹ฌ
Memory-mapped I/O Peripheral = ์ฃผ์†Œ
volatile Compiler ์ตœ์ ํ™” ๋ฐฉ์ง€
Struct ์ ‘๊ทผ Register group ์ถ”์ƒํ™”
Bit op Set/Clear/Toggle/Check
Startup Vector table โ†’ Reset handler โ†’ main
Linker script FLASH/RAM layout ์ •์˜
CMSIS ARM ํ‘œ์ค€ SW interface
Interrupt handler C ํ•จ์ˆ˜ + Linker ์—ฐ๊ฒฐ

C๋กœ SoC ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ hardware level์„ C pointer๋กœ ์ถ”์ƒํ™”ํ•˜๋Š” ์ž‘์—…. volatile, struct, bit op๋ฅผ ์ˆ™๋‹ฌํ•˜๋ฉด ์–ด๋–ค MCU๋„ ์ง์ ‘ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

C ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ข…ํ•ฉ

๋น„์Šทํ•œ ๊ธ€ ์ถ”์ฒœ

Comments (0)

No comments yet. Be the first to comment!