Skip to content

Commit

Permalink
add esp32c3 examples (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
felixwrt authored Jun 21, 2024
1 parent 85bea74 commit 7deb880
Show file tree
Hide file tree
Showing 28 changed files with 962 additions and 2 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/quickstart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,36 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
- run: cargo build -p sml-rs-serialport-example

build_esp_examples:
name: ESP Examples
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
project:
- esp32c3-power-meter-mock
- esp32c3-sml-reader
- esp32c3-sml-reader-async
action:
- command: build
args: --release
- command: build
args: --release --all-features
- command: fmt
args: --all -- --check --color always
- command: clippy
args: --all-features --workspace -- -D warnings
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@v1
with:
target: riscv32imc-unknown-none-elf
toolchain: nightly
components: rust-src, rustfmt, clippy
- name: Build
working-directory: examples/embedded/${{ matrix.project }}
run: cargo ${{ matrix.action.command }} ${{ matrix.action.args }}

lints:
name: Lints
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Embedded examples for the ESP32-C3 (#37)

## [0.4.0] - 2024-06-04

### Added
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ members = [".", "examples/serialport"]
[package]
name = "sml-rs"
version = "0.4.0"
authors = ["Felix Wirth <[email protected]>"]
authors = ["Felix Wirth <[email protected]>"]
description = "Smart Message Language (SML) parser written in Rust"
repository = "https://github.com/felixwrt/sml-rs"
license = "MIT OR Apache-2.0"
Expand Down
18 changes: 18 additions & 0 deletions examples/embedded/esp32c3-power-meter-mock/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[target.riscv32imc-unknown-none-elf]
runner = "espflash flash --monitor"


[env]
ESP_LOGLEVEL="INFO"

[build]
rustflags = [
# Required to obtain backtraces (e.g. when using the "esp-backtrace" crate.)
# NOTE: May negatively impact performance of produced code
"-C", "force-frame-pointers",
]

target = "riscv32imc-unknown-none-elf"

[unstable]
build-std = ["core"]
10 changes: 10 additions & 0 deletions examples/embedded/esp32c3-power-meter-mock/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"rust-analyzer.check.allTargets": false,
}
40 changes: 40 additions & 0 deletions examples/embedded/esp32c3-power-meter-mock/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[package]
name = "esp32c3-power-meter-mock"
version = "0.1.0"
authors = ["Felix Wirth <[email protected]>"]
edition = "2021"
license = "MIT OR Apache-2.0"

[workspace]

[dependencies]
embedded-io = "0.6.1"
esp-backtrace = { version = "0.12.0", features = [
"esp32c3",
"exception-handler",
"panic-handler",
"println",
] }
esp-hal = { version = "0.18.0", features = ["embedded-io", "esp32c3"] }
esp-hal-smartled = { version = "0.11.0", features = ["esp32c3"], optional = true}
esp-println = { version = "0.9.1", features = ["esp32c3", "log"] }
hex-literal = "0.4.1"
log = { version = "0.4.21" }
smart-leds = { version = "0.4.0", optional = true }

[features]
smart-led = ["dep:smart-leds", "dep:esp-hal-smartled"]

[profile.dev]
# Rust debug is too slow.
# For debug builds always builds with some optimization
opt-level = "s"

[profile.release]
codegen-units = 1 # LLVM can perform better optimizations using a single thread
debug = 2
debug-assertions = false
incremental = false
lto = 'fat'
opt-level = 's'
overflow-checks = false
52 changes: 52 additions & 0 deletions examples/embedded/esp32c3-power-meter-mock/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# esp32c3 Power Meter Mock

This is a simple program for the ESP32-C3 that continuously sends sml messages via UART.

The example is used to mock a digital german power meter and test the [`sml-rs`][1] library.

It sends an sml message approximately every second and turns an LED on while sending the data.

## Configuration

By default, the following pins are used:

- GPIO 9: UART TX pin used to send data
- GPIO 10: UART RX pin (unused, but needs to be provided to the UART peripheral)
- GPIO 18: LED pin (see below)

You can adapt the pin configuration in the source code (see the comment block "Pin configuration").

### Led configuration

This project can use either a smart RGB LED (such as the one found on the [ESP32-C3-DevKitC-02][2]) or a simple LED that can
be driven by setting the output to high / low.

By default, this project assumes a regular LED. Activate the `smart-led` feature to use a smart RGB LED:

```
cargo ... --features smart-led
```

## Usage

Install [`espflash`][3]:

```
cargo install espflash
```

Flash and run the example:

```
cargo run --relase
```

When using a smart RGB LED:

```
cargo run --relase --features smart-led
```

[1]: https://github.com/felixwrt/sml-rs
[2]: https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/hw-reference/esp32c3/user-guide-devkitc-02.html
[3]: https://github.com/esp-rs/espflash/tree/main/espflash
3 changes: 3 additions & 0 deletions examples/embedded/esp32c3-power-meter-mock/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
println!("cargo:rustc-link-arg-bins=-Tlinkall.x");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[toolchain]
channel = "nightly"
components = ["rust-src"]
targets = ["riscv32imc-unknown-none-elf"]

112 changes: 112 additions & 0 deletions examples/embedded/esp32c3-power-meter-mock/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#![no_std]
#![no_main]

use esp_backtrace as _;
#[cfg(not(feature = "smart-led"))]
use esp_hal::gpio::AnyOutput;
use esp_hal::{
clock::ClockControl,
delay::Delay,
gpio::{Io, Level},
peripherals::Peripherals,
prelude::*,
system::SystemControl,
uart::{
config::{Config, StopBits},
TxRxPins, Uart,
},
};
use hex_literal::hex;

#[cfg(feature = "smart-led")]
use esp_hal::rmt::Rmt;
#[cfg(feature = "smart-led")]
use esp_hal_smartled::{smartLedBuffer, SmartLedsAdapter};
#[cfg(feature = "smart-led")]
use smart_leds::RGB;

use embedded_io::Write;

// test data taken from https://github.com/devZer0/libsml-testing/blob/master/ISKRA_MT631-D1A52-K0z-H01_with_PIN.hex
const TEST_DATA: &[&[u8]] = &[
&hex!("1B1B1B1B010101017605099DFAAC6200620072630101760101050334A8E40B0A0149534B00047A5544726201650334A737620163D0BB007605099DFAAD620062007263070177010B0A0149534B00047A5544070100620AFFFF726201650334A737757707010060320101010101010449534B0177070100600100FF010101010B0A0149534B00047A55440177070100010800FF650010010401621E52FF650137C0C70177070100020800FF0101621E52FF62000177070100100700FF0101621B52005300C101010163F376007605099DFAAE620062007263020171016342DD001B1B1B1B1A0038EB"),
&hex!("1B1B1B1B010101017605099DFAAF6200620072630101760101050334A8E50B0A0149534B00047A5544726201650334A73862016303AF007605099DFAB0620062007263070177010B0A0149534B00047A5544070100620AFFFF726201650334A738757707010060320101010101010449534B0177070100600100FF010101010B0A0149534B00047A55440177070100010800FF650010010401621E52FF650137C0C80177070100020800FF0101621E52FF62000177070100100700FF0101621B52005300C201010163EA6F007605099DFAB162006200726302017101634BB0001B1B1B1B1A000705"),
&hex!("1B1B1B1B010101017605099DFAB26200620072630101760101050334A8E60B0A0149534B00047A5544726201650334A739620163DC95007605099DFAB3620062007263070177010B0A0149534B00047A5544070100620AFFFF726201650334A739757707010060320101010101010449534B0177070100600100FF010101010B0A0149534B00047A55440177070100010800FF650010010401621E52FF650137C0C80177070100020800FF0101621E52FF62000177070100100700FF0101621B52005300C101010163B703007605099DFAB462006200726302017101638FBB001B1B1B1B1A00D07B"),
&hex!("1B1B1B1B010101017605099DFAB56200620072630101760101050334A8E70B0A0149534B00047A5544726201650334A73A620163AE9F007605099DFAB6620062007263070177010B0A0149534B00047A5544070100620AFFFF726201650334A73A757707010060320101010101010449534B0177070100600100FF010101010B0A0149534B00047A55440177070100010800FF650010010401621E52FF650137C0C90177070100020800FF0101621E52FF62000177070100100700FF0101621B52005300C20101016324B6007605099DFAB762006200726302017101633C45001B1B1B1B1A00C2C5"),
&hex!("1B1B1B1B010101017605099DFAB86200620072630101760101050334A8E80B0A0149534B00047A5544726201650334A73B620163B08E007605099DFAB9620062007263070177010B0A0149534B00047A5544070100620AFFFF726201650334A73B757707010060320101010101010449534B0177070100600100FF010101010B0A0149534B00047A55440177070100010800FF650010010401621E52FF650137C0C90177070100020800FF0101621E52FF62000177070100100700FF0101621B52005300C201010163EAD0007605099DFABA620062007263020171016352F2001B1B1B1B1A00382E"),
];

#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = SystemControl::new(peripherals.SYSTEM);
let clocks = ClockControl::max(system.clock_control).freeze();
let delay = Delay::new(&clocks);
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);

// -----------------------------------------------------------------------
// Pin configuration - adapt to your board
// -----------------------------------------------------------------------
let led_pin = io.pins.gpio18;
let tx_pin = io.pins.gpio9;
// rx is unused, but needs to be provided for UART
let rx_pin = io.pins.gpio10;
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------

// Init logging
esp_println::logger::init_logger_from_env();

// LED Configuration
let mut led;
#[cfg(feature = "smart-led")]
{
let rmt = Rmt::new(peripherals.RMT, 80.MHz(), &clocks, None).unwrap();
let rmt_buffer = smartLedBuffer!(1);
led = SmartLedsAdapter::new(rmt.channel0, led_pin, rmt_buffer, &clocks);
}
#[cfg(not(feature = "smart-led"))]
{
led = AnyOutput::new(led_pin, Level::High);
}

// UART Configuration
let pins = TxRxPins::new_tx_rx(tx_pin, rx_pin);
let uart_config = Config::default()
.baudrate(9600)
.parity_none()
.stop_bits(StopBits::STOP1);
let mut uart1 =
Uart::new_with_config(peripherals.UART1, uart_config, Some(pins), &clocks, None);

// Main Loop
let mut data_iter = TEST_DATA.iter().cycle();
loop {
let data = data_iter.next().unwrap();
log::info!("Sending data!");
led_write(&mut led, Level::High);

uart1.write(data).unwrap();

led_write(&mut led, Level::Low);
delay.delay(1000.millis());
}
}

#[cfg(feature = "smart-led")]
fn led_write<S>(led: &mut S, level: Level)
where
S: smart_leds::SmartLedsWrite<Color = RGB<u8>>,
S::Error: core::fmt::Debug,
{
let color = match level {
Level::High => RGB::new(0, 0, 2),
Level::Low => RGB::new(0, 0, 0),
};
led.write([color]).unwrap()
}
#[cfg(not(feature = "smart-led"))]
fn led_write(led: &mut AnyOutput, level: Level) {
led.set_level(level)
}
18 changes: 18 additions & 0 deletions examples/embedded/esp32c3-sml-reader-async/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[target.riscv32imc-unknown-none-elf]
runner = "espflash flash --monitor"


[env]
ESP_LOGLEVEL="INFO"

[build]
rustflags = [
# Required to obtain backtraces (e.g. when using the "esp-backtrace" crate.)
# NOTE: May negatively impact performance of produced code
"-C", "force-frame-pointers",
]

target = "riscv32imc-unknown-none-elf"

[unstable]
build-std = ["core"]
10 changes: 10 additions & 0 deletions examples/embedded/esp32c3-sml-reader-async/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"rust-analyzer.check.allTargets": false,
}
43 changes: 43 additions & 0 deletions examples/embedded/esp32c3-sml-reader-async/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[package]
name = "esp32c3-sml-reader-async"
version = "0.1.0"
authors = ["Felix Wirth <[email protected]>"]
edition = "2021"
license = "MIT OR Apache-2.0"

[workspace]

[dependencies]
embassy-executor = { version = "0.5.0", features = ["task-arena-size-40960"] }
embassy-time = { version = "0.3.0", features = ["generic-queue-8"] }
embedded-io-async = "0.6.1"
esp-backtrace = { version = "0.12.0", features = [
"esp32c3",
"exception-handler",
"panic-handler",
"println",
] }
esp-hal = { version = "0.18.0", features = ["embedded-io-async", "esp32c3", "async"] }
esp-hal-embassy = { version = "0.1.0", features = ["esp32c3", "time-timg0"] }
esp-hal-smartled = { version = "0.11.0", features = ["esp32c3"], optional = true}
esp-println = { version = "0.9.1", features = ["esp32c3", "log"] }
log = { version = "0.4.21" }
smart-leds = { version = "0.4.0", optional = true }
sml-rs = { version = "0.4.0", default-features = false }

[features]
smart-led = ["dep:smart-leds", "dep:esp-hal-smartled"]

[profile.dev]
# Rust debug is too slow.
# For debug builds always builds with some optimization
opt-level = "s"

[profile.release]
codegen-units = 1 # LLVM can perform better optimizations using a single thread
debug = 2
debug-assertions = false
incremental = false
lto = 'fat'
opt-level = 's'
overflow-checks = false
Loading

0 comments on commit 7deb880

Please sign in to comment.