Add auto-detection feature to esp-println (#1658)
* Add auto-detection feature to esp-println * CHANGELOG.md * Minor README change * Build `esp-println` in CI
This commit is contained in:
parent
8a47e4254f
commit
f125c20cf2
47
.github/workflows/ci.yml
vendored
47
.github/workflows/ci.yml
vendored
@ -152,6 +152,53 @@ jobs:
|
||||
- name: Build esp-riscv-rt (riscv32imac, all features)
|
||||
run: cd esp-riscv-rt/ && cargo build --target=riscv32imac-unknown-none-elf --features=ci
|
||||
|
||||
esp-println:
|
||||
name: esp-println (${{ matrix.device.soc }})
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
device: [
|
||||
# RISC-V devices:
|
||||
{ soc: "esp32c2", target: "riscv32imc-unknown-none-elf" },
|
||||
{ soc: "esp32c3", target: "riscv32imc-unknown-none-elf" },
|
||||
{ soc: "esp32c6", target: "riscv32imac-unknown-none-elf" },
|
||||
{ soc: "esp32h2", target: "riscv32imac-unknown-none-elf" },
|
||||
# Xtensa devices:
|
||||
{ soc: "esp32", target: "xtensa-esp32-none-elf" },
|
||||
{ soc: "esp32s2", target: "xtensa-esp32s2-none-elf" },
|
||||
{ soc: "esp32s3", target: "xtensa-esp32s3-none-elf" },
|
||||
]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Install the Rust toolchain for RISC-V devices:
|
||||
- if: ${{ !contains(fromJson('["esp32", "esp32s2", "esp32s3"]'), matrix.device.soc) }}
|
||||
uses: dtolnay/rust-toolchain@v1
|
||||
with:
|
||||
target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf
|
||||
toolchain: stable
|
||||
components: rust-src
|
||||
# Install the Rust toolchain for Xtensa devices:
|
||||
- if: contains(fromJson('["esp32", "esp32s2", "esp32s3"]'), matrix.device.soc)
|
||||
uses: esp-rs/xtensa-toolchain@v1.5
|
||||
with:
|
||||
buildtargets: ${{ matrix.device.soc }}
|
||||
default: true
|
||||
ldproxy: false
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
# Make sure we're able to build with the default features and most common features enabled
|
||||
- name: Build (no features)
|
||||
run: |
|
||||
cargo xtask build-package \
|
||||
--features=${{ matrix.device.soc }},log \
|
||||
--target=${{ matrix.device.target }} \
|
||||
esp-println
|
||||
|
||||
extras:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
||||
2
esp-println/.cargo/config.toml
Normal file
2
esp-println/.cargo/config.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[unstable]
|
||||
build-std = ["alloc", "core"]
|
||||
43
esp-println/CHANGELOG.md
Normal file
43
esp-println/CHANGELOG.md
Normal file
@ -0,0 +1,43 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Add `auto` feature to auto-detect Serial-JTAG/UART communication (#1658)
|
||||
|
||||
### Fixed
|
||||
|
||||
### Changed
|
||||
|
||||
- `auto` is the default communication method (#1658)
|
||||
|
||||
### Removed
|
||||
|
||||
## [0.9.1] - 2024-03-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Un-pinned the defmt package's version number
|
||||
|
||||
## [0.9.0] - 2024-02-07
|
||||
|
||||
### Added
|
||||
|
||||
- Add support for ESP32-P4
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove ESP 8266 support
|
||||
|
||||
## [0.8.0] - 2023-12-21
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove RTT and defmt-raw support
|
||||
|
||||
@ -22,7 +22,7 @@ portable-atomic = { version = "1.6.0", optional = true, default-features = fal
|
||||
esp-build = { version = "0.1.0", path = "../esp-build" }
|
||||
|
||||
[features]
|
||||
default = ["dep:critical-section", "colors", "uart"]
|
||||
default = ["dep:critical-section", "colors", "auto"]
|
||||
log = ["dep:log"]
|
||||
|
||||
# You must enable exactly 1 of the below features to support the correct chip:
|
||||
@ -36,10 +36,13 @@ esp32s2 = []
|
||||
esp32s3 = []
|
||||
|
||||
# You must enable exactly 1 of the below features to enable to intended
|
||||
# communication method (note that "uart" is enabled by default):
|
||||
# communication method (note that "auto" is enabled by default):
|
||||
jtag-serial = ["dep:portable-atomic"] # C3, C6, H2, P4, and S3 only!
|
||||
no-op = []
|
||||
uart = []
|
||||
auto = ["dep:portable-atomic"]
|
||||
|
||||
# Don't print anything
|
||||
no-op = []
|
||||
|
||||
# Enables a `defmt` backend usable with espflash. We force rzcobs encoding to simplify implementation
|
||||
defmt-espflash = ["dep:defmt", "defmt?/encoding-rzcobs"]
|
||||
|
||||
@ -39,22 +39,23 @@ You can now `println!("Hello world")` as usual.
|
||||
`esp32c3`, `esp32c6`, `esp32h2`, `esp32s2`, and `esp32s3`.
|
||||
- One of these features must be enabled.
|
||||
- Only one of these features can be enabled at a time.
|
||||
- There is one feature for each supported communication method: `uart`, `jtag-serial` and `no-op`.
|
||||
- There is one feature for each supported communication method: `uart`, `jtag-serial` and `auto`.
|
||||
- Only one of these features can be enabled at a time.
|
||||
- `no-op`: Don't print anything.
|
||||
- `log`: Enables logging using [`log` crate].
|
||||
- `colors` enable colored logging.
|
||||
- `colors`: Enable colored logging.
|
||||
- Only effective when using the `log` feature.
|
||||
- `critical-section` enables critical sections.
|
||||
- `critical-section`: Enables critical sections.
|
||||
- `defmt-espflash`: This is intended to be used with [`espflash`], see `-L/--log-format` argument
|
||||
of `flash` or `monitor` subcommands of `espflash` and `cargo-espflash`. Uses [rzCOBS] encoding
|
||||
and adds framing.
|
||||
|
||||
## Default Features
|
||||
|
||||
By default, we use the `uart`, `critial-section` and `colors` features.
|
||||
Which means that it will print to the UART, use critical sections and output
|
||||
By default, we use the `auto`, `critial-section` and `colors` features.
|
||||
Which means that it will auto-detect if it needs to print to the UART or JTAG-Serial, use critical sections and output
|
||||
messages will be colored.
|
||||
If we want to use a communication method that is not `uart`, the default
|
||||
If we want to use a communication method that is not `auto`, the default
|
||||
one, we need to [disable the default features].
|
||||
|
||||
## Logging
|
||||
|
||||
@ -7,7 +7,7 @@ fn main() {
|
||||
);
|
||||
|
||||
// Ensure that only a single communication method is specified
|
||||
assert_unique_used_features!("jtag-serial", "uart");
|
||||
assert_unique_used_features!("jtag-serial", "uart", "auto");
|
||||
|
||||
// Ensure that, if the `jtag-serial` communication method feature is enabled,
|
||||
// either the `esp32c3`, `esp32c6`, `esp32h2`, or `esp32s3` chip feature is
|
||||
|
||||
@ -68,26 +68,94 @@ macro_rules! dbg {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "jtag-serial", feature = "auto"))]
|
||||
pub struct PrinterSerialJtag;
|
||||
|
||||
#[cfg(any(feature = "uart", feature = "auto"))]
|
||||
pub struct PrinterUart;
|
||||
|
||||
#[cfg(feature = "jtag-serial")]
|
||||
pub type PrinterImpl = PrinterSerialJtag;
|
||||
|
||||
#[cfg(feature = "uart")]
|
||||
pub type PrinterImpl = PrinterUart;
|
||||
|
||||
pub struct Printer;
|
||||
|
||||
impl core::fmt::Write for Printer {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
Printer.write_bytes(s.as_bytes());
|
||||
Printer::write_bytes(s.as_bytes());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Printer {
|
||||
pub fn write_bytes(&mut self, bytes: &[u8]) {
|
||||
#[cfg(not(feature = "auto"))]
|
||||
pub fn write_bytes(bytes: &[u8]) {
|
||||
with(|| {
|
||||
self.write_bytes_assume_cs(bytes);
|
||||
self.flush();
|
||||
PrinterImpl::write_bytes_assume_cs(bytes);
|
||||
PrinterImpl::flush();
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "auto")]
|
||||
pub fn write_bytes(bytes: &[u8]) {
|
||||
#[cfg(any(
|
||||
feature = "esp32c3",
|
||||
feature = "esp32c6",
|
||||
feature = "esp32h2",
|
||||
feature = "esp32s3"
|
||||
))]
|
||||
{
|
||||
// Decide if serial-jtag is used by checking SOF interrupt flag.
|
||||
// SOF packet is sent by the HOST every 1ms on a full speed bus.
|
||||
// Between two consecutive ticks, there will be at least 1ms (selectable tick
|
||||
// rate range is 1 - 1000Hz).
|
||||
// We don't reset the flag - if it was ever connected we assume serial-jtag is
|
||||
// used
|
||||
|
||||
#[cfg(feature = "esp32c3")]
|
||||
const USB_DEVICE_INT_RAW: *const u32 = 0x60043008 as *const u32;
|
||||
#[cfg(feature = "esp32c6")]
|
||||
const USB_DEVICE_INT_RAW: *const u32 = 0x6000f008 as *const u32;
|
||||
#[cfg(feature = "esp32h2")]
|
||||
const USB_DEVICE_INT_RAW: *const u32 = 0x6000f008 as *const u32;
|
||||
#[cfg(feature = "esp32s3")]
|
||||
const USB_DEVICE_INT_RAW: *const u32 = 0x60038000 as *const u32;
|
||||
|
||||
const SOF_INT_MASK: u32 = 0b10;
|
||||
|
||||
let is_serial_jtag =
|
||||
unsafe { (USB_DEVICE_INT_RAW.read_volatile() & SOF_INT_MASK) != 0 };
|
||||
|
||||
if is_serial_jtag {
|
||||
with(|| {
|
||||
PrinterSerialJtag::write_bytes_assume_cs(bytes);
|
||||
PrinterSerialJtag::flush();
|
||||
})
|
||||
} else {
|
||||
with(|| {
|
||||
PrinterUart::write_bytes_assume_cs(bytes);
|
||||
PrinterUart::flush();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
feature = "esp32c3",
|
||||
feature = "esp32c6",
|
||||
feature = "esp32h2",
|
||||
feature = "esp32s3"
|
||||
)))]
|
||||
with(|| {
|
||||
PrinterUart::write_bytes_assume_cs(bytes);
|
||||
PrinterUart::flush();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
feature = "jtag-serial",
|
||||
any(feature = "jtag-serial", feature = "auto"),
|
||||
any(
|
||||
feature = "esp32c3",
|
||||
feature = "esp32c6",
|
||||
@ -154,8 +222,8 @@ mod serial_jtag_printer {
|
||||
true
|
||||
}
|
||||
|
||||
impl super::Printer {
|
||||
pub fn write_bytes_assume_cs(&mut self, bytes: &[u8]) {
|
||||
impl super::PrinterSerialJtag {
|
||||
pub fn write_bytes_assume_cs(bytes: &[u8]) {
|
||||
if fifo_full() {
|
||||
// The FIFO is full. Let's see if we can progress.
|
||||
|
||||
@ -188,17 +256,17 @@ mod serial_jtag_printer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) {
|
||||
pub fn flush() {
|
||||
fifo_flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "uart", feature = "esp32"))]
|
||||
#[cfg(all(any(feature = "uart", feature = "auto"), feature = "esp32"))]
|
||||
mod uart_printer {
|
||||
const UART_TX_ONE_CHAR: usize = 0x4000_9200;
|
||||
impl super::Printer {
|
||||
pub fn write_bytes_assume_cs(&mut self, bytes: &[u8]) {
|
||||
impl super::PrinterUart {
|
||||
pub fn write_bytes_assume_cs(bytes: &[u8]) {
|
||||
for &b in bytes {
|
||||
unsafe {
|
||||
let uart_tx_one_char: unsafe extern "C" fn(u8) -> i32 =
|
||||
@ -208,14 +276,14 @@ mod uart_printer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) {}
|
||||
pub fn flush() {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "uart", feature = "esp32s2"))]
|
||||
#[cfg(all(any(feature = "uart", feature = "auto"), feature = "esp32s2"))]
|
||||
mod uart_printer {
|
||||
impl super::Printer {
|
||||
pub fn write_bytes_assume_cs(&mut self, bytes: &[u8]) {
|
||||
impl super::PrinterUart {
|
||||
pub fn write_bytes_assume_cs(bytes: &[u8]) {
|
||||
// On ESP32-S2 the UART_TX_ONE_CHAR ROM-function seems to have some issues.
|
||||
for chunk in bytes.chunks(64) {
|
||||
for &b in chunk {
|
||||
@ -234,11 +302,14 @@ mod uart_printer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) {}
|
||||
pub fn flush() {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "uart", not(any(feature = "esp32", feature = "esp32s2"))))]
|
||||
#[cfg(all(
|
||||
any(feature = "uart", feature = "auto"),
|
||||
not(any(feature = "esp32", feature = "esp32s2"))
|
||||
))]
|
||||
mod uart_printer {
|
||||
trait Functions {
|
||||
const TX_ONE_CHAR: usize;
|
||||
@ -350,8 +421,8 @@ mod uart_printer {
|
||||
}
|
||||
}
|
||||
|
||||
impl super::Printer {
|
||||
pub fn write_bytes_assume_cs(&mut self, bytes: &[u8]) {
|
||||
impl super::PrinterUart {
|
||||
pub fn write_bytes_assume_cs(bytes: &[u8]) {
|
||||
for chunk in bytes.chunks(Device::CHUNK_SIZE) {
|
||||
for &b in chunk {
|
||||
Device::tx_byte(b);
|
||||
@ -361,7 +432,7 @@ mod uart_printer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) {}
|
||||
pub fn flush() {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user