-
Embedded Swift 설치, 코드 작성, ESP32-C6에서 빌드 및 작동시키는 방법공부/Swift(프로그래밍 언어) 2026. 3. 21. 02:25반응형
맥북에 ESP32-C6 드라이버 및 필수 프로그램 설치 방법
[임베디드] ESP32-C6 맥북 등 macOS에서 빌드 및 동작 테스트 하기
ESP32-C6 라는 임베디드 보드의 빌드 및 동작이 잘 되는지 'macOS' 에서 확인하는 방법에 대해 알아보겠습니다.출처: Standard Toolchain Setup for Linux and macOS 1. 드라이버 설치하기ESP32-C6 개발 보드를 맥북
infoarmory.tistory.com
위 링크에서 ESP32-C6 드라이버 및 필수 프로그램을 설치해야 이 포스트의 내용을 진행할 수 있습니다. 결과를 실행하려면 ESP32-C6와 같은 마이크로 컨트롤러가 있어야 합니다.
WWDC24에서 임베디드 프로그래밍 등을 위한 Embedded Swift가 발표되었습니다. 발표 당시에는 굉장히 센세이셔널하고 시장을 혁신할 것이라 예상되었지만, 시간이 지나고 보니 그 정도까지는 아닌 것 같습니다. 어쨌든 Swift 언어를 사용해서 임베디드 프로그래밍을 할 수 있다고 하니, 그 방법을 알아보겠습니다.
출처
Build Embedded Swift Application for ESP32-C6

소개
Embedded Swift는 Swift 프로그래밍 언어의 강력한 기능과 표현력을 마이크로컨트롤러 및 기타 임베디드 시스템과 같은 제약이 있는 환경에서도 활용할 수 있도록 지원합니다. WWDC24 에서 발표된 Embedded Swift는 Swift의 핵심 기능을 유지하면서도 용량과 의존성을 크게 줄인 경량의 효율적인 Swift 하위 집합을 제공하는 것을 목표로 합니다. 이를 통해 리소스가 제한된 환경에서 개발하는 개발자들도 Swift의 최신 구문과 안전성 기능을 새롭고 흥미로운 방식으로 활용할 수 있게 됩니다.
Embedded Swift (임베디드 스위프트)란 무엇인가요?
Embedded Swift는 임베디드 시스템 및 베어메탈 프로그래밍에 적합한 작고 독립적인 바이너리를 생성하도록 설계된 실험적인 Swift 특수 컴파일 모드입니다. 불필요한 기능을 제거하고 필수 기능에 집중하여 최소한의 효율적인 코드를 생성합니다. 주요 목표는 전체 Swift 런타임과 관련된 큰 코드 사이즈를 줄이고, 생성된 코드를 단순화하며, 효과적인 데드 코드 제거를 가능하게 하는 것입니다.
Embedded Swift는 완전한 SDK 또는 HAL(하드웨어 추상화 계층; Hardware Abstraction Layer)이 아니라, Swift 코드를 기존 임베디드 개발 워크플로에 통합할 수 있는 오브젝트 파일로 컴파일하는 도구를 제공합니다. 동적 힙을 사용하는 환경과 사용하지 않는 환경 모두를 지원하며, 일반 Swift 프로젝트와의 코드 호환성을 보장하기 위해 Swift의 하위 집합(subset)으로 유지되는 것을 목표로 합니다.ESP32-C6용 Swift 시작하기
다음 예제는 ESP32-C6용 임베디드 Swift 애플리케이션을 구축하는 단계를 설명합니다.
하드웨어 설정
다음 하드웨어가 있는지 확인하십시오.
- ESP32-C6 개발 보드 (LED 내장된 모델 추천)
- 전원 및 프로그래밍용 USB-C 케이블

ESP32-C6 필수 조건
시작하기 전에 다음 사항을 확인하세요.
- ESP-IDF : ESP32용 공식 개발 프레임워크로, 올바르게 설치하고 셸에서 소싱해야 합니다. 이 튜토리얼은 ESP-IDF v6.0에서 테스트되었습니다. (설치 방법은 맨 위의 포스트 링크 참조)
- Swiftly : Swift 툴체인 설치 및 관리 프로그램입니다.
- Swift 6.2 개발 스냅샷(swiftly를 통해 설치됨). - Xcode, Swift 설치가 되어 있더라도 스냅샷은 따로 설치해야 합니다.
설치 및 사전작업
Swiftly - Swift 툴체인 설치
Swift 툴체인을 설치하세요. 먼저 swift.org/install 에 있는 공식 설치 가이드를 따라 Swiftly를 설치한 다음 Swift 6.2 개발 스냅샷을 설치하세요. (터미널에 입력)
# Install Swift 6.2 development snapshot swiftly install 6.2-snapshot깃허브에서 샘플 프로젝트 클론하기
이 저장소에는 두 가지 ESP32 예제가 포함되어 있습니다. 좀 더 고급 기능을 보여주는 LED 스트립 예제를 사용해 보겠습니다.
git clone https://github.com/swiftlang/swift-embedded-examples.git --single-branch --branch main cd swift-embedded-examples/esp32-led-strip-sdk # Use the 6.2 snapshot for this project (디렉토리 이동 후 아래 명령어 필수 입력) swiftly use 6.2-snapshot
사용 가능한 ESP32 예제- esp32-led-blink-sdk: 간단한 LED 깜빡임 예시
- Embedded Swift - ESP32-C6 - Led Blink (Wokwi 에서 보기 - 임베디드 시뮬레이션 사이트)
- esp32-led-strip-sdk: 네오픽셀 LED 스트립 제어 예시 (이 튜토리얼에서 사용됨)
- Embedded Swift - ESP32-C6 - Led Strip (Wokwi 에서 보기)
타깃(target) 설정
프로젝트에 올바른 타깃이 설정되어 있는지 확인하세요. esp32-led-strip-sdk가 현재 디렉토리인지 확인 후 처음 한 번 필수로 실행합니다. 이후 build 폴더가 생성되었다면 타깃 설정이 된 것입니다.
idf.py set-target esp32c6참고: 이 프로젝트는 ESP32-C3와 같은 다른 RISC-V 기반 타겟용으로도 빌드할 수 있습니다.
빌드 및 실행
프로젝트 빌드 및 플래싱
플래싱: 마이크로컨트롤러나 다른 임베디드 시스템의 플래시 메모리에 프로그램 코드를 기록하는 작업
애플리케이션을 컴파일하고 ESP32-C6에 USB-C 케이블을 연결한 후 플래싱하세요.
idf.py build idf.py flash idf.py monitor# 빌드, 플래시, 모니터를 한 번에 하기 idf.py build flash monitor
빌드 성공 화면 
LED Strip 동작 (GIF라 색이 바래 보입니다)
참고: 모니터 애플리케이션을 종료하려면 control + [ 를 입력해야 합니다.
모니터 화면 예제 예제 살펴보기
예제의 소스 코드인 Main.swift를 살펴보겠습니다.
//===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2023 Apple Inc. and the Swift project authors. // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // //===----------------------------------------------------------------------===// @_cdecl("app_main") func app_main() { print("Hello from Swift on ESP32-C6!") let n = 8 let ledStrip = LedStrip(gpioPin: 0, maxLeds: n) ledStrip.clear() var colors: [LedStrip.Color] = .init(repeating: .off, count: n) while true { colors.removeLast() colors.insert(.lightRandom, at: 0) for index in 0 ..< n { ledStrip.setPixel(index: index, color: colors[index]) } ledStrip.refresh() let blinkDelayMs: UInt32 = 500 vTaskDelay(blinkDelayMs / (1000 / UInt32(configTICK_RATE_HZ))) } }이 코드는
- ESP32-C6 마이크로컨트롤러에 연결된 LED 스트립을 초기화합니다.
- LedStrip 이라는 구조체는 LED를 다루기 위한 저레벨 명령어를 Swift에서 편리하게 사용할 수 있도록 래핑한 것입니다.
- `app_main` 함수는 먼저 메시지를 출력한 후, GPIO 핀 0에 최대 8개의 LED로 구성된 LED 스트립을 설정합니다.
- 그런 다음 스트립을 초기화하고 무한 루프에 진입하여 임의의 색상을 LED에 순환적으로 표시합니다.
- LED가 1개인 경우 코드를
ledStrip.setPixel(index: 0, color: .lightRandom)
letStrip.refresh()
로 줄일 수 있습니다.
- LED가 1개인 경우 코드를
- 각 반복마다 LED 색상을 업데이트하고, 스트립을 초기화한 후 500밀리초 동안 지연합니다. (vTaskDelay)
- configTICK_RATE_HZ 의 기본값은 100 입니다.
- configTICK_RATE_HZ 의 기본값은 100 입니다.
vTaskDelay란? (더보기)
더보기vTaskDelay는 FreeRTOS에서 태스크(작업)를 지정된 시간(틱, Tick) 동안 '블록(Blocked) 상태'로 만들어 CPU를 다른 태스크가 사용하도록 양보하는 함수입니다. 호출된 시점부터 상대적인 시간만큼 지연을 발생시키며, 일반적인 Delay와 달리 CPU를 낭비하지 않는 것이 특징입니다.
핵심 특징:- 동작 방식: vTaskDelay(ticks)가 호출되면, 해당 태스크는 즉시 실행 대기열에서 빠져나와 Blocked 상태가 되고, 시스템 틱이 설정된 시간(1000틱=1초)만큼 지나면 다시 Ready 상태로 전환됩니다.
- 상대적 시간: vTaskDelayUntil()과 달리, vTaskDelay()는 함수가 호출된 시점부터 시간을 재기 때문에 정확한 주기를 보장하지 않고 상대적인 지연을 발생시킵니다.
- 장점: delay()처럼 CPU를 비우고 루프를 돌지 않아, 낮은 우선순위 태스크도 실행 기회를 얻을 수 있어 멀티태스킹 효율이 극대화됩니다.
- 사용 예시: vTaskDelay(pdMS_TO_TICKS(1000)); (1000밀리초, 즉 1초 지연).
LedStrip 구조체
/// LED 스트립을 제어하기 위한 구조체입니다. /// ESP-IDF의 led_strip API를 Swift에서 사용하기 쉽게 감싼(wrapper) 형태입니다. struct LedStrip { private let handle: led_strip_handle_t /// LED 스트립을 초기화합니다. /// - Parameters: /// - gpioPin: LED 스트립이 연결된 GPIO 핀 번호 /// - maxLeds: 제어할 LED의 최대 개수 init(gpioPin: Int, maxLeds: Int) { var handle = led_strip_handle_t(bitPattern: 0) var stripConfig = led_strip_config_t( strip_gpio_num: Int32(gpioPin), max_leds: UInt32(maxLeds), led_model: LED_MODEL_WS2812, color_component_format: led_strip_color_format_rgb(), flags: .init(invert_out: 0) ) var spiConfig = led_strip_spi_config_t( clk_src: SPI_CLK_SRC_DEFAULT, spi_bus: SPI2_HOST, flags: .init(with_dma: 1) ) guard led_strip_new_spi_device(&stripConfig, &spiConfig, &handle) == ESP_OK, let handle = handle else { fatalError("cannot configure spi device") } self.handle = handle } /// LED 색상을 나타내는 구조체입니다. /// RGB(빨강, 초록, 파랑) 값을 사용합니다. struct Color { /// 최대 밝기의 흰색 static var white = Color(r: 255, g: 255, b: 255) /// 낮은 밝기의 흰색 static var lightWhite = Color(r: 16, g: 16, b: 16) /// 낮은 밝기의 랜덤 색상 static var lightRandom: Color { Color(r: .random(in: 0...16), g: .random(in: 0...16), b: .random(in: 0...16)) } /// LED를 끈 상태 (검정색) static var off = Color(r: 0, g: 0, b: 0) var r, g, b: UInt8 } /// 특정 위치의 LED 색상을 설정합니다. /// - Parameters: /// - index: LED 인덱스 (0부터 시작) /// - color: 설정할 색상 func setPixel(index: Int, color: Color) { led_strip_set_pixel( handle, UInt32(index), UInt32(color.r), UInt32(color.g), UInt32(color.b)) } /// 설정된 색상을 실제 LED 스트립에 반영합니다. /// setPixel 호출 후 반드시 호출해야 화면에 적용됩니다. func refresh() { led_strip_refresh(handle) } /// 모든 LED를 끕니다. func clear() { led_strip_clear(handle) } } func hsvToRgb(h: Float, s: Float, v: Float) -> LedStrip.Color { let c = v * s let x = c * (1 - abs((h / 60).truncatingRemainder(dividingBy: 2) - 1)) let m = v - c var r: Float = 0, g: Float = 0, b: Float = 0 switch h { case 0..<60: (r, g, b) = (c, x, 0) case 60..<120: (r, g, b) = (x, c, 0) case 120..<180:(r, g, b) = (0, c, x) case 180..<240:(r, g, b) = (0, x, c) case 240..<300:(r, g, b) = (x, 0, c) default: (r, g, b) = (c, 0, x) } return .init( r: UInt8((r + m) * 255), g: UInt8((g + m) * 255), b: UInt8((b + m) * 255) ) }- 주의사항: 기본 LED의 밝기가 매우 높기 때문에 낮은 밝기를 원한다면 rgb값의 최대치를 16~30 정도로 설정하세요
- hsvToRgb는 HSV값을 rgb로 변환하는 함수이며 낮은 밝기를 원한다면 v: 0.1 로 설정합니다.
- 이 구조체의 의의는 C 스타일의 기본 함수를 래핑해 Swift 스타일로 사용할 수 있다는 점입니다.
예제 응용: BPM(Beat Per Minutes)에 따라 깜빡이는 LED새로운 프로젝트를 만들 수도 있지만 기존 파일을 재활용해 여러 케이스를 번갈아가며 빌드하는 방법도 있습니다.
@_cdecl("app_main") func main() { ExampleBlink.run() // ExampleWhite.run() // ExampleMetronome.run() // ExampleRainbow.run() }ExampleMetronome
struct ExampleMetronome { static func run() { print("메트로놈: BPM 에 맞춰 랜덤 색상(light)이 깜빡임") // BPM to ms 공식: 60000 / BPM let BPM = 150 let delayMs: UInt32 = UInt32(60000 / BPM) let blinkMs: UInt32 = delayMs / 20 print( "BPM: \(BPM), delayMs: \(delayMs), blinkMs: \(blinkMs), (b-d): \(delayMs - blinkMs)" ) let strip = LedStrip(gpioPin: 0, maxLeds: 1) strip.clear() while true { strip.setPixel(index: 0, color: .lightRandom) strip.refresh() // configTICK_RATE_HZ: 100 -> 해상도는 10ms 단위 vTaskDelay(blinkMs / (1000 / UInt32(configTICK_RATE_HZ))) strip.setPixel(index: 0, color: .off) strip.refresh() vTaskDelay((delayMs - blinkMs) / (1000 / UInt32(configTICK_RATE_HZ))) } } }- BPM을 ms로 바꾸는 공식 = 60000 / BPM
- 1비트에 해당하는 ms 중 5%를 LED 표시하는 데에 사용 (blinkMs)
- 나머지는 off 상태로 BPM 구분을 명확하게 함 (delayMs - blinkMs)
참고 사항
빌드 목록에 Swift 파일을 추가하는 방법
main 폴더 (Swift 파일이 있는 곳)의 CMakeList.txt 파일을 열어 다음 부분에 추가
# List of Swift source files to build. target_sources(${COMPONENT_LIB} PRIVATE Main.swift LedStrip.swift )[참고] ESP32-C6 단독으로 해볼 수 있는 프로젝트 (더보기)
더보기ESP32-C6는 특히 Wi-Fi 6 + BLE + 저전력 + RISC-V 조합이라서 활용 범위가 넓습니다.
아래는 “보드 단독으로 해볼 만한 것” 위주로 정리했습니다.
1. Wi-Fi 기반 프로젝트
간단한 웹 서버
👉 브라우저에서 LED 제어
- http://IP/on
- http://IP/off
가능한 기능:
- LED 켜기/끄기
- 밝기 슬라이더
- 애니메이션 변경
Wi-Fi AP 모드
👉 ESP32가 공유기 역할
- 폰으로 직접 접속
- 인터넷 없이 제어 가능
예:
- “ESP_LED” 와이파이 생성
- 접속 → 웹 UI로 LED 제어
REST API 서버
👉 앱/스크립트에서 제어
curl http://esp.local/color?=red2. BLE (블루투스) 프로젝트
BLE LED 컨트롤러
👉 스마트폰 앱으로 제어
- 색상 변경
- 밝기 조절
- 애니메이션 선택
👉 Wi-Fi보다 전력 효율 좋음
BLE 비콘
👉 주변 기기 감지용
- iBeacon 스타일
- 근접 알림
3. 센서 없이도 가능한 것
소프트웨어 메트로놈
- BPM 설정
- LED 깜빡임
- 비트 강조
확장:
- 4/4, 3/4 패턴
- 다운비트 색상 다르게
LED 애니메이션 엔진
👉 여러 패턴 구현
- rainbow
- breathing
- wave
- fire effect
타이머 / 스케줄러
- 10초 카운트다운
- 특정 시간에 LED 점등
4. 조금 더 고급
OTA 업데이트
👉 Wi-Fi로 펌웨어 업데이트
- USB 없이 코드 업데이트
- 실전에서 많이 씀
NTP 시계
👉 인터넷 시간 동기화
- LED로 시간 표시
- 메트로놈 BPM 자동 맞춤
5. ESP32-C6 특화
Thread / Matter (고급)
👉 스마트홈 프로토콜
- 애플 홈킷 스타일
- IoT 기기 연동
👉 난이도 높지만 강력
반응형'공부 > Swift(프로그래밍 언어)' 카테고리의 다른 글
Embedded Swift: ESP32-C6을 Wifi에 연결시켜 웹 서버로 사용하기, 브라우저에서 LED 제어 (0) 2026.03.31 Swift iOS: 디바이스 자체 설정에 방향 락이 걸려있을 때도 인식하게 하는 법 (0) 2026.03.23 Swift iOS 프로젝트에서 경고창(얼럿)을 띄우는 방법 정리 (기본 방식 vs 라이브러리) (0) 2026.03.05 CocoaPods 서비스 종료? 2026년 이후 변화와 개발자가 알아야 할 점 (0) 2026.02.23 iOS Swift: 위젯(Widget) 넣기 (난이도: 어려움) (0) 2026.02.15