
For now, only the -c3. --- Open up LEDC fade support to all chips. The C6 chip needs some special handling because its fade registers also handle gamma, and the ESP chip needs some special handling because it has two banks of channels. The code to handle these is already present in channel.rs, but needs to be copied and adapted. Do that, and drop all the esp32c3 feature checks. --- Add a function to poll the duty-fade state Use the unmasked interrupt bit in the LEDC register block, since that will get updated by the hardware whether or not we've connected anything to the interrupt source. Also be sure to clear that bit before starting a new fade, so it's always clear while fading. This will allow dumb (non-async-code) polling of the fade state after one is started by the start_duty_fade API. --- Fix non-C3 devices to use the right int_raw bits These are inconsistently named between the esp32 variants. --- Add examples of hardware duty-cycle fading Just a relatively simple zero to 100 and back to zero, over a total of 2 seconds, to get a breathing effect. This does make the main loop{} have a 2-second period instead of the current nearly-zero period, but nothing else is happening so that's fine. --- Fix two bugs in hardware fading When figuring out how many duty-cycle changes need to happen per counter overflow, we need to use the absolute value of the difference between the start and end duty values, not the raw difference. When fading from (e.g.) 100% to 0, this will overflow, and both the debug-mode panic and the release-mode wrapping behavior give the wrong delta value. So calculate an absolute value difference first, and use that. Then, when running through the while loop that allocates bits between pwm_cycles and duty_cycle, the check on pwm_cycles was wrong -- since the value reduces each time through the loop, we need to keep looping as long as it's *above* some threshold, not below. --- Simplify and refactor duty-cycle fade code I'm not sure if this will fix the extremely-short fade times that we're seeing with the older code, but we'll see. Move all the calculations out of the ChannelHW implementations, and make those *just* set registers. The calculations are the same for all chip variants, so don't need to be duplicated for each chip feature, like the register macros are. Change the calculations from a loop doing bit shifts, to an explicit division and a couple of range checks. This way we can get a lot closer to the requested percentages and durations. Use the u32::abs_diff function instead of open-coding it (now that I see it exists). Use u16::try_from() to limit the range of values, and use try_into<u16> and map_err and the ? operator to more clearly handle numbers out of range. Drop the Result<> return type from the ChannelHW function, as it can't fail anymore. Fix the duty_range value -- before, when duty_exp was (say) 8, duty_range would be 256, and if one of the *_duty_pct values was 100, the start or end duty value would be too big. The range of start and end duty values is 0..255, so we have to subtract one to handle 100%. Finally, add a comment on the is_duty_fade_running{,_hw} methods. --- Some fades can't work; return errors for them. Add a new Error enum value with a sub-error enum with more details. Return it from the error cases in the fade method. If the calculated cycles_per_step is more than 10 bits, fail as well; the field in the register is only 10 bits wide. Fix all the examples to run a 1-second fade instead of a 2-second, since the 2-second fade will run into this error. (Assert that, as well.) --- When fading on a -c6 chip, set two more registers The gamma functionality of -c6 chips needs two more fields set. One tells the chip how many gamma stages it should iterate through, but we only implement linear fading, so always use 1. The other tells the chip to latch the value of the other gamma registers into the chosen slot, so even though its value never changes, the write needs to happen. --- Add changelog entry
esp32c3-hal
no_std
HAL for the ESP32-C3 from Espressif. Implements a number of the traits defined by embedded-hal.
This device uses the RISC-V ISA, which is officially supported by the Rust compiler via the riscv32imc-unknown-none-elf
target. Refer to the Getting Started section below for more information.
Documentation
Getting Started
Installing the Rust Compiler Target
The compilation target for this device is officially supported via the stable
release channel and can be installed via rustup:
$ rustup target add riscv32imc-unknown-none-elf
Supported boot methods
IDF Bootloader
The IDF second stage bootloader is the default bootloader solution.
By default, espflash fetches the required binaries (Bootloader and Partition Table) and flashes them onto the target device together with the Rust-based application firmware image.
MCUboot Secure Bootloader
MCUboot is a secure bootloader solution feature-wise equivalent to the IDF Bootloader. You may find more information on the documentation pages for MCUboot and the Espressif port:
Requirements
Booting from MCUboot secure bootloader requires the Rust application image to be built in a MCUboot-specific image format. You need to install the following dependencies:
# Required for generating the object file in Intel HEX format
cargo install cargo-binutils
rustup component add llvm-tools-preview
# MCUboot's tool for image signing and key management
pip install imgtool
Currently, MCUboot is still not supported as a booting option in espflash, so you'll need to use the esptool utility for flashing both the MCUboot bootloader and the Rust application binaries:
# Serial flasher utility for Espressif chips
pip install esptool
Download a prebuilt MCUboot bootloader image for the target device:
# Prebuilt MCUboot bootloader binary
curl -LO https://github.com/espressif/esp-nuttx-bootloader/releases/download/latest/mcuboot-esp32c3.bin
Booting the Hello World example from MCUboot
Build the Hello World example with MCUboot support:
cargo build --release --example hello_world --features mcu-boot
Then proceed to generating the application binary and flashing it onto the target device:
# Generate the object file in Intel HEX format
rust-objcopy -O ihex target/riscv32imc-unknown-none-elf/release/examples/hello_world app.hex
# Generate the application firmware image binary file in MCUboot-format
imgtool sign --pad --align 4 -v 0 -s auto -H 32 --pad-header -S 0x100000 app.hex app.bin
# Flash the application firmware image binary onto the target device
esptool.py -c esp32c3 -p /dev/ttyUSB0 -b 921600 --after no_reset write_flash -fs 4MB -fm dio -ff 40m 0x0 ./mcuboot-esp32c3.bin 0x110000 ./app.bin
Once the device is flashed, you may monitor the serial interface (e.g. with picocom
):
picocom -b 115200 /dev/ttyUSB0 --imap lfcrlf
Reset the board and MCUboot should load the Hello World example:
ESP-ROM:esp32c3-api1-20210207
Build:Feb 7 2021
rst:0x1 (POWERON),boot:0xc (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:2
load:0x3fcd8598,len:0x10cc
load:0x403c8000,len:0x2b90
load:0x403d0000,len:0x1364
entry 0x403c804a
[esp32c3] [INF] Enabling RNG early entropy source...
[esp32c3] [INF] *** Booting MCUboot build v1.8.0-86-g14763b1 ***
[esp32c3] [INF] Primary image: magic=good, swap_type=0x2, copy_done=0x1, image_ok=0x3
[esp32c3] [INF] Scratch: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
[esp32c3] [INF] Boot source: none
[esp32c3] [INF] Swap type: test
[esp32c3] [INF] Disabling RNG early entropy source...
[esp32c3] [INF] br_image_off = 0x10000
[esp32c3] [INF] ih_hdr_size = 0x20
[esp32c3] [INF] DRAM segment: start=0x3fcd0000, size=0x0, vaddr=0x3fcd0000
[esp32c3] [INF] IRAM segment: start=0x1d00, size=0x170c, vaddr=0x40380000
[esp32c3] [INF] start=0x40380004
Hello world!
Hello world!
Hello world!
Direct Boot
Direct Boot allows an application stored in the External Flash to be executed directly, without being copied into Internal RAM.
Booting the Hello World example using Direct Boot
Build the Hello World example with support for Direct Boot:
cargo build --release --example hello_world --features direct-boot
Then proceed to generating the application binary and flashing it onto the target device:
cargo espflash --release --format direct-boot --features direct-boot --example hello_world --monitor
The ROM Bootloader will identify the firmware image built with Direct Boot support and load it appropriately from the External Flash:
ESP-ROM:esp32c3-api1-20210207
Build:Feb 7 2021
rst:0x1 (POWERON),boot:0xc (SPI_FAST_FLASH_BOOT)
Hello world!
Hello world!
Hello world!
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.