튜토리얼: 누코드 개발 입문
누코드의 NU-40DK 보드를 가지고 개발을 시작하는 기본 흐름을 정리하는 글이다. 현재 누코드 보드 관련 글 작성 모임에 참여하고 있는데, 그 스터디에서 누코드를 가지고 개발을 하면서 직접 따라 해보고 기록해볼 필요를 느껴 이번 작업을 시작하게 되었다.
이 글은 간단하게 개발환경을 셋팅한 과정을 정리한 글이다. 앞으로는 이 환경을 바탕으로 실제 프로젝트를 만들어 진행하려고 한다.
다음 단계로는 새 프로젝트 템플릿을 만들고, 센서나 통신 모듈을 연동해 작동하는 예제를 하나씩 구현해볼 계획이다. 또한 빌드·플래시 과정을 자동화하고 소스 관리를 정리해 스터디 멤버들과 공유하겠다.
이 시리즈를 통해 초보자도 따라할 수 있는 실전 가이드를 차근차근 만들어가려고 한다.

처음에는 보드를 받고 나서 어떻게 개발을 시작해야 할지 막막했다. 다행히 좀 더 찾아보니 공식 튜토리얼 동영상(https://www.youtube.com/watch?v=EAJdOqsL9m8)을 발견해서 따라 해볼 수 있었다.
VS CODE 에서 SDK 설치
영상에서는 SDK 설치와 툴체인 구성, 환경 변수 설정, 예제 빌드 및 디바이스에 플래싱하는 기본 흐름을 차근차근 보여준다. 덕분에 VS CODE 기반으로 로컬 개발 환경을 빠르게 구성할 수 있었고, 샘플 애플리케이션을 빌드해서 실제 하드웨어에서 동작시키는 것까지 확인했다.
카카오톡으로 질문한 내용
하지만 빌드는 성공했지만 FLASH를 하지 못했다. 알고 보니 보드에 펌웨어를 올리려면 J-Link라는 외부 디버거/프로그래머가 필요했다. 이전 스터디 때 J-Link가 필요하다고 들었는데, 구체적으로 어떻게 연결해야 하는지 몰라서 결국에는 누코드 카톡방에 질문을 했다.
다행히도 필요한 장비를 한 대 무상으로 대여해 주겠다고 하셨다. 누코드 보드 자체적으로 J-Link를 바로 연결할 수 있는 버전이 추후 나올 예정이라 앞으로는 해당 장비가 필요 없을 것 같다. 이러한 개선이 역시 누코드가 지향하는 방향이랑 일치하는 것 같다. 어쨌든 당장 플래시를 진행하려면 필요해서 친절히 빌려주신 덕분에 문제를 해결할 수 있었다.

누코드 아래에 RESET, SWDCLK, GND, SWDIO, 3.3V 핀을 연결하여 J-Link 에 연결했다고 보면 된다. 아래는 J-Link로 누코드(NU-40DK)를 연결하고 플래시할 때 실제로 유의한 점과 간단한 절차이다.
RESET -> RESET (nRESET) SWDCLK -> SWCLK (또는 SWDCLK) SWDIO -> SWDIO GND -> GND 3.3V -> VTref (J-Link의 타겟 전원 감지/공급 핀) (주의: 보드에 이미 전원이 인가된 상태인지, J-Link에서 전원을 공급할지 여부를 반드시 확인하세요.)

nRF Connect for Desktop 를 통해서 J-Link 가 제대로 연결되었는지 확인 할 수 있다.
/*
* Copyright (c) 2016 Intel Corporation
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file Sample app to demonstrate PWM.
*/
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/device.h>
#include <zephyr/drivers/pwm.h>
static const struct pwm_dt_spec pwm_led0 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0));
#define PWM_PERIOD PWM_MSEC(20U)
#define BLINK_INTERVAL K_SECONDS(5U)
#define MIN_PERIOD (PWM_PERIOD / 128U)
int main(void)
{
uint32_t period;
int ret;
printk("PWM-based blinky\n");
if (!pwm_is_ready_dt(&pwm_led0)) {
printk("Error: PWM device %s is not ready\n",
pwm_led0.dev->name);
return 0;
}
period = PWM_PERIOD;
while ((ret = pwm_set_dt(&pwm_led0, period, period / 2U)) != 0) {
period /= 2U;
if (period < MIN_PERIOD) {
printk("Error %d: PWM device does not support a usable period\n",
ret);
return 0;
}
}
printk("Using PWM carrier %u nsec\n", period);
while (1) {
ret = pwm_set_dt(&pwm_led0, period, period);
if (ret) {
printk("Error %d: failed to turn LED on\n", ret);
return 0;
}
k_sleep(BLINK_INTERVAL);
ret = pwm_set_dt(&pwm_led0, period, 0U);
if (ret) {
printk("Error %d: failed to turn LED off\n", ret);
return 0;
}
k_sleep(BLINK_INTERVAL);
}
return 0;
}
위 코드는 PWM을 이용해 LED를 5초 간격으로 깜빡이게 하는 간단한 예제입니다.
주요 동작:
- DT(alias)로부터 pwm_led0 장치를 가져오고(pwm_dt_spec), pwm_is_ready_dt()로 준비 여부를 확인합니다.
- 초기에는 PWM 주기를 PWM_PERIOD(코드상 PWM_MSEC(20U), 즉 20ms)로 설정하고, pwm_set_dt()를 호출해 50% 듀티비트(period / 2U)를 시도합니다. 장치가 이 주기를 지원하지 않으면 주기를 절반으로 줄이면서(MIN_PERIOD까지) 재시도합니다.
- 사용 가능한 PWM 캐리어(period)를 찾으면 이를 printk로 출력합니다.
- 메인 루프에서는 BLINK_INTERVAL(K_SECONDS(5U), 즉 5초)만큼 대기하면서 LED를 켜기(듀티 = period)와 끄기(듀티 = 0)를 반복합니다. 이 때문에 LED가 5초 간격으로 깜빡이게 됩니다.
참고:
- 깜빡이는 주기를 바꾸려면 BLINK_INTERVAL 값을 변경하면 되고, 밝기(듀티비트)를 조절하려면 pwm_set_dt() 호출 시 전달하는 듀티 값을 수정하면 됩니다.
- 에러 발생 시 printk로 관련 메시지를 출력하므로 플래시 후 시리얼 콘솔을 통해 동작 상태와 오류를 확인할 수 있습니다.
앞으로 할일
앞으로는 워키토키처럼 즉시 의사소통이 가능한, 블루투스 기반의 ‘바이브코딩(vibe-coding)’ 기기를 만드는 것을 목표로 한다. 음성으로 바이브코딩을 하고 적용할지 말지는 버튼을 클릭해서 선택하는 단순한 기기이다.
이 계획을 바탕으로 우선 간단한 프로토타입을 만들고, 스터디 멤버들과 함께 실제 사용 시나리오에서 유용한 패턴 집합을 만들어가겠다.