임베디드

250623 임베디드 - MakeFile, HW review

_KDE_ 2025. 6. 23. 16:19

1. 과제 리뷰

이번에는 baremetal로 안함(이게 정석이지만 세팅할 것이 많음)

 

 

 

 

 

우리 외부에서 HW적으로 8MHz가 들어옴

 

HSI는 내부 CLK으로 16MHz 고정

 

HSE는 외부 CLK으로 8MHz로 사용됨

 

이 CLK을 증가시켜서 APB1과 APB2에 넣어줌


디버깅용 인터페이스가 Serial Wire와 JTAG이 있는데 우리는 Serial Wire를 사용


GPIO 설정

PIN 설정을 위와 같이 함


TIM2 설정

NVIC 세팅

Prescaler 15가 아니라 100-1로 변경


NVIC에서 TIM2가 global로 설정되어있는 것을 볼 수 있음 Preemption으로 Interrupt으 우선순위도 정해줄 수 있음


GPIO도 볼 수 있음


이걸 체크 안하면 모든 세팅이 한 파일에 만들어짐

GPIO, TIMER 등 각각 파일을 따로 분리하기 위해 체크

(분리하면 보기가 편해짐)

 

톱니바퀴 눌러서 기본 세팅  실행

위와 같이 세팅하면 이런식으로 Layer가 그려짐

 

여기에 지난번에 만들어 둔 driver, ap파일을 가져옴

 

Button Driver에서 HAL을 쓸거기 때문에 Button Driver에서 Hal을 불러와야 함 (FND Driver도 마찬가지)

 

callback이란??

메인이 아닌 다른 쪽(인터럽트 같은)에서 다른 함수를 부르는 것을 callback이라 함.

 

인터럽트 = "무언가 발생함!"
콜백 = "그때 자동으로 실행될 함수!"

 

주기적으로 걸리는 Interrupt는 위의 코드가 실행됨

위 코드를 ap_main으로 불러옴 (weak은 지우고)

 

그러면 위 함수가 ap_mian에도 있고 HAL에도 있지만 weak이 있으면 실행이 안됨.

즉 ap_main에 있는 것만 실행이 됨


 

elf가 실행 파일임

make clean하면 전부 깔끔하게 삭제

 

 

.c파일을 전부 compile하는 코드

 

쓰레드를 20개 사용해서 compile하겠다 (빠름)

 

다시 ls -l 쳐서 elf파일 생겼으면 compile잘 된것 임 

 

 

 

 

 

 

 

 

 

object파일(ap_main.o) 분석

어셈블리어로 바꾸어 줌(disassembly) 그리고 ">"의 의미는 파일로 만들어서 보겠다는 의미

 

ap_main.d 에  그 파일이 있음

 

 

 

 

 

 

 

이렇게 설정 해주면

 

base영역에서 data영역으로 바뀜

 

각 소스파일마다 함수와 변수가 있다.

링크되지 않은 오브젝트 파일은 함수가 어셈블리어로 쭉 되면서 

 

함수에 대해서 할당된 주소는 0 

왜냐하면 object파일이 여러개 생김

ap_main만 있는게 아니라 버튼, LED 등 여러개 있음

오브젝트 파일은 주소는 할당되어있지 않고 단지 Symbol(Section) 만 있음

 

obj파일은 섹션의 모음이다.(묶음)

 

주소할당해주는 것은 링커다.

 

gcc는 오브젝트파일 만들고 링커가 묶어서 주소할당을 해줌

 

section정보가 object파일에 모여있음

 

 

 

컴파일러를 이용해서 c를 object파일로 바꾸어 줌(머신코드로 바꾸어주지만 주소는 할당되어있지 않다, 섹션정보만 할당 ex)어떠너는 text, bss, data영역)

 

그리고 링커로 묶어줌

 

링커가 주소를 전부 할당해 줌


Linker 동작

flash영역, ROM영역 이런거 Linker가 어떻게 알까?

 

우리가 사용하는 MCU메모리, RAM메모리 사이즈가 다를 수 있음

 

Memory Section 정보가 있는 Script파일을 Linker에게 알려줘야 함

 

그 파일이

위의 ~.d, 링커 스크립트 파일임

 

ORIGIN : 시작 주소

LENGTH : 사이즈


Entry Point

Program의 시작점 

전원을 껐다 켜거나, reset을 하면 저 코드(ENTRY(Reset_Handler))가 불림

 

링커스크립터의 역할 : 주소가 주소를 할당하는 범위를 알려줌

섹션들이 어디에 들어갈지 알려줌

 

-estack : 전역변수

Memories definition의 그림이 위와 같음

 

-estack은 램의 시작주소 + 램의 크기 -> 제일 꼭대기를 의미

 

object파일은 주소가 할당되어있지 않음.

위와 같은 명령어는 "링커야 주소할당해라" 라는 명령어

 

모든 오브젝트들은 섹션의 정보의 집합

SECTIONS 순서대로 메모리 할당

.isr_vector -> text ...->rodata* 이 순서대로 할당

.isr vector는 FLASH 메모리에 저장해라

.text* -> wildcard : .text 뒤에 무엇이 붙었든 간에 FLASH 메모리에 들어가라

 

 

 

 

 

 

 

 

.data는 초기화되어있기 때문에 FLASH와 RAM에 전부 할당

bss : 초기화 되어있지않음 -> RAM영역에만 들어가라

 

인터넷 자동업데이트 같은거 할 때 이거 알아야 함

-> 상식으로 알아두자


 

Startup 코드

 

 

파워를 넣거나 reset을 하면 

stack pointer(sp)에 _estack을 넣어줌

 

.data section 초기화

Startup 코드에서 main함수를 부르고 있음

 

링커가 시작 주소까지 알려주고 있음

 

startup 코드에 벡터테이블이 있음 얘가 불려지면

여기 안에 있는

위 함수가 불려짐

startup 코드에 .isr_vector가 있는데 이것들이 아까 위에서 말한 (링커스크립트, ld파일) FLASH에 들어가게 됨

 

프로젝트 만들고 칩선택할 때 링커스크립터와 startup코드를 알아서 맞추어서 선택해줌


timwWatch.c 안에 아래와 같이 구조체로 선언

함수 안에 timeWatch가 선언된게 아니라 전역변수임

따라서  

main에서 이런 함수를 불러도 변수값이 유지가 됨

 

 

static을 써야 하는 경우는?

static은 보통 함수 안에서 지역 변수반복해서 호출될 때 값을 기억하도록 할 때 사용.