commit
						bab4affe7c
					
				
							
								
								
									
										1
									
								
								ci.sh
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								ci.sh
									
									
									
									
									
								
							| @ -189,6 +189,7 @@ cargo batch \ | |||||||
|     --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \ |     --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \ | ||||||
|     --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \ |     --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \ | ||||||
|     --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \ |     --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \ | ||||||
|  |     --- build --release --manifest-path examples/stm32u0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32u0 \ | ||||||
|     --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ |     --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ | ||||||
|     --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wb \ |     --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wb \ | ||||||
|     --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \ |     --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \ | ||||||
|  | |||||||
| @ -71,7 +71,7 @@ rand_core = "0.6.3" | |||||||
| sdio-host = "0.5.0" | sdio-host = "0.5.0" | ||||||
| critical-section = "1.1" | critical-section = "1.1" | ||||||
| #stm32-metapac = { version = "15" } | #stm32-metapac = { version = "15" } | ||||||
| stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d674277b78ca7400ecfeeb1b5af4e460a65c1a61" } | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-01ac9bfd035961dc75f32dcd6080501538246d5c" } | ||||||
| 
 | 
 | ||||||
| vcell = "0.1.3" | vcell = "0.1.3" | ||||||
| nb = "1.0.0" | nb = "1.0.0" | ||||||
| @ -97,7 +97,7 @@ proc-macro2 = "1.0.36" | |||||||
| quote = "1.0.15" | quote = "1.0.15" | ||||||
| 
 | 
 | ||||||
| #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} | ||||||
| stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d674277b78ca7400ecfeeb1b5af4e460a65c1a61", default-features = false, features = ["metadata"]} | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-01ac9bfd035961dc75f32dcd6080501538246d5c", default-features = false, features = ["metadata"]} | ||||||
| 
 | 
 | ||||||
| [features] | [features] | ||||||
| default = ["rt"] | default = ["rt"] | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ | |||||||
| #[cfg_attr(adc_v1, path = "v1.rs")] | #[cfg_attr(adc_v1, path = "v1.rs")] | ||||||
| #[cfg_attr(adc_l0, path = "v1.rs")] | #[cfg_attr(adc_l0, path = "v1.rs")] | ||||||
| #[cfg_attr(adc_v2, path = "v2.rs")] | #[cfg_attr(adc_v2, path = "v2.rs")] | ||||||
| #[cfg_attr(any(adc_v3, adc_g0, adc_h5), path = "v3.rs")] | #[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")] | ||||||
| #[cfg_attr(adc_v4, path = "v4.rs")] | #[cfg_attr(adc_v4, path = "v4.rs")] | ||||||
| #[cfg_attr(adc_g4, path = "g4.rs")] | #[cfg_attr(adc_g4, path = "g4.rs")] | ||||||
| mod _version; | mod _version; | ||||||
| @ -96,6 +96,7 @@ pub(crate) fn blocking_delay_us(us: u32) { | |||||||
|     adc_f3, |     adc_f3, | ||||||
|     adc_f3_v1_1, |     adc_f3_v1_1, | ||||||
|     adc_g0, |     adc_g0, | ||||||
|  |     adc_u0, | ||||||
|     adc_h5 |     adc_h5 | ||||||
| )))] | )))] | ||||||
| #[allow(private_bounds)] | #[allow(private_bounds)] | ||||||
| @ -114,6 +115,7 @@ pub trait Instance: SealedInstance + crate::Peripheral<P = Self> { | |||||||
|     adc_f3, |     adc_f3, | ||||||
|     adc_f3_v1_1, |     adc_f3_v1_1, | ||||||
|     adc_g0, |     adc_g0, | ||||||
|  |     adc_u0, | ||||||
|     adc_h5 |     adc_h5 | ||||||
| ))] | ))] | ||||||
| #[allow(private_bounds)] | #[allow(private_bounds)] | ||||||
|  | |||||||
| @ -19,6 +19,8 @@ impl<T: Instance> super::SealedAdcPin<T> for VrefInt { | |||||||
|                 let val = 13; |                 let val = 13; | ||||||
|             } else if #[cfg(adc_h5)] { |             } else if #[cfg(adc_h5)] { | ||||||
|                 let val = 17; |                 let val = 17; | ||||||
|  |             } else if #[cfg(adc_u0)] { | ||||||
|  |                 let val = 12; | ||||||
|             } else { |             } else { | ||||||
|                 let val = 0; |                 let val = 0; | ||||||
|             } |             } | ||||||
| @ -36,6 +38,8 @@ impl<T: Instance> super::SealedAdcPin<T> for Temperature { | |||||||
|                 let val = 12; |                 let val = 12; | ||||||
|             } else if #[cfg(adc_h5)] { |             } else if #[cfg(adc_h5)] { | ||||||
|                 let val = 16; |                 let val = 16; | ||||||
|  |             } else if #[cfg(adc_u0)] { | ||||||
|  |                 let val = 11; | ||||||
|             } else { |             } else { | ||||||
|                 let val = 17; |                 let val = 17; | ||||||
|             } |             } | ||||||
| @ -53,6 +57,8 @@ impl<T: Instance> super::SealedAdcPin<T> for Vbat { | |||||||
|                 let val = 14; |                 let val = 14; | ||||||
|             } else if #[cfg(adc_h5)] { |             } else if #[cfg(adc_h5)] { | ||||||
|                 let val = 2; |                 let val = 2; | ||||||
|  |             } else if #[cfg(adc_h5)] { | ||||||
|  |                 let val = 13; | ||||||
|             } else { |             } else { | ||||||
|                 let val = 18; |                 let val = 18; | ||||||
|             } |             } | ||||||
| @ -73,17 +79,29 @@ cfg_if! { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | cfg_if! { | ||||||
|  |     if #[cfg(adc_u0)] { | ||||||
|  |         pub struct DacOut; | ||||||
|  |         impl<T: Instance> AdcPin<T> for DacOut {} | ||||||
|  |         impl<T: Instance> super::SealedAdcPin<T> for DacOut { | ||||||
|  |             fn channel(&self) -> u8 { | ||||||
|  |                 19 | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl<'d, T: Instance> Adc<'d, T> { | impl<'d, T: Instance> Adc<'d, T> { | ||||||
|     pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { |     pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { | ||||||
|         into_ref!(adc); |         into_ref!(adc); | ||||||
|         T::enable_and_reset(); |         T::enable_and_reset(); | ||||||
|         T::regs().cr().modify(|reg| { |         T::regs().cr().modify(|reg| { | ||||||
|             #[cfg(not(adc_g0))] |             #[cfg(not(any(adc_g0, adc_u0)))] | ||||||
|             reg.set_deeppwd(false); |             reg.set_deeppwd(false); | ||||||
|             reg.set_advregen(true); |             reg.set_advregen(true); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         #[cfg(adc_g0)] |         #[cfg(any(adc_g0, adc_u0))] | ||||||
|         T::regs().cfgr1().modify(|reg| { |         T::regs().cfgr1().modify(|reg| { | ||||||
|             reg.set_chselrmod(false); |             reg.set_chselrmod(false); | ||||||
|         }); |         }); | ||||||
| @ -107,11 +125,11 @@ impl<'d, T: Instance> Adc<'d, T> { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn enable_vrefint(&self) -> VrefInt { |     pub fn enable_vrefint(&self) -> VrefInt { | ||||||
|         #[cfg(not(adc_g0))] |         #[cfg(not(any(adc_g0, adc_u0)))] | ||||||
|         T::common_regs().ccr().modify(|reg| { |         T::common_regs().ccr().modify(|reg| { | ||||||
|             reg.set_vrefen(true); |             reg.set_vrefen(true); | ||||||
|         }); |         }); | ||||||
|         #[cfg(adc_g0)] |         #[cfg(any(adc_g0, adc_u0))] | ||||||
|         T::regs().ccr().modify(|reg| { |         T::regs().ccr().modify(|reg| { | ||||||
|             reg.set_vrefen(true); |             reg.set_vrefen(true); | ||||||
|         }); |         }); | ||||||
| @ -125,7 +143,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||||||
| 
 | 
 | ||||||
|     pub fn enable_temperature(&self) -> Temperature { |     pub fn enable_temperature(&self) -> Temperature { | ||||||
|         cfg_if! { |         cfg_if! { | ||||||
|             if #[cfg(adc_g0)] { |             if #[cfg(any(adc_g0, adc_u0))] { | ||||||
|                 T::regs().ccr().modify(|reg| { |                 T::regs().ccr().modify(|reg| { | ||||||
|                     reg.set_tsen(true); |                     reg.set_tsen(true); | ||||||
|                 }); |                 }); | ||||||
| @ -145,7 +163,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||||||
| 
 | 
 | ||||||
|     pub fn enable_vbat(&self) -> Vbat { |     pub fn enable_vbat(&self) -> Vbat { | ||||||
|         cfg_if! { |         cfg_if! { | ||||||
|             if #[cfg(adc_g0)] { |             if #[cfg(any(adc_g0, adc_u0))] { | ||||||
|                 T::regs().ccr().modify(|reg| { |                 T::regs().ccr().modify(|reg| { | ||||||
|                     reg.set_vbaten(true); |                     reg.set_vbaten(true); | ||||||
|                 }); |                 }); | ||||||
| @ -168,9 +186,9 @@ impl<'d, T: Instance> Adc<'d, T> { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn set_resolution(&mut self, resolution: Resolution) { |     pub fn set_resolution(&mut self, resolution: Resolution) { | ||||||
|         #[cfg(not(adc_g0))] |         #[cfg(not(any(adc_g0, adc_u0)))] | ||||||
|         T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); |         T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | ||||||
|         #[cfg(adc_g0)] |         #[cfg(any(adc_g0, adc_u0))] | ||||||
|         T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); |         T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -231,9 +249,9 @@ impl<'d, T: Instance> Adc<'d, T> { | |||||||
|         Self::set_channel_sample_time(pin.channel(), self.sample_time); |         Self::set_channel_sample_time(pin.channel(), self.sample_time); | ||||||
| 
 | 
 | ||||||
|         // Select channel
 |         // Select channel
 | ||||||
|         #[cfg(not(adc_g0))] |         #[cfg(not(any(adc_g0, adc_u0)))] | ||||||
|         T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); |         T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); | ||||||
|         #[cfg(adc_g0)] |         #[cfg(any(adc_g0, adc_u0))] | ||||||
|         T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); |         T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel())); | ||||||
| 
 | 
 | ||||||
|         // Some models are affected by an erratum:
 |         // Some models are affected by an erratum:
 | ||||||
| @ -261,7 +279,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||||||
| 
 | 
 | ||||||
|     fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { |     fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { | ||||||
|         cfg_if! { |         cfg_if! { | ||||||
|             if #[cfg(adc_g0)] { |             if #[cfg(any(adc_g0, adc_u0))] { | ||||||
|                 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); |                 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); | ||||||
|             } else if #[cfg(adc_h5)] { |             } else if #[cfg(adc_h5)] { | ||||||
|                 match _ch { |                 match _ch { | ||||||
|  | |||||||
| @ -13,6 +13,8 @@ pub struct Crc<'d> { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// CRC configuration errlr
 | /// CRC configuration errlr
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||||
| pub enum ConfigError { | pub enum ConfigError { | ||||||
|     /// The selected polynomial is invalid.
 |     /// The selected polynomial is invalid.
 | ||||||
|     InvalidPolynomial, |     InvalidPolynomial, | ||||||
|  | |||||||
| @ -235,6 +235,23 @@ pub enum TriggerSel { | |||||||
|     Exti9 = 13, |     Exti9 = 13, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Trigger selection for U0.
 | ||||||
|  | #[cfg(stm32u0)] | ||||||
|  | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||||||
|  | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||||
|  | pub enum TriggerSel { | ||||||
|  |     Software = 0, | ||||||
|  |     Tim1 = 1, | ||||||
|  |     Tim2 = 2, | ||||||
|  |     Tim3 = 3, | ||||||
|  |     Tim6 = 5, | ||||||
|  |     Tim7 = 6, | ||||||
|  |     Tim15 = 8, | ||||||
|  |     Lptim1 = 11, | ||||||
|  |     Lptim2 = 12, | ||||||
|  |     Exti9 = 14, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// Trigger selection for G4.
 | /// Trigger selection for G4.
 | ||||||
| #[cfg(stm32g4)] | #[cfg(stm32g4)] | ||||||
| #[derive(Debug, Copy, Clone, Eq, PartialEq)] | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||||||
|  | |||||||
| @ -101,10 +101,11 @@ pub enum FlashBank { | |||||||
| #[cfg_attr(flash_h7ab, path = "h7.rs")] | #[cfg_attr(flash_h7ab, path = "h7.rs")] | ||||||
| #[cfg_attr(flash_u5, path = "u5.rs")] | #[cfg_attr(flash_u5, path = "u5.rs")] | ||||||
| #[cfg_attr(flash_h50, path = "h50.rs")] | #[cfg_attr(flash_h50, path = "h50.rs")] | ||||||
|  | #[cfg_attr(flash_u0, path = "u0.rs")] | ||||||
| #[cfg_attr(
 | #[cfg_attr(
 | ||||||
|     not(any( |     not(any( | ||||||
|         flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, |         flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, | ||||||
|         flash_g4, flash_h7, flash_h7ab, flash_u5, flash_h50 |         flash_g4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0 | ||||||
|     )), |     )), | ||||||
|     path = "other.rs" |     path = "other.rs" | ||||||
| )] | )] | ||||||
|  | |||||||
							
								
								
									
										96
									
								
								embassy-stm32/src/flash/u0.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								embassy-stm32/src/flash/u0.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,96 @@ | |||||||
|  | use core::ptr::write_volatile; | ||||||
|  | use core::sync::atomic::{fence, Ordering}; | ||||||
|  | 
 | ||||||
|  | use cortex_m::interrupt; | ||||||
|  | 
 | ||||||
|  | use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | ||||||
|  | use crate::flash::Error; | ||||||
|  | use crate::pac; | ||||||
|  | 
 | ||||||
|  | pub(crate) const fn is_default_layout() -> bool { | ||||||
|  |     true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||||||
|  |     &FLASH_REGIONS | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) unsafe fn lock() { | ||||||
|  |     pac::FLASH.cr().modify(|w| w.set_lock(true)); | ||||||
|  | } | ||||||
|  | pub(crate) unsafe fn unlock() { | ||||||
|  |     // Wait, while the memory interface is busy.
 | ||||||
|  |     while pac::FLASH.sr().read().bsy1() {} | ||||||
|  | 
 | ||||||
|  |     // Unlock flash
 | ||||||
|  |     if pac::FLASH.cr().read().lock() { | ||||||
|  |         pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123)); | ||||||
|  |         pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) unsafe fn enable_blocking_write() { | ||||||
|  |     assert_eq!(0, WRITE_SIZE % 4); | ||||||
|  |     pac::FLASH.cr().write(|w| w.set_pg(true)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) unsafe fn disable_blocking_write() { | ||||||
|  |     pac::FLASH.cr().write(|w| w.set_pg(false)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | ||||||
|  |     let mut address = start_address; | ||||||
|  |     for val in buf.chunks(4) { | ||||||
|  |         write_volatile(address as *mut u32, u32::from_le_bytes(val.try_into().unwrap())); | ||||||
|  |         address += val.len() as u32; | ||||||
|  | 
 | ||||||
|  |         // prevents parallelism errors
 | ||||||
|  |         fence(Ordering::SeqCst); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     wait_ready_blocking() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { | ||||||
|  |     let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; | ||||||
|  |     while pac::FLASH.sr().read().bsy1() {} | ||||||
|  |     clear_all_err(); | ||||||
|  | 
 | ||||||
|  |     interrupt::free(|_| { | ||||||
|  |         pac::FLASH.cr().modify(|w| { | ||||||
|  |             w.set_per(true); | ||||||
|  |             w.set_pnb(idx as u8); | ||||||
|  |             w.set_strt(true); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     let ret: Result<(), Error> = wait_ready_blocking(); | ||||||
|  |     pac::FLASH.cr().modify(|w| w.set_per(false)); | ||||||
|  |     ret | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> { | ||||||
|  |     while pac::FLASH.sr().read().bsy1() {} | ||||||
|  | 
 | ||||||
|  |     let sr = pac::FLASH.sr().read(); | ||||||
|  | 
 | ||||||
|  |     if sr.progerr() { | ||||||
|  |         return Err(Error::Prog); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if sr.wrperr() { | ||||||
|  |         return Err(Error::Protected); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if sr.pgaerr() { | ||||||
|  |         return Err(Error::Unaligned); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub(crate) unsafe fn clear_all_err() { | ||||||
|  |     // read and write back the same value.
 | ||||||
|  |     // This clears all "write 1 to clear" bits.
 | ||||||
|  |     pac::FLASH.sr().modify(|_| {}); | ||||||
|  | } | ||||||
| @ -23,7 +23,7 @@ fn common_init<T: Instance>() { | |||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[cfg(any(stm32l4, stm32l5, stm32wb))] |     #[cfg(any(stm32l4, stm32l5, stm32wb, stm32u0))] | ||||||
|     critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); |     critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); | ||||||
| 
 | 
 | ||||||
|     #[cfg(pwr_h5)] |     #[cfg(pwr_h5)] | ||||||
|  | |||||||
| @ -107,14 +107,14 @@ const EP_COUNT: usize = 8; | |||||||
| 
 | 
 | ||||||
| #[cfg(any(usbram_16x1_512, usbram_16x2_512))] | #[cfg(any(usbram_16x1_512, usbram_16x2_512))] | ||||||
| const USBRAM_SIZE: usize = 512; | const USBRAM_SIZE: usize = 512; | ||||||
| #[cfg(usbram_16x2_1024)] | #[cfg(any(usbram_16x2_1024, usbram_32_1024))] | ||||||
| const USBRAM_SIZE: usize = 1024; | const USBRAM_SIZE: usize = 1024; | ||||||
| #[cfg(usbram_32_2048)] | #[cfg(usbram_32_2048)] | ||||||
| const USBRAM_SIZE: usize = 2048; | const USBRAM_SIZE: usize = 2048; | ||||||
| 
 | 
 | ||||||
| #[cfg(not(usbram_32_2048))] | #[cfg(not(any(usbram_32_2048, usbram_32_1024)))] | ||||||
| const USBRAM_ALIGN: usize = 2; | const USBRAM_ALIGN: usize = 2; | ||||||
| #[cfg(usbram_32_2048)] | #[cfg(any(usbram_32_2048, usbram_32_1024))] | ||||||
| const USBRAM_ALIGN: usize = 4; | const USBRAM_ALIGN: usize = 4; | ||||||
| 
 | 
 | ||||||
| const NEW_AW: AtomicWaker = AtomicWaker::new(); | const NEW_AW: AtomicWaker = AtomicWaker::new(); | ||||||
| @ -159,7 +159,7 @@ fn calc_out_len(len: u16) -> (u16, u16) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[cfg(not(usbram_32_2048))] | #[cfg(not(any(usbram_32_2048, usbram_32_1024)))] | ||||||
| mod btable { | mod btable { | ||||||
|     use super::*; |     use super::*; | ||||||
| 
 | 
 | ||||||
| @ -180,7 +180,7 @@ mod btable { | |||||||
|         USBRAM.mem(index * 4 + 3).read() |         USBRAM.mem(index * 4 + 3).read() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| #[cfg(usbram_32_2048)] | #[cfg(any(usbram_32_2048, usbram_32_1024))] | ||||||
| mod btable { | mod btable { | ||||||
|     use super::*; |     use super::*; | ||||||
| 
 | 
 | ||||||
| @ -224,9 +224,9 @@ impl<T: Instance> EndpointBuffer<T> { | |||||||
|             let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); |             let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); | ||||||
|             val[..n].copy_from_slice(&buf[i * USBRAM_ALIGN..][..n]); |             val[..n].copy_from_slice(&buf[i * USBRAM_ALIGN..][..n]); | ||||||
| 
 | 
 | ||||||
|             #[cfg(not(usbram_32_2048))] |             #[cfg(not(any(usbram_32_2048, usbram_32_1024)))] | ||||||
|             let val = u16::from_le_bytes(val); |             let val = u16::from_le_bytes(val); | ||||||
|             #[cfg(usbram_32_2048)] |             #[cfg(any(usbram_32_2048, usbram_32_1024))] | ||||||
|             let val = u32::from_le_bytes(val); |             let val = u32::from_le_bytes(val); | ||||||
|             USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val); |             USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -6,10 +6,11 @@ license = "MIT OR Apache-2.0" | |||||||
| 
 | 
 | ||||||
| [dependencies] | [dependencies] | ||||||
| # Change stm32u083rc to your chip name, if necessary. | # Change stm32u083rc to your chip name, if necessary. | ||||||
| embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti"]  } | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"]  } | ||||||
| embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | ||||||
| embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | ||||||
| embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | ||||||
|  | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } | ||||||
| 
 | 
 | ||||||
| defmt = "0.3" | defmt = "0.3" | ||||||
| defmt-rtt = "0.4" | defmt-rtt = "0.4" | ||||||
| @ -21,5 +22,8 @@ panic-probe = { version = "0.3", features = ["print-defmt"] } | |||||||
| futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | ||||||
| heapless = { version = "0.8", default-features = false } | heapless = { version = "0.8", default-features = false } | ||||||
| 
 | 
 | ||||||
|  | micromath = "2.0.0" | ||||||
|  | chrono = { version = "0.4.38", default-features = false } | ||||||
|  | 
 | ||||||
| [profile.release] | [profile.release] | ||||||
| debug = 2 | debug = 2 | ||||||
|  | |||||||
							
								
								
									
										30
									
								
								examples/stm32u0/src/bin/adc.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								examples/stm32u0/src/bin/adc.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | 
 | ||||||
|  | use defmt::*; | ||||||
|  | use embassy_stm32::adc::{Adc, Resolution}; | ||||||
|  | use embassy_stm32::Config; | ||||||
|  | use embassy_time::Duration; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  | 
 | ||||||
|  | #[cortex_m_rt::entry] | ||||||
|  | fn main() -> ! { | ||||||
|  |     info!("Hello World!"); | ||||||
|  | 
 | ||||||
|  |     let mut config = Config::default(); | ||||||
|  |     { | ||||||
|  |         use embassy_stm32::rcc::*; | ||||||
|  |         config.rcc.mux.adcsel = mux::Adcsel::SYS; | ||||||
|  |     } | ||||||
|  |     let p = embassy_stm32::init(config); | ||||||
|  | 
 | ||||||
|  |     let mut adc = Adc::new(p.ADC1); | ||||||
|  |     adc.set_resolution(Resolution::BITS8); | ||||||
|  |     let mut channel = p.PC0; | ||||||
|  | 
 | ||||||
|  |     loop { | ||||||
|  |         let v = adc.read(&mut channel); | ||||||
|  |         info!("--> {}", v); | ||||||
|  |         embassy_time::block_for(Duration::from_millis(200)); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								examples/stm32u0/src/bin/crc.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								examples/stm32u0/src/bin/crc.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | 
 | ||||||
|  | use defmt::*; | ||||||
|  | use embassy_executor::Spawner; | ||||||
|  | use embassy_stm32::crc::{Config, Crc, InputReverseConfig, PolySize}; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  | 
 | ||||||
|  | #[embassy_executor::main] | ||||||
|  | async fn main(_spawner: Spawner) { | ||||||
|  |     let p = embassy_stm32::init(Default::default()); | ||||||
|  |     info!("Hello World!"); | ||||||
|  | 
 | ||||||
|  |     // Setup for: https://crccalc.com/?crc=Life, it never dieWomen are my favorite guy&method=crc32&datatype=ascii&outtype=0
 | ||||||
|  |     let mut crc = Crc::new( | ||||||
|  |         p.CRC, | ||||||
|  |         unwrap!(Config::new( | ||||||
|  |             InputReverseConfig::Byte, | ||||||
|  |             true, | ||||||
|  |             PolySize::Width32, | ||||||
|  |             0xFFFFFFFF, | ||||||
|  |             0x04C11DB7 | ||||||
|  |         )), | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     let output = crc.feed_bytes(b"Life, it never die\nWomen are my favorite guy") ^ 0xFFFFFFFF; | ||||||
|  | 
 | ||||||
|  |     defmt::assert_eq!(output, 0x33F0E26B); | ||||||
|  | 
 | ||||||
|  |     cortex_m::asm::bkpt(); | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								examples/stm32u0/src/bin/dac.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								examples/stm32u0/src/bin/dac.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | 
 | ||||||
|  | use defmt::*; | ||||||
|  | use embassy_stm32::dac::{DacCh1, Value}; | ||||||
|  | use embassy_stm32::dma::NoDma; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  | 
 | ||||||
|  | #[cortex_m_rt::entry] | ||||||
|  | fn main() -> ! { | ||||||
|  |     let p = embassy_stm32::init(Default::default()); | ||||||
|  |     info!("Hello World!"); | ||||||
|  | 
 | ||||||
|  |     let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); | ||||||
|  | 
 | ||||||
|  |     loop { | ||||||
|  |         for v in 0..=255 { | ||||||
|  |             dac.set(Value::Bit8(to_sine_wave(v))); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | use micromath::F32Ext; | ||||||
|  | 
 | ||||||
|  | fn to_sine_wave(v: u8) -> u8 { | ||||||
|  |     if v >= 128 { | ||||||
|  |         // top half
 | ||||||
|  |         let r = 3.14 * ((v - 128) as f32 / 128.0); | ||||||
|  |         (r.sin() * 128.0 + 127.0) as u8 | ||||||
|  |     } else { | ||||||
|  |         // bottom half
 | ||||||
|  |         let r = 3.14 + 3.14 * (v as f32 / 128.0); | ||||||
|  |         (r.sin() * 128.0 + 127.0) as u8 | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								examples/stm32u0/src/bin/flash.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								examples/stm32u0/src/bin/flash.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | 
 | ||||||
|  | use defmt::*; | ||||||
|  | use embassy_executor::Spawner; | ||||||
|  | use embassy_stm32::flash::Flash; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  | 
 | ||||||
|  | #[embassy_executor::main] | ||||||
|  | async fn main(_spawner: Spawner) { | ||||||
|  |     let p = embassy_stm32::init(Default::default()); | ||||||
|  |     info!("Hello World!"); | ||||||
|  | 
 | ||||||
|  |     let addr: u32 = 0x40000 - 2 * 1024; | ||||||
|  | 
 | ||||||
|  |     let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region; | ||||||
|  | 
 | ||||||
|  |     info!("Reading..."); | ||||||
|  |     let mut buf = [0u8; 32]; | ||||||
|  |     unwrap!(f.blocking_read(addr, &mut buf)); | ||||||
|  |     info!("Read: {=[u8]:x}", buf); | ||||||
|  |     info!("Erasing..."); | ||||||
|  |     unwrap!(f.blocking_erase(addr, addr + 2 * 1024)); | ||||||
|  | 
 | ||||||
|  |     info!("Reading..."); | ||||||
|  |     let mut buf = [0u8; 32]; | ||||||
|  |     unwrap!(f.blocking_read(addr, &mut buf)); | ||||||
|  |     info!("Read after erase: {=[u8]:x}", buf); | ||||||
|  | 
 | ||||||
|  |     info!("Writing..."); | ||||||
|  |     unwrap!(f.blocking_write( | ||||||
|  |         addr, | ||||||
|  |         &[ | ||||||
|  |             1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, | ||||||
|  |             30, 31, 32 | ||||||
|  |         ] | ||||||
|  |     )); | ||||||
|  | 
 | ||||||
|  |     info!("Reading..."); | ||||||
|  |     let mut buf = [0u8; 32]; | ||||||
|  |     unwrap!(f.blocking_read(addr, &mut buf)); | ||||||
|  |     info!("Read: {=[u8]:x}", buf); | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								examples/stm32u0/src/bin/i2c.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								examples/stm32u0/src/bin/i2c.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | 
 | ||||||
|  | use defmt::*; | ||||||
|  | use embassy_executor::Spawner; | ||||||
|  | use embassy_stm32::i2c::I2c; | ||||||
|  | use embassy_stm32::time::Hertz; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  | 
 | ||||||
|  | const ADDRESS: u8 = 0x5F; | ||||||
|  | const WHOAMI: u8 = 0x0F; | ||||||
|  | 
 | ||||||
|  | #[embassy_executor::main] | ||||||
|  | async fn main(_spawner: Spawner) { | ||||||
|  |     let p = embassy_stm32::init(Default::default()); | ||||||
|  |     let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default()); | ||||||
|  | 
 | ||||||
|  |     let mut data = [0u8; 1]; | ||||||
|  |     unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data)); | ||||||
|  |     info!("Whoami: {}", data[0]); | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								examples/stm32u0/src/bin/rng.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								examples/stm32u0/src/bin/rng.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | 
 | ||||||
|  | use defmt::*; | ||||||
|  | use embassy_executor::Spawner; | ||||||
|  | use embassy_stm32::rcc::mux::Clk48sel; | ||||||
|  | use embassy_stm32::rng::Rng; | ||||||
|  | use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  | 
 | ||||||
|  | bind_interrupts!(struct Irqs { | ||||||
|  |     RNG_CRYP => rng::InterruptHandler<peripherals::RNG>; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | #[embassy_executor::main] | ||||||
|  | async fn main(_spawner: Spawner) { | ||||||
|  |     let mut config = Config::default(); | ||||||
|  |     { | ||||||
|  |         use embassy_stm32::rcc::*; | ||||||
|  |         config.rcc.hsi = true; | ||||||
|  |         config.rcc.pll = Some(Pll { | ||||||
|  |             source: PllSource::HSI, // 16 MHz
 | ||||||
|  |             prediv: PllPreDiv::DIV1, | ||||||
|  |             mul: PllMul::MUL7, // 16 * 7 = 112 MHz
 | ||||||
|  |             divp: None, | ||||||
|  |             divq: None, | ||||||
|  |             divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz
 | ||||||
|  |         }); | ||||||
|  |         config.rcc.sys = Sysclk::PLL1_R; | ||||||
|  |         config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: false }); // needed for RNG
 | ||||||
|  |         config.rcc.mux.clk48sel = Clk48sel::HSI48; // needed for RNG (or use MSI or PLLQ if you want)
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let p = embassy_stm32::init(config); | ||||||
|  | 
 | ||||||
|  |     info!("Hello World!"); | ||||||
|  | 
 | ||||||
|  |     let mut rng = Rng::new(p.RNG, Irqs); | ||||||
|  | 
 | ||||||
|  |     let mut buf = [0u8; 16]; | ||||||
|  |     unwrap!(rng.async_fill_bytes(&mut buf).await); | ||||||
|  |     info!("random bytes: {:02x}", buf); | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								examples/stm32u0/src/bin/rtc.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								examples/stm32u0/src/bin/rtc.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | 
 | ||||||
|  | use chrono::{NaiveDate, NaiveDateTime}; | ||||||
|  | use defmt::*; | ||||||
|  | use embassy_executor::Spawner; | ||||||
|  | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||||||
|  | use embassy_stm32::Config; | ||||||
|  | use embassy_time::Timer; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  | 
 | ||||||
|  | #[embassy_executor::main] | ||||||
|  | async fn main(_spawner: Spawner) { | ||||||
|  |     let mut config = Config::default(); | ||||||
|  |     { | ||||||
|  |         use embassy_stm32::rcc::*; | ||||||
|  |         config.rcc.sys = Sysclk::PLL1_R; | ||||||
|  |         config.rcc.hsi = true; | ||||||
|  |         config.rcc.pll = Some(Pll { | ||||||
|  |             source: PllSource::HSI, // 16 MHz
 | ||||||
|  |             prediv: PllPreDiv::DIV1, | ||||||
|  |             mul: PllMul::MUL7, // 16 * 7 = 112 MHz
 | ||||||
|  |             divp: None, | ||||||
|  |             divq: None, | ||||||
|  |             divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz
 | ||||||
|  |         }); | ||||||
|  |         config.rcc.ls = LsConfig::default(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let p = embassy_stm32::init(config); | ||||||
|  | 
 | ||||||
|  |     info!("Hello World!"); | ||||||
|  | 
 | ||||||
|  |     let now = NaiveDate::from_ymd_opt(2020, 5, 15) | ||||||
|  |         .unwrap() | ||||||
|  |         .and_hms_opt(10, 30, 15) | ||||||
|  |         .unwrap(); | ||||||
|  | 
 | ||||||
|  |     let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | ||||||
|  |     info!("Got RTC! {:?}", now.and_utc().timestamp()); | ||||||
|  | 
 | ||||||
|  |     rtc.set_datetime(now.into()).expect("datetime not set"); | ||||||
|  | 
 | ||||||
|  |     // In reality the delay would be much longer
 | ||||||
|  |     Timer::after_millis(20000).await; | ||||||
|  | 
 | ||||||
|  |     let then: NaiveDateTime = rtc.now().unwrap().into(); | ||||||
|  |     info!("Got RTC! {:?}", then.and_utc().timestamp()); | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								examples/stm32u0/src/bin/spi.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								examples/stm32u0/src/bin/spi.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | 
 | ||||||
|  | use defmt::*; | ||||||
|  | use embassy_stm32::gpio::{Level, Output, Speed}; | ||||||
|  | use embassy_stm32::spi::{Config, Spi}; | ||||||
|  | use embassy_stm32::time::Hertz; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  | 
 | ||||||
|  | #[cortex_m_rt::entry] | ||||||
|  | fn main() -> ! { | ||||||
|  |     info!("Hello World!"); | ||||||
|  | 
 | ||||||
|  |     let p = embassy_stm32::init(Default::default()); | ||||||
|  | 
 | ||||||
|  |     let mut spi_config = Config::default(); | ||||||
|  |     spi_config.frequency = Hertz(1_000_000); | ||||||
|  | 
 | ||||||
|  |     let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config); | ||||||
|  | 
 | ||||||
|  |     let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); | ||||||
|  | 
 | ||||||
|  |     loop { | ||||||
|  |         let mut buf = [0x0Au8; 4]; | ||||||
|  |         cs.set_low(); | ||||||
|  |         unwrap!(spi.blocking_transfer_in_place(&mut buf)); | ||||||
|  |         cs.set_high(); | ||||||
|  |         info!("xfer {=[u8]:x}", buf); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								examples/stm32u0/src/bin/usart.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								examples/stm32u0/src/bin/usart.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | 
 | ||||||
|  | use defmt::*; | ||||||
|  | use embassy_stm32::usart::{Config, Uart}; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  | 
 | ||||||
|  | #[cortex_m_rt::entry] | ||||||
|  | fn main() -> ! { | ||||||
|  |     info!("Hello World!"); | ||||||
|  | 
 | ||||||
|  |     let p = embassy_stm32::init(Default::default()); | ||||||
|  | 
 | ||||||
|  |     let config = Config::default(); | ||||||
|  |     let mut usart = Uart::new_blocking(p.USART2, p.PA3, p.PA2, config).unwrap(); | ||||||
|  | 
 | ||||||
|  |     unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | ||||||
|  |     info!("wrote Hello, starting echo"); | ||||||
|  | 
 | ||||||
|  |     let mut buf = [0u8; 1]; | ||||||
|  |     loop { | ||||||
|  |         unwrap!(usart.blocking_read(&mut buf)); | ||||||
|  |         unwrap!(usart.blocking_write(&buf)); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										109
									
								
								examples/stm32u0/src/bin/usb_serial.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								examples/stm32u0/src/bin/usb_serial.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,109 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | 
 | ||||||
|  | use defmt::{panic, *}; | ||||||
|  | use defmt_rtt as _; // global logger
 | ||||||
|  | use embassy_executor::Spawner; | ||||||
|  | use embassy_stm32::usb::{Driver, Instance}; | ||||||
|  | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | ||||||
|  | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||||||
|  | use embassy_usb::driver::EndpointError; | ||||||
|  | use embassy_usb::Builder; | ||||||
|  | use futures::future::join; | ||||||
|  | use panic_probe as _; | ||||||
|  | 
 | ||||||
|  | bind_interrupts!(struct Irqs { | ||||||
|  |     USB_DRD_FS => usb::InterruptHandler<peripherals::USB>; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | #[embassy_executor::main] | ||||||
|  | async fn main(_spawner: Spawner) { | ||||||
|  |     let mut config = Config::default(); | ||||||
|  |     { | ||||||
|  |         use embassy_stm32::rcc::*; | ||||||
|  |         config.rcc.hsi = true; | ||||||
|  |         config.rcc.pll = Some(Pll { | ||||||
|  |             source: PllSource::HSI, // 16 MHz
 | ||||||
|  |             prediv: PllPreDiv::DIV1, | ||||||
|  |             mul: PllMul::MUL7, | ||||||
|  |             divp: None, | ||||||
|  |             divq: None, | ||||||
|  |             divr: Some(PllRDiv::DIV2), // 56 MHz
 | ||||||
|  |         }); | ||||||
|  |         config.rcc.sys = Sysclk::PLL1_R; | ||||||
|  |         config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
 | ||||||
|  |         config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; // USB uses ICLK
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let p = embassy_stm32::init(config); | ||||||
|  | 
 | ||||||
|  |     info!("Hello World!"); | ||||||
|  | 
 | ||||||
|  |     // Create the driver, from the HAL.
 | ||||||
|  |     let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); | ||||||
|  | 
 | ||||||
|  |     // Create embassy-usb Config
 | ||||||
|  |     let config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||||||
|  |     //config.max_packet_size_0 = 64;
 | ||||||
|  | 
 | ||||||
|  |     // Create embassy-usb DeviceBuilder using the driver and config.
 | ||||||
|  |     // It needs some buffers for building the descriptors.
 | ||||||
|  |     let mut config_descriptor = [0; 256]; | ||||||
|  |     let mut bos_descriptor = [0; 256]; | ||||||
|  |     let mut control_buf = [0; 7]; | ||||||
|  | 
 | ||||||
|  |     let mut state = State::new(); | ||||||
|  | 
 | ||||||
|  |     let mut builder = Builder::new( | ||||||
|  |         driver, | ||||||
|  |         config, | ||||||
|  |         &mut config_descriptor, | ||||||
|  |         &mut bos_descriptor, | ||||||
|  |         &mut [], // no msos descriptors
 | ||||||
|  |         &mut control_buf, | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     // Create classes on the builder.
 | ||||||
|  |     let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); | ||||||
|  | 
 | ||||||
|  |     // Build the builder.
 | ||||||
|  |     let mut usb = builder.build(); | ||||||
|  | 
 | ||||||
|  |     // Run the USB device.
 | ||||||
|  |     let usb_fut = usb.run(); | ||||||
|  | 
 | ||||||
|  |     // Do stuff with the class!
 | ||||||
|  |     let echo_fut = async { | ||||||
|  |         loop { | ||||||
|  |             class.wait_connection().await; | ||||||
|  |             info!("Connected"); | ||||||
|  |             let _ = echo(&mut class).await; | ||||||
|  |             info!("Disconnected"); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     // Run everything concurrently.
 | ||||||
|  |     // If we had made everything `'static` above instead, we could do this using separate tasks instead.
 | ||||||
|  |     join(usb_fut, echo_fut).await; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct Disconnected {} | ||||||
|  | 
 | ||||||
|  | impl From<EndpointError> for Disconnected { | ||||||
|  |     fn from(val: EndpointError) -> Self { | ||||||
|  |         match val { | ||||||
|  |             EndpointError::BufferOverflow => panic!("Buffer overflow"), | ||||||
|  |             EndpointError::Disabled => Disconnected {}, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { | ||||||
|  |     let mut buf = [0; 64]; | ||||||
|  |     loop { | ||||||
|  |         let n = class.read_packet(&mut buf).await?; | ||||||
|  |         let data = &buf[..n]; | ||||||
|  |         info!("data: {:x}", data); | ||||||
|  |         class.write_packet(data).await?; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								examples/stm32u0/src/bin/wdt.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								examples/stm32u0/src/bin/wdt.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | #![no_std] | ||||||
|  | #![no_main] | ||||||
|  | 
 | ||||||
|  | use defmt::*; | ||||||
|  | use embassy_executor::Spawner; | ||||||
|  | use embassy_stm32::gpio::{Level, Output, Speed}; | ||||||
|  | use embassy_stm32::wdg::IndependentWatchdog; | ||||||
|  | use embassy_time::Timer; | ||||||
|  | use {defmt_rtt as _, panic_probe as _}; | ||||||
|  | 
 | ||||||
|  | #[embassy_executor::main] | ||||||
|  | async fn main(_spawner: Spawner) { | ||||||
|  |     let p = embassy_stm32::init(Default::default()); | ||||||
|  |     info!("Hello World!"); | ||||||
|  | 
 | ||||||
|  |     let mut led = Output::new(p.PA5, Level::High, Speed::Low); | ||||||
|  | 
 | ||||||
|  |     let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000); | ||||||
|  |     wdt.unleash(); | ||||||
|  | 
 | ||||||
|  |     let mut i = 0; | ||||||
|  | 
 | ||||||
|  |     loop { | ||||||
|  |         info!("high"); | ||||||
|  |         led.set_high(); | ||||||
|  |         Timer::after_millis(300).await; | ||||||
|  | 
 | ||||||
|  |         info!("low"); | ||||||
|  |         led.set_low(); | ||||||
|  |         Timer::after_millis(300).await; | ||||||
|  | 
 | ||||||
|  |         // Pet watchdog for 5 iterations and then stop.
 | ||||||
|  |         // MCU should restart in 1 second after the last pet.
 | ||||||
|  |         if i < 5 { | ||||||
|  |             info!("Petting watchdog"); | ||||||
|  |             wdt.pet(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         i += 1; | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user