NUCLEO L432KC

STM32 L432KC 부트로더 개발하기(3)

jisungjay 2023. 7. 1. 19:38

위 부트로더 플로우에서 초록색 부분( 부트로더에서 app 으로 jump) 되는 과정을 구현해보았습니다.

 

project explorer에서 boot 프로젝트를 copy하고 paste 하게 되면 프로젝트가 복사됩니다.

이 프로젝트의 이름을 application으로 하고 개발을 진행합니다.

 

 

 

Application 코드에서는 링커스크립트의 메모리 영역 할당을 새로 해줘야 합니다.

그림에서 FLASH 영역의 ORIGIN 값을 이전에 Application의 base 주소로 정한 0x0800c800으로 바꾸고 길이도 맞게 바꿔줍니다.

 

 

빌드 후 Debug 폴더에 있는 *.map 파일을 확인하면 주소가 정상적으로 링크되었는지 확인할 수 있습니다.

[0x0800c800에 .isr_vector(인터럽트 벡터)가 위치한 것을 볼 수 있습니다.]

 

 

uint32_t JumpAddress;
pFunction JumpToApplication;
static void default_task(void)
{
	mem_data=*(uint64_t *)APP_META_ADDR;

	if( memcmp(&mem_data,data,(uint8_t)8) == 0) // BOOT DONE case
	{

		set_uart_data("Jump!");
		JumpAddress = *(__IO uint32_t*) (APP_BASE_ADDR + 4);
		JumpToApplication = (pFunction) JumpAddress;
		HAL_TIM_Base_DeInit(htim);
		__NVIC_DisableIRQ(TIM2_IRQn);
		__set_MSP(*(__IO uint32_t*) APP_BASE_ADDR);
		SCB->VTOR = APP_BASE_ADDR;

		JumpToApplication();
	}
	else
	{
		if(get_boot_step()==ERASE_STEP)
			step = ERASE_STEP;
	}
}

부트로더 쪽 코드에서는 위와 같은 코드를 추가해줍니다.

해당 task에서는 메타데이터 영역에 "BOOT DONE"이 기록되어 있을 경우 application으로 점프

그렇지 않을 경우 host로부터 erase 명령을 대기합니다.

 

 

 

몇가지 눈여겨 볼 점들을 짚어보겠습니다.

 

1) jump to application

JumpAddress = *(__IO uint32_t*) (APP_BASE_ADDR + 4);
JumpToApplication = (pFunction) JumpAddress;
JumpToApplication();

 

jump할 주소는 APP_BASE_ADDR+4 인 0x0800c804입니다. 그 이유는 인터럽트 벡터 테이블에서 찾을 수 있는데,

0x4 offset된 주소에 reset handler가 위치하는 것을 볼 수 있습니다. . 이 Reset handler 주소로 가서 스타트업 코드를 수행하도록 하는 것입니다.[참고 자료 : https://microcontrollerslab.com/what-is-interrupt-vector-table/ ]

 

 

2) 타이머 인터럽트 disable

 

HAL_TIM_Base_DeInit(htim);
__NVIC_DisableIRQ(TIM2_IRQn);

 

jump 하는 과정에서 인터럽트 발생 시 예상치 못한 동작을 경험할 수 있습니다.

저는 부트로더 코드에서 타이머를 사용하였기 때문에 timer를 disable 하고 인터럽트도 disable 시켜 이를 방지하고자 하였습니다.

 

3) VTOR 

 

SCB->VTOR = APP_BASE_ADDR;

 

VTOR은 인터럽트 벡터의 위치를 가리키는 레지스터인데, 해당 부분을 설정해주도록 합니다.

 

 

설정이 끝났으면, IDE에서 부트코드와 App 코드를 동시에 올려서 테스트를 진행해보겠습니다.

저는 이를 merge 코드 디버깅이라고 부릅니다.

debug configuration에 들어가서 사용중이던 디버깅 환경을 duplicate 합니다.

 

이후 위와 같이 셋팅을 해줍니다. 핵심은, Startup 메뉴에서 .elf 파일을 두가지(boot, app) 모두 load 하는 것입니다.

이를 통해 두 프로젝트의 이미지와 심볼을 동시에 확인하고 디버깅이 가능하도록 합니다.

 

이후에는 디버깅 버튼을 눌러 jump가 잘 되는지 확인합니다.

저는 코드 중간에 심어놓은 uart 코드를 통해 jump 여부를 추가로 확인하였습니다.