diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c0a9dc7712b..7fcd8bddfac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -224,10 +224,10 @@ jobs: run: cd esp32h2-hal/ && cargo +nightly check --examples --features=eh1,ufmt - name: check esp32h2-hal (async, i2c) run: cd esp32h2-hal/ && cargo check --example=embassy_i2c --features=embassy,embassy-time-systick,async - # - name: check esp32h2-hal (async, systick) - # run: cd esp32h2-hal/ && cargo +nightly check --example=embassy_hello_world --features=embassy,embassy-time-systick - # - name: check esp32h2-hal (async, timg0) - # run: cd esp32h2-hal/ && cargo +nightly check --example=embassy_hello_world --features=embassy,embassy-time-timg0 + - name: check esp32h2-hal (async, systick) + run: cd esp32h2-hal/ && cargo +nightly check --example=embassy_hello_world --features=embassy,embassy-time-systick + - name: check esp32h2-hal (async, timg0) + run: cd esp32h2-hal/ && cargo +nightly check --example=embassy_hello_world --features=embassy,embassy-time-timg0 # - name: check esp32h2-hal (async, gpio) # run: cd esp32h2-hal/ && cargo +nightly check --example=embassy_wait --features=embassy,embassy-time-systick,async # - name: check esp32h2-hal (async, spi) @@ -440,7 +440,7 @@ jobs: uses: dangoslen/changelog-enforcer@v3 with: changeLogPath: CHANGELOG.md - skipLabels: 'skip-changelog' - missingUpdateErrorMessage: 'Please add a changelog entry in the CHANGELOG.md file.' + skipLabels: "skip-changelog" + missingUpdateErrorMessage: "Please add a changelog entry in the CHANGELOG.md file." env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 5abc53b6e33..58f1cb72520 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,21 +24,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add LEDC hardware fade support - Added support for multicore async GPIO (#542) - Add initial support for MCPWM in ESP32-H2 (#544) +- Add some miscellaneous examples for the ESP32-H2 (#548) ### Fixed - DMA is supported for SPI3 on ESP32-S3 (#507) - `change_bus_frequency` is now available on `SpiDma` (#529) -- Fixed a bug where a GPIO interrupt could erroneously fire again causing the next `await` on that pin to instantly return `Poll::Ok` (#537) +- Fixed a bug where a GPIO interrupt could erroneously fire again causing the next `await` on that pin to instantly return `Poll::Ok` (#537) - Set `vecbase` on core 1 (ESP32, ESP32-S3) (#536) - ESP32-S3: Move PSRAM related function to RAM (#546) ### Changed + - Improve examples documentation (#533) ### Breaking -- As part of the refactoring in #537, the public GPIO type has changed. +- As part of the refactoring in #537, the public GPIO type has changed. ## [0.9.0] - 2023-05-02 diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index cd05d8cb4d0..58298ec9172 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -55,7 +55,7 @@ esp32 = { version = "0.23.0", features = ["critical-section"], optional = true esp32c2 = { version = "0.11.0", features = ["critical-section"], optional = true } esp32c3 = { version = "0.14.0", features = ["critical-section"], optional = true } esp32c6 = { version = "0.4.0", features = ["critical-section"], optional = true } -esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "5828519", package = "esp32h2", features = ["critical-section"], optional = true } +esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "ff70333", package = "esp32h2", features = ["critical-section"], optional = true } esp32s2 = { version = "0.14.0", features = ["critical-section"], optional = true } esp32s3 = { version = "0.18.0", features = ["critical-section"], optional = true } diff --git a/esp-hal-common/devices/esp32h2.toml b/esp-hal-common/devices/esp32h2.toml index 2a8df6e750a..29e9fb9671a 100644 --- a/esp-hal-common/devices/esp32h2.toml +++ b/esp-hal-common/devices/esp32h2.toml @@ -56,7 +56,7 @@ peripherals = [ "uart0", "uart1", # "uhci0", - # "usb_device", + "usb_device", # Additional peripherals defined by us (the developers): "adc", diff --git a/esp-hal-common/src/soc/esp32h2/peripherals.rs b/esp-hal-common/src/soc/esp32h2/peripherals.rs index 27841107d59..65e43bf18f6 100644 --- a/esp-hal-common/src/soc/esp32h2/peripherals.rs +++ b/esp-hal-common/src/soc/esp32h2/peripherals.rs @@ -58,6 +58,6 @@ crate::peripherals! { UART0 => true, UART1 => true, // UHCI0 => true, - // USB_DEVICE => true, + USB_DEVICE => true, RADIO => false, } diff --git a/esp-hal-common/src/systimer.rs b/esp-hal-common/src/systimer.rs index 5bab37803ca..2c05fd609a7 100644 --- a/esp-hal-common/src/systimer.rs +++ b/esp-hal-common/src/systimer.rs @@ -138,7 +138,7 @@ impl Alarm { #[cfg(esp32s2)] systimer.step.write(|w| w.timer_xtal_step().bits(0x1)); // run at XTAL freq, not 80 * XTAL freq - #[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))] + #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] { tconf.write(|w| w.target0_timer_unit_sel().clear_bit()); // default, use unit 0 systimer @@ -148,7 +148,7 @@ impl Alarm { conf(tconf, hi, lo); - #[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))] + #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] { match CHANNEL { 0 => { diff --git a/esp32h2-hal/Cargo.toml b/esp32h2-hal/Cargo.toml index e294212da49..39dd8cffdb4 100644 --- a/esp32h2-hal/Cargo.toml +++ b/esp32h2-hal/Cargo.toml @@ -61,6 +61,10 @@ embassy = ["esp-hal-common/embassy"] embassy-time-systick = ["esp-hal-common/embassy-time-systick", "embassy-time/tick-hz-16_000_000"] embassy-time-timg0 = ["esp-hal-common/embassy-time-timg0", "embassy-time/tick-hz-1_000_000"] +[[example]] +name = "embassy_hello_world" +required-features = ["embassy"] + [[example]] name = "embassy_i2c" -required-features = ["embassy", "async", "embassy-time-systick"] \ No newline at end of file +required-features = ["embassy", "async", "embassy-time-systick"] diff --git a/esp32h2-hal/examples/advanced_serial.rs b/esp32h2-hal/examples/advanced_serial.rs new file mode 100644 index 00000000000..b0812ffc205 --- /dev/null +++ b/esp32h2-hal/examples/advanced_serial.rs @@ -0,0 +1,89 @@ +//! This shows how to configure UART +//! You can short the TX and RX pin and see it reads what was written. +//! Additionally you can connect a logic analzyer to TX and see how the changes +//! of the configuration change the output signal. + +#![no_std] +#![no_main] + +use esp32h2_hal::{ + clock::ClockControl, + peripherals::Peripherals, + prelude::*, + timer::TimerGroup, + uart::{ + config::{Config, DataBits, Parity, StopBits}, + TxRxPins, + }, + Rtc, + Uart, + IO, +}; +use esp_backtrace as _; +use esp_println::println; +use nb::block; + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.PCR.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + // Disable the watchdog timers. For the ESP32-H2, this includes the Super WDT, + // and the TIMG WDTs. + let mut rtc = Rtc::new(peripherals.LP_CLKRST); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut timer0 = timer_group0.timer0; + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt1 = timer_group1.wdt; + + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + let config = Config { + baudrate: 115200, + data_bits: DataBits::DataBits8, + parity: Parity::ParityNone, + stop_bits: StopBits::STOP1, + }; + + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + let pins = TxRxPins::new_tx_rx( + io.pins.gpio1.into_push_pull_output(), + io.pins.gpio2.into_floating_input(), + ); + + let mut serial1 = Uart::new_with_config( + peripherals.UART1, + Some(config), + Some(pins), + &clocks, + &mut system.peripheral_clock_control, + ); + + timer0.start(250u64.millis()); + + println!("Start"); + loop { + serial1.write(0x42).ok(); + let read = block!(serial1.read()); + + match read { + Ok(read) => println!("Read {:02x}", read), + Err(err) => println!("Error {:?}", err), + } + + block!(timer0.wait()).unwrap(); + } +} diff --git a/esp32h2-hal/examples/embassy_hello_world.rs b/esp32h2-hal/examples/embassy_hello_world.rs new file mode 100644 index 00000000000..8fc888b15ad --- /dev/null +++ b/esp32h2-hal/examples/embassy_hello_world.rs @@ -0,0 +1,82 @@ +//! embassy hello world +//! +//! This is an example of running the embassy executor with multiple tasks +//! concurrently. + +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use embassy_executor::Executor; +use embassy_time::{Duration, Timer}; +use esp32h2_hal::{ + clock::ClockControl, + embassy, + peripherals::Peripherals, + prelude::*, + timer::TimerGroup, + Rtc, +}; +use esp_backtrace as _; +use static_cell::StaticCell; + +#[embassy_executor::task] +async fn run1() { + loop { + esp_println::println!("Hello world from embassy using esp-hal-async!"); + Timer::after(Duration::from_millis(1_000)).await; + } +} + +#[embassy_executor::task] +async fn run2() { + loop { + esp_println::println!("Bing!"); + Timer::after(Duration::from_millis(5_000)).await; + } +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + esp_println::println!("Init!"); + let peripherals = Peripherals::take(); + let mut system = peripherals.PCR.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + let mut rtc = Rtc::new(peripherals.LP_CLKRST); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt1 = timer_group1.wdt; + + // Disable watchdog timers + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + #[cfg(feature = "embassy-time-systick")] + embassy::init( + &clocks, + esp32h2_hal::systimer::SystemTimer::new(peripherals.SYSTIMER), + ); + + #[cfg(feature = "embassy-time-timg0")] + embassy::init(&clocks, timer_group0.timer0); + + let executor = EXECUTOR.init(Executor::new()); + executor.run(|spawner| { + spawner.spawn(run1()).ok(); + spawner.spawn(run2()).ok(); + }); +} diff --git a/esp32h2-hal/examples/systimer.rs b/esp32h2-hal/examples/systimer.rs new file mode 100644 index 00000000000..f7f2de8eab4 --- /dev/null +++ b/esp32h2-hal/examples/systimer.rs @@ -0,0 +1,138 @@ +//! This shows how to use the SYSTIMER peripheral including interrupts. +//! It's an additional timer besides the TIMG peripherals. + +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use critical_section::Mutex; +use esp32h2_hal::{ + clock::ClockControl, + interrupt, + interrupt::Priority, + peripherals::{self, Peripherals}, + prelude::*, + systimer::{Alarm, Periodic, SystemTimer, Target}, + timer::TimerGroup, + Delay, + Rtc, +}; +use esp_backtrace as _; +use esp_println::println; + +static ALARM0: Mutex>>> = Mutex::new(RefCell::new(None)); +static ALARM1: Mutex>>> = Mutex::new(RefCell::new(None)); +static ALARM2: Mutex>>> = Mutex::new(RefCell::new(None)); + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.PCR.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + // Disable the watchdog timers. For the ESP32-H2, this includes the Super WDT, + // and the TIMG WDTs. + let mut rtc = Rtc::new(peripherals.LP_CLKRST); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt1 = timer_group1.wdt; + + // Disable watchdog timers + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + let syst = SystemTimer::new(peripherals.SYSTIMER); + + println!("SYSTIMER Current value = {}", SystemTimer::now()); + + let alarm0 = syst.alarm0.into_periodic(); + alarm0.set_period(1u32.Hz()); + alarm0.clear_interrupt(); + alarm0.interrupt_enable(true); + + let alarm1 = syst.alarm1; + alarm1.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 2)); + alarm1.interrupt_enable(true); + + let alarm2 = syst.alarm2; + alarm2.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 3)); + alarm2.interrupt_enable(true); + + critical_section::with(|cs| { + ALARM0.borrow_ref_mut(cs).replace(alarm0); + ALARM1.borrow_ref_mut(cs).replace(alarm1); + ALARM2.borrow_ref_mut(cs).replace(alarm2); + }); + + interrupt::enable( + peripherals::Interrupt::SYSTIMER_TARGET0, + Priority::Priority1, + ) + .unwrap(); + interrupt::enable( + peripherals::Interrupt::SYSTIMER_TARGET1, + Priority::Priority2, + ) + .unwrap(); + interrupt::enable( + peripherals::Interrupt::SYSTIMER_TARGET2, + Priority::Priority2, + ) + .unwrap(); + + // Initialize the Delay peripheral, and use it to toggle the LED state in a + // loop. + let mut delay = Delay::new(&clocks); + + loop { + delay.delay_ms(10000u32); + } +} + +#[interrupt] +fn SYSTIMER_TARGET0() { + println!("Interrupt lvl1 (alarm0)"); + critical_section::with(|cs| { + ALARM0 + .borrow_ref_mut(cs) + .as_mut() + .unwrap() + .clear_interrupt() + }); +} + +#[interrupt] +fn SYSTIMER_TARGET1() { + println!("Interrupt lvl2 (alarm1)"); + critical_section::with(|cs| { + ALARM1 + .borrow_ref_mut(cs) + .as_mut() + .unwrap() + .clear_interrupt() + }); +} + +#[interrupt] +fn SYSTIMER_TARGET2() { + println!("Interrupt lvl2 (alarm2)"); + critical_section::with(|cs| { + ALARM2 + .borrow_ref_mut(cs) + .as_mut() + .unwrap() + .clear_interrupt() + }); +} diff --git a/esp32h2-hal/examples/usb_serial_jtag.rs b/esp32h2-hal/examples/usb_serial_jtag.rs new file mode 100644 index 00000000000..c256cf6da3c --- /dev/null +++ b/esp32h2-hal/examples/usb_serial_jtag.rs @@ -0,0 +1,99 @@ +//! This shows how to output text via USB Serial/JTAG. +//! You need to connect via the Serial/JTAG interface to see any output. +//! Most dev-kits use a USB-UART-bridge - in that case you won't see any output. + +#![no_std] +#![no_main] + +use core::{cell::RefCell, fmt::Write}; + +use critical_section::Mutex; +use esp32h2_hal::{ + clock::ClockControl, + interrupt, + peripherals::{self, Peripherals}, + prelude::*, + riscv, + timer::TimerGroup, + Cpu, + Rtc, + UsbSerialJtag, +}; +use esp_backtrace as _; +use nb::block; + +static USB_SERIAL: Mutex>> = Mutex::new(RefCell::new(None)); + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.PCR.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + let mut rtc = Rtc::new(peripherals.LP_CLKRST); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut timer0 = timer_group0.timer0; + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt1 = timer_group1.wdt; + + // Disable watchdog timers + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + let mut usb_serial = + UsbSerialJtag::new(peripherals.USB_DEVICE, &mut system.peripheral_clock_control); + + usb_serial.listen_rx_packet_recv_interrupt(); + + timer0.start(1u64.secs()); + + critical_section::with(|cs| USB_SERIAL.borrow_ref_mut(cs).replace(usb_serial)); + + interrupt::enable(peripherals::Interrupt::USB, interrupt::Priority::Priority1).unwrap(); + + interrupt::set_kind( + Cpu::ProCpu, + interrupt::CpuInterrupt::Interrupt1, + interrupt::InterruptKind::Edge, + ); + + unsafe { + riscv::interrupt::enable(); + } + + loop { + critical_section::with(|cs| { + writeln!( + USB_SERIAL.borrow_ref_mut(cs).as_mut().unwrap(), + "Hello world!" + ) + .ok(); + }); + + block!(timer0.wait()).unwrap(); + } +} + +#[interrupt] +fn USB() { + critical_section::with(|cs| { + let mut usb_serial = USB_SERIAL.borrow_ref_mut(cs); + let usb_serial = usb_serial.as_mut().unwrap(); + writeln!(usb_serial, "USB serial interrupt").unwrap(); + while let nb::Result::Ok(c) = usb_serial.read_byte() { + writeln!(usb_serial, "Read byte: {:02x}", c).unwrap(); + } + usb_serial.reset_rx_packet_recv_interrupt(); + }); +}