아트메가/이론

ATMEGA128 주솟값으로 제어하기

원원 2023. 2. 25. 21:05

안녕하세요. 오늘은 ATMEGA128의 PORTA를 데이터시트에 나와있는 주솟값으로 제어해보겠습니다.
주솟값으로 제어하는 테스트를 하는 이유는 다른 32bit mcu를 사용할 때 (STM,NXP등등) 주솟값으로 제어하는 방법을 알면 좋아서 먼저 비교적 간단한 8bit mcu인 ATMEGA로 해보겠습니다.

목표는 DDRA와 PORTA를 사용하지 않고 데이터시트에 나와있는 주소로 DDRA와 PORTA를 제어하는 것입니다.

 

먼저 DDRA 선언을 따라가보겠습니다.

#define DDRA	_SFR_IO8(0x1A)
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))

DDRA => _SFR_I08(0x1A) => _MMIO_BYTE((0x1A)+__SFR_OFFSET) =>
(*(volatile uint8_t *)((0x1A)+__SFR_OFFSET) =>
결국에는 DDRA는 (*(volatile unsigned char *)((0x1A)+__SFR_OFFSET) 입니다

 

__SFR_OFFSET은 아래에 정의되어있습니다. __AVR_ARCH__는 AVR ARCHITECTURE이고 컴파일러에 의해서 결정되는분인거같고 일반적으로 ATMEGA128은 5입니다. 그래서 __SFR_OFSET은 0x20입니다.
https://forum.arduino.cc/t/__avr_arch__-preprocessor-symbol-definition/561392

( _AVR_ARCH를 보는방법이 있습니다. 프로젝트에서 아래와같이 설정(-Wl,--verbose)한다음에 빌드를하면 참조하는 링커스크립트파일의 경로가 나오고 경로로가서 실행해보면 OUTPUT_ARCH(avr:5) 라고 적혀있습니다.
-Wl는 링커에게 옵션을 전달하는 역할을하고 --verbose는 링커에게 전달하는 옵션입니다. --verbose는 링커가 수행하는 단계별 작업과 사용하는 라이브러리 및 오브젝트 파일에 대한 정보를 자세히 출력합니다. ) 

#ifndef __SFR_OFFSET
#  if __AVR_ARCH__ >= 100
#    define __SFR_OFFSET 0x00
#  else
#    define __SFR_OFFSET 0x20
#  endif
#endif

그래서 DDRA는 (*(volatile unsigned char *)(0x3A) 입니다
DDRA의 주소는 0x3A입니다. 데이터시트에서도 확인이 가능합니다. PORTA의 주소는 0x3B입니다. ATMEGA128은 8bit이므로 주소가 1증가했습니다. 32bit mcu같은경우는 4가 증가합니다

이제 *(volatile unsigned char *)에 대해 알아보겠습니다. (unsigned char *)을 하면 부호없는 1바이트 정수를 가리키는 포인터로 케스팅하는겁니다. 여기에 *을 붙이면 *(unsigned char *)이고 부호없는 1바이트 정수를 가리키는 포인터의 값입니다. 여기에 volatile을 붙이면 최적화를 안한다는 의미입니다. volatile을 붙이면 프로그램에서 변수를 변경하는 명령문이 없어도 값이 변경될 수 있다는 의미입니다. 

 

이제 실제 프로그램에서 테스트해보겠습니다.  아래의 코드를 넣고 Watch로 여러 데이터들을 보겠습니다

#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>

int main(void)
{
	DDRA = 0x99;  
	PORTA = 0x11;
	while(1)
	{

	}
}

DDRA의 값과 *(volatile unsigned char *)0x3a의 값이 같습니다
PORTA의 값과 *(volatile unsigned char *)0x3b의 값이 같습니다.
AVR은 int가 2바이트입니다. 그래서 *(volatile unsigned int *)0x3a를 하면 0x1199가 나옵니다

 

이제 원래 하려고했던 DDRA,PORTA를 주솟값으로 바꿔서 제어해보겠습니다

#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>

int main(void)
{
	*(volatile unsigned int *)0x3a = 0x99;  
	*(volatile unsigned int *)0x3b = 0x11;
	while(1)
	{

	}
}

DDRA,PORTA를 사용했을때랑 주솟값을 사용했을때랑 같은 결과가 나왔습니다.

 

다음에는 ATMEGA128의 레지스터 제어하는걸 STM32 레지스터 제어하는거랑 비슷한 느낌으로 바꿔서 사용하는걸 테스트해보겠습니다

https://wowon.tistory.com/280