2017. 4. 3. 20:47 devel/개념
STMF4 시리즈 부트로더, iap 개발 팁
STMF4 시리즈 부트로더, iap 개발 팁
#0. 주의사항
작성자 컴맹임
MCU? 그거 유재석 말하는거 아니냐??
#1. 이게 왜 필요한데?
상용제품을 출시하면 펌웨어를 업데이트 해야할 일이 분명 있을 것이다.
jtag이나 st-link 라인을 실 제품에서는 제거해놓은 경우가 많고 제품을 죄다 뜯거나 할 수가 없으니 이런저런 기타 등등 문제로 uart를 통한 펌웨어 업데이트는 언젠가는 만나게 되는 문제다.
@ boot mode image
외부로 boot mode 핀을 두어 하드웨어적으로 컨트롤 할 수있게 만들면 모를까
근데 외부로 설정할 수 있는 pin을 두는 것도 size 측면에서 보면 쉬운 일은 아니다.
boot mode는 뭐 별거 아니다 pin설정 해서 평소 부팅하는 flash주소 영역으로 부팅하는게 아니라 그 외 system memory라고 불려지는(ram이 아니다) 영역으로 부팅하도록 MCU가 지원한다.
자. 그럼 그냥 uart인터럽트 핸들러 만들어서 특정 커맨드가 들어오면 펌웨어 업데이트 하도록 개발하면 되겠네라고 생각할지도 모른다.
목표는 괜찮은데 문제가 있다.
A. 펌웨어 크기가 크기 때문에 램의 용량을 벗어난다.
예를 들어 펌웨어가 200KB라고 하면 이걸 어떻게 메모리 할당 받을 수 있을까?
매우 힘들다고 할 수 있다. 그래도 메모리를 확보해서 다운 받았다고 치자
B. sector 0에 인터럽트 핸들러 코드가 있다 -_-;;;
뭔소리냐고? flash에 write할 코드가 flash에 있기 때문에 write하는 순간 인터럽트 핸들러 및 시스템 코드가 전체적으로 바보가 된다
linker descripton를 보면 이해가 빠르다.
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K
RAM (xrw) : ORIGIN = 0x20005000, LENGTH = 288K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
....
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
flash 메모리에 isr_vector 즉 인터럽트 핸들러 위치도 있고 우리가 작성한 프로그램코드 즉 text 영역도 flash에 있다
이렇기 때문에 메인 어플리케이션에서 flash를 write를 하는 순간 이 모든게 지워지고 꼬이기 때문에 ㅎㅎㅎㅎ 기기는 먹통이 될 것이다.
ram에 상주하는 ram function을 만들어도 이는 마찬가지
-> 결국 boot loader가 필요하구나!
2. 어떻게 동작하는가?
ok, boot loader가 필요한건 이해했어 그럼 어떻게 동작하는지도 알 수 있을까?
개략적인 디자인은 아래와 같다.
1. 전원 입력
2. 0x0800 0000로 이동 //flash address, 제품마다 주소다름
3. 부트로더 코드를 읽는다
if( uart로 5초 이내에 key 입력이 있었는가? ) { //yes
4. uart로 펌웨어 다운로드
5. flash write
6. reboot
}
else { //no
4. 메인 어플리케이션으로 이동
}
3. Reference
http://www.st.com/en/embedded-software/stsw-stm32067.html
이곳에서 소스코드를 받을 수 있다.
적당히 자신의 환경에 맞게 수정해서 사용하면 된다.
4. 개발
A. 큰 그림 그리기
boot loader는 flash sector 0만 사용한다(16KB)
메인 어플리케이션은 flash sector 1부터 시작한다(2MB - 16KB)
메인 어플리케이션 ISR Vector table 설정 확인
uart로 펌웨어를 전송 받을 때 1KB 정도로 나누어 작업한다. 메모리 크기도 문제고 flash write를 혼자 너무 오래 하면 진행 상황을 알 수 없으니…
B. 개발
테스트를 위해 먼저 작게 개발하기로 함
boot loader및 main application으로 점프가 정상적으로 되는 것을 확인한 후 uart 및 flash write 기능 추가
1. boot loader에서 led on
2. boot loader에서 start 메세지 출력
3. main application으로 jump!
4. main application 동작
C. boot loader
c code
#define APPLICATION_ADDRESS (uint32_t) 0x08004000
typedef void (*fptr)(void);
fptr jump_to_app;
uint32_t jump_addr;
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET); //LED ON
printf("boot loader start\n"); //메세지 출력
jump_addr = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
jump_to_app = (fptr) jump_addr;
/* init user app's sp */
printf("jump!\n");
__set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
jump_to_app();
cube mx에서 생성하였다.
uart랑 gpio설정 정도만 유지하고 나머지는 모두 비활성화 하여 코드 크기를 최소화 했다.
linker description
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 16K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
flash를 sector 0의 크기만큼만 사용하도록 설정
build 후 image의 크기 역시 맞아야 한다
D. Main Application
c code
#define FLASH_BASE 0x08000000U
// system_stm32f4xx.c
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
/* Vector Table Relocation in Internal FLASH */
//#define VECT_TAB_OFFSET 0x00
#define VECT_TAB_OFFSET 0x4000 //이 부분을 수정
/*!< Vector Table base offset field. This value must be a multiple of 0x200. */
isr vector 주소 설정을 확인한다.
iap 에서 점프 후 systick이 동작하지 않거나 하면 이 문제일 가능성이 높다.
linker description
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x8004000, LENGTH = 2032K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
flash의 크기가 sector 0를 뺀 만큼 줄어든다.
2048 - 16 = 2032KB
5. 테스트
LED가 켜지고 메세지가 출력되고 main application으로 성공적으로 jump한다.
이제 uart 다운로드 및 flash write만 포팅하면 된다
의외로 금방 포팅할 수 있다. 이를 무료로 풀어주신 stm사장님께 경롓!
'devel > 개념' 카테고리의 다른 글
주소가 주어진 영역 이내인지 확인 하는 방법 (0) | 2017.10.01 |
---|---|
주소가 aligned 인지 확인하는 방법 (0) | 2017.09.30 |
Linux Kernel DMA (0) | 2017.03.02 |
Linux Input Event Driver (0) | 2017.02.23 |
golang 고랭지 농업이 아니라 go 언어 (0) | 2016.12.01 |