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)
|
- name: Build esp-riscv-rt (riscv32imac, all features)
|
||||||
run: cd esp-riscv-rt/ && cargo build --target=riscv32imac-unknown-none-elf --features=ci
|
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:
|
extras:
|
||||||
runs-on: ubuntu-latest
|
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" }
|
esp-build = { version = "0.1.0", path = "../esp-build" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["dep:critical-section", "colors", "uart"]
|
default = ["dep:critical-section", "colors", "auto"]
|
||||||
log = ["dep:log"]
|
log = ["dep:log"]
|
||||||
|
|
||||||
# You must enable exactly 1 of the below features to support the correct chip:
|
# You must enable exactly 1 of the below features to support the correct chip:
|
||||||
@ -36,10 +36,13 @@ esp32s2 = []
|
|||||||
esp32s3 = []
|
esp32s3 = []
|
||||||
|
|
||||||
# You must enable exactly 1 of the below features to enable to intended
|
# 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!
|
jtag-serial = ["dep:portable-atomic"] # C3, C6, H2, P4, and S3 only!
|
||||||
no-op = []
|
|
||||||
uart = []
|
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
|
# Enables a `defmt` backend usable with espflash. We force rzcobs encoding to simplify implementation
|
||||||
defmt-espflash = ["dep:defmt", "defmt?/encoding-rzcobs"]
|
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`.
|
`esp32c3`, `esp32c6`, `esp32h2`, `esp32s2`, and `esp32s3`.
|
||||||
- One of these features must be enabled.
|
- One of these features must be enabled.
|
||||||
- Only one of these features can be enabled at a time.
|
- 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.
|
- Only one of these features can be enabled at a time.
|
||||||
|
- `no-op`: Don't print anything.
|
||||||
- `log`: Enables logging using [`log` crate].
|
- `log`: Enables logging using [`log` crate].
|
||||||
- `colors` enable colored logging.
|
- `colors`: Enable colored logging.
|
||||||
- Only effective when using the `log` feature.
|
- 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
|
- `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
|
of `flash` or `monitor` subcommands of `espflash` and `cargo-espflash`. Uses [rzCOBS] encoding
|
||||||
and adds framing.
|
and adds framing.
|
||||||
|
|
||||||
## Default Features
|
## Default Features
|
||||||
|
|
||||||
By default, we use the `uart`, `critial-section` and `colors` features.
|
By default, we use the `auto`, `critial-section` and `colors` features.
|
||||||
Which means that it will print to the UART, use critical sections and output
|
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.
|
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].
|
one, we need to [disable the default features].
|
||||||
|
|
||||||
## Logging
|
## Logging
|
||||||
|
|||||||
@ -7,7 +7,7 @@ fn main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Ensure that only a single communication method is specified
|
// 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,
|
// Ensure that, if the `jtag-serial` communication method feature is enabled,
|
||||||
// either the `esp32c3`, `esp32c6`, `esp32h2`, or `esp32s3` chip feature is
|
// 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;
|
pub struct Printer;
|
||||||
|
|
||||||
impl core::fmt::Write for Printer {
|
impl core::fmt::Write for Printer {
|
||||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||||
Printer.write_bytes(s.as_bytes());
|
Printer::write_bytes(s.as_bytes());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Printer {
|
impl Printer {
|
||||||
pub fn write_bytes(&mut self, bytes: &[u8]) {
|
#[cfg(not(feature = "auto"))]
|
||||||
|
pub fn write_bytes(bytes: &[u8]) {
|
||||||
with(|| {
|
with(|| {
|
||||||
self.write_bytes_assume_cs(bytes);
|
PrinterImpl::write_bytes_assume_cs(bytes);
|
||||||
self.flush();
|
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(
|
#[cfg(all(
|
||||||
feature = "jtag-serial",
|
any(feature = "jtag-serial", feature = "auto"),
|
||||||
any(
|
any(
|
||||||
feature = "esp32c3",
|
feature = "esp32c3",
|
||||||
feature = "esp32c6",
|
feature = "esp32c6",
|
||||||
@ -154,8 +222,8 @@ mod serial_jtag_printer {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::Printer {
|
impl super::PrinterSerialJtag {
|
||||||
pub fn write_bytes_assume_cs(&mut self, bytes: &[u8]) {
|
pub fn write_bytes_assume_cs(bytes: &[u8]) {
|
||||||
if fifo_full() {
|
if fifo_full() {
|
||||||
// The FIFO is full. Let's see if we can progress.
|
// 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();
|
fifo_flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "uart", feature = "esp32"))]
|
#[cfg(all(any(feature = "uart", feature = "auto"), feature = "esp32"))]
|
||||||
mod uart_printer {
|
mod uart_printer {
|
||||||
const UART_TX_ONE_CHAR: usize = 0x4000_9200;
|
const UART_TX_ONE_CHAR: usize = 0x4000_9200;
|
||||||
impl super::Printer {
|
impl super::PrinterUart {
|
||||||
pub fn write_bytes_assume_cs(&mut self, bytes: &[u8]) {
|
pub fn write_bytes_assume_cs(bytes: &[u8]) {
|
||||||
for &b in bytes {
|
for &b in bytes {
|
||||||
unsafe {
|
unsafe {
|
||||||
let uart_tx_one_char: unsafe extern "C" fn(u8) -> i32 =
|
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 {
|
mod uart_printer {
|
||||||
impl super::Printer {
|
impl super::PrinterUart {
|
||||||
pub fn write_bytes_assume_cs(&mut self, bytes: &[u8]) {
|
pub fn write_bytes_assume_cs(bytes: &[u8]) {
|
||||||
// On ESP32-S2 the UART_TX_ONE_CHAR ROM-function seems to have some issues.
|
// On ESP32-S2 the UART_TX_ONE_CHAR ROM-function seems to have some issues.
|
||||||
for chunk in bytes.chunks(64) {
|
for chunk in bytes.chunks(64) {
|
||||||
for &b in chunk {
|
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 {
|
mod uart_printer {
|
||||||
trait Functions {
|
trait Functions {
|
||||||
const TX_ONE_CHAR: usize;
|
const TX_ONE_CHAR: usize;
|
||||||
@ -350,8 +421,8 @@ mod uart_printer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::Printer {
|
impl super::PrinterUart {
|
||||||
pub fn write_bytes_assume_cs(&mut self, bytes: &[u8]) {
|
pub fn write_bytes_assume_cs(bytes: &[u8]) {
|
||||||
for chunk in bytes.chunks(Device::CHUNK_SIZE) {
|
for chunk in bytes.chunks(Device::CHUNK_SIZE) {
|
||||||
for &b in chunk {
|
for &b in chunk {
|
||||||
Device::tx_byte(b);
|
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