'ATMEGA128'에 해당되는 글 3건

  1. 2009.04.24 [ATmega1128] ATmega128은 Little endian일까 Big endian일까 2
  2. 2009.04.23 [AVR] DDRA, PORTA를 찾아보자. 1
  3. 2009.04.22 [DK-128] LED 순차적으로 점멸하기

[ATmega1128] ATmega128은 Little endian일까 Big endian일까

이를 확인하기 위해 다음과 같은 프로그램을 작성하였다.

  1. #include <avr/io.h>  
  2.   
  3. void delay_us(unsigned char time_us)  
  4. {  
  5.   
  6.         register unsigned char i;  
  7.   
  8.         for(i=0; i<time_us; i++)                     
  9.         {  
  10.                 asm volatile(" PUSH R0 ");     
  11.                 asm volatile(" POP R0 ");      
  12.                 asm volatile(" PUSH R0 ");  
  13.                 asm volatile(" POP R0 ");     
  14.                 asm volatile(" PUSH R0 ");   
  15.                 asm volatile(" POP R0");     
  16.         }  
  17. }  
  18.   
  19. void delay_ms(unsigned int time_ms)  
  20. {  
  21.         register unsigned int i;  
  22.         for(i=0; i<time_ms; i++)  
  23.         {  
  24.                 delay_us(250);  
  25.                 delay_us(250);  
  26.                 delay_us(250);  
  27.                 delay_us(250);  
  28.         }  
  29. }  
  30.   
  31. int main()  
  32. {  
  33.     int iData= 0x1234;  
  34.     unsigned    char *cP = (unsigned char*)&iData;  
  35.       
  36.     DDRF = 0xFF;    //포트F를 출력으로 설정  
  37.       
  38.     PORTF = *cP;  
  39.     delay_ms(3000);  //3초간 딜레이  
  40.     PORTF = *(cP+1);  
  41.       
  42.     return 0;  
  43. }  


 소스 코드를 보면 2바이트 int형 데이터를 선언하고(atmega128에서 int형은 2바이트),
1바이트 포인터로 주소값을 저장하였다.

 만약, Big endian이라면 0x12가 먼저 출력되고 3초뒤에 0x34가 출력될테고,
Little endian이라면 0x34가 먼저 출력되고 3초뒤에 0x12가 출력될 것 이다.

 키트를 연결시킨후 hex파일을 전송 시켜보았다.





 여기서 켜지는 것이 0이고, 불이 들어오지 않은 것이 1이다.
위의 사진에서 00110100으로 출력되고 3초뒤의 모습인 아래 사진에서 00010010으로 출력되는 것을 알 수 있다.
즉, 0x34 -> 3초뒤 ->0x12로 출력되는 것이다.

 따라서, 0x1234가 34, 12 의 순으로 역순으로 저장되어있기 때문에 Little endian방식으로 메모리에 저장하는 것을 알 수 있다.
2009. 4. 23. 11:47

[AVR] DDRA, PORTA를 찾아보자.

DDRA, PORTA는 도대체 어디에 정의되어 있을까?
헤더파일에서 직접 찾아보자.

소스코드를 보면 <stdio.h>처럼 많이 사용하는 io함수들을 사용하기 위해 아래와 같이 include한다.

#include <avr/io.h>

따라서 io.h를 살펴보면,

#elif defined (__AVR_ATmega128__)
#include <avr/iom128.h>

이라고 정의된 부분을 볼 수있다.

iom128.h를 찾아보자.(다른 MCU라면 해당 헤더파일을 찾으면 된다.)

imo128.h를 보면, (ctrl+f로 찾자)

/* Input Pins, Port A */
#define PINA      _SFR_IO8(0x19)

/* Data Direction Register, Port A */
#define DDRA      _SFR_IO8(0x1A)

/* Data Register, Port A */
#define PORTA     _SFR_IO8(0x1B)

이렇게 정의된 부분이 있다.

따라서 PORTA = 0xFF 라는 문장은,
_SFR_IO8(0x1B) = 0xFF 라고도 쓸수있다.

그렇다면, _SFR_IO8는 무엇일까.

아까 io.h를 다시 살펴보면,
#include <avr/sfr_defs.h> 라고 된 부분이 있다.
특수기능 레지스터에 대한 헤더파일인데, 이것을 열어보자.

#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)

이라고 된 부분을 보자.
이것은 매크로 함수인데, 뒷부분의 _MMIO...부분을 수행하는 것이다.

따라서,
PORTA = 0xFF;
_SFR_IO8(0x1B) = 0xFF;
_MMIO_BYTE((0x1B) + __SFR_OFFSET) = 0xFF;
세문장은 모두 같은 문장이 된다.

그렇다면 _MMIO_BYTE와 __SFR_OFFSET는 무엇일까.

sfr_defs.h에서 _MMIO_BYTE를 다시 찾아보면,

#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))

라고 정의된 부분을 찾을 수 있다.

따라서,
PORTA = 0xFF;
_SFR_IO8(0x1B) = 0xFF;
_MMIO_BYTE((0x1B) + __SFR_OFFSET) = 0xFF;
(*(volatile uint8_t *)((0x1B) + __SFR_OFFSET)) = 0xFF;
는 모두 같은 문장이 된다.

volatile에 대해서는 여기를 참조하도록하자. <volatile 한정자 보기>
uint8_t는 unsigned 타입의 정수형(int) 8bit의 타입이라는 것이다.(이 부분이 정의된 부분은 아직 못찾았다.)
즉, unsigned char의 포인터형이란 뜻이고, 괄호가 되있으므로 캐스팅(형변환)을 하겠다는 뜻이다.

__SFR_OFFSET을 찾아보자.
마찬가지로 sfr_defs.h에 정의되어있다.

#ifndef __SFR_OFFSET
/* Define as 0 before including this file for compatibility with old asm
   sources that don't subtract __SFR_OFFSET from symbolic I/O addresses.  */
#  if __AVR_ARCH__ >= 100
#    define __SFR_OFFSET 0x00
#  else
#    define __SFR_OFFSET 0x20
#  endif
#endif

조건은 호환모드인가 노멀모드인가를 판별하는 것이고
그에 따른 값을 정의한다. 따라서, 노멀모드이므로 0x20이 된다.

따라서,
PORTA = 0xFF;
_SFR_IO8(0x1B) = 0xFF;
_MMIO_BYTE((0x1B) + __SFR_OFFSET) = 0xFF;
(*(volatile uint8_t *)((0x1B) + __SFR_OFFSET)) = 0xFF;
(*(volatile uint8_t *)((0x1B) + 0x20)) = 0xFF;
(*(volatile uint8_t *)0x3B) = 0xFF;

즉, 0x3B주소지에서 1바이트 공간에 0xFF를 쓰겠다는 뜻이다.

그렇다면 0x3B는 무엇인가.
이는 atmega128의 스펙을 살펴봐야한다.
스펙을 살펴보면, PORTA 레지스터와 연결되어있음을 알수있다.

즉 0x3B에 데이터를 쓰게 되면 PORTA 레지스터에 데이터를 쓰는 것과 같은 것이다.

이를 활용하여 헤더파일을 작성할 수 있다.


 
  1. /* test.h*/  
  2. //중복을 막는다.   
  3. #ifndef _TEST_H_  
  4. #define _TEST_H_  
  5.   
  6. #define DDRA (*(volatile unsigned char*) 0x3A)  
  7. #define DDRB (*(volatile unsigned char*) 0x37)  
  8. #define DDRC (*(volatile unsigned char*) 0x34)  
  9. #define DDRD (*(volatile unsigned char*) 0x31)  
  10. #define DDRE (*(volatile unsigned char*) 0x22)  
  11. #define DDRF (*(volatile unsigned char*) 0x61)  
  12. #define DDRG (*(volatile unsigned char*) 0x64)  
  13.   
  14. #define PORTA (*(volatile unsigned char*) 0x3B)  
  15. #define PORTB (*(volatile unsigned char*) 0x38)  
  16. #define PORTC (*(volatile unsigned char*) 0x35)  
  17. #define PORTD (*(volatile unsigned char*) 0x32)  
  18. #define PORTE (*(volatile unsigned char*) 0x23)  
  19. #define PORTF (*(volatile unsigned char*) 0x62)  
  20. #define PORTG (*(volatile unsigned char*) 0x65)  
  21.   
  22. #define PINA (*(volatile unsigned char*) 0x39)  
  23. #define PINB (*(volatile unsigned char*) 0x36)  
  24. #define PINC (*(volatile unsigned char*) 0x33)  
  25. #define PIND (*(volatile unsigned char*) 0x3B)  
  26. #define PINE (*(volatile unsigned char*) 0x21)  
  27. #define PINF (*(volatile unsigned char*) 0x20)  
  28. #define PING (*(volatile unsigned char*) 0x63)  
  29.   
  30. #endif  



2009. 4. 22. 18:24

[DK-128] LED 순차적으로 점멸하기

소스코드

  1. #include <avr/io.h>  
  2. #include<avr/signal.h>  
  3. #include<avr/interrupt.h>  
  4.   
  5. void delay_us(unsigned char time_us)  
  6. {  
  7.   
  8.         register unsigned char i;  
  9.   
  10.         for(i=0; i<time_us; i++)                     
  11.         {  
  12.                 asm volatile(" PUSH R0 ");     
  13.                 asm volatile(" POP R0 ");      
  14.                 asm volatile(" PUSH R0 ");  
  15.                 asm volatile(" POP R0 ");     
  16.                 asm volatile(" PUSH R0 ");   
  17.                 asm volatile(" POP R0");     
  18.         }  
  19. }  
  20.   
  21. void delay_ms(unsigned int time_ms)  
  22. {  
  23.         register unsigned int i;  
  24.         for(i=0; i<time_ms; i++)  
  25.         {  
  26.                 delay_us(250);  
  27.                 delay_us(250);  
  28.                 delay_us(250);  
  29.                 delay_us(250);  
  30.         }  
  31. }  
  32.   
  33. void delay_s(unsigned int time_s)  
  34. {  
  35.         register unsigned int i;  
  36.         for(i=0; i<time_s; i++)  
  37.          delay_ms(1000);  
  38.   
  39. }  
  40.   
  41. int main()  
  42. {  
  43.   
  44.     int iFlag1 = 0x01;  
  45.     int iFlag2 = 0xff;  
  46.     int direct = 1;  
  47.     DDRF = 0xff;  
  48.   
  49.     while(1)  
  50.     {  
  51.         PORTF = iFlag1 ^ iFlag2;  
  52.         if(direct == 1)  
  53.         {  
  54.             iFlag1 = iFlag1<<1;  
  55.             if(iFlag1 == 0x80)   direct = -1;  
  56.         }  
  57.         else if(direct == -1)  
  58.         {  
  59.             iFlag1 = iFlag1>>1;  
  60.             if(iFlag1 == 0x01)   direct = 1;  
  61.         }  
  62.   
  63.         delay_ms(300);  
  64.     }      
  65.     return 0;  
  66. }