앞으로 포스팅될 게시물들은 각 기능에 대한 설명과 더불어 부분적인 소스를 제공할 것이다.

MCU를 처음배우는 사람들은 각 기능의 소스를 제공하더라도 활용하지 못하기 때문에

기본적인 펌웨어의 구조를 제시하겠다. 여기서 펌웨어란 임베디드에서의 소스코드(Source Code)를 말한다고 할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include 라이브러리들
 
#define 타이머 프리스케어 (타이머의 주기)
 
int 전역변수들(각 함수내에서 static으로 대체가능)
 
void Init_Timer(); //함수원형
 
void main() {
        초기화함수들 호출
        while(1) {
        } // 종료방지
}
 
void Init_Timer() { //함수정의
~~~~
}
 
void Timer_Handler() {
~~~~
}
 
cs

 1번째 줄은 라이브러리를 사용할 경우에 해당한다.

 

 3번째 줄의 타이머 프리스케어는 다음에 포스팅할 Timer 소스에서 자세히 설명하겠다.

간단히 말하면 타이머의 속도를 결정하는 역할을 한다.

 

 5번째 줄은 이전 포스팅에서 토글기능을 위해 static int 변수를 사용했었는데

static으로 함수 내부에 위치시켜 가독성을 좋게 할 수도 있고

해당 변수가 여러 곳에서 사용될 경우 전역변수로 처리한다.

 

나머지는 이미 설명한 바와 같다.

위와 같은 기본적인 틀에 필요한 기능들을 덧붙여 펌웨어를 작성하게 된다.

Posted by gharlic

 임베디드에서의 프로그래밍은 일반적인 소프트웨어 프로그래밍과 알고리즘을 짬에 있어서 차이가 발생한다.

Timer에 의해 인터럽트가 발생하는 것을 고려하여 펌웨어를 구현해야 한다는 점이다.

 

Timer

 자 여기서 타이머란 우리가 쉽게 생각할 수 있는 그 타이머이다.

개발자가 설정한 주기마다 인터럽트를 발생시킨다.

 

Interrupt

 인터럽트란 쉽게 얘기해 cpu가 일을 하고 있는데 거기에 태클을 거는 행위이다.

cpu는 기본적으로 한번에 하나의 일만 처리할 수 있다.

컴퓨터에서 인터넷서핑을 하면서 노래도 틀어놓고 동영상도 동시에 재생할 수 있는 것은

일을 잘게 나누어 노래도 잠깐 재생했다가 동영상도 잠깐 재생하는 것을 빠르게 반복하기 때문에

동시에 처리할 수 있는 것 처럼 보이는 것이다.

 즉 A라는 작업을 하던 도중 A를 중단(보류)시키고 B라는 일을 수행하게 하는 것이 인터럽트이다.

이 태클을 거는 행위를 타이머 인터럽트(Timer interrupt)라고 하고

인터럽트를 걸고 수행시키는 '일'을 인터럽트 서비스루틴(interrupt service routine)이라고 한다.

 

NVIC

 인터럽트란 어떤 일을 우선적으로 처리하기 위해 태클을 거는 행위라 했다.

그런데 동시에 여러 인터럽트가 발생했을 때는 어떻게 될까?

인터럽트에는 우선순위가 존재하고 NVIC(Nested Vectored Interrupt Controller)에 의해 관리된다.

NVIC에 의해 일종의 대기열이 생기게 되어 우선순위에 따라 순서를 정하게 된다.

 

우선순위에는 PP(Preemption Priority)와 SP(Sub Priority)가 있다.

PP가 높을 수록 먼저 인터럽트가 실행되게 되며

동일한 PP에서는 SP에 관계없이 먼저 실행된 인터럽트가 실행된다.

만약 동일한 PP의 인터럽트가 동시에 발생하거나 그 인터럽트들이 대기열에 있을 경우

SP가 높은 순서로 실행되게 된다. 

 

코딩은?

 MCU(Micror Controller Unit)에서의 코딩은 대부분 Main함수에서 이루어지지 않는다.

Main함수의 역할은 각 기능을 초기화시키는 Init함수를 호출하고

펌웨어가 종료되지 않도록 While문을 유지시키는 역할만 한다.

 

Timer Handler

 구현하고자 하는 기능들의 핵심적인 소스는 타이머 핸들러에 위치하게 된다.

타이머가 정지하는 매 주기마다 이 타이머 핸들러의 코드가 실행되게 된다.

 

예를 들어 보자

 LED가 하나 있을 때 그 LED가 1초마다 점멸을 하게 하고 싶다고 한다.

이때 일반적인 소프트웨어 프로그래밍에서는 다음과 같은 알고리즘을 따를 것이다.

1
2
3
4
5
6
반복 {
        LED를 켠다
        딜레이 1초
        LED를 끈다
        딜레이 1초
}
cs

 

 이 때 타이머와 인터럽트가 등장하면 방법이 달라진다.

1
2
3
4
5
6
7
8
9
타이머 핸들러 {
        static int 토글
        if( 토글 == 0(꺼짐) )
               LED를 켠다
               토글 = 1(켜짐)
        else
               LED를 끈다
               토글 = 0(꺼짐)
}       
cs

 두 알고리즘의 차이점은 딜레이의 유무이다.

타이머와 인터럽트가 존재하는 코드에서 딜레이 함수는 무의미하다.

이 알고리즘은 타이머의 주기를 1초로 설정했다고 가정했을 때의 알고리즘이다.

1초 마다 타이머 핸들러 블록의 알고리즘이 실행되게 된다.

그렇기 때문에 매 주기마다 현재상태를 토글시키게 해야한다는 것이다.

물론 이 예제만으론 설명이 부족하다. 차차 포스팅할 게시물에서 점차 이해하게 될 것이다.

 

정리

 타이머(Timer)는 일정주기마다 인터럽트(Interrupt)를 걸어 타이머핸들러(Timer Handler)의 소스를 실행하게 한다.

여러 인터럽트가 동시에 실행되더라고 NVIC가 알아서 처리하며, 우선순위를 설정할 수 있다.

타이머 핸들러에서의 알고리즘은 일반적인 순차식 알고리즘과 구조자체가 달라질 수 있기 때문에

알고리즘이 타이머의 매 주기마다 새로 실행된다는 점을 인지하고 알고리즘을 짜야한다.

 

 

 

 

 

 

'임베디드 > ARM Cortex-M4' 카테고리의 다른 글

Timer / Timer_Handler 소스  (0) 2015.07.08
라이브러리(library)코딩과 레지스터(Register)코딩  (0) 2015.07.08
펌웨어(Firmware)의 구조  (0) 2015.07.08
STM32F4 핀배열  (0) 2015.07.07
myCortex STM32F4 스펙  (0) 2015.07.07
Posted by gharlic

 

 

GPIO 핀을 선택함에 있어서 Timer등으로 이미 사용중인 핀과 중복이 없도록 선택해야한다.

Posted by gharlic