본문 바로가기

뭐라도 만들어보자!!( 프로젝트 )/임베디드

3. 임베디드 실습 : NVIC ~ 빈 main()

반응형

 드디어 코드를 작성할 수 있게 되었다. 그러면 바로 main()에다가 원하는 프로그램을 넣으면 되는가? 그렇지 않다. 우선적으로 .data와 .bss 영역을 초기화 해주어야 한다. .data 섹션의 초기화는 FLASH 영역에 저장된 .data를 RAM으로 복사해주어야하고, .bss 영역은 C 규약에 따라서 정적 심보의 초깃값을 0으로 해주어야 한다. 앞서서 target.ld에서 entry point를 isr_reset()으로 설정했음으로 초기화 작업을 해당 함수에서 해준다.

extern unsigned int _stored_data;
extern unsigned int _start_data;
extern unsigned int _end_data;
extern unsigned int _start_bss;
extern unsigned int _end_bss;
extern unsigned int _end_stack;
extern unsigned int _start_heap;

static volatile int zeroed_variable_in_bss;
static volatile int initialized_variable_in_data = 42;

#define STACK_PAINTING

static volatile unsigned int avail_mem = 0;
static unsigned int sp;

extern int main(void);

void isr_reset(void) {
    register unsigned int *src, *dst;
    src = (unsigned int *) &_stored_data;
    dst = (unsigned int *) &_start_data;
    /* Copy the .data section from flash to RAM. */
    while (dst < (unsigned int *)&_end_data) {
        *dst = *src;
        dst++;
        src++;
    }

    /* Initialize the BSS section to 0 */
    dst = &_start_bss;
    while (dst < (unsigned int *)&_end_bss) {
        *dst = 0U;
        dst++;
    }

    /* Paint the stack. */
    avail_mem = &_end_stack - &_start_heap;
#ifdef STACK_PAINTING
    {
        asm volatile("mrs %0, msp" : "=r"(sp)); //sp에 현재의 stack pointer를 저장한다.
        dst = ((unsigned int *)(&_end_stack)) - (8192 / sizeof(unsigned int)); ;
        while ((unsigned int)dst < sp) {
            *dst = 0xDEADC0DE;
            dst++;
        }
    }
#endif
    /* Run the program! */
    main();
}

 

 스택 페인팅은 스택 공간의 양을 측정하는 방식이다. 방식은 간단하다. bss 영역 이후로 stack 또는 heap 영역인데, 이 영역을 특정값으로 채워 주는 것이다. 최종적으로 dst에 저장되는 값은 heap과 stack의 경계가 될 것이고, 가용한 메모리 영역은 _end_bss ~ dst가 될 것이다.

 스택 페인팅까지 완료된 이후 main() 함수로 넘어갈 것이다.

 IVT(Interrupt Vector Table)를 등록해주어야 한다. 인터럽트란 정규 동작 이외에 소프트웨어적으로 또는 하드웨어적으로 정의된 동작을 의미한다. 전원 이상, 타이머 인터럽트, 하드웨어 오류 등 물리적인 인터럽트를 하드웨어 인터럽트라 하고, divided by 0, system call 등 소프트웨어적으로 정의되어 발생하는 인터럽트를 소프트웨어 인터럽트라고 한다. IVT는 여러가지 인터럽트에 대해 처리하기 위한 루틴 주소를 저장하고 있는 테이블을 의미한다.

 IVT의 저장 위치는 정해져 있고 형식도 정해져 있다. 보통은 code 영역에 제일 먼저 저장된다. IVT는 다음과 같이 구성된다.

 

 

 IVT가 FLASH에 저장된다고 해도, 실제로 인터럽트를 발생시킬려면 인터럽트를 활성화시켜야 하는데 이 부분은 다음에 다룰 것이다. 코드는 다음과 같다.

 

void isr_fault(void)
{
    /* Panic. */
    while(1) ;;
}


void isr_memfault(void)
{
    /* Panic. */
    while(1) ;;
}

void isr_busfault(void)
{
    /* Panic. */
    while(1) ;;
}

void isr_usagefault(void)
{
    /* Panic. */
    while(1) ;;
}


void isr_empty(void)
{
    /* Ignore the event and continue */
}

__attribute__ ((section(".isr_vector")))
void (* const IV[])(void) =
{
	(void (*)(void))(&_end_stack),
	isr_reset,                   // Reset
	isr_fault,                   // NMI
	isr_fault,                   // HardFault
	isr_memfault,                // MemFault
	isr_busfault,                // BusFault
	isr_usagefault,              // UsageFault
	0, 0, 0, 0,                  // 4x reserved
	isr_empty,                   // SVC
	isr_empty,                   // DebugMonitor
	0,                           // reserved
	isr_empty,                   // PendSV
	isr_systick,                   // SysTick

    isr_empty,              // NVIC_WWDG_IRQ 0
    isr_empty,              // PVD_IRQ 1
    isr_empty,              // TAMP_STAMP_IRQ 2
    isr_empty,              // RTC_WKUP_IRQ 3
    isr_empty,              // FLASH_IRQ 4
    isr_empty,              // RCC_IRQ 5
    isr_empty,              // EXTI0_IRQ 6
    isr_empty,              // EXTI1_IRQ 7
    isr_empty,              // EXTI2_IRQ 8
    isr_empty,              // EXTI3_IRQ 9
    isr_empty,              // EXTI4_IRQ 10
    isr_empty,              // DMA1_STREAM0_IRQ 11
    isr_empty,              // DMA1_STREAM1_IRQ 12
    isr_empty,              // DMA1_STREAM2_IRQ 13
    isr_empty,              // DMA1_STREAM3_IRQ 14
    isr_empty,              // DMA1_STREAM4_IRQ 15
    isr_empty,              // DMA1_STREAM5_IRQ 16
    isr_empty,              // DMA1_STREAM6_IRQ 17
    isr_empty,              // ADC_IRQ 18
    isr_empty,              // CAN1_TX_IRQ 19
    isr_empty,              // CAN1_RX0_IRQ 20
    isr_empty,              // CAN1_RX1_IRQ 21
    isr_empty,              // CAN1_SCE_IRQ 22
    isr_empty,              // EXTI9_5_IRQ 23
    isr_empty,              // TIM1_BRK_TIM9_IRQ 24
    isr_empty,              // TIM1_UP_TIM10_IRQ 25
    isr_empty,              // TIM1_TRG_COM_TIM11_IRQ 26
    isr_empty,              // TIM1_CC_IRQ 27
	isr_tim2 ,              // TIM2_IRQ 28
    isr_empty,              // TIM3_IRQ 29
    isr_empty,              // TIM4_IRQ 30
    isr_empty,              // I2C1_EV_IRQ 31
    isr_empty,              // I2C1_ER_IRQ 32
    isr_empty,              // I2C2_EV_IRQ 33
    isr_empty,              // I2C2_ER_IRQ 34
    isr_empty,              // SPI1_IRQ 35
    isr_empty,              // SPI2_IRQ 36
    isr_empty,              // USART1_IRQ 37
    isr_empty,              // USART2_IRQ 38
    isr_empty,              // USART3_IRQ 39
    isr_exti15_10,              // EXTI15_10_IRQ 40
    isr_empty,              // RTC_ALARM_IRQ 41
    isr_empty,              // USB_FS_WKUP_IRQ 42
    isr_empty,              // TIM8_BRK_TIM12_IRQ 43
    isr_empty,              // TIM8_UP_TIM13_IRQ 44
    isr_empty,              // TIM8_TRG_COM_TIM14_IRQ 45
    isr_empty,              // TIM8_CC_IRQ 46
    isr_empty,              // DMA1_STREAM7_IRQ 47



};

 

 특정 섹션에 저장될 것이라고 명시하는 방식은 __attribute__((section("section name")))으로 지정할 수 있다.

 당장은 isr_reset와 fault 함수들을 제외하고 빈 함수를 넣어주어도 된다. 보다시피 IVT의 첫 인덱스에는 스택의 마지막 주소가 저장된다.

 드디어 main() 함수를 불러올 수 있게 되었다. 다음 글에서는 가장 기본이 되는 clock을 설정해 볼 것이다. 이 것으로 글을 마친다.

 

/*
*startup.c
*/
#include "register.h"

#define MAX_TIM			4294967295

extern unsigned int _stored_data;
extern unsigned int _start_data;
extern unsigned int _end_data;
extern unsigned int _start_bss;
extern unsigned int _end_bss;
extern unsigned int _end_stack;
extern unsigned int _start_heap;

static volatile int zeroed_variable_in_bss;
static volatile int initialized_variable_in_data = 42;

#define STACK_PAINTING

static volatile unsigned int avail_mem = 0;
static unsigned int sp;

extern int main(void);

void isr_reset(void) {
    register unsigned int *src, *dst;
    src = (unsigned int *) &_stored_data;
    dst = (unsigned int *) &_start_data;
    /* Copy the .data section from flash to RAM. */
    while (dst < (unsigned int *)&_end_data) {
        *dst = *src;
        dst++;
        src++;
    }

    /* Initialize the BSS section to 0 */
    dst = &_start_bss;
    while (dst < (unsigned int *)&_end_bss) {
        *dst = 0U;
        dst++;
    }

    /* Paint the stack. */
    avail_mem = &_end_stack - &_start_heap;
#ifdef STACK_PAINTING
    {
        asm volatile("mrs %0, msp" : "=r"(sp));
        dst = ((unsigned int *)(&_end_stack)) - (8192 / sizeof(unsigned int)); ;
        while ((unsigned int)dst < sp) {
            *dst = 0xDEADC0DE;
            dst++;
        }
    }
#endif
    /* Run the program! */
    main();
}

void isr_fault(void)
{
    /* Panic. */
    while(1) ;;
}


void isr_memfault(void)
{
    /* Panic. */
    while(1) ;;
}

void isr_busfault(void)
{
    /* Panic. */
    while(1) ;;
}

void isr_usagefault(void)
{
    /* Panic. */
    while(1) ;;
}


void isr_empty(void)
{
    /* Ignore the event and continue */
}

uint32_t SYS_TIM; //just simple timer(i didn't consider overflow)
uint32_t BIGGER_SYS_TIM;
uint32_t TIMER;
void isr_systick()
{
	if (TIMER > 0)
		TIMER--;

	if(SYS_TIM < MAX_TIM)
		SYS_TIM++;
	else
	{
		SYS_TIM = 0;
		BIGGER_SYS_TIM++;
	}
}

bool pressed;
void isr_exti15_10()
{
	EXTI->PR |= 1 << 13;
	pressed = !pressed;
}

uint32_t TIM2_TIMER;
void isr_tim2()
{
	TIM2->SR &= ~((uint32_t)1 << 0);
	if(TIM2_TIMER > 0)
		TIM2_TIMER--;
}

__attribute__ ((section(".isr_vector")))
void (* const IV[])(void) =
{
	(void (*)(void))(&_end_stack),
	isr_reset,                   // Reset
	isr_fault,                   // NMI
	isr_fault,                   // HardFault
	isr_memfault,                // MemFault
	isr_busfault,                // BusFault
	isr_usagefault,              // UsageFault
	0, 0, 0, 0,                  // 4x reserved
	isr_empty,                   // SVC
	isr_empty,                   // DebugMonitor
	0,                           // reserved
	isr_empty,                   // PendSV
	isr_systick,                   // SysTick

    isr_empty,              // NVIC_WWDG_IRQ 0
    isr_empty,              // PVD_IRQ 1
    isr_empty,              // TAMP_STAMP_IRQ 2
    isr_empty,              // RTC_WKUP_IRQ 3
    isr_empty,              // FLASH_IRQ 4
    isr_empty,              // RCC_IRQ 5
    isr_empty,              // EXTI0_IRQ 6
    isr_empty,              // EXTI1_IRQ 7
    isr_empty,              // EXTI2_IRQ 8
    isr_empty,              // EXTI3_IRQ 9
    isr_empty,              // EXTI4_IRQ 10
    isr_empty,              // DMA1_STREAM0_IRQ 11
    isr_empty,              // DMA1_STREAM1_IRQ 12
    isr_empty,              // DMA1_STREAM2_IRQ 13
    isr_empty,              // DMA1_STREAM3_IRQ 14
    isr_empty,              // DMA1_STREAM4_IRQ 15
    isr_empty,              // DMA1_STREAM5_IRQ 16
    isr_empty,              // DMA1_STREAM6_IRQ 17
    isr_empty,              // ADC_IRQ 18
    isr_empty,              // CAN1_TX_IRQ 19
    isr_empty,              // CAN1_RX0_IRQ 20
    isr_empty,              // CAN1_RX1_IRQ 21
    isr_empty,              // CAN1_SCE_IRQ 22
    isr_empty,              // EXTI9_5_IRQ 23
    isr_empty,              // TIM1_BRK_TIM9_IRQ 24
    isr_empty,              // TIM1_UP_TIM10_IRQ 25
    isr_empty,              // TIM1_TRG_COM_TIM11_IRQ 26
    isr_empty,              // TIM1_CC_IRQ 27
	isr_tim2 ,              // TIM2_IRQ 28
    isr_empty,              // TIM3_IRQ 29
    isr_empty,              // TIM4_IRQ 30
    isr_empty,              // I2C1_EV_IRQ 31
    isr_empty,              // I2C1_ER_IRQ 32
    isr_empty,              // I2C2_EV_IRQ 33
    isr_empty,              // I2C2_ER_IRQ 34
    isr_empty,              // SPI1_IRQ 35
    isr_empty,              // SPI2_IRQ 36
    isr_empty,              // USART1_IRQ 37
    isr_empty,              // USART2_IRQ 38
    isr_empty,              // USART3_IRQ 39
    isr_exti15_10,              // EXTI15_10_IRQ 40
    isr_empty,              // RTC_ALARM_IRQ 41
    isr_empty,              // USB_FS_WKUP_IRQ 42
    isr_empty,              // TIM8_BRK_TIM12_IRQ 43
    isr_empty,              // TIM8_UP_TIM13_IRQ 44
    isr_empty,              // TIM8_TRG_COM_TIM14_IRQ 45
    isr_empty,              // TIM8_CC_IRQ 46
    isr_empty,              // DMA1_STREAM7_IRQ 47



};
/*main.c*/
int main()
{
	while(1)
    {
    
    }
    
    return 0;
}

 

반응형