소개

이 책의 목표는 Espressif 장치에서 Rust 프로그래밍 언어의 포괄적인 사용 가이드를 제공하는 것입니다.

Espressif 장치의 Rust 프로그래밍 언어의 지원이 현재 빠르게 진행 중에 있습니다. 이 때문에 이 문서의 일부가 빠르게 변경될수 있으며 오래되어있을수있습니다.

Rust on ESP 관련 툴과 라이브러리는 Gihtub의 esp-rs organization를 참고하세요. 이 organization은 Espressif 직원 뿐만 아니라 커뮤니티 구성원도 관리합니다

모든 기술적 질문과 이슈에 대해 자유롭게 esp-rs community on Matrix 에 참여하세요! 이 커뮤니티는 모두에게 열려있습니다!

이 책의 독자층

이 책은 Rust에 대한 경험이 있는 사람들을 대상으로 하며, 임베디드 개발 및 전자제품에 대한 초보적인 지식을 전제로 합니다. 위 경험이 없는 사람들에게는 먼저 가정 및 전제조건리소스섹션을 읽어보고 최신 정보를 얻도록 권장합니다

가정 및 전제조건

  • Rust 프로그래밍 언어를 편하게 사용할 수 있으며 데스크톱 환경에서 응용 프로그램을 작성하고 실행했습니다.
  • 이 책은 Rust 2021년 에디션을 기준으로 하므로 코드 관용구를 숙지해야합니다.
  • C또는 C++ 등과 같은 언어로 임베디드 시스템을 개발하는데 편안하고 다음 개념에 익숙해야합니다
    • cross-compilation
    • UART, SPI, I2C, 등과 같은 일반적인 디지털 인터페이스.
    • Memory-mapped peripherals
    • Interrupts

리소스

위에서 언급한 내용에 대해 잘 모르거나 경험이 부족한 경우 또는 이 책에서 언급한 특정 주제에 대해 더 많은 정보를 원하시면 도움이 될 수 있습니다.

ResourceDescription
The Rust Programming LanguageRust에 대해 잘 모르신다면 이 책을 먼저 읽으시는것이 좋습니다.
The Embedded Rust Book여기서 Rust's Embedded Working Group에서 제공하는 여러 리소스를 찾을 수 있습니다.
The EmbedonomiconRust 임베디드 프로그래밍에서 중요한 세부내용들
Embedded Rust (std) on EspressifEspressif SoCs를 위한 std 사용 가이드
Embedded Rust (no_std) on EspressifEspressif SoCs를 위한 no_std 사용 가이드

Translations

이 책은 자발적으로 번역되었습니다. 번역이 아래 리스트에 포함되길 원한다면 Pull Request 열어서 추가해주세요.

사용법

이 책은 계단식 챕터로 구성된 책입니다. 따라서 이전 챕터에 내용을 이해하지 못한채 다음 챕터로 넘어간다면 이해에 어려움이 있습니다.

이 책에 컨트리뷰팅하기

이 책에 대한 작업은 이 저장소에 저장됩니다.

이 책을 따라가는데 어려움이 있거나 책의 일부분이 명확하지않다면 그것은 버그입니다.

이 책 리포지토리의 이슈탭에 제보해주세요.

오타 수정 및 번역 이슈의 경우 한국어 리포지토리 이슈탭에 제보해주시면 빠르게 응답하겠습니다.

자료의 재사용

이 책은 다음 라이선스로 배포됩니다:

  • 이 책에 수록된 코드 샘플 및 독립 Cargo 프로젝트는 MIT LicenseApache License v2.0의 조건에 따라 라이센스가 부여됩니다.
  • 이 책에 수록된 산문, 그림, 도표는 Creative Commons CC-BY-SA v4.0 조건에 따라 라이센스가 부여됩니다..

요약하면, 작업에 당사의 텍스트 또는 이미지를 사용하려면 다음과 같은 작업이 필요합니다:

  • 출처를 명시해야 합니다.(예: 슬라이드에 이 책을 언급하고 관련 페이지 링크를 제공합니다)
  • CC-BY-SA v4.0 license에 대한 링크를 제공해야 합니다.
  • 어떤 내용을 변경했는지 표시하고 동일한 라이센스에 따라 당사의 내용을 변경할 수 있습니다

이 책이 유용하다고 생각되면 알려주세요!

개발 접근 방식의 개요

Espressif chips에서 Rust를 사용하는 방법은 다음과 같습니다.:

  • std 라이브러리, a.k.a. 스탠다드 라이브러리 사용하기.
  • core라이브러리 (no_std), a.k.a. 배어메탈 개발 사용하기.

두 접근 방식 모두 장점과 단점이 있으므로, 프로젝트의 필요에 따라 결정을 내려야 합니다. 이 장에는 두 가지 접근 방식에 대한 개요가 포함되어 있습니다.

The Embedded Rust Book의 다양한 런타임 비교도 참조하십시오.

GitHub의 esp-rs organization은 Espressif 칩에서 Rust를 실행하는 것과 관련된 여러 저장소의 홈입니다. 필요한 크레이트의 대부분은 여기에 소스 코드를 호스팅하고 있다.

네이밍 컨벤션 레포지토리

esp-rs organization에서, 우리는 다음과 같은 표현을 사용합니다:

  • esp-로 시작하는 저장소는 no_std 접근 방식에 초점을 맞추고 있다. 예를 들어, esp-hal
    • no_std는 베어 메탈 위에서 작동하므로, esp-는 Espressif chip 이다.
  • esp-idf-로 시작하는 저장소는 std 접근 방식에 초점을 맞추고 있다. 예를 들어, esp-idf-hal
    • std는 베어 메탈을 제외하고 esp-idf-추가 레이어가 필요합니다.

Espressif 제품 지원

⚠️ 참고:

  • ✅ - 이 기능은 구현되어있거나 지원됩니다.
  • ⏳ - 그 기능은 개발 중입니다.
  • ❌ - 이 기능은 지원되지 않습니다.
Chipstdno_std
ESP32
ESP32-C2
ESP32-C3
ESP32-C6
ESP32-S2
ESP32-S3
ESP32-H2
ESP8266

⚠️ 참고: ESP8266 시리즈는 이 책의 범위를 벗어난다. ESP8266 시리즈에 대한 Rust 지원은 제한적이며 Espressif에서 공식적으로 지원되지 않습니다.

특정 상황에서 지원되는 제품은 책 전체에서 _지원되는Espressif 제품들_이라고 불릴 것이다.

스탠다드 라이브러리 사용하기 (std)

Espressif는 ESP-IDF라고 불리는 C 기반 개발 프레임워크를 제공합니다. ESP32로 시작하는 모든 Espressif 칩을 지원하거나 지원할 것입니다. 이 프레임워크는 ESP8266을 _지원하지 않는다_는 점에 유의하십시오.

ESP-IDF는 그 위에 Rust 표준 라이브러리(std)를 구축하기에 충분한 기능을 갖춘 newlib 환경을 제공한다. 이것은 Epressif 장치에서 std 지원을 활성화하기 위해 취해지고 있는 접근 방식이다.

현재 지원되는 사항

Rust std 개발을 위해 지원되는 Espressif 제품은 ESP-IDF 프레임워크에서 지원하는 제품입니다. 다양한 버전의 ESP-IDF와 Espressif 칩 지원에 대한 자세한 내용은 이 표를 참조하십시오.

std를 사용할 때, thread, mutex 및 기타 synchronization primitives, collections, 난수 생성, 소켓 등을 포함하여 ESP-IDF에 존재하는 많은 기능에 액세스할 수 있습니다.

esp-rs 관련된 Crate들

리포지토리설명
embedded-svc임베디드 서비스들을 위한 추상화 trait들 (WiFi, Network, Httpd, Logging, etc.)
esp-idf-svcesp-idf 드라이버를 사용하는 embedded-svc 구현.
esp-idf-halesp-idf 프레임워크를 사용한 embedded-hal 및 기타 trait들의 구현.
esp-idf-sysesp-idf 개발 프레임워크에 대한 Rust 바인딩입니다. 드라이버, Wi-Fi 등에 대한 raw (unsafe) 액세스를 제공합니다.

앞서 언급한 crate들은 상호 의존성을 가지고 있으며, 이 관계는 아래에서 볼 수 있다.

graph TD;
    esp-idf-hal --> esp-idf-sys & embedded-svc
    esp-idf-svc --> esp-idf-sys & esp-idf-hal & embedded-svc

Standard Library(std)를 사용할 경우

  • 풍부한 기능: 임베디드 시스템 요구사항에 네트워킹 프로토콜, 파일 I/O 또는 복잡한 데이터 구조 등의 지원과 같은 많은 기능이 필요한 경우, std 라이브러리를 사용한다면 광범위한 기능을 제공하여 복잡한 어플리케이션을 만들때 유용합니다.
  • 이식성: std crate는 다양한 플랫폼과 아키텍처에서 사용할 수 있는 표준화된 API 세트를 제공하여 이식 가능하고 재사용 가능한 코드를 더 쉽게 작성할 수 있도록 합니다.
  • 신속한 개발: std crate는 낮은 수준의 세부 사항에 대해 너무 많이 걱정하지 않고 빠르고 효율적으로 애플리케이션을 구축하는 데 사용할 수 있는 풍부한 기능 세트를 제공합니다.

코어 라이브러리 사용하기 (no_std)

임베디드 Rust 개발자들에게는 no_std 를 사용하는것이 더 친숙할수 있습니다. std (Rust 스탠다드 라이브러리) 를 사용하지않고 부분집합인 core 라이브러리를 사용합니다. The Embedded Rust Book 에는 훌륭한 세션이 있습니다.

여기서 주의할 점은 no_std 은 Rust core 라이브러리를 사용한다는 것입니다. Rust standard 의 일부이기때문에 no_std crate는 std 환경에서 컴파일 할 수 있습니다. 하지만, 역은 성립하지않습니다: std crate는 no_std 환경에서 컴파일 할 수 없습니다. 이 정보는 어떤 라이브러리를 선택할지 결정할 때 기억할 가치가 있습니다.

현재 지원사항들

아래 표는 다양한 Espressif 제품에 대한 현재 no_std 지원에 대해 설명합니다.

HALWi-Fi/BLE/ESP-NOWBacktraceStorage
ESP32
ESP32-C2
ESP32-C3
ESP32-C6
ESP32-H2
ESP32-S2
ESP32-S3

⚠️ Note:

  • ✅ Wi-Fi/BLE/ESP-NOW에서 대상이 적어도 나열된 기술 중 하나를 지원하는 것을 의미합니다. 자세한 내용은 esp-wifi repository의 Current support 표를 참조하십시오.
  • ESP8266 HAL은 유지보수 모드이며 이 칩에 대해서는 더 이상 개발이 이루어지지 않습니다.

esp-rs 관련 Crates

RepositoryDescription
esp-hal하드웨어 추상계층
esp-pacsPeripheral 접근crates
esp-wifiWi-Fi, BLE and ESP-NOW 지원
esp-alloc간단한 Heap 할당자
esp-printlnprint!, println!
esp-backtrace예외상황과 패닉 핸들러
esp-storage암호화되지 않은 플래시 메모리에 액세스할 수 있는 임베디드 스토리지 traits

Core Library(no_std)를 권장하는 예시

  • 작은 메모리 사용량: 임베디드 시스템의 리소스가 제한되어있고 메모리 사용량이 적어야 하는 경우 std 기능을 사용하면 컴파일 되는 최종 바이너리 크기와 컴파일 시간이 많이 들기 때문에, bare-matal을 사용할 가능성이 높습니다.
  • 하드웨어 직접 제어: 임베디드 시스템에서 낮은 수준의 장치 드라이버나 특수 하드웨어 기능에 대한 액세스와 같이 하드웨어에 대한 보다 직접적인 제어가 필요한 경우 std 가 하드웨어와 직접 상호 작용하기 어려울 수 있는 추상화를 추가하기 때문에 베어메탈을 사용하는 것이 좋습니다
  • 시간이 중요한 어플리케이션: 임베디드 시스템이 실시간적 퍼포먼스와 빠른 응답속도를 요구한다면, std 는 예측할 수 없는 지연과 오버헤드를 초래할 수 있으므로 no_std를 사용하는 것이 좋습니다.
  • 커스텀 요구사항들: 베어메탈을 사용하면 애플리케이션의 동작을 보다 맞춤화하고 세밀하게 제어할 수 있으므로 전문화된 환경이나 비표준 환경에서 유용하게 사용할 수 있습니다.

Setting Up a Development Environment

현재, Espressif SoCs는 RISC-V and Xtensa 두 가지 아키텍처를 기반으로 하고 있습니다.

두 아키텍처 모두 stdno_std 접근 방식을 지원합니다.

개발 환경을 설정하려면 다음을 수행합니다:

  1. Rust 설치하기
  2. 대상 장치에 대한 설치 요구사항

대상 아키텍처와 상관없이, std 개발을 위해서 std 개발 요구사항 설치를 잊지마세요.

개발환경은 컨테이너에서 호스팅할 수 있으니 참고하시기 바랍니다..

Rust 설치

Rust가 설치되어있는지 확인하십시오. 설치되어있지 않은경우, rustup웹사이트를 참고하십시오.

🚨 Warning: 유닉스 기반 시스템을 사용할 때 시스템 패키지 관리자(예시. brew, apt, dnf, etc.)를 통해 설치한다면, 다양한 문제와 비호환성이 발생할 수 있으므로 대신 rustup을 사용하는 것이 가장 좋습니다.

Windows를 사용하는 경우 아래 나열된 ABI 중 하나를 설치했는지 확인합니다. 자세한 내용은 rustup 책의 Windows 챕터를 참고하세요.

  • MSVC: 추천하는 ABI, rustup 기본 요구사항 리스트에 있습니다. Visual Studio에서 만든 소프트웨어와 상호운용하려면 이것을 사용하세요.
  • GNU: GCC 툴체인을 사용하는 ABI. MinGW/MSYS2 툴체인으로 만들어진 소프트웨어와 함께 사용하려면 직접 설치하세요.

대체 설치방법도 참고하세요.

RISC-V 타겟 only

RISC-V 구조 기반 Espressif chips의 어플리케이션을 빌드하려면 다음을 따라주세요

  1. rust-src component와 함께 nightly 툴체인을 설치해주세요:

    rustup toolchain install nightly --component rust-src
    

    위의 명령은 rust 소스 코드를 다운로드합니다. rust-src는 std-lib, core-lib and build-config와 같은 항목들을 포함합니다.
    rust-src를 다운로드하는것은 두 가지 이유때문에 중요합니다:

    • Determinism(결정론) - core와 std 라이브러리의 내부를 볼 수 있습니다. 높은 수준의 확실성이 필요한 소프트웨어를 작성해야하는 경우, 사용 중인 라이브러리를 확인하는 것이 좋습니다.
    • custom targets 빌드하기 - rustc는 새 커스텀 타겟의 컴포넌트를 만들때 rust-src를 사용한다. 만약 rust에서 지원을 안하는 triple-target을 타겟으로 할때, rust-src 다운로드는 필수입니다.

    For more info on custom targets, read this Chapter from the Embedonomicon.

    커스텀 타겟에 대한 자세한 내용은 Embedonomicon의 이 챕터를 읽으세요

  2. 타겟을 설정합니다:

    • no_std (베어 메탈) 어플리케이션의 경우 다음을 실행합니다:

      rustup target add riscv32imc-unknown-none-elf # For ESP32-C2 and ESP32-C3
      rustup target add riscv32imac-unknown-none-elf # For ESP32-C6 and ESP32-H2
      

      이 대상은 현재 Tier 2입니다. Rust에서 다양한 RISC-V extensions을 포함하는 riscv32 대상의 다양한 맛을 주목하십시오.

    • std 어플리케이션의 경우:

    이 대상은 현재 Tier 3이므로 rustup을 통해 배포되는 사전 빌드된 개체가 없으며 no_std 대상과 달리 설치할 필요가 없습니다. 장치에 대한 올바른 대상은 러스트북의 *-esp-idf 섹션을 참조하십시오.

    • riscv32imc-esp-espidf 는 ESP32-C2 및 ESP32-C3 와 같은 atomics을 지원하지않는 SoC 용입니다.
    • riscv32imac-esp-espidf 는 atomics를 지원하는 SoC(ESP32-C6, ESP32-H2, and ESP32-P4 등)용입니다.
  3. std 프로젝트들을 빌드하려면 다음을 설치하여야합니다:

이제 Espressif의 RISC-V 칩에 프로젝트를 구축하고 실행할 수 있을 것입니다.

RISC-VXtensa 타겟

espupXtensaRISC-V 아키텍처를 위한 Rust 어플리케이션을 개발하는 데 필요한 구성 요소의 설치 및 유지 관리를 단순화하는 도구입니다..

1. espup설치

espup를 설치하려면, 아래 명령어를 터미널에 실행하세요:

cargo install espup

미리 컴파일된 릴리스 바이너리를 직접 다운로드하거나 cargo-binstall을 사용할 수도 있습니다.

2. 필수 툴체인 설치

다음을 실행하여 지원되는 모든 Espressif 대상에 대한 Rust 애플리케이션을 개발하는 데 필요한 모든 도구를 설치하십시오:

espup install

⚠️ 참고: std 애플리케이션은 std 개발 요구사항에서 다루는 추가 소프트웨어를 설치해야 합니다.

3. 환경 변수 설정하기

espup은 프로젝트를 구축하는 데 필요한 몇 가지 환경 변수가 포함된 내보내기 파일을 만들 것이다.

Windows (%USERPROFILE%\export-esp.ps1)

  • 이 파일을 실행할 필요가 없습니다. 수정된 환경변수를 보여주는 용도로 만든것입니다.

유닉스 기반 운영체제 - ($HOME/export-esp.sh). 파일을 sourcing하기위한 다른 방법들이 있습니다:

  • 매 터미널에서 이 파일을 source하기:

    1. 해당 파일을 source하기: . $HOME/export-esp.sh

    이 방식은 매 새 쉘을 열때마ㅏ 실행해줘야합니다.

  • export-esp.sh를 실행하는 alias 만들기:

    1. 쉘 프로파일 (.profile, .bashrc, .zprofile, 등.)에 다음 명령어를 복사 붙여넣기 하세요: alias get_esprs='. $HOME/export-esp.sh'
    2. 터미널 세션을 재시작하시거나 source [프로파일 경로] 명령어를 실행하세요, 예를 들면, source ~/.bashrc.

    이 방식은 매 쉘마다 sourcing을 안해도됩니다, export-esp.sh스크립트는 새로운 쉘이 실행될때 자동으로 실행됩니다.

espup는 무엇을 설치하나요?

Espressif 대상을 지원하기위해, espup 다음과 같은 도구를 설치합니다.

  • Espressif 대상 지원을 위한 Espressif Rust fork
  • RISC-V 대상을 위한 nightly 툴체인
  • Xtensa대상을 위한 LLVM fork
  • final binary를 링크하는 GCC 툴체인

fork 컴파일러는 표준 Rust 컴파일러와 공존할 수 있으며, 둘 다 시스템에 설치할 수 있습니다. fork 컴파일러는 오버로딩 메소드를 사용할 때 호출됩니다.

⚠️ 참고: 우리는 fork를 업스트림하기위해 노력을 하고있습니다

  1. LLVM fork에 변화는 이미 진행중입니다, tracking issue를 확인하세요.
  2. Rust 컴파일러 Fork들에 대해, LLVM 변경이 수락되면, 우리는 Rust 컴파일러 변경을 진행할 것입니다.

오류가 발생하면, 문제 해결 장을 확인하세요.

Xtensa Targets를 위한 다른 설치 방법

  • rust-build 설치 스크립트 사용. 이것은 과거에 권장되는 방법이었지만, 이제 설치 스크립트는 기능이 frozen되었다. 모든 새로운 기능은 espup에만 포함될 것입니다. 원본 Repository [README][https://github.com/esp-rs/rust-build.git]를 참조하십시오.
  • 소스에서 Xtensa Rust 컴파일러를 구축하세요. 이 과정은 계산 비용이 많이 들고 시스템에 따라 완료하는 데 한 시간 이상이 걸릴 수 있습니다. 이 접근 방식을 취할 주요 이유가 없다면 권장되지 않습니다. 여기 소스에서 빌드할 리포지토리가 있습니다: esp-rs/rust repository.

std 개발 요구사항

대상 아키텍처에 관계없이, std 애플리케이션을 구축하는 데 필요한 다음과 같은 도구가 설치되어 있는지 확인하십시오:

  • ESP-IDF 전제조건:

  • ldproxy 바이너리 크레이트: ldproxy에 대한 인수로도 주어진 실제 링커에 링커 인수를 전달하는 도구. 실행하여 설치하세요:

    cargo install ldproxy
    

⚠️ 참고: std 런타임은 ESP-IDF (Espressif IoT Development Framework)를 호스팅 환경으로 사용하지만 사용자는 설치할 필요가 없습니다. ESP-IDF는 std 애플리케이션을 구축할 때 모든 std 프로젝트가 사용해야 하는 크레이트인 esp-idf-sys에 의해 자동으로 다운로드되고 설치됩니다.

Containers 사용하기

로컬 시스템에 직접 설치하는 대신, 컨테이너 내에서 개발 환경을 호스팅할 수 있습니다. Espressif는 RISC-VXtensa 대상 아키텍처를 모두 지원하고 stdno_std 개발을 모두 가능하게 하는 idf-rust 이미지를 제공합니다.

linux/arm64linux/amd64 플랫폼에 대한 수많은 태그를 찾을 수 있습니다.

각 Rust 릴리스에 대해, 우리는 다음과 같은 명명 규칙으로 태그를 생성합니다:

  • <chip>_<rust-toolchain-version>
    • 예를 들어, esp32_1.64.0.0에는 std를 개발하기 위한 생태계와 1.64.0.0 Xtensa Rust 툴체인이 있는 ESP32no_std 애플리케이션이 포함되어 있습니다.

특별 케이스가 있다.:

  • <chip>은 모든 Espressif 대상과의 호환성을 나타내는 모든 것이 될 수 있습니다.
  • <rust-toolchain-version> can be latest which indicates the latest release of the Xtensa Rust toolchain
  • <rust-toolchain-version>Xtensa Rust 툴체인의 최신 릴리스를 나타내는 최신일 수 있습니다.

운영 체제에 따라 Docker, Podman, 또는 Lima와 같은 컨테이너 런타임을 선택할 수 있습니다.

자신만의 어플리케이션 만들기

적절한 Rust 컴파일러와 툴체인이 설치되면, 이제 애플리케이션을 만들 준비가 되었습니다.

다음과 같은 방법으로 어플리케이션을 만들 수 있습니다.

  • (강력권장) 템플릿에서 생성: 구성된 프로젝트를 제공하고, 시간을 절약하며, 가능한 오류를 방지합니다.

  • cargo를 사용하여 처음부터 시작하세요: 프로젝트의 여러 부분을 구성해야 하기 때문에 더 많은 전문 지식이 필요합니다.

    ⚠️ 참고: Cargo로 프로젝트를 시작하는 것은 어떤 이점도 제공하지 않으며, Rust에서 프로젝트를 생성하는 일반적인 방법이기 때문에 여기에만 언급됩니다.

이 장에서는 cargo로 처음부터 프로젝트를 만드는 방법에 대한 지침을 다루지 않으며, 템플릿 프로젝트에서 프로젝트를 생성하는 데에만 초점을 맞출 것이다.

이 장에서 사용되는 도구는 다음 장 Tooling에서 더 자세히 다룰 것이며, 필요할 때 자유롭게 참조하십시오.

템플릿으로 프로젝트 만들기

현재 두 템플릿 레포지토리를 유지하고있습니다.

두 템플릿 모두 기존 템플릿을 기반으로한 새 프로젝트를 만들 수 있는 도구 cargo-generate 기반으로 합니다.

두 템플릿 모두 기존 템플릿을 기반으로 새 프로젝트를 만들 수 있는 도구인 cargo-generate를 기반으로 합니다. 우리의 경우, esp-idf-template 또는 esp-template를 사용하여 필요한 모든 구성과 종속성을 가진 애플리케이션을 생성할 수 있습니다.

  1. cargo generate를 설치합니다:

    cargo install cargo-generate
    
  2. 템플릿 중 하나를 기반으로 프로젝트를 생성하세요.:

    • esp-template:

      cargo generate esp-rs/esp-template
      

      템플릿 프로젝트에 대한 자세한 내용은 Understanding esp-template을 참조하십시오.

    • esp-idf-template:

      cargo generate esp-rs/esp-idf-template cargo
      

      템플릿 프로젝트에 대한 자세한 내용은 Understanding esp-idf-template을 참조하십시오.

    cargo generate 서브커맨드가 호출되면, 타겟 앱에 관한 몇 가지 질문에 답하라는 메시지가 표시됩니다. 이 과정이 완료되면, 당신은 모든 올바른 구성으로 빌드 가능한 프로젝트를 갖게 될 것입니다.

  3. 생성된 프로젝트를 빌드/실행하세요:

    • cargo build를 사용하여 적절한 툴체인과 대상을 사용하여 프로젝트를 컴파일하세요.
    • cargo run을 사용하여 프로젝트를 컴파일하고, 플래시하고, 타겟 장치로 시리얼 모니터를 여세요.

템플릿에서 개발 컨테이너 사용하기

두 템플릿 저장소 모두 Dev Containers 지원에 대한 프롬프트가 있습니다. 템플릿 README의 Dev Containers 섹션에서 자세한 내용을 참조하십시오.

개발 컨테이너는 Setting up a Development Environment장의 Using Container 섹션에서 설명된 idf-rust 컨테이너 이미지를 사용합니다. 이 이미지는 설치 없이 Espressif 칩용 Rust 애플리케이션을 개발할 준비가 된 환경을 제공합니다. Dev Containers는 또한 Wokwi simulator 시뮬레이터와 통합하여 프로젝트를 시뮬레이션하고 web-flash를 사용하여 컨테이너에서 깜박일 수 있습니다.

esp-template의 이해

이제 no_std 프로젝트를 생성하는 방법을 알았으니, 생성된 프로젝트에 포함된 것을 검사하고, 모든 부분을 이해하고, 실행해 봅시다.

생성된 프로젝트 검사하기

다음 질답으로 esp-template에서 프로젝트를 만들 때:

  • 어떤 MCU가 타겟인가? · esp32c3
  • 고급 템플릿 옵션을 구성하시겠습니까? · false

이 설명을 위해, 우리는 기본값을 사용할 것입니다. 추가 수정을 원한다면, 기본값을 사용하지 않을 때 추가 프롬프트들을 참조하십시오.

다음과 같은 파일 구조를 생성합니다.:

├── .cargo
│   └── config.toml
├── src
│   └── main.rs
├── .gitignore
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
└── rust-toolchain.toml

더 나아가기 전에, 이 파일들이 무엇을 위한 것인지 봅시다.

  • .cargo/config.toml

    • Cargo 구성설정

    • 이것은 프로젝트를 올바르게 구축하기 위한 몇 가지 옵션을 정의합니다.

    • runner = "espflash flash --monitor" - cargo run 으로 코드를 플래시하고 모니터를 할 수 있게합니다.

  • src/main.rs

  • .gitignore

    • 어떤 폴더와 파일을 무시해야 하는지 git에게 알려줍니다.
  • Cargo.toml

    • 일반적인 카고 매니페스트는 프로젝트의 일부 메타 데이터와 종속성을 선언합니다.
  • LICENSE-APACHE, LICENSE_MIT

    • 그것들은 러스트 생태계에서 사용되는 가장 일반적인 라이선스이다.

      다른 라이선스를 사용하려면, 이 파일을 삭제하고 Cargo.toml에서 라이선스를 변경할 수 있습니다.

  • rust-toolchain.toml

    • 사용할 Rust 툴체인을 정의합니다.
      • 툴체인은 당신의 목표에 따라 nightly 또는 esp가 될 것입니다.

Understanding main.rs

 1 #![no_std]
 2 #![no_main]
  • #![no_std]
    • 이것은 러스트 컴파일러에게 이 코드가 libstd를 사용하지 않는다는 것을 알려줍니다.
  • #![no_main]
    • no_main 속성은 이 프로그램이 인수를 받는 명령줄 응용 프로그램에 맞는 표준 메인 인터페이스를 사용하지 않을 것이라고 말한다. 표준 메인 대신, 우리는 사용자 지정 진입점을 정의하기 위해 riscv-rt 크레이트의 항목 속성을 사용할 것입니다. 이 프로그램에서, 우리는 진입점을 main으로 명명했지만, 다른 이름이 사용될 수 있었다. 엔트리포인트 함수는 발산함수여야 한다. 즉, fn foo() -> !; 이 유형은 함수가 절대 반환되지 않는다는 것을 나타냅니다. 이는 프로그램이 절대 종료되지 않는다는 것을 의미합니다.
 4 use esp_backtrace as _;
 5 use esp_println::println;
 6 use hal::{clock::ClockControl, peripherals::Peripherals, prelude::*, timer::TimerGroup, Rtc};
  • use esp_backtrace as _;
    • 우리는 베어메탈 환경에 있기 때문에, 코드에서 패닉이 발생하면 실행되는 패닉 핸들러가 필요합니다.
    • 사용할 수 있는 몇 가지 다른 크레이트(예: panic-halt)가 있지만 esp-backtrace는 백트레이스의 주소를 프린트하는 구현을 제공합니다. espflash/espmonitor와 함께 이러한 주소는 소스 코드 위치로 디코딩될 수 있습니다.
  • use esp_println::println;
    • println! implementation을 제공합니다
  • use hal:{...}
    • 몇가지 사용할 것들을 esp-hal에서 가져옵니다
 8 #[entry]
 9 fn main() -> ! {
10    let peripherals = Peripherals::take();
11    let mut system = peripherals.SYSTEM.split();
12    let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
13
14    // Disable the RTC and TIMG watchdog timers
15    let mut rtc = Rtc::new(peripherals.RTC_CNTL);
16    let timer_group0 = TimerGroup::new(
17        peripherals.TIMG0,
18        &clocks,
19        &mut system.peripheral_clock_control,
20    );
21    let mut wdt0 = timer_group0.wdt;
22    let timer_group1 = TimerGroup::new(
23        peripherals.TIMG1,
24        &clocks,
25        &mut system.peripheral_clock_control,
26    );
27    rtc.swd.disable();
28    rtc.rwdt.disable();
29    wdt0.disable();
30    wdt1.disable();
31
32    println!("Hello world!");
33
34    loop {}
35 }

main 함수 속 내용들:

  • let peripherals = Peripherals::take().unwrap();
    • HAL 드라이버는 보통 PAC(peripheral access crate)을 통해 접근하는 주변 장치의 소유권을 갖는다.
    • 여기서 우리는 PAC(peripheral access crate)의 모든 주변 장치를 가져가서 나중에 HAL 드라이버에게 전달합니다.
  • let mut system = peripherals.SYSTEM.split();
    • 때때로 peripheral 장치(여기서 시스템 peripheral 장치)는 거친 입자이며 HAL 드라이버에 정확히 맞지 않습니다. 그래서 여기서 우리는 시스템 주변 장치를 드라이버에 전달되는 더 작은 조각으로 나눕니다.
  • let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
    • 여기서 우리는 시스템 clock를 구성합니다 - 이 경우, 기본값을 권장합니다
    • clock을 freeze하여 추후에 바꾸지 못하도록 합니다.
    • 몇몇 드라이버들은 rate와 duration 계산 방법에 대한 clock의 레퍼런스를 필요로 합니다
  • 다음 코드 블록은 부팅 후 워치독을 비활성화하기 위해 일부 주변 장치(즉, RTC와 두 타이머 그룹)를 인스턴스화합니다.
    • 이 코드가 없으면 잠시 후 SoC가 다시 부팅됩니다.
    • 재부팅을 방지하는 또 다른 방법은 워치독에 전원을 공급하는 것입니다
  • println!("Hello world!");
    • "Hello world!" 출력합니다
  • loop {}
    • 함수는 절대 반환되지 않아야하기 때문에 루프에서 "아무것도하지 않습니다"

코드 실행

코드를 빌드하고 실행하는 것은 어렵지 않습니다.

cargo run

이렇게 하면 configuration에 따라 코드가 빌드되고 espflash를 실행하여 코드를 보드에 플래시합니다.

우리의 runner configurationespflash--monitor 인수도 있기때문에, 우리는 코드출력을 볼수있습니다.

espflash 를 설치했는지 확인하세요,그렇지 않으면 이 단계가 fail 하게됩니다. espflash 설치방법은 다음과 같습니다.: cargo install espflash

이와 유사한 내용을 확인해야 합니다:

[2023-04-17T14:17:08Z INFO ] Serial port: '/dev/ttyACM0'
[2023-04-17T14:17:08Z INFO ] Connecting...
[2023-04-17T14:17:09Z INFO ] Using flash stub
[2023-04-17T14:17:09Z WARN ] Setting baud rate higher than 115,200 can cause issues
Chip type:         esp32c3 (revision v0.3)
Crystal frequency: 40MHz
Flash size:        4MB
Features:          WiFi, BLE
MAC address:       60:55:f9:c0:39:7c
App/part. size:    203,920/4,128,768 bytes, 4.94%
[00:00:00] [========================================]      13/13      0x0
[00:00:00] [========================================]       1/1       0x8000
[00:00:01] [========================================]      64/64      0x10000
[2023-04-17T14:17:11Z INFO ] Flashing has completed!
Commands:
    CTRL+R    Reset chip
    CTRL+C    Exit

...
Hello world!

여기에 표시되는 것은 1단계 및 2단계 부트로더의 메시지와 "Hello world" 메시지입니다!

이것은 실제 코드가 동작하는 것입니다

재부팅 단축키는 CTRL+R , exit 단축키는 CTRL+C 입니다.

프로젝트를 빌드하는 동안 문제가 발생하면 문제 해결 장을 참조하십시오.

esp-idf-template의 이해

이제 우리는 std 프로젝트를 생성하는 방법을 알았으니, 생성된 프로젝트에 무엇이 포함되어 있는지 검사하고 그것의 모든 부분을 이해하려고 노력합시다.

생성된 프로젝트 점검

다음과 같은 답변으로 esp-idf-template에서 프로젝트를 만들 때:

  • 어떤 MCU를 타겟으로 하시나요? · esp32c3
  • 고급 템플릿 옵션들을 설정하겠습니까? · false

이 설명을 위해, 우리는 디폴트값을 사용할 것입니다. 추가 수정을 원한다면, 디폴트 값을 사용하지 않을 때 additional prompts를 참조하십시오.

다음과 같은 파일 구조를 생성해야 합니다:

├── .cargo
│   └── config.toml
├── src
│   └── main.rs
├── .gitignore
├── build.rs
├── Cargo.toml
├── rust-toolchain.toml
└── sdkconfig.defaults

더 나아가기 전에, 이 파일들이 무엇을 위한 것인지 봅시다.

  • .cargo/config.toml
    • Cargo 구성설정
    • 타겟 포함
    • runner = "espflash flash --monitor" - cargo run 으로 코드를 플래시하고 모니터를 할 수 있게합니다.
    • 사용할 링커를 포함합니다. 위 케이스는 ldproxy를 포함합니다.
    • 활성화된 불안정한 build-std Cargo 기능이 포함되어 있습니다.
    • 프로젝트가 사용할 ESP-IDF 버전을 esp-idf-sys에 알려주는 ESP-IDF-VERSION 환경 변수를 포함합니다.
  • src/main.rs
    • 새로 생성된 프로젝트의 주요 소스 파일
    • 자세한 내용은 아래의 main.rs의 이해 섹션을 참조하십시오.
  • .gitignore
    • 어떤 폴더와 파일을 무시해야 하는지 git에게 알려줍니다.
  • build.rs
    • ldproxy에 대한 링커 인수를 전파합니다.
  • Cargo.toml
    • 프로젝트의 일부 메타 데이터와 종속성을 선언하는 일반적인 Cargo 매니페스트
  • rust-toolchain.toml
    • 사용할 Rust 툴체인을 정의합니다.
      • 툴체인은 당신의 목표에 따라 nightly 또는 esp 될 것입니다.
  • sdkconfig.defaults
    • ESP-IDF 기본값에서 재정의된 값을 포함합니다.

main.rs의 이해

1 use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
2
3 fn main() {
4     // It is necessary to call this function once. Otherwise some patches to the runtime
5     // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
6     esp_idf_sys::link_patches();
7     println!("Hello, world!");
8 }

첫 번째 줄은 루트 크레이트가 주 함수를 정의하는 바이너리 상자일 때 ESP-IDF 진입점이 정의된 것을 가져오기입니다.

그런 다음, 우리는 몇 줄이 있는 일반적인 주요 기능을 가지고 있습니다:

  • Rust에서 구현된 ESP-IDF에 대한 몇 가지 패치가 최종 실행 파일과 연결되도록 하는 esp_idf_sys::link_patches 함수에 대한 호출

    우리는 콘솔에 유명한 "Hello, world!"를 인쇄합니다.

코드 실행하기

코드를 빌드하고 실행하는 것은 어렵지 않습니다.

cargo run

이렇게 하면 configuration에 따라 코드가 빌드되고 espflash를 실행하여 코드를 보드에 플래시합니다.

우리의 runner configurationespflash--monitor 인수도 있기때문에, 우리는 코드출력을 볼수있습니다.

espflash 를 설치했는지 확인하세요,그렇지 않으면 이 단계가 fail 하게됩니다. espflash 설치방법은 다음과 같습니다.: cargo install espflash

이와 유사한 내용을 확인해야 합니다:

[2023-04-18T08:05:09Z INFO ] Connecting...
[2023-04-18T08:05:10Z INFO ] Using flash stub
[2023-04-18T08:05:10Z WARN ] Setting baud rate higher than 115,200 can cause issues
Chip type:         esp32c3 (revision v0.3)
Crystal frequency: 40MHz
Flash size:        4MB
Features:          WiFi, BLE
MAC address:       60:55:f9:c0:39:7c
App/part. size:    478,416/4,128,768 bytes, 11.59%
[00:00:00] [========================================]      13/13      0x0
[00:00:00] [========================================]       1/1       0x8000
[00:00:04] [========================================]     227/227     0x10000
[2023-04-18T08:05:15Z INFO ] Flashing has completed!
Commands:
    CTRL+R    Reset chip
    CTRL+C    Exit

...
I (344) cpu_start: Starting scheduler.
Hello, world!

여기에 표시되는 것은 1단계 및 2단계 부트로더의 메시지와 "Hello world" 메시지입니다!

이것은 실제 코드가 동작하는 것입니다

재부팅 단축키는 CTRL+R , exit 단축키는 CTRL+C 입니다.

프로젝트를 빌드하는 동안 문제가 발생하면 문제 해결 장을 참조하십시오.

no_std 어플리케이션 만들기

no_std 애플리케이션을 개발하는 방법을 배우고 싶다면, 다음 교육 자료를 참조하십시오:

교육은 ESP32-C3-DevKit-RUST-1을 기반으로 합니다. 다른 Espressif 개발 보드를 사용할 수 있지만 코드 변경 및 구성 변경이 필요할 수 있습니다.

⚠️ 참고: 모든 SoC esp-hal의 예제 폴더 아래에 특정 주변 장치의 사용을 다루는 몇 가지 예가 있습니다. 예: esp32c3-hal/examples

std 어플리케이션 만들기

std 애플리케이션을 개발하는 방법을 배우고 싶다면, Ferrous Systems와 함께 개발된 다음 교육 자료를 참조하십시오:

교육은 ESP32-C3-DevKit-RUST-1을 기반으로 합니다. 다른 Espressif 개발 보드를 사용할 수 있지만, 코드 변경과 구성 변경이 필요할 수 있습니다.

⚠️ 참고: esp-idf-hal의 예제 폴더 아래에 특정 주변 장치의 사용을 다루는 몇 가지 예가 있습니다. 즉, esp-idf-hal/examples.

개발도구

이제 필요한 종속성을 설치했고, 템플릿 프로젝트를 생성하는 방법을 알고 있기 때문에, 몇 가지 도구를 더 자세히 다룰 것입니다. 이 도구들은 Espressif chips을 위한 Rust 애플리케이션을 훨씬 쉽게 개발할 것이다.

이 장에서, 우리는 espflash/cargo-espflash를 제시하고, Visual Studio Code를 IDE로 제안하고, 현재 사용 가능한 시뮬레이션 및 디버깅 방법을 파헤칠 것입니다.

Visual Studio Code

더 일반적인 개발 환경 중 하나는 RA라고도 알려진 Rust Analyzer와 함께 Microsoft의 Visual Studio Code 텍스트 편집기입니다.

Visual Studio Code는 풍부한 확장 생태계를 갖춘 오픈 소스 및 크로스 플랫폼 그래픽 텍스트 편집기입니다. Rust Analyzer extension은 Rust를 위한 언어 서버 프로토콜의 구현을 제공하며 자동 완성, 이동 정의 등과 같은 기능을 추가로 포함합니다.

Visual Studio Code는 가장 인기 있는 패키지 관리자를 통해 설치할 수 있으며, 설치 프로그램은 공식 웹사이트에서 사용할 수 있습니다. Rust Analyzer extension은 내장된 확장 관리자를 통해 Visual Studio Code에 설치할 수 있습니다.

Rust Analyzer와 함께 도움이 될 수 있는 다른 extension들이 있습니다:

팁과 요령

no_std에서의 Rust Analyzer 사용하기

std를 지원하지 않는 대상을 위해 개발하는 경우, Rust Analyzer는 이상하게 동작할 수 있으며, 종종 다양한 오류를 보고합니다. 이것은 프로젝트에 .vscode/settings.json 파일을 만들고 다음을 채워서 해결할 수 있습니다:

{
  "rust-analyzer.checkOnSave.allTargets": false
}

Cargo Hints When Using Custom Toolchains

커스텀 툴체인을 사용할때 Cargo hints

Xtensa 대상과 마찬가지로 사용자 지정 툴체인을 사용하는 경우, 사용자 경험을 개선하기 위해 rust-toolchain.toml 파일을 통해 cargo에 몇 가지 힌트를 제공할 수 있습니다.

[toolchain]
channel = "esp"
components = ["rustfmt", "rustc-dev"]
targets = ["xtensa-esp32-none-elf"]

다른 IDE들

우리는 Rust를 잘 지원하고 개발자들 사이에서 인기가 있기 때문에 VS Code를 다루기로 결정했습니다. CLionvim과 같은 유사한 Rust를 지원하는 다른 IDE도 있지만, 이는 이 책의 범위를 벗어납니다.

espflash

espflash는 Espressif SoCs 와 modules을 위한 esptool.py를 기반으로 하는 시리얼 플래시 usb 유틸리티입니다.

espflash 저장소에는 두 개의 crate들, cargo-espflashespflash가 포함되어 있습니다. 이 crate 대한 자세한 내용은 아래의 각 섹션을 참조하십시오.

⚠️ Note: 아래에 표시된 espflashcargo-espflash 명령은 버전 2.0 이상이 사용되었다고 가정합니다.

cargo-espflash

교차 컴파일과 플래싱을 처리하는 cargo에 대한 하위 명령을 제공합니다.

cargo-espflash를 설치하려면, 필요한 종속성이 설치되어 있는지 확인한 다음, 다음 명령을 실행하십시오:

cargo install cargo-espflash

이 명령은 Cargo 프로젝트, 즉 Cargo.toml 파일이 포함된 디렉토리 내에서 실행되어야 합니다. 예를 들어, 'blinky'라는 예제를 만들려면, 결과 바이너리를 장치에 플래시한 다음, 시리얼 모니터를 시작하십시오:

cargo espflash flash --example=blinky --monitor

자세한 내용은 cargo-espflash README를 참조하십시오.

espflash

ELF 파일을 장치에 플래시하는 독립형 명령줄 애플리케이션을 제공합니다.

espflash를 설치하려면, 필요한 종속성이 설치되어 있는지 확인한 다음, 다음 명령을 실행하십시오:

cargo install espflash

이미 다른 방법으로 ELF 바이너리를 구축했다고 가정하면, 특히 espflash를 사용하여 장치에 다운로드하고 시리얼 포트를 모니터링할 수 있습니다. 예를 들어, idf.py를 사용하여 ESP-IDF에서 getting-started/blinky예제를 구축했다면, 다음과 같은 것을 실행할 수 있습니다:

espflash flash build/blinky --monitor

자세한 내용은 espflash README를 참조하십시오.

espflash는 프로젝트의 .cargo/config.toml 파일에 다음을 추가하여 Cargo runner로 사용할 수 있습니다.

[target.'cfg(any(target_arch = "riscv32", target_arch = "xtensa"))']
runner = "espflash flash --monitor"

이 구성을 사용하면 cargo run을 사용하여 애플리케이션을 플래시하고 모니터링할 수 있습니다.

디버깅

이 장에서 다룰 다른 도구를 사용하여 러스트 응용 프로그램을 디버깅하는 것도 가능합니다.

모든 디버깅 방법에서 어떤 칩이 지원되는지 보려면 아래 표를 참조하십시오:

probe-rsOpenOCD
ESP32
ESP32-C2
ESP32-C3
ESP32-C6
ESP32-H2
ESP32-S2
ESP32-S3

USB-JTAG-SERIAL Peripheral

우리의 최근 제품 중 일부는 외부 하드웨어 디버거 없이 디버깅할 수 있는 USB-JTAG-SERIAL주변 장치를 포함합니다. 인터페이스 구성에 대한 자세한 정보는 이 주변 장치를 지원하는 칩의 공식 문서에서 찾을 수 있습니다:

  • ESP32-C3

    • 내장 JTAG 인터페이스의 가용성은 ESP32-C3 개정판에 따라 다릅니다:
      • 0.3보다 오래된 개정판에는 JTAG 인터페이스가 내장되어 있지 않습니다.
      • 개정판 0.3(및 그 이상)에는 JTAG 인터페이스가 내장되어 있으며, 디버깅하기 위해 외부 장치를 연결할 필요가 없습니다.

    ESP32-C3 개정판을 찾으려면, 다음을 실행하세요:

    cargo espflash board-info
    # or
    espflash board-info
    
  • ESP32-C6

  • ESP32-H2

  • ESP32-S3

probe-rs

probe-rs 프로젝트는 다양한 디버그 프로브를 사용하여 임베디드 MCU와 상호 작용하는 도구 세트입니다. 그것은 OpenOCD, pyOCD, Segger tools 등과 유사하다. 다음을 포함하되 이에 국한되지 않는 도구 모음과 함께 ARM & RISC-V 아키텍처에 대한 지원이 있습니다.

probe-rs 웹사이트의 설치셋업 지침을 따르세요.

USB-JTAG-SERIAL peripheral 장치가 포함된 Espressif 제품은 외부 하드웨어 없이 probe-rs를 사용할 수 있습니다.

probe-rs으로 플래싱하기

probe-rsESP-IDF image format을 지원하기 때문에 대상에 어플리케이션을 플래시하는 데 사용할 수 있습니다.

  • ESP32-C3 플래싱하는 명령어 예제: probe-rs run --chip esp32c3

flash 명령은 프로젝트의 .cargo/config.toml파일에 다음을 추가하여 사용자 지정 Cargo runner로 설정할 수 있습니다.

[target.'cfg(any(target_arch = "riscv32", target_arch = "xtensa"))']
runner = "probe-rs run --chip esp32c3"

이 구성을 사용하면 cargo run을 사용하여 애플리케이션을 플래시하고 모니터링할 수 있습니다.

VS Code 익스텐션

VS 코드에는 probe-rs 확장이 있습니다. 설치, 구성 및 사용 방법에 대한 자세한 내용은 probe-rs VS Code 문서를 참조하십시오.

launch.json 예제

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "probe-rs-debug",
            "request": "launch",
            "name": "Launch",
            "cwd": "${workspaceFolder}",
            "chip": "esp32c3", //!MODIFY
            "flashingConfig": {
                "flashingEnabled": true,
                "resetAfterFlashing": true,
                "haltAfterReset": true,
                "formatOptions": {
                    "format": "idf" //!MODIFY (or remove). Valid values are: 'elf'(default), 'idf'
                }
            },
            "coreConfigs": [
                {
                    "coreIndex": 0,
                    "programBinary": "target/riscv32imc-unknown-none-elf/debug/${workspaceFolderBasename}", //!MODIFY
                    "rttEnabled": true,
                    "rttChannelFormats": [
                        {
                            "channelNumber": 0,
                            "dataFormat": "String",
                            "showTimestamp": true,
                        }
                    ]
                }
            ]
        },
        {
            "type": "probe-rs-debug",
            "request": "attach",
            "name": "Attach",
            "cwd": "${workspaceFolder}",
            "chip": "esp32c3", //!MODIFY
            "coreConfigs": [
                {
                    "coreIndex": 0,
                    "programBinary": "target/riscv32imc-unknown-none-elf/debug/${workspaceFolderBasename}", //!MODIFY
                    "rttEnabled": true,
                    "rttChannelFormats": [
                        {
                            "channelNumber": 0,
                            "dataFormat": "String",
                            "showTimestamp": true,
                        }
                    ]
                }
            ]
        }
    ]
}

⚠️ 참고: 예제 launch.jsonrtt를 사용하며, esp-printlnesp-backtrace와 같은 일부 상자에서 이러한 기능을 활성화해야 할 수 있습니다. esp-printlnesp-backtrace를 사용하는 ESP32-C3 no_std 프로젝트 예제:

esp-backtrace = { version = "0.9.0", features = ["esp32c3", "panic-handler", "exception-handler", "print-rtt"] }
esp-println = { version = "0.7.0", features = ["esp32c3", "rtt"], default-features = flase }

Launch 구성은 장치를 플래시하고 디버깅 프로세스를 시작하는 반면 Attach는 이미 실행 중인 장치의 응용 프로그램에서 디버깅을 시작합니다. 자세한 내용은 launch와 attach의 차이점 에 대한 VS Code 문서를 참조하십시오.

cargo-flashcargo-embed

probe-rs는 이 두 가지 도구와 함께 제공됩니다:

  • cargo-flash: 빌드된 바이너리를 타겟에 다운로드하고 실행하는 플래시 도구.
  • cargo-embed: RTT 터미널이나 GDB 서버를 열 수 있는 cargo-flash의 슈퍼셋. configuration file은 동작을 정의하는 데 사용할 수 있다.

GDB Integration

probe-rs에는 일반적인 도구로 일반적인 워크플로우에 통합할 수 있는 GDB 스텁이 포함되어 있습니다. probe-rs gdb 명령은 기본적으로 포트 1337에서 GDB 서버를 실행합니다.

지원되는 모든 Espressif 제품이 있는 GDB는 espressif/binutils-gdb에서 얻을 수 있습니다.

OpenOCD

probe-rs와 마찬가지로, OpenOCD는 Xtensa 아키텍처를 지원하지 않습니다. 그러나, Espressif는 Espressif의 칩을 지원하는 espressif/openocd-esp32 리포지토리에서 OpenOCD의 fork 리포지토리를 유지합니다.

플랫폼에 openocd-esp32를 설치하는 방법에 대한 지침은 Espressif 문서에서 찾을 수 있습니다.

지원되는 모든 Espressif 제품이 있는 GDB는 espressif/binutils-gdb에서 얻을 수 있습니다.

일단 설치되면, 올바른 인수로 openocd를 실행하는 것만큼 간단합니다. USB-JTAG-SERIAL peripheral 장치가 내장된 칩의 경우, 일반적으로 ESP32-C3에서 즉시 작동하는 구성 파일이 있습니다.

openocd -f board/esp32c3-builtin.cfg

다른 구성의 경우, 칩과 인터페이스를 지정해야 할 수 있습니다. 예를 들어, J-Link가 있는 ESP32:

openocd -f interface/jlink.cfg -f target/esp32.cfg

VS Code Extension

OpenOCD는 Espressif 제품을 디버깅하기 위해 cortex-debug 확장을 통해 VS 코드에서 사용할 수 있습니다.

Configuration

  1. 필요한 경우, 외부 JTAG 어댑터를 연결하세요.
    1. ESP-IDF 프로그래밍 가이드의 다른 JTAG 인터페이스 구성 섹션을 참조하십시오. 예: Section for ESP32

⚠️ Note: Windows에서는, USB Serial Converter A 0403 6010 00드라이버가 WinUSB이어야 합니다.

  1. VSCode 설정하기
    1. Cortex-Debug VS Code 확장 익스텐션 설치하기.
    2. 디버그하려는 프로젝트 트리에 .vscode/launch.json 파일을 만드세요.
    3. executable, svdFile, serverpathtoolchainPrefix 필드를 업데이트하십시오.
{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      // more info at: https://github.com/Marus/cortex-debug/blob/master/package.json
      "name": "Attach",
      "type": "cortex-debug",
      "request": "attach", // launch will fail when attempting to download the app into the target
      "cwd": "${workspaceRoot}",
      "executable": "target/xtensa-esp32-none-elf/debug/.....", //!MODIFY
      "servertype": "openocd",
      "interface": "jtag",
      "toolchainPrefix": "xtensa-esp32-elf", //!MODIFY
      "openOCDPreConfigLaunchCommands": ["set ESP_RTOS none"],
      "serverpath": "C:/Espressif/tools/openocd-esp32/v0.11.0-esp32-20220411/openocd-esp32/bin/openocd.exe", //!MODIFY
      "gdbPath": "C:/Espressif/tools/riscv32-esp-elf-gdb/riscv32-esp-elf-gdb/bin/riscv32-esp-elf-gdb.exe", //!MODIFY
      "configFiles": ["board/esp32-wrover-kit-3.3v.cfg"], //!MODIFY
      "overrideAttachCommands": [
        "set remote hardware-watchpoint-limit 2",
        "mon halt",
        "flushregs"
      ],
      "overrideRestartCommands": ["mon reset halt", "flushregs", "c"]
    }
  ]
}

여러 코어들을 디버깅하기

때때로 GDB 또는 VSCode에서 각 코어를 개별적으로 디버깅해야 할 수도 있습니다. 이 경우, set ESP_RTOS noneset ESP_RTOS hwthread으로 바꾸십시오. 이것은 각 코어를 GDB의 하드웨어 스레드로 보이게 할 것이다. 이것은 현재 Espressif 공식 문서에 문서화되어 있지 않지만 OpenOCD 문서에 문서화되어 있습니다: https://openocd.org/doc/html/GDB-and-OpenOCD.html

시뮬레이팅

프로젝트를 시뮬레이션하는 것은 편리할 수 있다. 그것은 사용자가 CI를 사용하여 프로젝트를 테스트하고, 하드웨어를 사용할 수 없는 프로젝트와 다른 많은 시나리오를 시도할 수 있게 해준다.

현재, Espressif 칩에서 Rust 프로젝트를 시뮬레이션하는 몇 가지 방법이 있다. 모든 방법에는 몇 가지 한계가 있지만, 빠르게 진화하고 매일 나아지고 있다.

이 장에서, 우리는 현재 사용 가능한 시뮬레이션 도구에 대해 논의할 것이다.

모든 시뮬레이션 방법에서 어떤 칩이 지원되는지 보려면 아래 표를 참조하십시오:

WokwiQEMU
ESP32
ESP32-C2
ESP32-C3
ESP32-C6
ESP32-H2
ESP32-S2
ESP32-S3

Wokwi

Wokwi는 Espressif Chips에서 Rust 프로젝트(stdno_std 모두) 시뮬레이션을 지원하는 온라인 시뮬레이터입니다. 예시 목록과 새로운 프로젝트를 시작하는 방법은 wokwi.com/rust를 참조하십시오.

Wokwi는 다른 많은 기능 중에서 Wi-Fi 시뮬레이션, 가상 로직 분석기 및 GDB debugging을 제공합니다. 자세한 내용은 Wokwi 문서를 참조하십시오. ESP 칩의 경우, 현재 지원되는 시뮬레이션 기능 표가 있습니다.

Wokwi VS Code 확장프로그램 사용하기

Wokwi는 몇 개의 파일만 추가하여 코드 편집기에서 직접 프로젝트를 시뮬레이션할 수 있는 VS 코드 확장 프로그램을 제공합니다. 자세한 내용은 Wokwi 문서를 참조하십시오. VS 코드 디버거를 사용하여 코드를 디버깅할 수도 있습니다. 코드 디버깅을 참조하십시오.

templates을 사용하고 기본값을 사용하지 않을 때, 프롬프트가 있습니다 (Wokwi VS Code 확장으로 Wokwi 시뮬레이션을 지원하는 프로젝트 구성) Wokwi VS Code 확장자를 사용하는 데 필요한 파일을 생성합니다.

Wokwi VS Code example

Using wokwi-server

wokwi-server는 프로젝트의 Wokwi 시뮬레이션을 시작하기 위한 CLI 도구입니다. 즉, 기계나 컨테이너에 프로젝트를 구축하고 결과 바이너리를 시뮬레이션할 수 있습니다.

wokwi-server는 또한 칩 자체 이외의 더 많은 하드웨어 부품으로 다른 Wokwi 프로젝트에서 결과 바이너리를 시뮬레이션할 수 있습니다. 자세한 지침은 wokwi-server README의 해당 섹션을 참조하십시오.

커스텀 칩들

Wokwi는 Wokwi에서 지원되지 않는 구성 요소의 동작을 프로그래밍할 수 있는 사용자 지정 칩을 생성할 수 있습니다. 자세한 내용은 공식 Wokwi 문서를 참조하십시오.

커스텀 칩은 Rust로도 쓸 수 있습니다! 자세한 내용은 Wokwi Custom Chip API를 참조하십시오. 예를 들어, Rust의 커스텀 inverter chip.

QEMU

Espressif는 Espressif 칩에서 작동하도록 필요한 패치와 함께 espressif/QEMU에서 QEMU 포크를 유지합니다. QEMU를 구축하고 프로젝트를 에뮬레이트하는 방법에 대한 지침은 QEMU wiki를 참조하십시오.

QEMU를 구축하면, qemu-system-xtensa 파일이 있어야 합니다.

프로젝트를 QEMU에서 실행하기

⚠️ Note: 현재 ESP32만 지원되므로, xtensa-esp32-espidf 대상을 위해 컴파일하고 있는지 확인하세요.

QEMU에서 프로젝트를 실행하려면 부트로더와 파티션 테이블이 병합된 펌웨어/이미지가 필요합니다. 우리는 그것을 생성하기 위해 cargo-espflash를 사용할 수 있습니다:

cargo espflash save-image --chip esp32 --merge <OUTFILE> --release

espflash를 사용하는 것을 선호한다면, 먼저 프로젝트를 구축한 다음 이미지를 생성하여 동일한 결과를 얻을 수 있습니다.

cargo build --release
espflash save-image --merge ESP32 target/xtensa-esp32-espidf/release/<NAME> <OUTFILE>

이제, QEMU에서 이미지를 실행하세요:

/path/to/qemu-system-xtensa -nographic -machine esp32 -drive file=<OUTFILE>,if=mtd,format=raw

문제 해결

이 장에서는 우리가 시간이 지남에 따라 직면한 특정 질문과 일반적인 문제, 그리고 그들의 해결책과 함께 나열합니다. 이 페이지는 선택된 ESP 생태계와 독립적인 일반적인 문제를 수집합니다. 여기에 나열된 문제를 찾을 수 없다면, 적절한 저장소에서 문제를 열거나 Matrix room에서 문의하십시오.

잘못된 Rust Toolchain 사용

$ cargo build
error: failed to run `rustc` to learn about target-specific information

Caused by:
  process didn't exit successfully: `rustc - --crate-name ___ --print=file-names --target xtensa-esp32-espidf --crate-type bin --crate-type rlib --crate-type dylib --crate-type cdylib --crate-type staticlib --crate-type proc-macro --print=sysroot --print=cfg` (exit status: 1)
  --- stderr
  error: Error loading target specification: Could not find specification for target "xtensa-esp32-espidf". Run `rustc --print target-list` for a list of built-in targets

이전 오류나 유사한 오류가 발생한다면, 아마도 적절한 Rust 툴체인을 사용하지 않을 것입니다. Xtensa 대상의 경우, Espressif Rust 포크 툴체인을 사용해야 한다는 것을 기억하세요. 몇 가지 방법이 있습니다:

  • 커맨드 라인에서 툴체인 단축키 재정의: cargo +esp.

  • RUSTUP_TOOLCHAIN 환경 변수를 esp로 설정하세요.

  • 디렉토리 재정의 설정: rustup 재정의 세트 esp

  • 프로젝트에 rust-toolchain.toml 파일을 추가하세요:

    [toolchain]
    channel = "esp"
    
  • esp디폴트 툴체인으로 세팅한다.

툴체인 재정의에 대한 자세한 내용은 The rustup book의 재정의 장을 참조하십시오.

Windows

긴 Path 네임

Windows를 사용할 때, 긴 경로 이름을 사용하는 경우 새 프로젝트를 구축하는 데 문제가 발생할 수 있습니다. 게다가 - 그리고 std 애플리케이션을 빌드하려고 하는 경우 - 프로젝트 경로가 ~ 10자보다 길면 빌드가 어려운 오류와 함께 실패합니다.

문제를 해결하려면 프로젝트 이름을 줄이고 드라이브 루트로 옮겨야 합니다. C:\myproj. 또한 Windows subst 유틸리티(예: subst r: <pathToYourProject>)를 사용하는 동안 프로젝트 위치를 그대로 유지하면서 빌드 중에 짧은 경로를 사용하는 쉬운 솔루션처럼 보일 수 있지만, 짧고 대체된 경로가 Windows API에 의해 실제 (긴) 위치로 확장되기 때문에 작동하지 않습니다.

또 다른 대안은 Linux용 Windows 하위 시스템(WSL)을 설치하고, 네이티브 Linux 파일 파티션 내부로 프로젝트를 이동하고, WSL 내부에 빌드하고, WSL 외부에서 컴파일된 MCU ELF 파일만 플래시하는 것입니다.

Missing ABI

  Compiling cc v1.0.69
error: linker `link.exe` not found
  |
  = note: The system cannot find the file specified. (os error 2)

note: the msvc targets depend on the msvc linker but `link.exe` was not found

note: please ensure that VS 2013, VS 2015, VS 2017 or VS 2019 was installed with the Visual C++ option

error: could not compile `compiler_builtins` due to previous error
warning: build failed, waiting for other jobs to finish...
error: build failed

이 오류의 이유는 MSVC C++가 누락되어 컴파일 시간 요구 사항을 충족하지 못하기 때문입니다. [Visual Studio 2013(또는 그 이상) 또는 Visual C++ Build Tools 2019][ Visual Studio 2013 (or later) or the Visual C++ Build Tools 2019]를 설치하십시오. 비주얼 스튜디오의 경우, "C++ 도구"와 "윈도우 10 SDK" 옵션을 확인하세요. GNU ABI를 사용하는 경우, MinGW/MSYS2 툴체인을 설치하세요.

esp-idf-hal 기반 프로젝트들

LIBCLANG_PATH 환경변수가 정의되지않았을때

thread 'main' panicked at 'Unable to find libclang: "couldn't find any valid shared libraries matching: ['libclang.so', 'libclang-*.so', 'libclang.so.*', 'libclang-*.so.*'], set the `LIBCLANG_PATH` environment variable to a path where one of these files can be found (invalid: [])"', /home/esp/.cargo/registry/src/github.com-1ecc6299db9ec823/bindgen-0.60.1/src/lib.rs:2172:31

우리는 bindgen이 ESP-IDF C 헤더에 Rust 바인딩을 생성하기 위해 libclang이 필요합니다. Espup에서 생성된 내보내기 파일을 소싱했는지 확인하십시오. 환경 변수 설정을 참조하십시오.

ldproxy가 보이지않을때

error: linker `ldproxy` not found
  |
  = note: No such file or directory (os error 2)

std 애플리케이션을 구축하려는 경우 ldproxy를 설치해야 합니다. std 개발 요구 사항 보기

cargo install ldproxy

sdkconfig.defaults파일이 업데이트되었지만 아무런 영향을 미치지 않는 것으로 나타남

적용하려면 sdkconfig.defaults의 변경 사항을 위해 프로젝트를 정리하고 재구성해야 합니다.

cargo clean
cargo build

이 페이지에 언급된 Crate에 대한 문서가 오래되었거나 누락되었습니다

docs.rs에 의해 부과된 자원 제한으로 인해, 문서를 작성하는 동안 인터넷 접속이 차단됩니다. 이러한 이유로, 우리는 esp-idf-sys 또는 그것에 따라 어떤 crate에도 대한 문서를 만들 수 없습니다.

대신, 우리는 문서를 만들고 GitHub 페이지에서 직접 호스팅하고 있습니다:

작업 main의 스택 오버플로가 감지되었습니다

2단계 부트로더가 이 오류를 보고한다면, 주요 작업에 대한 스택 크기를 늘려야 할 것입니다. 이것은 sdkconfig.defaults 파일에 다음을 추가하여 수행할 수 있습니다:

CONFIG_ESP_MAIN_TASK_STACK_SIZE=7000

이 예에서, 우리는 주요 작업의 스택에 7kB를 할당하고 있다.

워치독 타이머를 비활성화하는 방법?

sdkconfig.defaults 파일에 추가하세요:

CONFIG_INT_WDT=n
CONFIG_ESP_TASK_WDT=n

이러한 구성 파일을 수정할 때 재구축하기 전에 프로젝트를 정리해야 한다는 것을 기억하세요.

espflash

rtc_clk_init: Possibly invalid CONFIG_XTAL_FREQ setting

이 문제는 26MHz 크리스탈 오실레이터가 있는 ESP32 모듈을 사용하는 사용자에 의해 보고됩니다. 이 문제의 근본 원인은 espflash에 의해 깜박이는 기본 부트로더가 40MHz 크리스탈을 예상한다는 것이다.

esp-idf-sys 기반 프로젝트 빌드하는 경우

26MHz 크리스탈을 사용하도록 sdkconfig가 제대로 설정되어 있는지 확인하세요. 다음과 같은 구성 옵션을 포함해야 합니다:

CONFIG_XTAL_FREQ_26=y

또한 espflash보다 cargo-espflash를 사용하는 것을 선호해야 합니다. cargo-espflash는 프로젝트와 통합되며 기본 부팅 로더 대신 프로젝트 옆에 내장된 부트로더를 플래시합니다.

espflash를 사용하려면, --bootloader를 사용하여 적절한 부트로더 이미지를 지정해야 합니다. target/<MCU의 대상 폴더>/<빌드에 따라 디버그 또는 릴리스>/build/esp-idf-sys-*/build/bootloader/bootloader.bin에서 부트로더를 찾을 수 있습니다.

esp-hal 기반 프로젝트를 구축하는 경우

HAL(ESP32, ESP32-C2)이 올바른 결정 주파수로 구성되어 있는지 확인하세요. 이렇게 하려면, 기본 기능을 비활성화하고 xtal-26mhz를 활성화해야 합니다(다른 기본 기능 외에).

flasing 일때, --bootloader를 사용하여 적절한 부트로더 이미지를 지정해야 합니다. 현재 esp-idf 기반 프로젝트를 사용하여 이 부트로더를 구축해야 합니다(Rust 또는 C 기반은 동등하게 작동해야 하며, esp-idf-template로 설정된 프로젝트를 권장합니다).