mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-30 13:50:38 +00:00
Initial support for I2C in ESP32-H2 (#538)
* feat: ✨ Enable i2c peripheral * feat: ✨ Add I2cExt1 for H2 * feat: ✨ Initial i2c support * feat: ✨ Add i2c examples * ci: ✨ Add embassy_i2c check * ci: 🐛 Fix features * docs: 📝 Update changelog * feat: ✨ Add read_efuse example
This commit is contained in:
parent
4dde817530
commit
e2442f2d47
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -222,6 +222,8 @@ jobs:
|
||||
# confident that they link.
|
||||
- name: check esp32h2-hal (common features)
|
||||
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)
|
||||
|
@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Add initial support for SHA in ESP32-H2 (#527)
|
||||
- Add initial support for AES in ESP32-H2 (#528)
|
||||
- Add blinky_erased_pins example for ESP32-H2 (#530)
|
||||
- Add initial support for I2C in ESP32-H2 (#538)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
@ -15,8 +15,8 @@ peripherals = [
|
||||
# "hmac",
|
||||
# "hp_apm",
|
||||
# "hp_sys",
|
||||
# "i2c0",
|
||||
# "i2c1",
|
||||
"i2c0",
|
||||
"i2c1",
|
||||
# "i2s0",
|
||||
"interrupt_core0",
|
||||
"intpri",
|
||||
|
@ -135,7 +135,7 @@ enum Ack {
|
||||
Nack,
|
||||
}
|
||||
|
||||
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
|
||||
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
|
||||
enum Opcode {
|
||||
RStart = 6,
|
||||
Write = 1,
|
||||
@ -648,11 +648,7 @@ pub trait Instance {
|
||||
// Configure frequency
|
||||
self.set_frequency(clocks.i2c_clock.convert(), frequency);
|
||||
|
||||
// Propagate configuration changes (only necessary with C2, C3, and S3)
|
||||
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
|
||||
self.register_block()
|
||||
.ctr
|
||||
.modify(|_, w| w.conf_upgate().set_bit());
|
||||
self.update_config();
|
||||
|
||||
// Reset entire peripheral (also resets fifo)
|
||||
self.reset();
|
||||
@ -850,7 +846,7 @@ pub trait Instance {
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
|
||||
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
|
||||
/// Sets the frequency of the I2C interface by calculating and applying the
|
||||
/// associated timings - corresponds to i2c_ll_cal_bus_clk and
|
||||
/// i2c_ll_set_bus_timing in ESP-IDF
|
||||
@ -938,7 +934,7 @@ pub trait Instance {
|
||||
) {
|
||||
unsafe {
|
||||
// divider
|
||||
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
|
||||
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
|
||||
self.register_block().clk_conf.modify(|_, w| {
|
||||
w.sclk_sel()
|
||||
.clear_bit()
|
||||
@ -1275,8 +1271,8 @@ pub trait Instance {
|
||||
|
||||
fn update_config(&self) {
|
||||
// Ensure that the configuration of the peripheral is correctly propagated
|
||||
// (only necessary for C3 and S3 variant)
|
||||
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
|
||||
// (only necessary for C2, C3, C6, H2 and S3 variant)
|
||||
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
|
||||
self.register_block()
|
||||
.ctr
|
||||
.modify(|_, w| w.conf_upgate().set_bit());
|
||||
|
@ -17,8 +17,8 @@ crate::peripherals! {
|
||||
// HMAC => true,
|
||||
// HP_APM => true,
|
||||
// HP_SYS => true,
|
||||
// I2C0 => true,
|
||||
// I2C1 => true,
|
||||
I2C0 => true,
|
||||
I2C1 => true,
|
||||
// I2S0 => true,
|
||||
INTERRUPT_CORE0 => true,
|
||||
INTPRI => true,
|
||||
|
@ -380,6 +380,14 @@ impl PeripheralClockControl {
|
||||
system.i2c0_conf.modify(|_, w| w.i2c0_rst_en().clear_bit());
|
||||
}
|
||||
}
|
||||
#[cfg(i2c1)]
|
||||
Peripheral::I2cExt1 => {
|
||||
#[cfg(esp32h2)]
|
||||
{
|
||||
system.i2c1_conf.modify(|_, w| w.i2c1_clk_en().set_bit());
|
||||
system.i2c1_conf.modify(|_, w| w.i2c1_rst_en().clear_bit());
|
||||
}
|
||||
}
|
||||
#[cfg(rmt)]
|
||||
Peripheral::Rmt => {
|
||||
system.rmt_conf.modify(|_, w| w.rmt_clk_en().set_bit());
|
||||
|
@ -38,11 +38,12 @@ esp-hal-common = { version = "0.9.0", features = ["esp32h2"], path = "../es
|
||||
aes = "0.8.2"
|
||||
critical-section = "1.1.1"
|
||||
crypto-bigint = { version = "0.5.2", default-features = false }
|
||||
embassy-executor = { version = "0.2.0", features = ["nightly", "integrated-timers"] }
|
||||
embassy-executor = { version = "0.2.0", features = ["nightly", "integrated-timers", "arch-riscv32", "executor-thread"] }
|
||||
embedded-graphics = "0.7.1"
|
||||
esp-backtrace = { version = "0.7.0", features = ["esp32h2", "panic-handler", "exception-handler", "print-uart"] }
|
||||
# esp-hal-smartled = { version = "0.1.0", features = ["esp32h2"], path = "../esp-hal-smartled" }
|
||||
esp-println = { version = "0.5.0", features = ["esp32h2"] }
|
||||
lis3dh-async = "0.7.0"
|
||||
sha2 = { version = "0.10.6", default-features = false}
|
||||
smart-leds = "0.3.0"
|
||||
ssd1306 = "0.7.1"
|
||||
@ -59,3 +60,7 @@ async = ["esp-hal-common/async", "embedded-hal-async"]
|
||||
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_i2c"
|
||||
required-features = ["embassy", "async", "embassy-time-systick"]
|
101
esp32h2-hal/examples/embassy_i2c.rs
Normal file
101
esp32h2-hal/examples/embassy_i2c.rs
Normal file
@ -0,0 +1,101 @@
|
||||
//! Embassy I2C
|
||||
//!
|
||||
//! Folowing pins are used:
|
||||
//! SDA GPIO1
|
||||
//! SCL GPIO2
|
||||
//!
|
||||
//! Depending on your target and the board you are using you have to change the
|
||||
//! pins.
|
||||
//!
|
||||
//! This is an example of running the embassy executor with IC2. It uses an
|
||||
//! LIS3DH to get accelerometer data.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_executor::Executor;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use esp32h2_hal::{
|
||||
clock::ClockControl,
|
||||
embassy,
|
||||
i2c::I2C,
|
||||
peripherals::{Interrupt, Peripherals, I2C0},
|
||||
prelude::*,
|
||||
timer::TimerGroup,
|
||||
Priority,
|
||||
Rtc,
|
||||
IO,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use lis3dh_async::{Lis3dh, Range, SlaveAddr};
|
||||
use static_cell::StaticCell;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn run(i2c: I2C<'static, I2C0>) {
|
||||
let mut lis3dh = Lis3dh::new_i2c(i2c, SlaveAddr::Alternate).await.unwrap();
|
||||
lis3dh.set_range(Range::G8).await.unwrap();
|
||||
|
||||
loop {
|
||||
let norm = lis3dh.accel_norm().await.unwrap();
|
||||
esp_println::println!("X: {:+.5} Y: {:+.5} Z: {:+.5}", norm.x, norm.y, norm.z);
|
||||
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
}
|
||||
}
|
||||
|
||||
static EXECUTOR: StaticCell<Executor> = StaticCell::new();
|
||||
|
||||
#[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 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 io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let i2c0 = I2C::new(
|
||||
peripherals.I2C0,
|
||||
io.pins.gpio1,
|
||||
io.pins.gpio2,
|
||||
400u32.kHz(),
|
||||
&mut system.peripheral_clock_control,
|
||||
&clocks,
|
||||
);
|
||||
|
||||
esp32h2_hal::interrupt::enable(Interrupt::I2C_EXT0, Priority::Priority1).unwrap();
|
||||
|
||||
let executor = EXECUTOR.init(Executor::new());
|
||||
executor.run(|spawner| {
|
||||
spawner.spawn(run(i2c0)).ok();
|
||||
});
|
||||
}
|
69
esp32h2-hal/examples/i2c_bmp180_calibration_data.rs
Normal file
69
esp32h2-hal/examples/i2c_bmp180_calibration_data.rs
Normal file
@ -0,0 +1,69 @@
|
||||
//! Read calibration data from BMP180 sensor
|
||||
//!
|
||||
//! This example dumps the calibration data from a BMP180 sensor
|
||||
//!
|
||||
//! The following wiring is assumed:
|
||||
//! - SDA => GPIO1
|
||||
//! - SCL => GPIO2
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use esp32h2_hal::{
|
||||
clock::ClockControl,
|
||||
gpio::IO,
|
||||
i2c::I2C,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
timer::TimerGroup,
|
||||
Rtc,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use esp_println::println;
|
||||
|
||||
#[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 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 io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
// Create a new peripheral object with the described wiring
|
||||
// and standard I2C clock speed
|
||||
let mut i2c = I2C::new(
|
||||
peripherals.I2C0,
|
||||
io.pins.gpio1,
|
||||
io.pins.gpio2,
|
||||
100u32.kHz(),
|
||||
&mut system.peripheral_clock_control,
|
||||
&clocks,
|
||||
);
|
||||
|
||||
loop {
|
||||
let mut data = [0u8; 22];
|
||||
i2c.write_read(0x77, &[0xaa], &mut data).ok();
|
||||
|
||||
println!("{:02x?}", data);
|
||||
}
|
||||
}
|
141
esp32h2-hal/examples/i2c_display.rs
Normal file
141
esp32h2-hal/examples/i2c_display.rs
Normal file
@ -0,0 +1,141 @@
|
||||
//! I2C Display example
|
||||
//!
|
||||
//! This example prints some text on an SSD1306-based
|
||||
//! display (via I2C)
|
||||
//!
|
||||
//! The following wiring is assumed:
|
||||
//! - SDA => GPIO1
|
||||
//! - SCL => GPIO2
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use embedded_graphics::{
|
||||
mono_font::{
|
||||
ascii::{FONT_6X10, FONT_9X18_BOLD},
|
||||
MonoTextStyleBuilder,
|
||||
},
|
||||
pixelcolor::BinaryColor,
|
||||
prelude::*,
|
||||
text::{Alignment, Text},
|
||||
};
|
||||
use esp32h2_hal::{
|
||||
clock::ClockControl,
|
||||
gpio::IO,
|
||||
i2c::I2C,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
timer::TimerGroup,
|
||||
Rtc,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use nb::block;
|
||||
use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306};
|
||||
|
||||
#[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 io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
// Create a new peripheral object with the described wiring
|
||||
// and standard I2C clock speed
|
||||
let i2c = I2C::new(
|
||||
peripherals.I2C0,
|
||||
io.pins.gpio1,
|
||||
io.pins.gpio2,
|
||||
100u32.kHz(),
|
||||
&mut system.peripheral_clock_control,
|
||||
&clocks,
|
||||
);
|
||||
|
||||
// Start timer (5 second interval)
|
||||
timer0.start(5u64.secs());
|
||||
|
||||
// Initialize display
|
||||
let interface = I2CDisplayInterface::new(i2c);
|
||||
let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
|
||||
.into_buffered_graphics_mode();
|
||||
display.init().unwrap();
|
||||
|
||||
// Specify different text styles
|
||||
let text_style = MonoTextStyleBuilder::new()
|
||||
.font(&FONT_6X10)
|
||||
.text_color(BinaryColor::On)
|
||||
.build();
|
||||
let text_style_big = MonoTextStyleBuilder::new()
|
||||
.font(&FONT_9X18_BOLD)
|
||||
.text_color(BinaryColor::On)
|
||||
.build();
|
||||
|
||||
loop {
|
||||
// Fill display bufffer with a centered text with two lines (and two text
|
||||
// styles)
|
||||
Text::with_alignment(
|
||||
"esp-hal",
|
||||
display.bounding_box().center() + Point::new(0, 0),
|
||||
text_style_big,
|
||||
Alignment::Center,
|
||||
)
|
||||
.draw(&mut display)
|
||||
.unwrap();
|
||||
|
||||
Text::with_alignment(
|
||||
"Chip: ESP32-H2",
|
||||
display.bounding_box().center() + Point::new(0, 14),
|
||||
text_style,
|
||||
Alignment::Center,
|
||||
)
|
||||
.draw(&mut display)
|
||||
.unwrap();
|
||||
|
||||
// Write buffer to display
|
||||
display.flush().unwrap();
|
||||
// Clear display buffer
|
||||
display.clear();
|
||||
|
||||
// Wait 5 seconds
|
||||
block!(timer0.wait()).unwrap();
|
||||
|
||||
// Write single-line centered text "Hello World" to buffer
|
||||
Text::with_alignment(
|
||||
"Hello World!",
|
||||
display.bounding_box().center(),
|
||||
text_style_big,
|
||||
Alignment::Center,
|
||||
)
|
||||
.draw(&mut display)
|
||||
.unwrap();
|
||||
|
||||
// Write buffer to display
|
||||
display.flush().unwrap();
|
||||
// Clear display buffer
|
||||
display.clear();
|
||||
|
||||
// Wait 5 seconds
|
||||
block!(timer0.wait()).unwrap();
|
||||
}
|
||||
}
|
48
esp32h2-hal/examples/read_efuse.rs
Normal file
48
esp32h2-hal/examples/read_efuse.rs
Normal file
@ -0,0 +1,48 @@
|
||||
//! This shows how to read selected information from eFuses.
|
||||
//! e.g. the MAC address
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use esp32h2_hal::{
|
||||
clock::ClockControl,
|
||||
efuse::Efuse,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
timer::TimerGroup,
|
||||
Rtc,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use esp_println::println;
|
||||
|
||||
#[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 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();
|
||||
|
||||
println!("MAC address {:02x?}", Efuse::get_mac_address());
|
||||
println!("Flash Encryption {:?}", Efuse::get_flash_encryption());
|
||||
|
||||
loop {}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user