본문 바로가기
임베디드.일렉트로닉스

VSCode 에서 nRF5 개발 기초. Zephyr OS 기반

by i.got.it 2026. 2. 25.

 

VSCode 에서 nRF5 개발 

 

VSCode  에서 nRF5 (예 : nRF52840, nRF54L15) 칩에서 작동하는 코드를 VSCode 에서 작성하고 칩에 기록하여 실행하고 VSCode 의 터미널에 출력 까지 하는 전체 작업 플로우 핵심 정리. 

 

-본 개발환경은  RTOS 인 Zephyr (발음 : 제퍼) OS 기본 적용된다.  

 

 

 

 

VSCode 에서 개발환경 셋팅 

- nRF Connect for VSCode 개발환경 구축되어야 한다. 

별도정리 : https://igotit.tistory.com/5652

 

nRF Connect for VS Code . 포터블 설치

nRF Connect for VS Code . 포터블 설치    - 외장 SSD 에 VS Code 를  Portable 설치(상세보기 : https://igotit.tistory.com/4313)하고 나서  - 포터블 VS Code 실행하여 아래 영상의  2분 40초 이후 의 설치 진행하면

igotit.tistory.com

 

 

VSCode 에서 작업  폴더 열기 

 

나의 경우는 1개의 폴더 WORK_NRF5_VSCode 하위에 프로젝트 1개 단위로 폴더 만들 것이다. 이 폴더를 먼저 VSCode 에서 열어둔다.  Open Folder 클릭하여 작업 루트 폴더 열어둔다. 

 

 

nRF app 생성. 

VSCode 왼쪽 메뉴 nRF Connect  아이콘 클릭 -> WELCOME -> Create a new application 클릭하여 생성시작한다. 생성옵션이 보인다. 본 예에서는 가장 간단한 blank application 선택했다. 

 

 

 

app 용 폴더 이름을 지정한다. 이 폴더하위에 소스 및 빌드 결과 파일들이 만들어짐. 

 

EXPLORE 에서 자동 생성된 파일들이 보인다. 소스는 main.c 1개 자동 생성되어있다. 또한 prj.conf 파일도 생성되어있고 비어있는데 개발과정중  자주 접근하여 설정 하게된다. 예. CONFIG_BT=y  식으로 기록하여 블루투스 관련 기능 활성화한다는 식으로 설정한다. 

 

 

nRF Connect 의 APPLICATION 에서는 아래처럼 test_first 라는 app 이 추가된게 보인다. 

 

 

 

Add build configuration 

앞의 화면에서 test_first 하위에 보이는 Add build configuration 을 클릭하여 타겟보드가 무엇이며, 사용할 SDK 버전이 무엇인지 등을 지정해야한다(아래 화면). Board target 만 내가 nRF52840dk 를 이용할 것이므로 아래처럼 선택했고, 나머지는 모두 기본 값 상태에서 최하단 버튼 클릭하면 관련 파일 자동생성되고 빌드까지 진행된다. 

 

 

 첫 빌드 과정은 시간이 꽤 길다. 약 2분 소요되고 완료되고 나면 아래화면처럼 build 된 파일들 보여주고, ACTION 이라는 부분도 활성화된다. build 된 파일 중 merged.hex 가 칩에 기록되어야 하는 최종 펌웨어 파일이다. 

ACTION 부분의 flash 클릭하면 타겟칩에  펌웨어 기록되고 실행상태로 된다.

 

 

 

 

 

 

prinfk 로 VSCode 에서 문자열 출력 보기. 

기본 만들어진 main.c 상태로는 칩에 기록해도 칩의 작동상황을 VSCode 측에서 알 수단이 없다. 코드에 아래처럼 printk 함수 추가하여 문자열 출력을 VSCode 에서  볼 수 있도록한다. 디버깅시 매우 편리한 수단. 

 

main.c 

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h> // printk 사용을 위해 포함

int main(void)
{
printk("Hello! nRF52840 Start.\n");

    while (1) {
        printk("Running... 1 second passed\n");
       
        // 1000ms (1초) 지연
        k_msleep(1000);
    }

}

 

 

VSCode 에서 nRF Serial Terminal 활성화하기. 

아래 화면처럼 1번 Open Terminal 클릭하여 VSCode 하단에 터미널 창이 보이게 하고 , 

 

 

위 화면의 터미널 창 상단 오른쪽의 + 표시 클릭하여 2번 nRF Serial Terminal 클릭하면 아래처럼 COM 포트 선택창에서 nRF52840 DK 를 선택한다.   

 

아래 TERMINAL 에서 보이는 문자열이 칩에서 printk 실행 결과를 보여준다. 

 

 

RTOS 스레드 생성해보기. 

main.c 에서  아래처럼 제퍼 OS 에서의 스레드 생성 코드를 추가하자. 

이렇게 하면 main while 실행과 동시에 스레드도  실행된다. 

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h> // printk 사용을 위해 포함



/* 1. 스레드 설정 (스택 크기 및 우선순위) */
#define MY_STACK_SIZE 1024
#define MY_PRIORITY 7

/* 2. 스레드가 실행할 함수 정의 */
void my_thread_logic(void *dummy1, void *dummy2, void *dummy3)
{
    while (1) {
        printk("  [Thread] Hello Thread!\n");
        k_msleep(500); // 0.5초 대기
    }
}

/* 3. 스레드 정적 생성 */
K_THREAD_DEFINE(my_tid, MY_STACK_SIZE,
                my_thread_logic, NULL, NULL, NULL,
                MY_PRIORITY, 0, 0);


int main(void)
{
printk("Hello! nRF52840 Start.\n");

    while (1) {
        printk("Running... 1 second passed\n");
        
        // 1000ms (1초) 지연
        k_msleep(1000); 
    }

}

 

 

위 코드를 빌드하고 칩에 falsh 하면  터미널에서 아래처럼 스레드 실행과 main while 문 내의 실행 상황을 확인가능하다. 

 

 

printk 대신 LOG_INF 함수 사용하기. 

앞의 코드에서 문자열 출력하는 함수 printk() 를 사용하여 개발했다가 나중에 이것 비활성 하는것 매우 번거로운 처리다. 제퍼 OS 에 제공되는 LOG_함수 이용하면 enable, disable 하기 편하기 때문에 개발 과정중 문자열 출력은 필수 이 함수를 이용하는게 좋다. 

 

main.c 에 아래처럼 LOG_INF 함수로 문자열 출력하게 수정하고, 

#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>  // Zephyr의 로깅 시스템 헤더 포함

LOG_MODULE_REGISTER(test_first, LOG_LEVEL_INF); // 모듈 이름과 기본 레벨 설정
//LOG_ 함수예.
//LOG_INF("Hello! Main While "); // printk 대신 사용
//LOG_ERR("Something went wrong!");           // 에러 메시지
//LOG_DBG("Variable x = %d", x);              // 디버그용 (평소엔 안 보임)

/* 1. 스레드 설정 (스택 크기 및 우선순위) */
#define MY_STACK_SIZE 1024
#define MY_PRIORITY 7

/* 2. 스레드가 실행할 함수 정의 */
void my_thread_logic(void *dummy1, void *dummy2, void *dummy3)
{
    while (1) {
        LOG_INF("Hello! thread "); // printk 대신 사용
        k_msleep(500); // 0.5초 대기
    }
}

/* 3. 스레드 정적 생성 */
K_THREAD_DEFINE(my_tid, MY_STACK_SIZE,
                my_thread_logic, NULL, NULL, NULL,
                MY_PRIORITY, 0, 0);


int main(void)
{
    while (1) {
        
        LOG_INF("Hello! Main While "); // printk 대신 사용

        // 1000ms (1초) 지연
        k_msleep(1000); 
    }

}

 

prj.conf 파일에 아래처럼 CONFIG_LOG=y 를 추가한다. 

 

위와같이 설정한 것을 빌드하여 칩에 기록하고 실행하면 터미널에서 아래처럼 보인다. 

 

 

 

로그출력에 함수명 자동 포함 

아래 define 문처럼 정의하고 코드상에서 MY_LOG_INF("test"); 처럼 기록하면 로그출력시 문자열 앞에  함수이름이  앞에 자동으로 부착된다. 

// ANSI 색상 코드 정의
#define ANSI_COLOR_RESET  "\x1b[0m"
#define ANSI_COLOR_GREEN  "\x1b[32m"
#define ANSI_COLOR_BLUE  "\x1b[34m"
#define ANSI_COLOR_RED  "\x1b[31m"
#define ANSI_COLOR_PURPLE  "\x1b[35m"

// 함수명 자동 포함 
#define MY_LOG_INF(fmt, ...) LOG_INF("[%s] : " fmt, __func__, ##__VA_ARGS__) 
#define MY_LOG_ERR(fmt, ...) LOG_ERR("[%s] : " fmt, __func__, ##__VA_ARGS__) 
#define MY_LOG_WRN(fmt, ...) LOG_WRN("[%s] : " fmt, __func__, ##__VA_ARGS__) 
// 함수명 색상 지정. 
#define MY_LOG_INF_C(fmt, ...) LOG_INF(ANSI_COLOR_GREEN "[%s] : " ANSI_COLOR_RESET fmt, __func__, ##__VA_ARGS__)

 

로그 출력예.

[함수명] 이 자동 추가되어있고, MY_LOG_INF_C 로 출력한것은 함수명 색상이 녹색으로 표현된다. 

 

 

 

이후 문자열 출력 필요없는 경우엔 CONFIG_LOG=n 으로 변경하여 빌드하면 문자열 출력관련은 빌드에서 모두 제외된다. VSCode 로 문자열 정상적으로 출력된 이유는 defconfig 파일에 CONFIG_SERIAL=y, CONFIG_UART_CONSOLE=y, CONFIG_PRINTK=y  로 설정 되어있기 때문이다. 양산 펌웨어에서는 필요없기에 prj.conf   파일에 CONFIG_LOG=n 외에도 아래처럼 추가로 비활성 설정한다. 

 

# 양산 시 prj.conf에 추가하여 기본값을 덮어씌움
CONFIG_LOG=n # Zephyr의 로깅 시스템
CONFIG_SERIAL=n # UART 드라이버
CONFIG_UART_CONSOLE=n # 디버거 메시지를 UART 로 쏠지말지.
CONFIG_PRINTK=n # printk 사용 안 함 (로그 시스템이 UART를 사용하도록)

 

 

 

 

 

 

J-Link RTT 설정법.

앞의 설명에서의 로그출력용 하드웨어 수단으로 칩내장 UART 이용하는 경우이며, J-Link RTT 이용한 로그 출력도 가능하다. 이런 경우 설정은 아래와 같다. UART , RTT 중 1개만 선택해도 되고 모두 선택해도된다. 아래예는 RTT 만 선택한 것. 

 

prj.conf 에 기록


### 시작. 로그관련 설정. 
CONFIG_LOG=y # 로그 시스템 활성화
# 로그 레벨 설정 (0: None, 1: Error, 2: Warning, 3: Info, 4: Debug) 예:2로 설정하면 0,1,2 만 출력.
CONFIG_LOG_DEFAULT_LEVEL=4 

# 로그출력위한 RTT 백엔드 
CONFIG_USE_SEGGER_RTT=y
CONFIG_LOG_BACKEND_RTT=y

# 로그출력위한 UART 백엔드
CONFIG_SERIAL=n
CONFIG_LOG_BACKEND_UART=n

# 콘솔 출력(printk)을 어디로 보낼지 결정 (보통 하나만 선택)
CONFIG_UART_CONSOLE=n 
CONFIG_RTT_CONSOLE=n
### 끝. 로그관련 설정.

 

 

기타. 

조금 더 상세한 기본 사용법은 아래 영상 참조. 

 

 

 

 

다른 폴더에 있는 소스 활용 방법 . CMakeLists.txt 에 추가해야함. 

프로젝트 폴더에 모든 소스들이 있지 않고 별도의 폴더에 있는 소스를 프로젝트에 포함시키는 방법. 

 

예. 아래 처럼 프로젝트 폴더 와 전혀 다른 폴더 CySDK_nRF5_Zephyr 에 하위 폴더들이 있고, 각 폴더마다 .c, .h 파일들이 있다고 하자. 

 

 

 

현재 작업중인 프로젝트 소스에서 위 파일들을 포함시키기 위해서는 현재 프로젝트 폴더에 만들어져 있는 CMakeLists.txt 에서 정보를 기록해줘야 한다. 아래 처럼  주석 #1,#2,#3 형식으로 추가하고, 프로젝트 내의 소스에서 #inlcude <ble/cy_blenus_p.h> 이런 식으로 인클루드 하고, cy_blenus_p.c 의 함수 호출하면 된다. 

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(test_blenus_p1)

target_sources(app PRIVATE
        src/main.c
)



# 1. SDK 루트 경로 설정 (상대 경로 기준)
set(CySDK_nRF5_Zephyr_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../CySDK_nRF5_Zephyr)

# 2. 헤더 파일 검색 경로 한 번에 등록. 루트만 등록하고 인클루드시 활용예. #include <ble/cy_blenus_p.h>
target_include_directories(app PRIVATE 
    ${CySDK_nRF5_Zephyr_PATH}
)

# 3. 컴파일할 소스 파일들 등록. 프로젝트에서 사용하는것 모두 수동 등록해야함. 
target_sources(app PRIVATE
    ${CySDK_nRF5_Zephyr_PATH}/ble/cy_blenus_p.c
    #${CySDK_nRF5_Zephyr_PATH}/adc/cy_adc.c
    #${CySDK_nRF5_Zephyr_PATH}/gpio/cy_gpio.c
)

 

 

prj.conf , Kconfig 체계적으로 활용하는 방법

프로젝트 생성하면 기본 prj.conf 파일이 만들어지고 이곳에 프로젝트에서 사용하는 모듈들 활성화하는 구문을 아래예처럼 작성하는데,  prj.conf  파일에서 내 프로젝트에서 사용되는 모든 요소들의 것이 기록되어야 한다. 

CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_ZEPHYR_NUS=y

 

그런데 앞의 내가 작성하는 모듈화된 함수들(cy_blenus_p.c )  이 작동하기 위해서 필요한 요소를 프로젝트에 있는 prj.conf 에서 세부설정을 기록하게 하면 모듈화 되지 못하므로 매우 산만해진다. 모듈화된 함수 관련 된 설정을 모아두고 이를 prj.conf 에서 간단하게 활성화하는 체계가 요구된다.

 

아래 그 방법 정리. 

 

프로젝트 폴더에 파일 Kconfg

프로젝트 폴더에 파일 Kconfig 만들어 추가하고 아래처럼  주석 #1 에 내가 사용하는 Kconfig 파일들 연결 시키고  주석 #2 에 있는 것은 제퍼기본 KConfig 를 기록한다. 앞에 기록된 설정이 우선 한다. 즉 여러  Kconfig 파일내에 동일 심볼의 설정들이 있는 경우  아래 리스트에서 뒤에 있는 것은 무시되고 앞에 있는 설정이 적용됨.

프로젝트 루트에 Kconfig 파일이 없다면 툴체인에 있는 Kconfig 를 참조하여 빌드하지만, 프로젝트 폴더에 Kconfig 파일이 있다면 이 파일을 참조하여 빌드 된다. 

 

 

다른 폴더 (본 예에서는 CySDK_nRF5_Zephyr ) 에도 파일 Kconfig 추가

아래 예처럼 기록한다. 아래 예는 1개의 Kconfig 파일에 CySDK_nRF5_Zephyr 에서의 구현되어있는 모듈들 전체를 통합 제공하는 방식으로 했다. 굳이 통합하지 않아도 되며 필요에 따라  CySDK_nRF5_Zephyr 에 있는 하위 폴더 ble, spi , uart 하위에 KConfig 파일 만들어서 해당 모듈에 대한것만 기록해서 프로젝트폴더에 있는 Kconfig 파일에 각각을 기록해도 된다(위 그림에서 주석처리된 구문들처럼 기록하면 됨.) .


#  응용 프로젝트의 prj.conf 에서 구문작성예  
# CONFIG_CySDK_BLENUS_P=y
# CONFIG_CySDK_BLENUS_C=y

menu "CySDK Kconfig"

# for cy_blenus_p.c/h
config CySDK_BLENUS_P
    bool "Enable CySDK BLE NUS Peripheral"
    select BT
    select BT_PERIPHERAL
    #select BT_NUS #이것만 활성화 시켜도 NUS 서비스가 부착되고 BT_ZEPHYR_NUS 에 의한것도 부착됨.  
    select BT_ZEPHYR_NUS #BT_ZEPHYR_NUS 활성화 시켜야 NUS 서비스가 제대로 동작함. (예: ble_nus_init() 함수에서 BT_ZEPHYR_NUS의 초기화 함수가 호출됨)
    help
      BLE NUS Peripheral 위한 설정

# for cy_blenus_c.c/h
config CySDK_BLENUS_C
    bool "Enable CySDK BLE NUS Central"
    select BT
    select BT_CENTRAL
    #select BT_NUS
    select BT_ZEPHYR_NUS 
    help
      BLE NUS Central 위한 설정

# MTU가 247일 때 버퍼 크기도 함께 맞춤 (P/C 공통 혹은 개별)
config BT_BUF_ACL_TX_SIZE
    default 251 if CySDK_BLENUS_P || CySDK_BLENUS_C

config BT_BUF_ACL_RX_SIZE
    default 251 if CySDK_BLENUS_P || CySDK_BLENUS_C

config BT_L2CAP_TX_MTU
    default 247 if CySDK_BLENUS_P || CySDK_BLENUS_C

endmenu

 

 

 

프로젝트의 prj.conf

내 프로젝트에서 CySDK_nRF5_Zephyr  의 cy_blenus_p.c 를 활용하는 경우 내 프로젝트의 prj.conf 파일에 아래처럼 1개만 기록하면 cy_blenus_p.c  에서 필수 요구되는 설정들이 모두 달성된다. 

CONFIG_CySDK_BLENUS_P=y

 

 

 

C++ 로 코딩하기. 

별도정리. https://igotit.tistory.com/6471

 

nRF Connect SDK VSCode . C++ 로 코딩하기

nRF Connect SDK VSCode . C++ 위한 필수 설정 nRF Connect SDK VSCode 컴파일 환경은 파일 확장자 C 로 된 것은 C 컴파일 되고, 파일확장자 cpp 로 된것은 C++ 컴파일 가능하나 필수 아래와 같은 설정을 해줘야 한

igotit.tistory.com

 

 

 

 

 

연관 

 

 

 

nRF Connect for VS Code .개요 . 포터블 설치

nRF Connect for VS Code 개요 통합 개발 환경: Nordic Semiconductor의 nRF52, nRF53, nRF54 및 nRF91 시리즈를 위한 차세대 VS Code 기반 IDE 확장팩.강력한 확장성: 범용적인 VS Code 환경을 그대로 사용하면서, Nordic 전

igotit.tistory.com

 

 

 

 

Zephyr (제퍼) . RTOS . 경량

Zephyr (제퍼)- 경량 RTOS . nRF52840 ( ARM Cortex M4F, 1MByte flash, 256kbyte ram. 64MHz )급에서도 활용 가능. - 라이센스 : 오픈소스- 관리주체 : 리눅스재단 - 커널 , 라이브러리, 장치드라이버, 프로토콜 스택, 파

igotit.tistory.com

 

 

 

 

 

J-LINK . 디버거

J-LINK - SEGGER 사의 JTAG/SWD 디버거 기기 브랜드 명. J-LINK 20핀 커넥터 JTAG 핀맵 J-LINK 20핀 커넥터 SWD 핀맵 - 20핀 중에 실제 기능 할당된 핀은 1,7,9,11,15,19, GND 총 7핀. - 실제 사용시 SWO와 5V-Supply 는 거의

igotit.tistory.com

 

 

 

 

 

칩. nRF52840. 블루투스 5.0

품번 : nRF52840 특징. - BT5.0 ( 및 ANT/802.154.4 Zigbee, Thread /Proprietary 용도로도 사용가능. Multi Protocol)- On Chip NFC Tag.- ARM Cortex M4F, 1MByte flash, 256kbyte ram. 64MHz.- SPI : 32MHz.- ADC : 12bit, 200ksps.- USB 2.0- 패키지 : 7x

igotit.tistory.com

 

 

 

nRF54L15 . BLE 5.4 SoC Cortex-M33 128MHz

nRF54L15 - NORDIC 사의 nRF54L 시리즈의 첫 출시 칩. - BLE 5.4 - RF Power : Max 8dBm - Arm Cortex-M33 128MHz (nRF52840 대비 2배 더 고속) - 1.5MByte 플래시 메모리. - 256KByte RAM 연관 칩. nRF52840. 블루투스 5.0 품번 : nRF52840

igotit.tistory.com

 

 


첫 등록 : 2026.02.25

최종 수정 : 2026.03.03

단축 주소 : https://igotit.tistory.com/6461


 

댓글



비트코인




            암호화폐/외환/나스닥/골드          
       
현물 |선물 인버스 |선물 USDT , bybit MT5               프랍 트레이딩. MT4,MT5