본문 바로가기
Embedded/Atmel

Mac에서 Atmel(AVR) MCU 개발을 위한 환경 구축 - 3 : Makefile로 자동화

by Gordon_ 2025. 4. 3.

- 개발 환경

Macbook Pro 14 (M3)

macOS : Sequoia 15.4

 

개발 보드 : NewTC AVR MEGA 128 개발보드

프로그래머 : NewTC AVR용 USPISP V7.0

Jtag 프로그래머 및 디버거 : AVR JTAG ICE USB

 

- 소스 코드

https://github.com/MainForm/AVR-makefile-template

 

GitHub - MainForm/AVR-makefile-template

Contribute to MainForm/AVR-makefile-template development by creating an account on GitHub.

github.com

 


0. 사전 작업 (Toolchain을 설치 하지 않았다면)

https://littlebitodd-developer.tistory.com/34

 

Mac에서 Atmel(AVR) MCU 개발을 위한 환경 구축 - 1 Toolchain 설치

- 개발 환경Macbook Pro 14 (M3)macOS : Sequoia 15.4 개발 보드 : NewTC AVR MEGA 128 개발보드프로그래머 : NewTC AVR용 USPISP V7.0Jtag 프로그래머 및 디버거 : AVR JTAG ICE USB1. 서론  사실 Atmel MCU는 윈도우에서 AVR studio

littlebitodd-developer.tistory.com

 

1. 서론

  지금까지 터미널을 통해 명령어를 수작업으로 하나씩 입력하여 컴파일부터 업로드까지의 흐름을 확인해보았습니다. 이제 Makefile를 통해 지금까지 했던 것들을 자동화해볼 것입니다.

 

2. 프로젝트 폴더 구조 구축

#Project folder 생성 및 이동
mkdir -p ~/Documents/atmel/withMakefile
cd ~/Documents/atmel/withMakefile

# .c 또는 .cpp 파일을 관리하는 폴더
mkdir src
# Header 파일을 관리하는 폴더
mkdir include

# main.c 파일 생성
touch ./src/main.c
# Makefile 생성
touch Makefile

 

최종적으로 프로젝트 폴더 내 다음과 같이 파일을 구성하면 이제 거의 완료 하였습니다.

 

3. 테스트 프로그램 작성

./src/main.c 에 LED가 점등하는 간단한 테스트 프로그램을 작성하도록 하겠습니다.

// CPU 클력 설정
#define F_CPU 16000000UL
// MCU 설정
#define __AVR_ATmega128A__

#include <avr/io.h>
#include <util/delay.h>

int main(void){
    DDRA = 0x01; // PA0을 출력으로 설정

    while(1){
        PORTA = 0x01; // PA0의 출력을 HIGH로 설정
        _delay_ms(1000); // 1초 딜레이
        PORTA = 0x00; // PA0의 출력을 HIGH로 설정
        _delay_ms(1000); // 1초 딜레이
    }

    return 0;
}

 

4. Makefile 작성

이 포스트는 Makefile에 대해 알아보는 포스트가 아니므로 제가 미리 작성한 Makefile를 그대로 사용하는 것을 추천드립니다.

MCU = atmega128a
F_CPU = 16000000UL

# Parts can be found by script avrdude -p ?
AD_PART = m128a
# Programmer can be found by script avrdude -c ?
AD_PROG = stk500v2
#AD_PROG = jtag1

# Port can be found by script ls /dev/tty.*
AD_PORT = /dev/tty.usbmodem00000000000011
#AD_PORT = /dev/tty.usbserial-110

CC := avr-gcc
CXX := avr-g++
AD := avrdude
GDB := avr-gdb
AVRICE := avarice
OBJCOPY := avr-objcopy

GDB_IP := localhost
GDB_PORT := 4242

TARGET = $(BUILD_DIR)/out

SRC_DIR := ./src
BUILD_DIR := ./build
INCLUDE_DIR = -I./include

CFLAGS = -Wall -Os -g -mmcu=$(MCU) -DF_CPU=$(F_CPU)

C_SRCS = $(shell find $(SRC_DIR) -name '*.c')
C_OBJS = $(C_SRCS:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)

CXX_SRCS = $(shell find $(SRC_DIR) -name '*.cpp')
CXX_OBJS = $(CXX_SRCS:$(SRC_DIR)/%.cpp=$(BUILD_DIR)/%.o)

SECTIONS := -j .text -j .data

.PHONY: all clean upload debug avarice
all: $(TARGET).hex

$(TARGET).hex: $(TARGET).bin
	$(OBJCOPY) $(SECTIONS) -O ihex $< $@

$(TARGET).bin: $(C_OBJS) $(CXX_OBJS)
	@mkdir -p $(BUILD_DIR)
	$(CXX) $(CFLAGS) $^ -o $@

# compile .c files to .o files
$(C_OBJS): $(C_SRCS)
	@mkdir -p $(BUILD_DIR)
	$(CXX) $(CFLAGS) $(INCLUDE_DIR) -c $< -o $@

# compile .cpp files to .o files
$(CXX_OBJS): $(CXX_SRCS)
	@mkdir -p $(BUILD_DIR)
	$(CXX) $(CFLAGS) $(INCLUDE_DIR) -c $< -o $@

clean:
	rm -rf $(BUILD_DIR)

upload: $(TARGET).hex
	$(AD) -p $(AD_PART) -c $(AD_PROG) -P $(AD_PORT) -U flash:w:$<

debug: $(TARGET).bin
# run avarice in background for making gdb server
# avarice will be killed when connection of gdb is disconnected
	$(AVRICE) --jtag $(AD_PORT) :$(GDB_PORT)	&
	$(GDB) -ex 'target remote $(GDB_IP):$(GDB_PORT)' $(TARGET).bin

avarice:
	$(AVRICE) --jtag $(AD_PORT) :$(GDB_PORT)

 

여기서 먼저 수정해야할 변수에 대해서 알아보도록 하겠습니다.

4.1 Makefile 변수 설정

  • MCU = atmega128a
        개발하려는 MCU를 설정합니다.
  • F_CPU = 16000000UL
         MCU의 클럭을 설정합니다.
  • AD_PART = m128a
         펌웨어를 업로드하려는 MCU를 설정합니다.
         avrdude -p '?' 을 통해 지원하는 MCU를 확인 할 수 있습니다.
  • AD_PROG = stk500v2
       펌웨어를 업로드하려는 프로그래머를 설정합니다. (현재 NewTC AVR용 USPISP V7.0 사용)
       avrdude -c '?' 을 통해 지원하는 프로그래머를 확인 할 수 있습니다.
  • AD_PORT = /dev/tty.usbmodem00000000000011
        프로그래머의 디바이스 파일을 설정합니다.

5. Makefile를 통해 펌웨어 빌드 및 업로드

# 프로젝트 빌드(.hex 파일 생성)
make

 

자동적으로 빌드 폴더가 생성되고 정상적으로 out.hex가 생성되었음을 확인하였습니다.

 

# 펌웨어(out.hex)를 mcu에 업로드
make upload

자동적으로  out.hex 펌웨어가 업로드되었음을 확인하였습니다.

 

만약 업로드가 되지 않는다면 반드시 Makefile 변수(AD_PART, AD_PROG, AD_PORT)를 제대로 설정하였는지 확인 해보시기 바랍니다.