본문 바로가기
Embedded 실습/AT91SAM7S256

구조체를 이용한 메모리 접근

by 중동콜링 2013. 5. 22.

지금껏 ARM에 코딩할 때 define문으로 레지스터를 각각 지정하여 

사용하는 방법을 썼는데, ATMEL사에서 제공하는 헤더파일을 이용하면

각기 따로 define문을 이용하여 지정할 필요 없이

바로 코드를 작성할 수 있다.


이는 메모리 주소와 구조체, 포인터의 특성을 이용하여 사용하는 것이다.



#include <stdio.h>

#define BASE  ((struct SMART *)0x12FF60)

struct SMART
{
  int A;
  int B;
  int C;
  int D;
};

int main()
{
  int array[4= {0x110x220x330x44};
  int *ip = array;
  struct SMART *ssp;
  
  printf("  int[] :  %X\t%X\t%X\t%X\n", array[0], array[1], array[2], array[3]);
  printf("   *int :  %X\t%X\t%X\t%X\n", *(ip+0), *(ip+1), *(ip+2), *(ip+3));

  ssp = (struct SMART *)array;

  printf("*struct :  %X\t%X\t%X\t%X\n", ssp->A, ssp->B, ssp->C, ssp->D);

  printf("Address of array : %p\n", array);
  printf("((struct SMART *)0x12FF60)->A : %X\n", ((struct SMART *)0x12FF60)->A);  // 쌩 주소를 주소값으로 인식->*형으로 CASTING
  printf("((struct SMART *)0x12FF60)->B : %X\n", ((struct SMART *)0x12FF60)->B);
  printf("((struct SMART *)0x12FF60)->C : %X\n", ((struct SMART *)0x12FF60)->C);
  printf("((struct SMART *)0x12FF60)->D : %X\n", ((struct SMART *)0x12FF60)->D);

  printf("BASE->A : %X\n", BASE->A);
  printf("BASE->B : %X\n", BASE->B);
  printf("BASE->C : %X\n", BASE->C);
  printf("BASE->D : %X\n", BASE->D);

  return 0;
}


위의 소스에서 구조체 int형 배열 array와 구조체 struct SMART의 포인터 ssp를 선언했는데,

ssp = (struct SMART *)array;

와 같이 형변환하여 ssp에 array의 시작주소를 대입해주었다.

struct SMART
{
  int A;
  int B;
  int C;
  int D;
};
int array[4= {0x110x220x330x44};

구조체 struct SMART는 각 멤버가 모두 int형으로 int형 배열과 같은 크기의 자료형을 가진다.
그러므로, 구조체 포인터 ssp에 배열의 시작주소를 대입하면
구조체 멤버에 접근하는 방식으로(ssp->A) 각 배열요소에 접근할 수 있다.

printf("*struct :  %X\t%X\t%X\t%X\n", ssp->A, ssp->B, ssp->C, ssp->D);

여기서 더 나아가서, array의 시작주소를 printf()로 출력하여 알아본 후,
printf("Address of array : %p\n", array);

메모리 주소에 구조체의 멤버 포인터 접근 방식으로도 직접 접근이 가능하다.
printf("((struct SMART *)0x12FF60)->A : %X\n"((struct SMART *)0x12FF60)->A);

#define BASE  ((struct SMART *)0x12FF60)
printf("BASE->A : %X\n", BASE->A);
아니면 위와 같이 array의 시작주소 자체를 define문으로 정의한 후
그 이름으로 구조체멤버에 접근하는 방식으로 접근할 수도 있다.

#define AT91C_BASE_SYS       (AT91_CAST(AT91PS_SYS)   0xFFFFF000) // (SYS) Base Address
#define AT91C_BASE_AIC       (AT91_CAST(AT91PS_AIC)   0xFFFFF000) // (AIC) Base Address
#define AT91C_BASE_PDC_DBGU  (AT91_CAST(AT91PS_PDC)   0xFFFFF300) // (PDC_DBGU) Base Address
#define AT91C_BASE_DBGU      (AT91_CAST(AT91PS_DBGU)  0xFFFFF200) // (DBGU) Base Address
#define AT91C_BASE_PIOA      (AT91_CAST(AT91PS_PIO)   0xFFFFF400) // (PIOA) Base Address
#define AT91C_BASE_CKGR      (AT91_CAST(AT91PS_CKGR)  0xFFFFFC20) // (CKGR) Base Address
#define AT91C_BASE_PMC       (AT91_CAST(AT91PS_PMC)   0xFFFFFC00) // (PMC) Base Address
#define AT91C_BASE_RSTC      (AT91_CAST(AT91PS_RSTC)  0xFFFFFD00) // (RSTC) Base Address
#define AT91C_BASE_RTTC      (AT91_CAST(AT91PS_RTTC)  0xFFFFFD20) // (RTTC) Base Address
#define AT91C_BASE_PITC      (AT91_CAST(AT91PS_PITC)  0xFFFFFD30) // (PITC) Base Address
#define AT91C_BASE_WDTC      (AT91_CAST(AT91PS_WDTC)  0xFFFFFD40) // (WDTC) Base Address
#define AT91C_BASE_VREG      (AT91_CAST(AT91PS_VREG)  0xFFFFFD60) // (VREG) Base Address

위의 코드는 ATMEL사에서 제공하는 <AT91SAM7S256.h> 의 일부 코드인데
모든 주변장치의 시작주소가 define되어 있는것을 확인할 수 있다.

#ifndef __ASSEMBLY__
typedef struct _AT91S_PMC {
  AT91_REG   PMC_SCER;   // System Clock Enable Register
  AT91_REG   PMC_SCDR;   // System Clock Disable Register
  AT91_REG   PMC_SCSR;   // System Clock Status Register
  AT91_REG   Reserved0[1];   // 
  ......
} AT91S_PMC, *AT91PS_PMC;

그리고 위 코드와 같이 주변장치의 레지스터를 구조체로 묶어 정의해 놓았는데,
이를 위에서 정리한 방법과 같이 AT91C_BASE_PMC->PMC_SCER 와 같이 
(define으로 정의된 메모리 베이스주소)->(구조체 멤버)
와 같은 형식으로 각 레지스터를 사용할 수 있다.