Brise

STM32 + FreeRTOS 이용시 printf를 수행하면 hardfault가 생기는 경우 본문

MCU

STM32 + FreeRTOS 이용시 printf를 수행하면 hardfault가 생기는 경우

naudhizb 2020. 2. 15. 23:45
반응형


STM32를 사용하여 펌웨어를 작성할 때에 태스크 코드에서 printf를 수행할 때 특정 경우에 오류가 발생하는 것을 볼 수 있다. 

또는 malloc을 사용하여 큰 용량의 데이터를 Heap에서 확보하고자 할때 오류가 발생한다. 


malloc에서 보았다시피 이 문제는 FreeRTOS 때문에 생기는 문제다.

(정확히는 FreeRTOS와 STM32에서 기본적으로 제공하는 newlib의 Heap이 충돌하는 문제이다. 둘 모두 ST마이크로에서 제공하는 코드인 것은 함정)


자세히 내용을 설명하자면 


newlib에서는 printf를 수행하거나 malloc을 수행할 때 특정 경우에 한하여 더 큰 메모리를 요구하여 메모리 영역을 확보하는 코드인 _sbrk함수를 호출한다. 


기본적인 펌웨어에서는 힙이 스택을 침해하는 것을 막기 위하여 sbrk함수에서 스택의 위치인 스택포인터 값을 확인하여 메모리 블럭을 확보할 수 있는지를 확인하는 코드가 존재한다. 


하지만 FreeRTOS를 사용하는 경우에는 해당 스택 포인터가 가리키는 곳이 메인 스택의 포인터가 아닌 FreeRTOS의 Heap영역 안에 존재하는 스택 포인터를 가리키게 된다. 그리고 이 영역은 메모리 중의 .bss영역에 속해 있기 때문에 Heap보다 아래 주소에 위치하게 된다. 

(stm32에서 스택은 높은 메모리 영역에서 아래 방향으로, 힙은 낮은 메모리 영역에서 높은 방향으로, 변수들은 힙 아래 영역에 위치하게 되어있다.)


때문에 sbrk함수에서는 실제 메모리가 여유가 있더라도, 확보 할 수 없다는 메세지를 밷게 되어 있으며, 이 리턴 값 때문에 HardFault가 발생하게 된다. 


이를 workaround를 하는 방법은 여러가지가 있을 수 있는데, 


1. sbrk함수가 적정 값을 반환하도록 변경하는 방법

2. sbrk함수를 호출하지 않는 printf함수를 사용하는 방법

(3. sbrk함수를 호출하지 않도록 malloc을 오버라이딩하는 방법) --> newlib의 printf는 sbrk를 직접 호출하기 때문에 무용지물이다. 



이 중에서 개인적으로는 2번방법을 선호한다. 


http://www.nadler.com/embedded/newlibAndFreeRTOS.html


해당 글의 아래부분을 보면


https://github.com/mpaland/printf


이 오픈소스가 제공되어 있는데, 


이 코드의 printf.c와 printf.h를 받은 뒤에 printf를 사용하는 코드에 printf.h 헤더를 포함하면된다. 


또는 프로젝트 전체의 코드의 Define을 처리하여 사용하는 방법이 있을 수 있다. 

반응형
Comments