코코아팹은 누구나 창의적 아이디어를 현실로 만들어 낼 수 있도록
만들고, 공유하고, 배울 수 있는 터전이
되고자 합니다.
아이디와 비밀번호를 잊으셨나요?아이디 / 비밀번호 찾기
코코아팹 회원이 아니신가요? 회원가입
2016-02-16 14:20:19
보통 MCU(Micro Control Unit)의 FW(Firmware) 개발하는 사람들은 avr-gcc, IAR, Code vision등의 컴파일러를 사용하여 개발한다.
Arduino IDE의 경우, AVR-GCC를 이용하여 컴파일 한다.
AVR-GCC는 대표적인 오픈 소스 기반의 컴파일러로 왠만한 상용컴파일러에 뒤지지 않으며, ATmel Stduio와도 통합되어 편리하게 사용할수 있다.
곧 Arduino IDE에서 GCC기반의 코딩을 하면 먹힌다.
여기서는 Arduino IDE의 Blink예제를 펌웨어 레벨 관점에서 분석하여 보자...
Blink예제는 오렌지 보드의 13이라고 써져있는 LED를 약 1초 간격으로, 점등과 소등을 반복하는 예제이다.
/*
Blink
Turns on an LED on for one second, then off for one second, repeatedly.
Most Arduinos have an on-board LED you can control. On the Uno and
Leonardo, it is attached to digital pin 13. If you're unsure what
pin the on-board LED is connected to on your Arduino model, check
the documentation at http://www.arduino.cc
This example code is in the public domain.
modified 8 May 2014
by Scott Fitzgerald
*/
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin 13 as an output.
pinMode(13, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
아두이노 설치 폴더의 해당 경로에서 wiring_digital.c를 보면, digitalWrite()함수의 내부를 확인할 수 있다.
(설치경로 예> D:\Util\arduino\arduino-1.6.6-windows\arduino-1.6.6\hardware\arduino\avr\cores\arduino\wiring_digital.c)
void digitalWrite(uint8_t pin, uint8_t val)
{
uint8_t timer = digitalPinToTimer(pin); ...................ⓐ
uint8_t bit = digitalPinToBitMask(pin); ...................ⓑ
uint8_t port = digitalPinToPort(pin); ...................ⓒ
volatile uint8_t *out; ....................................ⓓ
if (port == NOT_A_PIN) return;
// If the pin that support PWM output, we need to turn it off
// before doing a digital write.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
out = portOutputRegister(port); ...........................ⓔ
uint8_t oldSREG = SREG; ...........................ⓕ
cli();
if (val == LOW) {
*out &= ~bit; ......................................ⓖ
} else {
*out |= bit; ......................................ⓗ
}
SREG = oldSREG; ......................................ⓘ
}
ⓐ uint8_t timer = digitalPinToTimer(pin);
uint8_t는 unsigned char나 signed char로 변수 선언에 있어서 데이터의 크기가 프랫폼마다 다르기 때문에, 사용되는 고정 길이 데이터 형식이다. Primitive System Data Type이라고 부른다. 이 코드에서 uint8_t대신 unsigned char로 사용하여도 상관없다.
stdint.h의 헤더파일에 명시되어 있다.
digitalPinToTimer는 #define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) ) 로
Arduino.h에 선언되어 있다.
(설치경로 예>D:\Util\arduino\arduino-1.6.6-windows\arduino-1.6.6\hardware\arduino\avr\cores\arduino\Arduino.h)
pgm_read_byte라는 것은 오렌지 보드의 MCU인 ATmega328P의 프로그램 메모리(32KB)에 읽는 것이다.
MCU는 프로그램 메모리(32KB), SRAM(2KB)이다. 불과 2KB밖에 안되는 데이터 메모리(SRMA)의 사용을 줄이기 위하여, 고안된 것이다.
digital_pin_to_timer_PGM은 Pins_arduino.h에 명시 되어 있다.
const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
NOT_ON_TIMER, /* 0 - port D */
NOT_ON_TIMER,
NOT_ON_TIMER,
// on the ATmega168, digital pin 3 has hardware pwm
#if defined(__AVR_ATmega8__)
NOT_ON_TIMER,
#else
TIMER2B,
#endif
NOT_ON_TIMER,
// on the ATmega168, digital pins 5 and 6 have hardware pwm
#if defined(__AVR_ATmega8__)
NOT_ON_TIMER,
NOT_ON_TIMER,
#else
TIMER0B,
TIMER0A,
#endif
NOT_ON_TIMER,
NOT_ON_TIMER, /* 8 - port B */
TIMER1A,
TIMER1B,
#if defined(__AVR_ATmega8__)
TIMER2,
#else
TIMER2A,
#endif
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER, /* 14 - port C */
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
};
#endif
const는 읽기 전용으로 사용한다는 것이며, 처음 상수를 정의 할때, 사용된다.
PROGMEM은 데이터를 프로그램 메모리(32KB)에 저장하는 메크로이다. 왜 사용하는지는 위에서 설명하였다.
digitalWrite(13, HIGH)을 하였을 경우, digital_pin_to_timer_PGM에서 13번째에 해당하는 NOT_ON_TIMER 로
결국, timer = digitalPinToTimer(13); 의 리턴값은 NOT_ON_TIMER 이다.
만약, 오렌지 보드의 PWM포트인 digital IO3을 사용했을때는, timer = digitalPinToTimer(3);
으로 리턴값이 TIMER2B로 설정되는대,
digitalWrite의 함수의 if (timer != NOT_ON_TIMER) turnOffPWM(timer);
NOT_ON_TIMER가 아니면 PWM기능을 끄라는 명령을 한다. 즉. PWM기능을 이미 사용하고 있을때, 기능을 꺼두기 위함이다.
Requiem