Light Senser Test

사용 컴파일러 : AVR-gcc

헤더 파일 :
소스 파일 :

'임베디드(embbeded) > Atmega' 카테고리의 다른 글

[Atmega128] lightSenser(8.25)  (2) 2009.08.25
  1. Michael Kors outlet 2013.07.27 00:39

    사람들은 죽을걸 알면서도 살잖아 .사랑은 원래 유치한거에요

  2. ugg 2013.07.27 08:02

    당신은 내가사랑할 만한 사람이 아니예요,사랑하지 않으면 안될 사람이예요.

TinyOS 에서의 RF Chip (CC2420) 동작 원리

 

현재 IEEE 802.15.4 프로토콜의 MAC layer 표준에 상응하는 2.4GHz대역의 CC2420이 센서 네트워크 플랫폼의 radio chip으로 많이 사용되고 있다. TinyOS (U.C.Berkeley에서 제작한 센서네트워크 OS) 에도 CC2420에 대한 부분이 포함되어 있으며 이는 CC2420을 동작하게 하는 드라이버 부분과 backoff 및 CCA 알고리즘이 추가 구현되어 있다.
이 문서는 TinyOS에서 구현된 CC2420의 동작 원리를 분석하여, RF 메커니즘의 이해를 돕고자 하는데 그 의의가 있다.
 
1. IEEE 802.15.4 프로토콜
 
IEEE 802.15.4 의 standard feature는 다음과 같다.
The IEEE 802.15.4-2003 standard
      • Data rates of 250 kbps, 40 kbps, and 20 kbps.
      Two addressing modes; 16-bit short and 64-bit IEEE addressing.
      Support for critical latency devices, such as joysticks.
      CSMA-CA channel access.
      Automatic network establishment by the coordinator.
      Fully handshaked protocol for transfer reliability.
      Power management to ensure low power consumption.
      16 channels in the 2.4GHz ISM band, 10 channels in the 915MHz I and one 
        channel in the 868MHz band.
 
또한, CC2420의 간단한 specification을 보면 다음과 같다.
 
The IEEE 802.15.4-2003 standard
      true single-chip 2.4 GHz (16 channels in ISM band)
      Max data rate : 250Kbps
      Low current consumption (RX: 19.7 mA, TX: 17.4 mA)
 
위와 같이, CC2420은 IEEE 802.15.4 MAC hardware를 지원 가능하다. CSMA-CA에 대한 부분은 tinyos에서 B-MAC이란 MAC protocol을 사용해서 보완하고 있다.
 
2. CC2420 driver
 
CC2420은 MCU와 4-wire SPI-bus configuration interface (SI, SO, SCLK and CSn). 로 연결되어 SPI통신을 통한 동작을 기본으로 한다.

 
 
CSN은 SPI Chip select로,  SPI 통신의 enable/disable을 담당한다. 일반적으로 low상태일 때, enable이 되고, High 일 때, disable이 된다. SI는 SPI Bus의 Input으로 사용되고, SO는 SPI Bus의 Output으로 사용된다. SCLK는 SPI Bus의 serial clock으로 사용된다.
atmega에서는 SPI를 컨트롤하는 레지스터를 갖고 있어서, 간단한 설정만으로도 SPI통신이 가능하다. 하지만 msp430 계열은 SPI를 컨트롤하는 레지스터가 없기 때문에, UART를 SPI mode로 변경하여 사용한다. TinyOS에서는 SPI mode의 초기화를 각 architectre별로 다음과 같이 구현하고 있다.
 
------------------------------------------------------------------------------
Atmega -
 
TOSH_MAKE_SPI_SCK_OUTPUT();
TOSH_MAKE_MISO_INPUT();      // miso
TOSH_MAKE_MOSI_OUTPUT();    // mosi
sbi (SPSR, SPI2X);           // Double speed spi clock
sbi(SPCR, MSTR);             // Set master mode
cbi(SPCR, CPOL);               // Set proper polarity...
cbi(SPCR, CPHA);               // ...and phase
cbi(SPCR, SPR1);             // set clock, fosc/2 (~3.6 Mhz)
cbi(SPCR, SPR0);
//    sbi(SPCR, SPIE);          // enable spi port interrupt
sbi(SPCR, SPE);              // enable spi port
------------------------------------------------------------------------------
------------------------------------------------------------------------------
MSP430
 
call USARTControl.disableUART(); call USARTControl.disableI2C();
atomic {
   TOSH_SEL_SIMO1_MODFUNC();
   TOSH_SEL_SOMI1_MODFUNC();
   TOSH_SEL_UCLK1_MODFUNC();
   IE2 &= ~(UTXIE1 | URXIE1);  // interrupt disable
   U1CTL |= SWRST;
   U1CTL |= CHAR | SYNC | MM;  // 8-bit char, spi-mode, USART as master
   U1CTL &= ~(0x20); U1TCTL = STC ;     // 3-pin
   U1TCTL |= CKPH;    // half-cycle delayed UCLK
   if (l_ssel & 0x80) {
     U1TCTL &= ~(SSEL_0 | SSEL_1 | SSEL_2 | SSEL_3);
     U1TCTL |= (l_ssel & 0x7F);
   }
   else {
     U1TCTL &= ~(SSEL_0 | SSEL_1 | SSEL_2 | SSEL_3);
     U1TCTL |= SSEL_SMCLK; // use SMCLK, assuming 1MHz
if (l_br != 0) {
   U1BR0 = l_br & 0x0FF;
   U1BR1 = (l_br >> 8) & 0x0FF;
 }
 else {
   U1BR0 = 0x02;   // as fast as possible
   U1BR1 = 0x00;
 }
 U1MCTL = 0;
 ME2 &= ~(UTXE1 | URXE1); //USART UART module disable
 ME2 |= USPIE1;  // USART SPI module enable
 U1CTL &= ~SWRST;
 IFG2 &= ~(UTXIFG1 | URXIFG1);
 IE2 &= ~(UTXIE1 | URXIE1);  // interrupt disabled
------------------------------------------------------------------------------
 
위에서 보듯이, atmega는 6~7번의 레지스터 세팅으로 SPI 통신을 초기화 할 수 있지만, msp430은 일반적인 UART 설정을 기본으로 초기화한다. 실제로, 일반 UART 초기화와의 차이점은 SPI module disable/enable을 제어하는 레지스터의 설정밖에 없다.(USPIEx) 초기화 후에, 간단한 SPI read/write function을 기본으로 작성된 여러가지 함수를 이용해서 CC2420을 제어하게 된다. 몇몇 중요 함수들의 예는 다음과 같다. (Hmote기준)
 
HPLCC2420.cmd(uint8_t addr) :
CC2420으로 하나의 command를 보내고, 수신된 status 값을 리턴한다.
HPLCC2420.read(uint8_t addr) :
CC2420으로부터 16-bit 레지스터 값을 받아온다.
HPLCC2420FIFO.readRXFIFO (uint8_t length, uint8_t *data) :
RX FIFO 큐로부터 length만큼 값을 받아오고, data에 저장한다.
HPLCC2420FIFO.writeTXFIFO(uint8_t length, uint8_t *data) :
data에 저장된 length만큼의 데이터를 TX FIFO에 write한다.
 
이제 이 함수들을 어떻게 사용하여 CC2420을 제어하는지 살펴보자.
CC2420의 드라이버 및 B-MAC이 구현된 부분은 /opt/tinyos-1.x/tos/lib/CC2420Radio 이다. 각 architecture별로
구현된 SPI/SPI응용 함수들을 이용하여 CC2420의 제어가 가능하다.
드라이버에서 가장 처음에 하는 일은 CC2420의 power on, reset toggle 을 하는 것이다.
 
------------------------------------------------------------------------------
//turn on power
call CC2420Control.VREFOn();
// toggle reset
TOSH_CLR_CC_RSTN_PIN();TOSH_wait();
TOSH_SET_CC_RSTN_PIN();TOSH_wait();
------------------------------------------------------------------------------
그 다음은 CC2420의 crystal을 enable시킴으로서, CC2420의 동작을 위한 최소한의 하드웨어 설정을 마친다. CC2420으로 CC2420_SXOSCON(0x01)이란 command를 보내면 crystal이 동작하게 된다.
 
------------------------------------------------------------------------------
async command result_t CC2420Control.OscillatorOn() {
......
status = call HPLChipcon.cmd(CC2420_SXOSCON);   //turn-on crystal
......
------------------------------------------------------------------------------
 
CC2420의 send 모드는 크게 두가지로 나눌 수 있다. 채널이 clear될 때까지 기다리다가 clear되는 순간 전송을 하는 방식과, 채널의 상태에 관계없이 전송을 하는 방식이다.
 
------------------------------------------------------------------------------
async command result_t CC2420Control.TxMode() {
   call HPLChipcon.cmd(CC2420_STXON);
   return SUCCESS;
 }
//Shift the CC2420 Radio into transmit mode when the next clear channel
is detected.
async command result_t CC2420Control.TxModeOnCCA() {
  call HPLChipcon.cmd(CC2420_STXONCCA);
  return SUCCESS;
 }
------------------------------------------------------------------------------
 
CC2420의 receive모드는 다음과 같다
------------------------------------------------------------------------------
async command result_t CC2420Control.RxMode() {
  call HPLChipcon.cmd(CC2420_SRXON);
  return SUCCESS;
}
------------------------------------------------------------------------------
 
CC2420Control 에 모듈의 초기화, TX/RX 모드 함수, RF power및 frequency 설정을 하는 기본 함수들이 포함되어 있다면, CC2420Radio는 송/수신에 직접적이면서 복잡한 함수들이 포함되어 있다.
송신 함수는 sendPacket(), startSend(), tryToSend()함수로 구현되어 있다.
startSend는 말그대로 송신을 시작하는 함수로, TXFIFO에 송신할 패킷을 length만큼 write하게 된다.
이 함수가 종료되면 패킷들이 FIFO에서 송출되기를 기다린다.
 
------------------------------------------------------------------------------
task void startSend() {
  // flush the tx fifo of stale data
  if (!(call HPLChipcon.cmd(CC2420_SFLUSHTX))) {
    sendFailed();
    return;
  }
  // write the txbuf data to the TXFIFO
  if (!(call HPLChipconFIFO.writeTXFIFO(txlength+1,(uint8_t*)txbufptr))) {
    sendFailed();
    return;
  }
}
------------------------------------------------------------------------------
 
sendPacket은 RF로 패킷을 보내는 함수이다. tryToSend에서 call되어 사용되어 지며, 채널이 clear되면 전송되는 방식을 사용한다.
 
------------------------------------------------------------------------------
void sendPacket() {
  uint8_t status;
  call HPLChipcon.cmd(CC2420_STXONCCA);
  status = call HPLChipcon.cmd(CC2420_SNOP);
……..
}
------------------------------------------------------------------------------
 
tryToSend는 CCA핀을 read했을 때, High상태라면, 즉 채널이 clear하다면 sendPacket을 call하여 패킷을 전송하고,
채널이 사용중이라면 normal operation을 계속해서 수행한다.
 
------------------------------------------------------------------------------
void tryToSend() {
     …………..
       // if a FIFO overflow occurs or if the data length is invalid, flush
       // the RXFIFO to get back to a normal state.
       if ((!TOSH_READ_CC_FIFO_PIN() && !TOSH_READ_CC_FIFOP_PIN())) {
         flushRXFIFO();
       }
       if (TOSH_READ_RADIO_CCA_PIN()) {
         atomic stateRadio = TX_STATE;
         sendPacket();
       }
       else {
         // if we tried a bunch of times, the radio may be in a bad state
         // flushing the RXFIFO returns the radio to a non-overflow state
         // and it continue normal operation (and thus send our packet)
         if (countRetry-- <= 0) {
           flushRXFIFO();
           countRetry = MAX_SEND_TRIES;
           if (!post startSend())
             sendFailed();
           return;
         }
……………
}
------------------------------------------------------------------------------
 
tryToSend는 startSend가 종료되는 시점에 실행이 된다. 즉 startSend에서 TXFIFO를 채우면
HPLChipconFIFO.TXFIFODone()이 실행되고, 이 함수안에서 tryToSend를 실행하게 되어, FIFO에 write된 패킷이
무선으로 전송된다.
 
 
rxMode로 설정되어 있을 때, 같은 주파수대의 패킷이 들어오면, FIFOP에 interrupt가 발생한다. Interrupt가 발생했을 때, FIFOP.fired 라는 인터럽트 함수가 실행하게 되고, 이는 수신된 패킷을 RXFIFO로 write한다.
RXFIFO로 값이 모두 들어오면, HPLChipconFIFO.RXFIFODone()라는 함수가 실행된다.
 
------------------------------------------------------------------------------
async event result_t FIFOP.fired() {
     …………..
     /** Check for RXFIFO overflow **/
     if (!TOSH_READ_CC_FIFO_PIN()){
       flushRXFIFO();
       return SUCCESS;
     }
     atomic {
         if (post delayedRXFIFOtask()) {
           call FIFOP.disable();
         }
         else {
           flushRXFIFO();
         }
     }
     // return SUCCESS to keep FIFOP events occurring
     return SUCCESS;
  }
------------------------------------------------------------------------------
 
HPLChipconFIFO.RXFIFODone()이 실행되면 데이터 예외처리를 거쳐서 정상적인 length의 패킷을 rxbufptr 버퍼에 저장한다. rxbufptr에 할당이 되는 *data는 TOS_MsgPtr 의 구조체 변수 크기에 맞게 바이트 단위로 parsing되서 저장된다. 
length가 길면 패킷은 버려지고, 짧으면 crc, RSSI, LQI값을 맟춰서 할당한다.
 
 
------------------------------------------------------------------------------
async event result_t HPLChipconFIFO.RXFIFODone(uint8_t length, uint8_t *data){
…………….
rxbufptr = (TOS_MsgPtr)data;
……………
if (rxbufptr->length > TOSH_DATA_LENGTH) {
  flushRXFIFO();
  atomic bPacketReceiving = FALSE;
  return SUCCESS;
}
// adjust destination to the right byte order
rxbufptr->addr = fromLSB16(rxbufptr->addr);
// if the length is shorter, we have to move the CRC bytes
rxbufptr->crc = data[length-1] >> 7;
// put in RSSI
rxbufptr->strength = data[length-2];
// put in LQI
rxbufptr->lqi = data[length-1] & 0x7F;
……………
}
------------------------------------------------------------------------------
 
지금까지 TinyOS에서의 CC2420이 마이크로 컨트롤러와 어떻게 통신을 하고 동작을 하는지를 알아보았다.
물론 위의 설명은 CC2420의 동작원리를 충분히 이해하기엔 너무 개략적이고 의미 중심적이다.
따라서 윗글은 CC2420소스를 처음 접하여 분석하고자 하는 분에게 소스의 전반적인 구성을 이해하는데 참조할 수 있는 자료라 할 수 있겠다.
 

 


앞에 이어서 그러면 사용자 정의 문자 출력을 해 보도록 합시다.


사용자 정의 문자를 지정하는데 사용하는 메모리는 CG RAM이며, 이 CG RAM에는 5x8 도트를 사용하는 경우에는 최대 8문자, 5x10 도트를 사용하는 경우에는 최대 4문자를 쓸수 있습니다. 사용자 정의 문자는 위 그림의 00H~0fH의 영역에 할당되어 있는데 1문자가 2개의 코드 영역을 차지하므로 실제 코드값은 00H~07H(또는08H~0fH)로 사용 됩니다.

1. 사용자 정의 문자 코드는 00H~0FH 영역에 해당되며, 이중에서 아래의 3비트만이 유효하고, b3은 don't care이므로 실제 코드값은 00H~07H(또는 08H~0FH)로 지정해야 합니다.

2.  위 문자 정의에서 보시듯이 제일 아래단은 커서를 위해서 비워 두는게 좋습니다.

3. CG RAM data에 사용되는데 b5~b7은 사용되지 않는 데이터 영역이므로 b0~b4까지 데이터를 채워 주시면 됩니다.

그럼 아래 함수를 보면서 이해를 해 보도록 합시다. ^^


이 소스를 실행 시킨 실행 화면 입니다.

위 사진에서 보시듯이(해상도가 낮아서 죄송합니다.ㅎ) 8개의 구역을 이용하여 [이현]이라는 한자를 입력한 것입니다.

이렇게 Text LCD에 사용자 정의 입력을 할 수도 있지만 8글자라는 한계가 있어서 한글을 표현하려면 Graphic LCD를 이용하는 편이 좋습니다. 

결론은 Text LCD는 영어를 문자로 표현할 때 가장 좋은 것이라는 것을 느꼈습니다.

역시 영어가 중요한 것 같습니다. ㅋㅋ

서비스로 전체 소스를 올려봅니다.



  1. 곽동호 2010.02.11 13:34

    안녕하세요.

    제가 지금 TXET LCD를 구동해보려고 하는데

    소스 좀 얻을 수 있을까요...??

    메인과 헤더 모두 받고 싶습니다.

    kb2clsrn@nate.com

    바쁘시지 않다면 좀 보내주세요.

    감사합니다.

텍스트 LCD를 사용하기 위해서는 텍스트 LCD를 우선적으로 제어를 해야 합니다.
LCD를 제어하는 방법에 대해서는 각 제조사의 Data Sheet를 보면 자세하게 나와 있고, 또한 시중에서의 책을 찾아봐도 무방하지만, 각 제품의 특징이 있기 마련이니 가능하면 Data Sheet를 참조해서 제어를 시도하시길 바랍니다.

우선 제가 사용하는 LCD(HY-1602W-204)의 Data Sheet의 제어 및 출력 명령을 찾아보겠습니다.

위 데이터 시트를 통해서 LCD의 자세한 스펙을 알 수 있으므로 상당히 유용해다고 할 수 있습니다.

 LCD의 초기화 과정을 살펴 보겠습니다.

1. 전원을 투입합니다.
2. 초기화를 시작하기 전에 30 ms 이상을 기다립니다.
3. Function Set 명령을 보냅니다.
4. Display ON/OFF control 명령을 보냅니다.
5. Entry mode set 명령을 보냅니다.
6. DD RAM 어드레스를 보냅니다.
7. 표시할 문자 데이터를 보냅니다.
8. 필요할 경우 6~7 과정을 반복합니다.

텍스트형 LCD 모듈의 DD RAM은 표시할 문자들의 ASCII 코드 데이터가 저장되는 내부 메모리이며 모두 80개의 번지가 있는데, 화면의 각 행과 열의 문자 위치에는 고유한 어드레스 값이 부여되어 있습니다. 그런데, 첫번째 행은 DD RAM 어드레스가 00H부터 시작되고 2번째 행은 항생 40H부터 시작되므로, LCD 모듈이 2행 이상으로 구성되는 경우에 각 행과 행 사이에는 어드레스가 연속하여 있지 않게 되어 주의하여야 한다. 또한, 물리적으로 4행으로 되어 있는 LCD 모듈은 어드레스가 1행과 3행이 이어져 있고 2행과 4행이 이어져 있어서 논리적으로 2행으로 동작한다.





[본 프로그램의 동작환경]
 * 컴파일러 arm-elf-gcc
 * 사용된 arm : AT91SAM7S256
 * 사용된 보드 : AT91SAM7S64 BOARD



ARM은 다양한 기능을 제공한다. 그중에 USART를 이용하여 시리얼 통신을 하는 프로그램을 짜게 되었다. 
 이 프로그램은 아주 단순한 기능을 제공 한다. 
 ARM의 플래쉬 메모리에 프로그램을 싣고 ARM을 작동시킨 후 터미널에 프로그램에 설정한 대로 하이퍼 터미널에 통신 상태를 적용시킨 후 키보드로 입력을 하면 입력한 내용이 터미널 창에 뜨는 기능이다.

 프로그램 작성방법은 아래 PDF의 설명을 따라서 프로그램을 작성한다.
 다만 위 설명중 루프백 설정을 하는 부분이 있다. 그 부분을 노멀 모드로 바꿔주어야 자신이 입력한 키 입력이 터미널에 출력되는 것이 보일 것이다.

그럼 소스파일을 한번 보자.
이 소스는 헤더파일을 분리하였기 때문에 헤더파일도 같이 보아야 한다.
이 프록그램은 makefile을 사용하여 프로그램을 컴파일을 할 수 있도록 한다.
그럼 makefile을 보자
Universal Synchronous and Asynchronous serial Receiver and Transmitter = USART
이 USART는 산업표준인[=UART] 비동기방식만을 제공하는게 아니라 동기와 비동기를 모두 제공해주는 직렬 통신 포트이다.

[제공기능]
- 전이중 통신이 가능
- 동기와 비동기를 지원
- Master와 Slave Clocked Synchronous Operation4
- High Resolution Baud Rate Generator
등등 다양한 기능을 제공해 준다. 

[동기와 비동기의 작동방식]
1) 동기식
- master : 전송속도를 결정할때 내부 클럭을 사용
- slave : XCKn 단자로 입력되는 클럭 신호에 의해 동작
2) 비동기식
- 항상 내부 클럭에 의하여 Baud Rate가 결정됨

[USART의 레지스터]
1) USARTn I/O Data Register - UDRn
 - UDRn은 Data 송수신을 위한 레지스터이다.
 - 이 레지스터는 2byte로 되어 있다.(ATMEL128에서의 2byte는 INT형이다.)
   2Byte의 공간중 1Byte는 Read를 위한 공간이고, 1Byte는 Write를 위한 공간이다.

2) USART Control and Status Register A - UCSRnA
- 포트의 송수신 동작을 제어, 송수신 상태를 저장하는 기능
 
3) USART Control and Status Register B - USCRnB
- 포트의 송수신 동작을 제어
- 전송데이터를 9비트로 설정한 경우에 전송 데이터의 9번째 비트값을 저장하는 기능 수행
 
4) USART Control and Status Register C - USCRnC
- 포트의 송수신 동작을 제어
 
5) USART Baud Rate Registers - UBRRnH and UBRRnL
- 16비트중 12비트만 유효
- 포트의 송수신 속도를 설정하는 기능을 수행
- 레지스터 write 하는 경우 상위 바이트인 UBRRnH부터 먼저 write 하고 그다음 UBRRnL write 함
  
[USART 인터럽트]
- USART의 인터럽트는 3가지가 있다.
1) TX Complete (송신완료)
2) TX Data Register Empty (송신 데이터 레지스터 준비완료)
3) RX Complete (수신완료)
 
[USART를 3부분으로 나누기]
1) 클럭 발생부 - Baud Rate Generator, 동기모드에서 클럭과 동기를 취하는 회로를 구성
2) 송신부 - 송신 버퍼, 송신 시프트 레지스터, 패리티 발생기(오류체크)
3) 수신부 - 수신 버퍼, 수신 시프트 레지스터, 패리티 검사기

[하드웨어]
= HIN232C
이 칩은 120kbps의 최대 속도를 낼 수 있고, 0 ~ 70도의 온도를 견딜 수 있다.
  1. 우하앤랴ㅣ다 2009.05.06 09:38

    님들 근데 이거 다 긁어서 올리고 다 읽어는 보신거임?

1.     프로그램의 개요

- 이프로그램은 IO Port를 제어를 위해 사용하는 DDRx PORTx DDRF PORTF를이용해

다이오드를 순차적으로 점등 시키는 프로그램을 작성한다.

2.     프로그램의 내용

- 먼저프로그램의 avr io를 저어하기 위해 avr/io.h를 선언한다.

그리고 DDRFoutput을 하게 설정을 한다.

PORTF0xFF를 넣어서 점멸을 시켜 놓은 뒤에 1 0부터 7까지의 위치로 shift연산시켜^(xor)연산을 시킨다.

      -  이 작업을 반대로 시킨다.

- DDRx Port xData Direction Register로서 입출력의 방향을 설정하는 레지스터이고, PORTxPort x Data Register 데이터 출력에 해당하는 레지스터이고, PINx Port x Input Pins Address로서 포트핀의 입력에 해당하는 PINx 레지스터이다. 이것에 대한정의는 <avr/io.h>를 통해서 찾아 볼수 있다.

이 헤더 파일은avr폴더 밑에 io.h라는 파일을 찾을 있다. 하지만 이 헤더파일은 각 버전에 대한 io헤더파일의 연결자 헤더파일이었다. 이중 MCU의 해당 버전을 찾게 도와주는 파일이있는데 makefile이 바로 그것이다.  그 중 지금 공부하는 프로세서가atmega128이니 iom128.h가 헤더 파일로 되어있을있다. 안에 DDRx DDRA에 대해 설정 되어 있는 내용을 찾아보니

/* Data Register, Port A */

#define PORTA    _SFR_IO8(0x1B)

/* Data Direction Register, Port A */

#define DDRA     _SFR_IO8(0x1A)

/* Input Pins, Port A */

#define PINA     _SFR_IO8(0x19) 로 정의 되어 있었다.

DDRA를 우선적으로 살펴보면 _SFR_IO8(0x1A)define한다는 의미인 것이다. 하지만 이 부분은 매크로함수 _SFR_IO8과 이 매크로의 인자인 0x1A로 되어있다는 사실을 알 수 있을 것이다. PORTx PINx 또한 마찬가지로 구성 되어있음을 알 수 있을 것이다.

0x1A를 데이터 시트에서 찾아보면 교재마다 다르겠지만본인의 교재 중 363p - 데이터 시트의 Register Summary의 내용 중 $1A(아트멜에서는 16진수의 표시를 $로 한다.)의이름은 DDRA로 되어 있음을 확인 할 수 있었다. 매크로함수를 통해 DDRA 포트 레지스터로 접근한는 내용임을 짐작하게 한다.

그럼_SFR_IO8()이란 함수를 찾아보아야 자세한 내용을 찾아볼 수 있을 것 같다. 이 함수에대해서 알아보기 위해 iom128.h에서 include하고있는 sfr_def.h이란 헤더파일을 찾아봐야한다. 이 헤더파일은 macros for accessing AVR special function registers에 대한 헤더파일이라는 것을 알 수 있었다. 그럼 _SFR_IO8()이란 무엇인가를 찾아봐야 할 차례인 것 같다.

찾으면 2가지의코드가 나올 것인다.

#define _SFR_IO8(io_addr) ((io_addr) +__SFR_OFFSET) : 이코드는 우리가 찾는 코드가 아니다.

#define_SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET) : 이코드가 찾는 내용이다.

음 점입가경이다._SFR_IO8(io의 주소)(_MMIO_BYTE매크로에 io의 주소를 넣은 값)(__SFR_OFFSET)을 더한 값이 된다. 그중 모르는 내용이 2가지나 나왔는데 _MMIO_BYTE __SFR_OFFSET에 대한 정보가 필요해 졌다. 하지만 걱정 하지 말자. 이번에 찾을 내용은 sfr_def.h안에 다 있는 내용이다.

_MMIO_BYTE를 찾게 되면

#define _MMIO_BYTE(mem_addr) (*(volatileuint8_t *)(mem_addr))를 찾게 된다.

이 매크로를 읽어보면 voliatile타입의 uint8_t인데 이 것을 해석해보면 unsigned int 8bit type이라는 것이다. 결론적으로 unsigned char라는 의미가 될 것이다. (이것도 헤더파일을따라가다 보면 나오는데 별 의미없는 소모적인 일이 될 것 같으므로 생략하겠다.

이번에는 __SFR_OFFSET을찾아보자. 이 부분은 굳이 보지 않아도 되는 내용이지만 읽어보면 도움은 될

이라고 생각된다.이 매크로는 Atmel의지원해주는 기능에 관련된 내용인데 이 Atmega 프로세서는nomal modecompatibility mode를 지원해 준다. 즉 일반모드와 확장모드를 지원해 준다는 의미이고, 기본적으로 일반모드를사용하게 된다.

#ifndef __SFR_OFFSET

#  if__AVR_ARCH__ >= 100

#   define __SFR_OFFSET 0x00  // 이부분이 확장모드이다

# else

#   define __SFR_OFFSET 0x20  // 이부분이 전용모드이다.

# endif

#endif

결론적으로 __SFR_OFFSET은 일반 모드를 쓰면0x20인 것이다. 그럼 모든 의미를 다 찾아 보았다.

그 중 volatile키워드에 대해 잠시 알아보면 volatile은 휘발성이란 의미를 가지고 있는데 이 키워드를 사용해서 정의한 변수는 그것을 사용하는 문장 외에다른 것에 의해서(운영체제나 하드웨어) 변경될 수 있으므로키워드를 사용해서 정의한 변수는 눈에 보이는 문장만을 상대로 함부로 최적화 시키지 말아하 한다는 것을 의미한다., 함부로 컴파일러가 코드 최적화 시키지 않게 하는 키워드인 것이다.그리고 unit8_t란 변수 타입은unsigned char와 같은 의미를 지닌다.

지금껏 찾은 내용을 소스로 정리를 해 보았다.

//PORTA= 0xff;

//_SFT_IO(0x1B) = 0xff;

//_MMIO_BYTE((0x1B) + __SFR_OFFSET) = 0xff;

//(*(volatile uint8_t *))((0x1B) + __SFR_OFFSET) = 0xff;

//(*(volatileuint8_t *)(0x3B)) = 0xff;

(*(volatile unsigned char *)(0x3B)) = 0xff;

이 소스코드가 각 줄이 동일한 의미를 가진다는 것을 이때까지의 내용을 통해서 이젠 알아 볼 수 있을 것이라고 생각한다.

자 이제 모든 함수헤더를 찾아본 것 같다. 이제까지의 내용을 정리해 보면 DDRx PORTx, PINx는 매크로함수이고, 데이터 타입은 (*(voliatile unsigned char *)이며, 인자를받아서 그 인자를 해당 레지스터에 채워주는 명령인 것이다

+ Recent posts