스타트업 코드 실행 경로
전원을 인가하면 ARM core는 최초 Reset 신호(PORESETn)가 인가 된다.
참고 링크: http://recipes.egloos.com/5044366
참고 링크: https://developer.arm.com/documentation/ddi0337/e/Clocking-and-Resets/Cortex-M3-reset-modes/Power-on-reset
Reset 신호가 인가 되면 아래와 같은 register가 세팅이 된다.
- SP (Stack Pointer)는 address 0x00000000 로 부터 MSP(Main Stack Pointer) 값으로 세팅
- PC(Program Counter)는 address가 0x000000004인 reset vector의 value로 값이 세팅이 된다.
STM32의 경우 전원을 인가 Boot mode selection pins에 따라서 시 SP, PC 레지스터가 설정이 된다.
현재 스터디 중인 STM32 Boot mode가 Main Flash Memory로 설정 되어 있어 SP, PC 레지스터는 다음과 같이 설정이 된다.
SP (Stack Pointer)는 address 0x00000000 로 부터 MSP(Main Stack Pointer) 값으로 세팅 STM32의 MSP는 0x020005000
=> DCode bus 를 이용하여 0x00000000로 접근 후 0x00000000 주소에 저장되어 있는 MSP 값인 0x020005000으로 SP를 세팅PC(Program Counter)는 address가 0x000000004로 부터 reset vector의 value 0x8000384 로 값이 세팅이 된다.
=> ICode bus 를 이용하여 0x00000004로 접근 후 0x00000004 주소에 저장되어 있는 reset vector의 value 값인 0x8000384로 PC를 세팅
=> 0x8000384는 Reset_Handler로 스타트업 코드에 정의 되어 있다.
Dcode-bus 설명 링크: https://developer.arm.com/documentation/ddi0337/e/Bus-Interface/DCode-bus-interface
Icode-bus 설명 링크: https://developer.arm.com/documentation/ddi0337/e/Bus-Interface/ICode-bus-interface
SP와 PC가 세팅되는 참고 영상: https://www.youtube.com/watch?v=3brOzLJmeek
<0x0000000 부터 시작하는 메모리 맵>
<0x8000000 부터 시작하는 메모리 맵>
.elf의 파일의 맵은확인시 [0x8000000 ~ 0x800127f]까지 구성이 되어 있고 STM32CubeProgrammer로 보드를 연결하여
메모리 맵을 확인 시 [0x0000000 ~ 0x000127f] 과 [0x8000000 ~ 0x800127f] 의 메모리 맵이 같은 것을 확였다.
<.elf 파일 메모리 맵>
[0x0000000 ~ 0x000127f] 과 [0x8000000 ~ 0x800127f] 의 메모리 맵이 같은 이유를 찾아보았다.
- STM32의 컨셉이 SHADOWING concept이기 때문이다.
STM32의 SHADOWING concept 설명: https://community.st.com/s/question/0D50X00009XkXNqSAN/how-does-memory-work-in-cortex-m3
2. STM32가 Booting 시 boot configuration을 확인한 후에 flash memory를 remap 하기 때문이다.
STM32의 flash memory remap 설명: https://cwiki.apache.org/confluence/display/NUTTX/STM32+Null+Pointer+Detection
Q1. System memory 사이즈와 Flash memory 사이즈가 다른 이유?
Q2. STM32가 어떻게 메모리를 SHADOWING 또는 remap을 하는가?
디버깅 시 Reset Handler가 호출되는 어드레스 사진
STM32 데이터 시트 메뉴얼
4 Memory mapping Figure 11. Memory map 참고
STM32 레퍼런스 메뉴얼
3.1 System architecture 참고
3.4 Boot configuration 참고
스타트업 코드에서 Reset_Handler가 실행되는 순서는 아래와 같다.
- STM32에 전원 연결 시 Reset이 발생
- Boot configuration 확인하여 Boot mode 선택
- Boot mode가 Main Flash Memory 인 것을 확인
- ICode와 DCode Bus를 이용하여 SP: 0x020005000, PC: 0x8000384 를 세팅
- 스타트업 코드의 Reset_Handler 실행
STM32CubeIDE는 디버그 모드 시 GDB Server를 이용하며 디버그 모드 실행 시 Reset_Handler가 호출되는 순서는 다음과 같다.
- ST-Link 연결 시 Reset 신호 발생 아래와 같이 Connect under reset 옵션으로 ST-Link 연결 시 Reset이 발생
- Boot configuration 확인하여 Boot mode 선택
- Boot mode가 Main Flash Memory 인 것을 확인
- SP: 0x020005000, PC: 0x8000384 를 세팅
- 아래와 같이 Download True로 설정 시 Erasing internal memory sectors [0 4] 가 실행 된다.
Debug Configuration
Debug 실행 후 로그
- Download 진행
- 디버그 모드 시 GDB는 링커 스크립트에 정의된 ENTRY(Reset_Handler) 주소를 PC 레지스터에 설정한다.
- 스타트업 코드의 Reset_Handler 실행
** ENTRY 란 프로그램의 시작 지점을 정의한다.
참고 링크: https://www.st.com/resource/en/user_manual/um2609-stm32cubeide-user-guide-stmicroelectronics.pdf
링커 스트립터 파일에서 ENTRY(Reset_Handler)를 아래와 같이 주석 처리 후 STM32CubeIDE는 디버그 모드 실행 시 Hard Fault가 발생
STM32CubeIDE Run 동작 시에도 ENTRY(Reset_Handler)를 주석 처리 시 PC register가 설정이 되지 않아 정상 동작을 하지 않았다.
이유는 GDB Server는 Entry Pointer를 찾았는데 이 값을 찾지 못해 PC 값을 0xfffffff로 세팅한 것으로 예상한다.
링커 스트크립터 파일에서 Entry Point를 주석 처리 한 후 아래와 같이 Debug Configuration에서 Download false로 설정하여 디버그/Run 실행 시 정상 동작한다.
Debug Configuration false
GDB monitor reset command 설명
이유는 Download false 시 GBD Server 스크립트에 monitor reset이 포함되어 있어 reset 후 코드가 바로 시작되어 정상 동작을 하는 것으로 예상한다.
STM32CubeProgrammer로 다운로드 후 STM32의 PC register를 설정하지 않아 스타트업 코드의 Reset_Handler가 실행 되지 않는다.
아래와 같은 Case로 테스트를 진행
Case1) 링커 스트립터 파일에서 ENTRY(Reset_Handler)를 주석 처리 후 빌드 한 .elf 파일을 STM32CubeProgrammer로 다운로드 후 STM32를 동작 시
Reset_Handler가 실행 되지 않는다.
Case2) 링커 스트립터 파일에서 ENTRY(Reset_Handler)를 주석을 해제한 후 빌드 한 .elf 파일을 STM32CubeProgrammer로 다운로드 후 STM32를 동작 시 Reset_Handler가 실행 되지 않는다.
Case3) STM32CubeProgrammer로 다운로드 후 STM32의 Reset 버튼을 누른 후 동작 확인 Reset_Handler가 실행 됨
Case4) STM32CubeProgrammer로 다운로드 후 STM32 Power Cable을 다시 연결 Reset_Handler가 실행 됨
테스트 결과 ENTRY(Reset_Handler)는 디버깅 시 필요한 지시자라고 생각한다.