-1.
요약
https://freertos.org/Documentation/02-Kernel/03-Supported-devices/01-FreeRTOS-porting-guide
freeRTOS의 공식문서에 있는 porting guide를 따라
cubeIDE에서 커스텀커널을 추가하는 과정을 기록한 글입니다.
제대로 된 정보는 위 문서를 참조
0.
RTOS를 배우기 위해서
STM32 보드를 많이 사용하고는 한다.
다만 25년 현재 시점을 기준으로..
디바이스마트나, 다른 전자부품 판매처에서
STM32 Discovery 보드보다는 STM32 Nucleo보드를 국내에 비축해두고 있어서..
NUF103RB 제품명을 가진 뉴클리오 보드를 구매했다.
1.
ARM에서 제공하는 CMSIS API를 이용하면,
간단하게 커널을 올릴 수 있으나..
이러한 기능에 의지하지 않고 쌩으로 MCU에 커널을 올리는 방법을
알아두는 것이 좋다고 한다.
2.
FreeRTOS를 제공하는
freertos.org에서는 두가지 버전의 커널을 다운받을 수 있다.
20240601 LTS와
20221001 LTS가 존재하는데,
라이센스나 폴더구조가 조금 다르다.
20221001 버전의 커널을 받아서 압축을 해제해줬다.
3.
CubeIDE를 이용한 프로젝트에
추가적인 폴더를 만들어준 후,
다운 받은 FreeRTOS 폴더 내부의
License 폴더와 Source를 복사해서 넣어준다.
4.
Source-Portable 폴더에는
여러가지 하드웨어와 컴파일러의 조합이 존재하는데,
CMakeLists를 보면
Texas Instrument, NXP, Renesas와 같은 유명한 반도체 회사들의 제품에
대응되는 조합을 확인해볼 수 있다.
사실 이때까지 뭐 써본 컴파일러가 얼마나 있것냐.. GCC나 G++ 컴파일러 밖에 모르겠다
빌드에 관한 더 자세한 내용은 CMake를 조사하는걸로 하고 넘어가자
5.
Nucleo 보드는 이 중에서도
CortexM3 칩을 사용하기 때문에..
GCC - ComtexM3 조합으로 포팅을 해줘야 한다.
https://www.st.com/resource/en/datasheet/stm32f103rb.pdf
공식 홈페이지에 들어갔는데
데이타시트가 어디있는걸까..
https://www.st.com/en/evaluation-tools/nucleo-f103rb.html
6.
Discovery 보드는
ARM Cortext M4F 칩을 사용한다.
해당 보드명 + datasheet를 구글에 검색해서
https://www.alldatasheet.co.kr/
에서 데이터시트를 구했다.
디스커버리가 비싼 이유가 있었네..
뉴클리오는 한세대 이전칩을 사용한다.
7.
이렇게 찾은 코드가
보드에 적합한 C로 작성된 아키텍처 레벨의 포트 코드이다.
8.
이제 이렇게 프로젝트 내부에 저장한 폴더를 CubeIDE에서 확인하고,
해당 폴더의 속성에 들어가서,
체크된 'Build 과정에서 해당 폴더의 리소스를 예외처리' 옵션을 해제해주고
Apply and Close 해준다.
9.
이후, 우리는 해당 프로젝트의
Core-Src 폴더에 들어가서 코드를 작성하고 컴파일 할 예정
10.
CubeIDE에서 진행하는 일반적인 프로젝트는
CMSIS API로 커널을 추가한 다음에
main.c에서 원하는 코드를 작성하고,
stm32f1xx_it.c에서 인터럽트 핸들러, Sytem Exception Handler 등을 처리한다.
syscalls.c에서 write, read등의 함수를 처리할 것이고
sysmem.c에서 메모리관리(heap management, 동적 메모리할당)를 처리할 것이다.
11.
sysmem.c는 이번 프로젝트에서는 사용하지 않을것이다.
freeRTOS커널에서
FreeRTOS-portable-MemMang의 heap_1.c ~ heap_5.c 의 파일들로 관리할 것이기 때문이다.
12.
망치아이콘이나, 탐색기의 프로젝트를 우클릭하여 빌드를 해주면..
13.
에러가 잔뜩 뜨는 것을 확인할 수 있다.
FreeRTOS.h가 없어서 생기는 문제이다.
14.
커널을 하위 폴더에 저장만 해두고
빌드 과정에 필요한 헤더파일, 경로설정을 하지 않아서 그렇다.
우리가 ThirdParty폴더의 FreeRTOS를 이용하여 빌드하겠다는 정보를 제공해줘야한다.
프로젝트 탐색기의 FreeRTOS_Project를 우클릭하여 Property 설정을 클릭하고..
C/C++ Build - Setting - MCU GCC Compiler - Include paths - add icon을 선택한 후
Thrid Party 폴더의 FreeRTOS - include 폴더를 path로 추가해주자.
15.
또, 같은 방식으로 해당 커널의 아키텍처레벨 포트 파일인
ThirdParty-FreeRTOS-portable-GCC-ARM_CM3
폴더를 추가해주자.
16.
이렇게 두 Path를 추가하고 Apply해준다.
rebuild뭐시기 하고 경고창이 뜬다면 Yes해주자.
17.
이제 이상태로 빌드를 하면..
FreeRTOSConfig.h가 없다고 에러가 뜬다.
18.
결국 이런 문제를 해결하기 위해서는
구글이나 스택오버플로우 검색을 하거나, GPT에게 묻거나 하는 방법이 제일 강력할 것이다.
머지 않아 GPT가 이러한 문제들도 자동으로 해주는 시대가 거의 다 온것 같다만..
마이너한 제품일수록 해당 커뮤니티의 포럼에 묻고, 공식문서, 데이타시트를 뜯어보고..
최후의 방법으로 해당 회사에 메일을 보내고 응답을 받아보거나
직접 실험을 하는 수순으로
문제 해결을 해 나가야 할 것이다.
19.
여하튼 강의를 따라가는게 아니였다면,
공식 문서에서 FreeRTOSConfig.h 문제를 찾았어야 했을것이다.
https://freertos.org/Documentation/02-Kernel/03-Supported-devices/01-FreeRTOS-porting-guide
이게 무슨 문제인지 겨우 알아내었고,
차후의 문서를 뜯어보면서
https://freertos.org/Documentation/02-Kernel/03-Supported-devices/02-Customization
FreeRTOSConfig.h를
프로젝트에 직접 추가해줘야 함을 알 수 있었다.
FreeRTOS is customized using a configuration file called FreeRTOSConfig.h. Every FreeRTOS application must have a FreeRTOSConfig.h header file in its pre-processor include path. FreeRTOSConfig.h tailors the RTOS kernel to the application being built. It is therefore specific to the application, not the RTOS, and should be located in an application directory, not in one of the RTOS kernel source code directories.
Each demo application included in the RTOS source code download has its own FreeRTOSConfig.h file. Some of the demos are quite old and do not contain all the available configuration options. Configuration options that are omitted are set to a default value within an RTOS source file.
Here is a typical FreeRTOSConfig.h definition, followed by an explanation of each parameter:
20.
Macro의 형태로 define된 configuration items를 모두 다 알아야 할 필요는 없다.
필요할 때만 추가적으로 찾아보면 되는데,
다만, processor dependant 한 item들이 있는데,
Interrupt nesting behaviour configuration 같은 item들은
차후에 중요한 요소이니, 눈 여겨볼 필요가 있다.
21.
다운 받은 커널의 데모 어플리케이션을 확인할 수 있다.
.. \FreeRTOSv202212.01\FreeRTOS\Demo
각 보드에 맞는 데모 프로젝트에서
나는 뉴클리오의 Cortex M3의 프로젝트를 찾을 수 있다.
22.
이 데모 프로젝트를 들여다보면
FreeRTOSConfig.h를 찾을 수 있다.
이걸 프로토타입으로다가
프로젝트에 복사해서 쓰면 된다.
23.
프로젝트의 Path에다가, FreeRTOSConfig.h 가 있는 FreeRTOS폴더를 추가해주자.
24.
휴. 빌드가 성공했다.
25.
나는 뉴클리오 보드라서 다행히 성공했는데,
근데, 디스커버리 보드를 기준으로 빌드하는 강의에서는
SytemCoreClock과 같은 item이 FreeRTOSConfig.h에서 Undeclared되어서 문제가 발생하는 등의 문제가 있어보인다.
SytemCoreClock이라는 변수가
프로젝트폴더/Core/Src/system_stm32f4xx.c 에서 extern변수의 형태로
정의가 되어있는 문제였다.
-------------------------------------
(*여기서 부터는 내가 발생한 문제는 아니다.. 그냥 교수님 이슈해결방식을 보려고 메모함)
26.
저쪽 강의 기준으로
FreeRTOSConfig.h에서,
#ifdef __ICCARM__
#include<stdint.h>
extern uint32_t SystemCoreClock;
#endif
와 같이 매크로상에서, 외부변수를 받아오도록 정의가 되어있었고,
ICCARM이라는 컴파일러를 사용할 시에만 그런 식으로 SystemCoreClock 변수를
받아오도록 하고 있었는데,
우리는 앞서 말했듯이 GNU 컴파일러를 기준으로 포팅했다.
그래서 #ifdef __ICCARM__ 코드를
#if definded (__ICCARM__) || defined(__GNUC) || defined(__CC_ARM)
과 같이 컴파일러에 대한 예외처리를 추가함으로서
문제를 해결하고 있다.
27.
인도교수님께서
뭔 문제가 발생하면 빌드해보고 콘솔에서 오류보고
바로바로 해결을 하고 있다.
port.c 파일에서
SVC_handler, PendSV_handler, SysTic_Handler가 multiple defined되어서
또 이슈가 발생하고 있다.
28.
ThirdParty에 존재하는 커스텀 커널 이외에도
기존에 있던 Core/Src 파일에 stm32f4xx_it.c파일에서
중복정의되어서 이러한 문제가 발생했다고 한다.
29.
해당 프로젝트를 관리하는 FreeRTOS_Projects.ioc 파일에서
Device Configuration툴을 열고
Pinout & Configuration 메뉴에서
System Core - NVIC을 선택하고
Pendable request for system service, Time base : System tick timer, System service all via SWI instruction
항목에 대해서
Generate IRQ handler의 체크박스를 해제한 후,
ioc를 저장하고, Project-Generate Code를 수행하거나,
ioc를 종료하면서 generate code를 yes해주면,
프로젝트의 코드가 생성되는 것을 볼 수 있다.
30
undefined reference to 'vApplictionTicHook'
undefined reference to 'vApplicationStackOverflowHook'
문제가 발생했는데,
FreeRTOSConfig.h에서
'HOOK'를 검색해서 매크로로 1 혹은 그 이상의 숫자로 지정되어 있는 관련 HOOK들을를
0으로 설정(turn off)함으로서 이슈를 해결하고 있다.
TickHook, MallockFailedHook + StackOverflowHook 이렇게 세 변수를 0으로 꺼주고 있다.
31.
디스커버리 보드를 기준으로는
이런식으로로 발생한 오류를 다 해결하고
정상적으로 프로젝트를 빌드할 수 있더라.
32.
250411
실제 프로젝트를 빌드하면서
뉴클리오보드 M3를 쓰는데,
vApplicationTickHook / vApplicationMallocFailedHook
같은게 레퍼런싱이 안된다고 나온다.
FreeRTOSconfig.h에서 여러 후크를 꺼주고,
vAssertCalled에 대해서
따로 커널내부에 c파일을 만들어서 임의로 땜빵해놓기는 했다.
interrupt로 인한 task disable이후 무한루프를 도는 함수라고한다.
이렇게 하니까 빌드는 되는데..
https://m.blog.naver.com/kim1417/221133864249
https://www.freertos.org/Documentation/02-Kernel/03-Supported-devices/02-Customization#configASSERT
vAssertcalled는 알아서 정의하라는데..
이 부분이 곤란하네
33.
vAssertcalled부터 시작해서
어디가 문제인지 모르겠다..
빌드자체는 되는데
디버깅 들어가니까 vAssertcalled 무한루프나
메인문 무한루프에 갇히는데
프로젝트 제거하고 처음부터 다시해야겠네..
34.
cubeIDE에서는 GUI를 통해서 추가적인 미들웨어나 FreeRTOS와 같은 커널을
쉽게 추가해줄 수 있는 기능을 제공해준다.
해당 STM32프로젝트의 ioc파일을연 뒤, Pinout & Configuration - Middleware and Software Packs
- FREERTOS를 선택한 뒤, 인터페이스를 CMSIS_V2를 선택해주고
SystemCore의 SYS에서 timebase등을 설정해준뒤 저장하면
적절한 FreeRTOS커널을 써드파티 폴더에 넣어서 코드를 생성해준다.
ARM에서 제공해준 CMSIS API를 이용한 방식이며
직접 커널을 추가하려고 했던 기존의 방식과 기존의 목표와는 다르지만..
Discovery보드와 여러방면에서 FreeRTOSConfig.h의 구성이 달라 에러가 발생하여 어쩔수 없이 이 방법으로 가야겠다.
(1) 헤더파일의 PATH를 추가하는 순서가 문제였다
(2) Config.h의 꺼서는 안되는 매크로를 껐다
(3) 다른 문제였다
같은 원인이 의심되는데...
일단 강의를 위해서 CMSIS v2를 사용하여 올려놓고 나중에 와서 고치는 수밖에..
35
디버그 세팅에서, SWM 인터페이스를 사용하고,
SWV 사용설정을 Enable한 뒤, 자신의 보드에 맞는 코어클럭을 설정해준다.
muf103rb기준 64클럭
그리고 디버그 모드에 진입하면
window - show view - SWV - SWV Data Console을 클릭하여
ITM tracing window를 켜주고,
트레이스 설정에서 itm활성포트의 0번을 체크해주고 저장하면 된다.
그 후 SWV trace start를 누르고
HAL_Init()에서 걸린 디버깅을 재생하는 아이콘을 눌러 Resume해주면..
성공적으로 Task를 생성하고 문자열을 ITM으로 출력하는 것을 확인할 수 있다.
자세히 보면 순서대로 출력이 안되는 것을 볼 수 있는데, task switching이 일어나서 그렇다.
제대로 출력하려면, mutex를 달아주거나
freeRTOS.h의 configUSE_PREEMPTION 매크로를 0으로 설정하고,
main문의 taskYIELD(); 함수를 각 핸들러의 끝마다 작성해주는 과정이 필요할 것이다.
36.
ITM관련 기능은 Cortex M3이후의 코어에 대해 제공해주는 tracing unit이다.
Syscall의 write를 io가 아니라 Instrumental Trace Marcocell, ITM 영역의 버퍼에 write하고,
ITM이 연결된 SWO Pin을 통해서 STLink Debug Circuit으로 전달된다.
디버그모드를 사용할시에, 이 Debug Circuit에 저장된 정보를
주기적으로 USB와 PC 및 IDE를 통해 확인할수 있다.
37.
내가 듣고 있는 강의는, 인도의 FastBit Embeded Lab에서 올라온 STM32강의이고,
일부는 유튜브에 무료로 풀려있다.
문제는.. 나온지 7년정도 된 강의라서
해당 보드(STM32F407X-DISC-1)가 아니면
너무 수정해야할 것들이 많다는 점이다.
그냥 CMSIS_V2로 FreeRTOS 올려서 쓰는 것은 크게 어려운게 아니다.
문제는 자잘한 디렉토리 구조 차이,
매크로 설정차이,
외부디버깅툴 설정 과정에서 강의랑 다른게 상당히 많아서
결국 실패로 돌아간다는 점이다.
FreeRTOSConfig.h에서 수정해줘야 할 매크로(SysTic, Hook, 각종 OnOff)
들이 다른 보드들과 많이 다르고
SEGGER의 SystemView와 같은 디버거를 사용하기 위해
커널 내부에 헤더파일 수정, 새로운 함수추가, Path설정 을
하면서 오류를 잡기가 여간 쉬운게 아니다.
SysView 문서를 보고 하나하나 수정해야 하는데,
다 수정을 했다고 생각하는데도,
막상 돌아가보면 어디선가 오류가 난다.
38.
그래서 디스커버리 F407 보드를 새로 샀다.
오래된 회사에서 윈도우XP로 돌아가는 시스템을
괜히 계속해서 쓰는게 아닌 이유를 몸소 느낀다.
39.
결국 강의에서 제공해주는 깃헙 레포에서
프로젝트를 복사해왔다.
CMSIS를 이용해 커널을 받을 경우
FreeRTOS 10.3v가 설치되고,
FreeRTOS 22.xx 버젼과 상당히 다르다.
SEGGER SysView에서는 10.4버젼을 기준으로
해결방법을 설명하고 있다.
그게 아니면 문서를 보고 커널을 하나하나 뜯어서 수정해야한다.
'지식이 늘었다 > RTOS' 카테고리의 다른 글
FreeRTOS와 task creation, SRAM, 힙 메모리 (0) | 2025.04.15 |
---|---|
Task란 무엇인가?, xTaskCreate, xTaskDelete (0) | 2025.04.11 |
RTOS의 인터페이스 - CMSIS (0) | 2025.04.09 |
RTOS의 포팅이란? (0) | 2025.04.08 |
RTOS란 무엇인가 (2) GPOS와 비교 (0) | 2025.04.07 |