AVR

5 Data in Program Space

siwall 2014. 4. 17. 16:16

5.1 Introduction

GCC는 특별한 키워드 __attribute__를 가지고 있다.

AVR GCC에서는 이런 특별한 기능들을 progmem이라고 부른다.

이런 특성들은 데이터 선언에 사용되거나, data를 flash 메모리에 위치시키도록 할 수 있다.

AVR-Libc는 PROGMEM 매크로를 제공한다. PROGMEM 매크로는 <avr/pgmspace.h> 헤더파일에 정의되어 있다.


5.2 A Note On const

const 키워드에 대한 설명...read-only 특성


5.3 프로그램 영역에서의 데이터 입출력

다음과 같은 전역 데이터를 만들었다고 가정하자:

unsigned char mydata[11][10] =

{

{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09},

{0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13},

{0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D},

{0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27},

{0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31},

{0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B},

{0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45},

{0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F},

{0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59},

{0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63},

{0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D}

};

다음과 같은 코드로 이 데이터에 접근할 수 있다.

byte = mydata[i][j];


이제 데이터를 프로그램 메모리에 저장하고 싶다. 

#include <avr/pgmspace.h>

.

.

.

unsigned char mydata[11][10] PROGMEM =

{

{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09},

{0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13},

{0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D},

{0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27},

{0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31},

{0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B},

{0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45},

{0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F},

{0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59},

{0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63},

{0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D}

};


이렇게 하면 데이터가 프로그램 영역에 저장된다. 컴파일하고 링크하고 map 파일을 열어보면 올바른 위치에 데이터가 있는것을 확인할 수 있다.

이제 데이터가 프로그램 영역에 위치해 있다. 데이터에 접근하기 위한 위의 코드는 더이상 동작하지 않는다.

코드를 통해 만들어진 주소는 Data 영역을 가리키게 되기 때문이다. 실제 데이터는 프로그램 메모리에 있는데 말이다.


데이터를 읽기 위해서는 다음과 같이 코드를 만들어야 한다.

byte = pgm_read_byte(&(mydata[i][j]));


pgm_read_* 매크로는 프로그램 영역의 주소를 가져와서 그 주소에 있는 데이터를 읽어온다.

읽어올 데이터 사이즈가 다를 경우에는 매크로도 달라져야 한다.



5.4 Storing and Retrieving Strings in the Program Space


char *string_table[] =

{

"String 1",

"String 2",

"String 3",

"String 4",

"String 5"

};


그리고 PROGMEM 매크로를 정의의 끝에 추가한다.

char *string_table[] PROGMEM =

{

"String 1",

"String 2",

"String 3",

"String 4",

"String 5"

};

맞을까? 틀릴까?

이렇게하면 string_table 변수는 프로그램 영역에 들어가지만, string 자체는 data 메모리에 위치하게 된다.

string을 프로그램 영역에 넣으려면,  다음처럼 각 string에 대해서 명시적으로 선언해줘야 한다.


char string_1[] PROGMEM = "String 1";

char string_2[] PROGMEM = "String 2";

char string_3[] PROGMEM = "String 3";

char string_4[] PROGMEM = "String 4";

char string_5[] PROGMEM = "String 5";


그리고 나서, 다음과 같이 테이블에 대한 심볼을 사용한다.


PGM_P string_table[] PROGMEM =

{

string_1,

string_2,

string_3,

string_4,

string_5

};


string_table 이 프로그램 영역에 위치하게 되고, string_table은 string 들에 대한 포인터 배열이 된다. 

PGM_P 는 프로그램 영역에 위치하는 문자에 대한 포인터를 정의하는 매크로이다.


프로그램 영역에 존재하는 string을 RAM의 버퍼에 copy하기 위한 예제

void foo(void)

{

char buffer[10];

for (unsigned char i = 0; i < 5; i++)

{

strcpy_P(buffer, (PGM_P)pgm_read_word(&(string_table[i])));

// Display buffer on LCD.

}

return;

}




'AVR' 카테고리의 다른 글

8 How to Build a Library  (0) 2014.04.17
7 Inline Assembler Cookbook  (0) 2014.04.17
6 avr-libc and assembler programs  (0) 2014.04.17
4 Memory Sections  (0) 2014.04.17
3 Memory Areas and Using malloc()  (0) 2014.04.17