Compare commits

..

13 Commits

Author SHA1 Message Date
03325ea81b update embedded-storage{,-async}, remove patch. 2023-12-04 13:48:36 +01:00
52fabbfb46 Merge pull request #2224 from cbruiz/stm32g0-usb_spi
Add support for HSE Oscillator in stm32g0
2023-12-04 12:32:52 +00:00
09592ffa6a stm32/rcc: Add support for HSE Oscillator in stm32g0 2023-12-04 13:28:00 +01:00
b867f9b5b6 Merge pull request #2241 from adamgreig/stm32-uid
STM32: Add UID driver
2023-12-03 23:22:57 +00:00
198ef8183e STM32: Add UID driver 2023-12-03 23:17:49 +00:00
696c703b8c Merge pull request #2237 from badrbouslikhin/main
stm32/rcc: make h7 rm0399 power supply configurable
2023-12-03 22:47:34 +00:00
521cdef8a1 Merge pull request #2245 from peter9477/nrf52-qspi-zerolen-fix
nrf52/qspi: avoid infinite busy-wait read/write with zero-len buf
2023-12-03 23:21:32 +01:00
1dc31c4627 Merge pull request #2244 from embassy-rs/rm-xtensa
executor: remove arch-xtensa.
2023-12-03 23:21:17 +01:00
9fb2eb7470 nrf52/qspi: avoid infinite busy-wait on QSPI read/write with zero-len buffer, fixes #2115 2023-12-03 16:35:39 -05:00
ea43d74780 stm32/rcc: add missing h7 power config 2023-12-02 14:55:00 +01:00
22c39fd697 stm32/rcc: refactor h7 rm0455,rm0468 and rm0468 power management 2023-12-02 14:47:36 +01:00
87c0f1525d stm32/rcc: enable power supply configurability for rm0455 and rm0468 2023-12-02 14:45:36 +01:00
c97f65ac60 stm32/rcc: make h7 rm0399 power supply configurable 2023-12-01 15:05:31 +01:00
30 changed files with 230 additions and 47 deletions

View File

@ -1,3 +0,0 @@
[patch.crates-io]
embedded-storage = { git = "https://github.com/rust-embedded-community/embedded-storage", rev = "634302740f8d676538c3890748e7d7dfe372a040" }
embedded-storage-async = { git = "https://github.com/rust-embedded-community/embedded-storage", rev = "634302740f8d676538c3890748e7d7dfe372a040" }

View File

@ -29,8 +29,8 @@ log = { version = "0.4", optional = true }
ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true }
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
embassy-sync = { version = "0.4.0", path = "../../embassy-sync" }
embedded-storage = "0.3.0"
embedded-storage-async = { version = "0.4.0" }
embedded-storage = "0.3.1"
embedded-storage-async = { version = "0.4.1" }
salty = { git = "https://github.com/ycrypto/salty.git", rev = "a9f17911a5024698406b75c0fac56ab5ccf6a8c7", optional = true }
signature = { version = "1.6.4", default-features = false }

View File

@ -21,8 +21,8 @@ embassy-nrf = { path = "../../embassy-nrf" }
embassy-boot = { path = "../boot", default-features = false }
cortex-m = { version = "0.7.6" }
cortex-m-rt = { version = "0.7" }
embedded-storage = "0.3.0"
embedded-storage-async = { version = "0.4.0" }
embedded-storage = "0.3.1"
embedded-storage-async = { version = "0.4.1" }
cfg-if = "1.0.0"
nrf-softdevice-mbr = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-softdevice.git", branch = "master", optional = true }

View File

@ -24,8 +24,8 @@ embassy-time = { path = "../../embassy-time" }
cortex-m = { version = "0.7.6" }
cortex-m-rt = { version = "0.7" }
embedded-storage = "0.3.0"
embedded-storage-async = { version = "0.4.0" }
embedded-storage = "0.3.1"
embedded-storage-async = { version = "0.4.1" }
cfg-if = "1.0.0"
[features]

View File

@ -23,8 +23,8 @@ embassy-stm32 = { path = "../../embassy-stm32", default-features = false }
embassy-boot = { path = "../boot", default-features = false }
cortex-m = { version = "0.7.6" }
cortex-m-rt = { version = "0.7" }
embedded-storage = "0.3.0"
embedded-storage-async = { version = "0.4.0" }
embedded-storage = "0.3.1"
embedded-storage-async = { version = "0.4.1" }
cfg-if = "1.0.0"
[features]

View File

@ -25,8 +25,8 @@ embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
] }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" }
embedded-hal-async = { version = "=1.0.0-rc.2" }
embedded-storage = "0.3.0"
embedded-storage-async = { version = "0.4.0" }
embedded-storage = "0.3.1"
embedded-storage-async = { version = "0.4.1" }
nb = "1.0.0"
defmt = { version = "0.3", optional = true }

View File

@ -106,7 +106,7 @@ cortex-m = "0.7.6"
critical-section = "1.1"
rand_core = "0.6.3"
fixed = "1.10.0"
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
embedded-storage-async = "0.4.0"
cfg-if = "1.0.0"

22
embassy-nrf/src/qspi.rs Normal file → Executable file
View File

@ -391,8 +391,13 @@ impl<'d, T: Instance> Qspi<'d, T> {
///
/// The difference with `read` is that this does not do bounds checks
/// against the flash capacity. It is intended for use when QSPI is used as
/// a raw bus, not with flash memory.
/// a raw bus, not with flash memory.
pub async fn read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
// Avoid blocking_wait_ready() blocking forever on zero-length buffers.
if data.len() == 0 {
return Ok(());
}
let ondrop = OnDrop::new(Self::blocking_wait_ready);
self.start_read(address, data)?;
@ -409,6 +414,11 @@ impl<'d, T: Instance> Qspi<'d, T> {
/// against the flash capacity. It is intended for use when QSPI is used as
/// a raw bus, not with flash memory.
pub async fn write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
// Avoid blocking_wait_ready() blocking forever on zero-length buffers.
if data.len() == 0 {
return Ok(());
}
let ondrop = OnDrop::new(Self::blocking_wait_ready);
self.start_write(address, data)?;
@ -425,6 +435,11 @@ impl<'d, T: Instance> Qspi<'d, T> {
/// against the flash capacity. It is intended for use when QSPI is used as
/// a raw bus, not with flash memory.
pub fn blocking_read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
// Avoid blocking_wait_ready() blocking forever on zero-length buffers.
if data.len() == 0 {
return Ok(());
}
self.start_read(address, data)?;
Self::blocking_wait_ready();
Ok(())
@ -436,6 +451,11 @@ impl<'d, T: Instance> Qspi<'d, T> {
/// against the flash capacity. It is intended for use when QSPI is used as
/// a raw bus, not with flash memory.
pub fn blocking_write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
// Avoid blocking_wait_ready() blocking forever on zero-length buffers.
if data.len() == 0 {
return Ok(());
}
self.start_write(address, data)?;
Self::blocking_wait_ready();
Ok(())

View File

@ -71,7 +71,7 @@ chrono = { version = "0.4", default-features = false, optional = true }
embedded-io = { version = "0.6.0" }
embedded-io-async = { version = "0.6.1" }
embedded-storage = { version = "0.3" }
embedded-storage-async = { version = "0.4.0" }
embedded-storage-async = { version = "0.4.1" }
rand_core = "0.6.4"
fixed = "1.23.1"

View File

@ -46,8 +46,8 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.2" }
embedded-hal-async = { version = "=1.0.0-rc.2" }
embedded-hal-nb = { version = "=1.0.0-rc.2" }
embedded-storage = "0.3.0"
embedded-storage-async = { version = "0.4.0" }
embedded-storage = "0.3.1"
embedded-storage-async = { version = "0.4.1" }
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }

View File

@ -63,6 +63,8 @@ pub mod sai;
pub mod sdmmc;
#[cfg(spi)]
pub mod spi;
#[cfg(uid)]
pub mod uid;
#[cfg(usart)]
pub mod usart;
#[cfg(usb)]

View File

@ -10,10 +10,18 @@ use crate::time::Hertz;
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum HseMode {
/// crystal/ceramic oscillator (HSEBYP=0)
Oscillator,
/// external analog clock (low swing) (HSEBYP=1)
Bypass,
}
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
HSE(Hertz),
HSE(Hertz, HseMode),
HSI(HSIPrescaler),
PLL(PllConfig),
LSI,
@ -61,7 +69,7 @@ impl Default for PllConfig {
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum PllSource {
HSI,
HSE(Hertz),
HSE(Hertz, HseMode),
}
/// Clocks configutation
@ -90,7 +98,7 @@ impl PllConfig {
pub(crate) fn init(self) -> Hertz {
let (src, input_freq) = match self.source {
PllSource::HSI => (vals::Pllsrc::HSI, HSI_FREQ),
PllSource::HSE(freq) => (vals::Pllsrc::HSE, freq),
PllSource::HSE(freq, _) => (vals::Pllsrc::HSE, freq),
};
let m_freq = input_freq / self.m;
@ -125,8 +133,11 @@ impl PllConfig {
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
}
PllSource::HSE(_) => {
RCC.cr().write(|w| w.set_hseon(true));
PllSource::HSE(_, mode) => {
RCC.cr().write(|w| {
w.set_hsebyp(mode != HseMode::Oscillator);
w.set_hseon(true);
});
while !RCC.cr().read().hserdy() {}
}
}
@ -177,9 +188,12 @@ pub(crate) unsafe fn init(config: Config) {
(HSI_FREQ / div, Sw::HSI)
}
ClockSrc::HSE(freq) => {
ClockSrc::HSE(freq, mode) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
RCC.cr().write(|w| {
w.set_hseon(true);
w.set_hsebyp(mode != HseMode::Oscillator);
});
while !RCC.cr().read().hserdy() {}
(freq, Sw::HSE)

View File

@ -117,6 +117,75 @@ impl From<TimerPrescaler> for Timpre {
}
}
/// Power supply configuration
/// See RM0433 Rev 4 7.4
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
#[derive(PartialEq)]
pub enum SupplyConfig {
/// Default power supply configuration.
/// V CORE Power Domains are supplied from the LDO according to VOS.
/// SMPS step-down converter enabled at 1.2V, may be used to supply the LDO.
Default,
/// Power supply configuration using the LDO.
/// V CORE Power Domains are supplied from the LDO according to VOS.
/// LDO power mode (Main, LP, Off) will follow system low-power modes.
/// SMPS step-down converter disabled.
LDO,
/// Power supply configuration directly from the SMPS step-down converter.
/// V CORE Power Domains are supplied from SMPS step-down converter according to VOS.
/// LDO bypassed.
/// SMPS step-down converter power mode (MR, LP, Off) will follow system low-power modes.
DirectSMPS,
/// Power supply configuration from the SMPS step-down converter, that supplies the LDO.
/// V CORE Power Domains are supplied from the LDO according to VOS
/// LDO power mode (Main, LP, Off) will follow system low-power modes.
/// SMPS step-down converter enabled according to SDLEVEL, and supplies the LDO.
/// SMPS step-down converter power mode (MR, LP, Off) will follow system low-power modes.
SMPSLDO(SMPSSupplyVoltage),
/// Power supply configuration from SMPS supplying external circuits and potentially the LDO.
/// V CORE Power Domains are supplied from voltage regulator according to VOS
/// LDO power mode (Main, LP, Off) will follow system low-power modes.
/// SMPS step-down converter enabled according to SDLEVEL used to supply external circuits and may supply the LDO.
/// SMPS step-down converter forced ON in MR mode.
SMPSExternalLDO(SMPSSupplyVoltage),
/// Power supply configuration from SMPS supplying external circuits and bypassing the LDO.
/// V CORE supplied from external source
/// SMPS step-down converter enabled according to SDLEVEL used to supply external circuits and may supply the external source for V CORE .
/// SMPS step-down converter forced ON in MR mode.
SMPSExternalLDOBypass(SMPSSupplyVoltage),
/// Power supply configuration from an external source, SMPS disabled and the LDO bypassed.
/// V CORE supplied from external source
/// SMPS step-down converter disabled and LDO bypassed, voltage monitoring still active.
SMPSDisabledLDOBypass,
}
/// SMPS step-down converter voltage output level.
/// This is only used in certain power supply configurations:
/// SMPSLDO, SMPSExternalLDO, SMPSExternalLDOBypass.
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
#[derive(PartialEq)]
pub enum SMPSSupplyVoltage {
V1_8,
V2_5,
}
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
impl SMPSSupplyVoltage {
/// Convert SMPSSupplyVoltage to u8 representation.
fn to_u8(&self) -> u8 {
match self {
SMPSSupplyVoltage::V1_8 => 0b01,
SMPSSupplyVoltage::V2_5 => 0b10,
}
}
}
/// Configuration of the core clocks
#[non_exhaustive]
pub struct Config {
@ -144,6 +213,9 @@ pub struct Config {
pub timer_prescaler: TimerPrescaler,
pub voltage_scale: VoltageScale,
pub ls: super::LsConfig,
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
pub supply_config: SupplyConfig,
}
impl Default for Config {
@ -177,6 +249,9 @@ impl Default for Config {
timer_prescaler: TimerPrescaler::DefaultX2,
voltage_scale: VoltageScale::Scale0,
ls: Default::default(),
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
supply_config: SupplyConfig::Default,
}
}
}
@ -195,12 +270,58 @@ pub(crate) unsafe fn init(config: Config) {
});
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
PWR.cr3().modify(|w| {
// hardcode "Direct SPMS" for now, this is what works on nucleos with the
// default solderbridge configuration.
w.set_sden(true);
w.set_ldoen(false);
});
{
match config.supply_config {
SupplyConfig::Default => {
PWR.cr3().modify(|w| {
w.set_sdlevel(0b00);
w.set_sdexthp(false);
w.set_sden(true);
w.set_ldoen(true);
w.set_bypass(false);
});
}
SupplyConfig::LDO => {
PWR.cr3().modify(|w| {
w.set_sden(false);
w.set_ldoen(true);
w.set_bypass(false);
});
}
SupplyConfig::DirectSMPS => {
PWR.cr3().modify(|w| {
w.set_sdexthp(false);
w.set_sden(true);
w.set_ldoen(false);
w.set_bypass(false);
});
}
SupplyConfig::SMPSLDO(ref smps_supply_voltage)
| SupplyConfig::SMPSExternalLDO(ref smps_supply_voltage)
| SupplyConfig::SMPSExternalLDOBypass(ref smps_supply_voltage) => {
PWR.cr3().modify(|w| {
w.set_sdlevel(smps_supply_voltage.to_u8());
w.set_sdexthp(matches!(
config.supply_config,
SupplyConfig::SMPSExternalLDO(_) | SupplyConfig::SMPSExternalLDOBypass(_)
));
w.set_sden(true);
w.set_ldoen(matches!(
config.supply_config,
SupplyConfig::SMPSLDO(_) | SupplyConfig::SMPSExternalLDO(_)
));
w.set_bypass(matches!(config.supply_config, SupplyConfig::SMPSExternalLDOBypass(_)));
});
}
SupplyConfig::SMPSDisabledLDOBypass => {
PWR.cr3().modify(|w| {
w.set_sden(false);
w.set_ldoen(false);
w.set_bypass(true);
});
}
}
}
// Validate the supply configuration. If you are stuck here, it is
// because the voltages on your board do not match those specified

29
embassy-stm32/src/uid.rs Normal file
View File

@ -0,0 +1,29 @@
/// Get this device's unique 96-bit ID.
pub fn uid() -> &'static [u8; 12] {
unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() }
}
/// Get this device's unique 96-bit ID, encoded into a string of 24 hexadecimal ASCII digits.
pub fn uid_hex() -> &'static str {
unsafe { core::str::from_utf8_unchecked(uid_hex_bytes()) }
}
/// Get this device's unique 96-bit ID, encoded into 24 hexadecimal ASCII bytes.
pub fn uid_hex_bytes() -> &'static [u8; 24] {
const HEX: &[u8; 16] = b"0123456789ABCDEF";
static mut UID_HEX: [u8; 24] = [0; 24];
static mut LOADED: bool = false;
critical_section::with(|_| unsafe {
if !LOADED {
let uid = uid();
for (idx, v) in uid.iter().enumerate() {
let lo = v & 0x0f;
let hi = (v & 0xf0) >> 4;
UID_HEX[idx * 2] = HEX[hi as usize];
UID_HEX[idx * 2 + 1] = HEX[lo as usize];
}
LOADED = true;
}
});
unsafe { &UID_HEX }
}

View File

@ -20,7 +20,7 @@ embedded-hal = { version = "0.2.6" }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
[features]
default = ["panic-reset"]

View File

@ -16,7 +16,7 @@ defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
panic-reset = { version = "0.1.1" }
embedded-hal = { version = "0.2.6" }
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"

View File

@ -16,7 +16,7 @@ defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
panic-reset = { version = "0.1.1" }
embedded-hal = { version = "0.2.6" }
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"

View File

@ -16,7 +16,7 @@ embassy-time = { path = "../../../../embassy-time", features = [] }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = { version = "0.7" }
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
embedded-storage-async = "0.4.0"
cfg-if = "1.0.0"

View File

@ -14,7 +14,7 @@ embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32" }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
cortex-m-rt = { version = "0.7" }
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
embedded-storage-async = "0.4.0"
cfg-if = "1.0.0"

View File

@ -33,7 +33,7 @@ cortex-m-rt = "0.7.0"
panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
rand = { version = "0.8.4", default-features = false }
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
usbd-hid = "0.6.0"
serde = { version = "1.0.136", default-features = false }
embedded-hal = { version = "1.0.0-rc.2" }

View File

@ -23,7 +23,7 @@ cortex-m-rt = "0.7.0"
panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
rand = { version = "0.8.4", default-features = false }
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
usbd-hid = "0.6.0"
serde = { version = "1.0.136", default-features = false }

View File

@ -23,7 +23,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
heapless = { version = "0.8", default-features = false }
nb = "1.0.0"
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
static_cell = { version = "2", features = ["nightly"]}
[profile.release]

View File

@ -22,5 +22,5 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
heapless = { version = "0.8", default-features = false }
nb = "1.0.0"
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
static_cell = { version = "2", features = ["nightly"]}

View File

@ -25,7 +25,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
heapless = { version = "0.8", default-features = false }
nb = "1.0.0"
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
micromath = "2.0.0"
static_cell = { version = "2", features = ["nightly"]}
chrono = { version = "^0.4", default-features = false}

View File

@ -26,7 +26,7 @@ heapless = { version = "0.8", default-features = false }
nb = "1.0.0"
rand_core = "0.6.3"
critical-section = "1.1"
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
static_cell = { version = "2", features = ["nightly"]}
[profile.release]

View File

@ -30,7 +30,7 @@ rand_core = "0.6.3"
critical-section = "1.1"
micromath = "2.0.0"
stm32-fmc = "0.3.0"
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
static_cell = { version = "2", features = ["nightly"]}
# cargo build/run

View File

@ -30,7 +30,7 @@ rand_core = "0.6.3"
critical-section = "1.1"
micromath = "2.0.0"
stm32-fmc = "0.3.0"
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
static_cell = { version = "2", features = ["nightly"]}
chrono = { version = "^0.4", default-features = false }

View File

@ -18,7 +18,7 @@ embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["de
defmt = "0.3"
defmt-rtt = "0.4"
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
embedded-io = { version = "0.6.0" }
embedded-io-async = { version = "0.6.1" }

View File

@ -19,7 +19,7 @@ embedded-hal = "0.2.6"
panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
heapless = { version = "0.8", default-features = false }
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
[profile.release]
debug = 2

View File

@ -18,7 +18,7 @@ defmt-rtt = "0.4"
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0"
embedded-hal = "0.2.6"
embedded-storage = "0.3.0"
embedded-storage = "0.3.1"
panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
heapless = { version = "0.8", default-features = false }