Compare commits
	
		
			8 Commits
		
	
	
		
			apidoc-emb
			...
			boot-nrf-s
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 896690c415 | ||
|  | c8eb128a56 | ||
|  | 22ee868f04 | ||
|  | 1c3cf347cb | ||
|  | 13c107e815 | ||
|  | 52a801fdb7 | ||
|  | fc6e70caa5 | ||
|  | f9d0daad80 | 
							
								
								
									
										4
									
								
								ci.sh
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								ci.sh
									
									
									
									
									
								
							| @@ -91,12 +91,12 @@ cargo batch  \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f417zg,defmt,exti,time-driver-any,time \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f423zh,defmt,exti,time-driver-any,time \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f427zi,defmt,exti,time-driver-any,time \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,embedded-sdmmc,time \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f437zi,log,exti,time-driver-any,time \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f439zi,defmt,exti,time-driver-any,time \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446ze,defmt,exti,time-driver-any,time \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f469zi,defmt,exti,time-driver-any,time \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f479zi,defmt,exti,time-driver-any,embedded-sdmmc,time \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f479zi,defmt,exti,time-driver-any,time \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f730i8,defmt,exti,time-driver-any,time \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi,defmt,exti,time-driver-any,time \ | ||||
|     --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h735zg,defmt,exti,time-driver-any,time \ | ||||
|   | ||||
| @@ -4,6 +4,12 @@ name = "embassy-boot-nrf" | ||||
| version = "0.1.0" | ||||
| description = "Bootloader lib for nRF chips" | ||||
| license = "MIT OR Apache-2.0" | ||||
| repository = "https://github.com/embassy-rs/embassy" | ||||
| categories = [ | ||||
|     "embedded", | ||||
|     "no-std", | ||||
|     "asynchronous", | ||||
| ] | ||||
|  | ||||
| [package.metadata.embassy_docs] | ||||
| src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/nrf/src/" | ||||
| @@ -25,7 +31,7 @@ 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 } | ||||
| nrf-softdevice-mbr = { version = "0.2.0", optional = true } | ||||
|  | ||||
| [features] | ||||
| defmt = [ | ||||
|   | ||||
| @@ -4,6 +4,12 @@ name = "embassy-boot-rp" | ||||
| version = "0.1.0" | ||||
| description = "Bootloader lib for RP2040 chips" | ||||
| license = "MIT OR Apache-2.0" | ||||
| repository = "https://github.com/embassy-rs/embassy" | ||||
| categories = [ | ||||
|     "embedded", | ||||
|     "no-std", | ||||
|     "asynchronous", | ||||
| ] | ||||
|  | ||||
| [package.metadata.embassy_docs] | ||||
| src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-rp-v$VERSION/src/" | ||||
|   | ||||
| @@ -4,6 +4,12 @@ name = "embassy-boot-stm32" | ||||
| version = "0.1.0" | ||||
| description = "Bootloader lib for STM32 chips" | ||||
| license = "MIT OR Apache-2.0" | ||||
| repository = "https://github.com/embassy-rs/embassy" | ||||
| categories = [ | ||||
|     "embedded", | ||||
|     "no-std", | ||||
|     "asynchronous", | ||||
| ] | ||||
|  | ||||
| [package.metadata.embassy_docs] | ||||
| src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/stm32/src/" | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| #![no_std] | ||||
| #![doc = include_str!("../README.md")] | ||||
| #![warn(missing_docs)] | ||||
|  | ||||
| // must go first! | ||||
| mod fmt; | ||||
| @@ -15,6 +16,9 @@ use embassy_sync::blocking_mutex::Mutex; | ||||
| use embassy_sync::waitqueue::WakerRegistration; | ||||
| use embassy_sync::zerocopy_channel; | ||||
|  | ||||
| /// Channel state. | ||||
| /// | ||||
| /// Holds a buffer of packets with size MTU, for both TX and RX. | ||||
| pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> { | ||||
|     rx: [PacketBuf<MTU>; N_RX], | ||||
|     tx: [PacketBuf<MTU>; N_TX], | ||||
| @@ -24,6 +28,7 @@ pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> { | ||||
| impl<const MTU: usize, const N_RX: usize, const N_TX: usize> State<MTU, N_RX, N_TX> { | ||||
|     const NEW_PACKET: PacketBuf<MTU> = PacketBuf::new(); | ||||
|  | ||||
|     /// Create a new channel state. | ||||
|     pub const fn new() -> Self { | ||||
|         Self { | ||||
|             rx: [Self::NEW_PACKET; N_RX], | ||||
| @@ -39,33 +44,45 @@ struct StateInner<'d, const MTU: usize> { | ||||
|     shared: Mutex<NoopRawMutex, RefCell<Shared>>, | ||||
| } | ||||
|  | ||||
| /// State of the LinkState | ||||
| struct Shared { | ||||
|     link_state: LinkState, | ||||
|     waker: WakerRegistration, | ||||
|     hardware_address: driver::HardwareAddress, | ||||
| } | ||||
|  | ||||
| /// Channel runner. | ||||
| /// | ||||
| /// Holds the shared state and the lower end of channels for inbound and outbound packets. | ||||
| pub struct Runner<'d, const MTU: usize> { | ||||
|     tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>, | ||||
|     rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>, | ||||
|     shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>, | ||||
| } | ||||
|  | ||||
| /// State runner. | ||||
| /// | ||||
| /// Holds the shared state of the channel such as link state. | ||||
| #[derive(Clone, Copy)] | ||||
| pub struct StateRunner<'d> { | ||||
|     shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>, | ||||
| } | ||||
|  | ||||
| /// RX runner. | ||||
| /// | ||||
| /// Holds the lower end of the channel for passing inbound packets up the stack. | ||||
| pub struct RxRunner<'d, const MTU: usize> { | ||||
|     rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>, | ||||
| } | ||||
|  | ||||
| /// TX runner. | ||||
| /// | ||||
| /// Holds the lower end of the channel for passing outbound packets down the stack. | ||||
| pub struct TxRunner<'d, const MTU: usize> { | ||||
|     tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>, | ||||
| } | ||||
|  | ||||
| impl<'d, const MTU: usize> Runner<'d, MTU> { | ||||
|     /// Split the runner into separate runners for controlling state, rx and tx. | ||||
|     pub fn split(self) -> (StateRunner<'d>, RxRunner<'d, MTU>, TxRunner<'d, MTU>) { | ||||
|         ( | ||||
|             StateRunner { shared: self.shared }, | ||||
| @@ -74,6 +91,7 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     /// Split the runner into separate runners for controlling state, rx and tx borrowing the underlying state. | ||||
|     pub fn borrow_split(&mut self) -> (StateRunner<'_>, RxRunner<'_, MTU>, TxRunner<'_, MTU>) { | ||||
|         ( | ||||
|             StateRunner { shared: self.shared }, | ||||
| @@ -86,10 +104,12 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     /// Create a state runner sharing the state channel. | ||||
|     pub fn state_runner(&self) -> StateRunner<'d> { | ||||
|         StateRunner { shared: self.shared } | ||||
|     } | ||||
|  | ||||
|     /// Set the link state. | ||||
|     pub fn set_link_state(&mut self, state: LinkState) { | ||||
|         self.shared.lock(|s| { | ||||
|             let s = &mut *s.borrow_mut(); | ||||
| @@ -98,6 +118,7 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     /// Set the hardware address. | ||||
|     pub fn set_hardware_address(&mut self, address: driver::HardwareAddress) { | ||||
|         self.shared.lock(|s| { | ||||
|             let s = &mut *s.borrow_mut(); | ||||
| @@ -106,16 +127,19 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     /// Wait until there is space for more inbound packets and return a slice they can be copied into. | ||||
|     pub async fn rx_buf(&mut self) -> &mut [u8] { | ||||
|         let p = self.rx_chan.send().await; | ||||
|         &mut p.buf | ||||
|     } | ||||
|  | ||||
|     /// Check if there is space for more inbound packets right now. | ||||
|     pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> { | ||||
|         let p = self.rx_chan.try_send()?; | ||||
|         Some(&mut p.buf) | ||||
|     } | ||||
|  | ||||
|     /// Polling the inbound channel if there is space for packets. | ||||
|     pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { | ||||
|         match self.rx_chan.poll_send(cx) { | ||||
|             Poll::Ready(p) => Poll::Ready(&mut p.buf), | ||||
| @@ -123,22 +147,26 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Mark packet of len bytes as pushed to the inbound channel. | ||||
|     pub fn rx_done(&mut self, len: usize) { | ||||
|         let p = self.rx_chan.try_send().unwrap(); | ||||
|         p.len = len; | ||||
|         self.rx_chan.send_done(); | ||||
|     } | ||||
|  | ||||
|     /// Wait until there is space for more outbound packets and return a slice they can be copied into. | ||||
|     pub async fn tx_buf(&mut self) -> &mut [u8] { | ||||
|         let p = self.tx_chan.receive().await; | ||||
|         &mut p.buf[..p.len] | ||||
|     } | ||||
|  | ||||
|     /// Check if there is space for more outbound packets right now. | ||||
|     pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { | ||||
|         let p = self.tx_chan.try_receive()?; | ||||
|         Some(&mut p.buf[..p.len]) | ||||
|     } | ||||
|  | ||||
|     /// Polling the outbound channel if there is space for packets. | ||||
|     pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { | ||||
|         match self.tx_chan.poll_receive(cx) { | ||||
|             Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), | ||||
| @@ -146,12 +174,14 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Mark outbound packet as copied. | ||||
|     pub fn tx_done(&mut self) { | ||||
|         self.tx_chan.receive_done(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'d> StateRunner<'d> { | ||||
|     /// Set link state. | ||||
|     pub fn set_link_state(&self, state: LinkState) { | ||||
|         self.shared.lock(|s| { | ||||
|             let s = &mut *s.borrow_mut(); | ||||
| @@ -160,6 +190,7 @@ impl<'d> StateRunner<'d> { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     /// Set the hardware address. | ||||
|     pub fn set_hardware_address(&self, address: driver::HardwareAddress) { | ||||
|         self.shared.lock(|s| { | ||||
|             let s = &mut *s.borrow_mut(); | ||||
| @@ -170,16 +201,19 @@ impl<'d> StateRunner<'d> { | ||||
| } | ||||
|  | ||||
| impl<'d, const MTU: usize> RxRunner<'d, MTU> { | ||||
|     /// Wait until there is space for more inbound packets and return a slice they can be copied into. | ||||
|     pub async fn rx_buf(&mut self) -> &mut [u8] { | ||||
|         let p = self.rx_chan.send().await; | ||||
|         &mut p.buf | ||||
|     } | ||||
|  | ||||
|     /// Check if there is space for more inbound packets right now. | ||||
|     pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> { | ||||
|         let p = self.rx_chan.try_send()?; | ||||
|         Some(&mut p.buf) | ||||
|     } | ||||
|  | ||||
|     /// Polling the inbound channel if there is space for packets. | ||||
|     pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { | ||||
|         match self.rx_chan.poll_send(cx) { | ||||
|             Poll::Ready(p) => Poll::Ready(&mut p.buf), | ||||
| @@ -187,6 +221,7 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Mark packet of len bytes as pushed to the inbound channel. | ||||
|     pub fn rx_done(&mut self, len: usize) { | ||||
|         let p = self.rx_chan.try_send().unwrap(); | ||||
|         p.len = len; | ||||
| @@ -195,16 +230,19 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> { | ||||
| } | ||||
|  | ||||
| impl<'d, const MTU: usize> TxRunner<'d, MTU> { | ||||
|     /// Wait until there is space for more outbound packets and return a slice they can be copied into. | ||||
|     pub async fn tx_buf(&mut self) -> &mut [u8] { | ||||
|         let p = self.tx_chan.receive().await; | ||||
|         &mut p.buf[..p.len] | ||||
|     } | ||||
|  | ||||
|     /// Check if there is space for more outbound packets right now. | ||||
|     pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { | ||||
|         let p = self.tx_chan.try_receive()?; | ||||
|         Some(&mut p.buf[..p.len]) | ||||
|     } | ||||
|  | ||||
|     /// Polling the outbound channel if there is space for packets. | ||||
|     pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { | ||||
|         match self.tx_chan.poll_receive(cx) { | ||||
|             Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), | ||||
| @@ -212,11 +250,18 @@ impl<'d, const MTU: usize> TxRunner<'d, MTU> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Mark outbound packet as copied. | ||||
|     pub fn tx_done(&mut self) { | ||||
|         self.tx_chan.receive_done(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Create a channel. | ||||
| /// | ||||
| /// Returns a pair of handles for interfacing with the peripheral and the networking stack. | ||||
| /// | ||||
| /// The runner is interfacing with the peripheral at the lower part of the stack. | ||||
| /// The device is interfacing with the networking stack on the layer above. | ||||
| pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>( | ||||
|     state: &'d mut State<MTU, N_RX, N_TX>, | ||||
|     hardware_address: driver::HardwareAddress, | ||||
| @@ -257,17 +302,22 @@ pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>( | ||||
|     ) | ||||
| } | ||||
|  | ||||
| /// Represents a packet of size MTU. | ||||
| pub struct PacketBuf<const MTU: usize> { | ||||
|     len: usize, | ||||
|     buf: [u8; MTU], | ||||
| } | ||||
|  | ||||
| impl<const MTU: usize> PacketBuf<MTU> { | ||||
|     /// Create a new packet buffer. | ||||
|     pub const fn new() -> Self { | ||||
|         Self { len: 0, buf: [0; MTU] } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Channel device. | ||||
| /// | ||||
| /// Holds the shared state and upper end of channels for inbound and outbound packets. | ||||
| pub struct Device<'d, const MTU: usize> { | ||||
|     rx: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>, | ||||
|     tx: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>, | ||||
| @@ -314,6 +364,9 @@ impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A rx token. | ||||
| /// | ||||
| /// Holds inbound receive channel and interfaces with embassy-net-driver. | ||||
| pub struct RxToken<'a, const MTU: usize> { | ||||
|     rx: zerocopy_channel::Receiver<'a, NoopRawMutex, PacketBuf<MTU>>, | ||||
| } | ||||
| @@ -331,6 +384,9 @@ impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A tx token. | ||||
| /// | ||||
| /// Holds outbound transmit channel and interfaces with embassy-net-driver. | ||||
| pub struct TxToken<'a, const MTU: usize> { | ||||
|     tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf<MTU>>, | ||||
| } | ||||
|   | ||||
| @@ -56,7 +56,6 @@ cortex-m = "0.7.6" | ||||
| futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||||
| rand_core = "0.6.3" | ||||
| sdio-host = "0.5.0" | ||||
| embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | ||||
| critical-section = "1.1" | ||||
| stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2234f380f51d16d0398b8e547088b33ea623cc7c" } | ||||
| vcell = "0.1.3" | ||||
|   | ||||
| @@ -1538,53 +1538,3 @@ foreach_peripheral!( | ||||
|         impl Instance for peripherals::$inst {} | ||||
|     }; | ||||
| ); | ||||
|  | ||||
| #[cfg(feature = "embedded-sdmmc")] | ||||
| mod sdmmc_rs { | ||||
|     use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx}; | ||||
|  | ||||
|     use super::*; | ||||
|  | ||||
|     impl<'d, T: Instance, Dma: SdmmcDma<T>> BlockDevice for Sdmmc<'d, T, Dma> { | ||||
|         type Error = Error; | ||||
|  | ||||
|         async fn read( | ||||
|             &mut self, | ||||
|             blocks: &mut [Block], | ||||
|             start_block_idx: BlockIdx, | ||||
|             _reason: &str, | ||||
|         ) -> Result<(), Self::Error> { | ||||
|             let mut address = start_block_idx.0; | ||||
|  | ||||
|             for block in blocks.iter_mut() { | ||||
|                 let block: &mut [u8; 512] = &mut block.contents; | ||||
|  | ||||
|                 // NOTE(unsafe) Block uses align(4) | ||||
|                 let block = unsafe { &mut *(block as *mut _ as *mut DataBlock) }; | ||||
|                 self.read_block(address, block).await?; | ||||
|                 address += 1; | ||||
|             } | ||||
|             Ok(()) | ||||
|         } | ||||
|  | ||||
|         async fn write(&mut self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error> { | ||||
|             let mut address = start_block_idx.0; | ||||
|  | ||||
|             for block in blocks.iter() { | ||||
|                 let block: &[u8; 512] = &block.contents; | ||||
|  | ||||
|                 // NOTE(unsafe) DataBlock uses align 4 | ||||
|                 let block = unsafe { &*(block as *const _ as *const DataBlock) }; | ||||
|                 self.write_block(address, block).await?; | ||||
|                 address += 1; | ||||
|             } | ||||
|             Ok(()) | ||||
|         } | ||||
|  | ||||
|         fn num_blocks(&self) -> Result<BlockCount, Self::Error> { | ||||
|             let card = self.card()?; | ||||
|             let count = card.csd.block_count(); | ||||
|             Ok(BlockCount(count)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -111,6 +111,20 @@ where | ||||
|         poll_fn(move |cx| self.poll_wait(cx)) | ||||
|     } | ||||
|  | ||||
|     /// non-blocking method to try and take the signal value. | ||||
|     pub fn try_take(&self) -> Option<T> { | ||||
|         self.state.lock(|cell| { | ||||
|             let state = cell.replace(State::None); | ||||
|             match state { | ||||
|                 State::Signaled(res) => Some(res), | ||||
|                 state => { | ||||
|                     cell.set(state); | ||||
|                     None | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     /// non-blocking method to check whether this signal has been signaled. | ||||
|     pub fn signaled(&self) -> bool { | ||||
|         self.state.lock(|cell| { | ||||
|   | ||||
| @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" | ||||
|  | ||||
| [dependencies] | ||||
| # Change stm32f429zi to your chip name, if necessary. | ||||
| embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"]  } | ||||
| embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"]  } | ||||
| embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | ||||
| embassy-executor = { version = "0.4.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | ||||
| embassy-time = { version = "0.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user