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/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/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/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 \ | ||||
|  | ||||
| @ -71,7 +71,7 @@ rand_core = "0.6.3" | ||||
| sdio-host = "0.5.0" | ||||
| critical-section = "1.1" | ||||
| #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" | ||||
| nb = "1.0.0" | ||||
| @ -97,7 +97,7 @@ proc-macro2 = "1.0.36" | ||||
| quote = "1.0.15" | ||||
| 
 | ||||
| #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] | ||||
| default = ["rt"] | ||||
|  | ||||
| @ -10,7 +10,7 @@ | ||||
| #[cfg_attr(adc_v1, path = "v1.rs")] | ||||
| #[cfg_attr(adc_l0, path = "v1.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_g4, path = "g4.rs")] | ||||
| mod _version; | ||||
| @ -96,6 +96,7 @@ pub(crate) fn blocking_delay_us(us: u32) { | ||||
|     adc_f3, | ||||
|     adc_f3_v1_1, | ||||
|     adc_g0, | ||||
|     adc_u0, | ||||
|     adc_h5 | ||||
| )))] | ||||
| #[allow(private_bounds)] | ||||
| @ -114,6 +115,7 @@ pub trait Instance: SealedInstance + crate::Peripheral<P = Self> { | ||||
|     adc_f3, | ||||
|     adc_f3_v1_1, | ||||
|     adc_g0, | ||||
|     adc_u0, | ||||
|     adc_h5 | ||||
| ))] | ||||
| #[allow(private_bounds)] | ||||
|  | ||||
| @ -19,6 +19,8 @@ impl<T: Instance> super::SealedAdcPin<T> for VrefInt { | ||||
|                 let val = 13; | ||||
|             } else if #[cfg(adc_h5)] { | ||||
|                 let val = 17; | ||||
|             } else if #[cfg(adc_u0)] { | ||||
|                 let val = 12; | ||||
|             } else { | ||||
|                 let val = 0; | ||||
|             } | ||||
| @ -36,6 +38,8 @@ impl<T: Instance> super::SealedAdcPin<T> for Temperature { | ||||
|                 let val = 12; | ||||
|             } else if #[cfg(adc_h5)] { | ||||
|                 let val = 16; | ||||
|             } else if #[cfg(adc_u0)] { | ||||
|                 let val = 11; | ||||
|             } else { | ||||
|                 let val = 17; | ||||
|             } | ||||
| @ -53,6 +57,8 @@ impl<T: Instance> super::SealedAdcPin<T> for Vbat { | ||||
|                 let val = 14; | ||||
|             } else if #[cfg(adc_h5)] { | ||||
|                 let val = 2; | ||||
|             } else if #[cfg(adc_h5)] { | ||||
|                 let val = 13; | ||||
|             } else { | ||||
|                 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> { | ||||
|     pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { | ||||
|         into_ref!(adc); | ||||
|         T::enable_and_reset(); | ||||
|         T::regs().cr().modify(|reg| { | ||||
|             #[cfg(not(adc_g0))] | ||||
|             #[cfg(not(any(adc_g0, adc_u0)))] | ||||
|             reg.set_deeppwd(false); | ||||
|             reg.set_advregen(true); | ||||
|         }); | ||||
| 
 | ||||
|         #[cfg(adc_g0)] | ||||
|         #[cfg(any(adc_g0, adc_u0))] | ||||
|         T::regs().cfgr1().modify(|reg| { | ||||
|             reg.set_chselrmod(false); | ||||
|         }); | ||||
| @ -107,11 +125,11 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|     } | ||||
| 
 | ||||
|     pub fn enable_vrefint(&self) -> VrefInt { | ||||
|         #[cfg(not(adc_g0))] | ||||
|         #[cfg(not(any(adc_g0, adc_u0)))] | ||||
|         T::common_regs().ccr().modify(|reg| { | ||||
|             reg.set_vrefen(true); | ||||
|         }); | ||||
|         #[cfg(adc_g0)] | ||||
|         #[cfg(any(adc_g0, adc_u0))] | ||||
|         T::regs().ccr().modify(|reg| { | ||||
|             reg.set_vrefen(true); | ||||
|         }); | ||||
| @ -125,7 +143,7 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
| 
 | ||||
|     pub fn enable_temperature(&self) -> Temperature { | ||||
|         cfg_if! { | ||||
|             if #[cfg(adc_g0)] { | ||||
|             if #[cfg(any(adc_g0, adc_u0))] { | ||||
|                 T::regs().ccr().modify(|reg| { | ||||
|                     reg.set_tsen(true); | ||||
|                 }); | ||||
| @ -145,7 +163,7 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
| 
 | ||||
|     pub fn enable_vbat(&self) -> Vbat { | ||||
|         cfg_if! { | ||||
|             if #[cfg(adc_g0)] { | ||||
|             if #[cfg(any(adc_g0, adc_u0))] { | ||||
|                 T::regs().ccr().modify(|reg| { | ||||
|                     reg.set_vbaten(true); | ||||
|                 }); | ||||
| @ -168,9 +186,9 @@ impl<'d, T: Instance> Adc<'d, T> { | ||||
|     } | ||||
| 
 | ||||
|     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())); | ||||
|         #[cfg(adc_g0)] | ||||
|         #[cfg(any(adc_g0, adc_u0))] | ||||
|         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); | ||||
| 
 | ||||
|         // Select channel
 | ||||
|         #[cfg(not(adc_g0))] | ||||
|         #[cfg(not(any(adc_g0, adc_u0)))] | ||||
|         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())); | ||||
| 
 | ||||
|         // 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) { | ||||
|         cfg_if! { | ||||
|             if #[cfg(adc_g0)] { | ||||
|             if #[cfg(any(adc_g0, adc_u0))] { | ||||
|                 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); | ||||
|             } else if #[cfg(adc_h5)] { | ||||
|                 match _ch { | ||||
|  | ||||
| @ -13,6 +13,8 @@ pub struct Crc<'d> { | ||||
| } | ||||
| 
 | ||||
| /// CRC configuration errlr
 | ||||
| #[derive(Debug)] | ||||
| #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||
| pub enum ConfigError { | ||||
|     /// The selected polynomial is invalid.
 | ||||
|     InvalidPolynomial, | ||||
|  | ||||
| @ -235,6 +235,23 @@ pub enum TriggerSel { | ||||
|     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.
 | ||||
| #[cfg(stm32g4)] | ||||
| #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||||
|  | ||||
| @ -101,10 +101,11 @@ pub enum FlashBank { | ||||
| #[cfg_attr(flash_h7ab, path = "h7.rs")] | ||||
| #[cfg_attr(flash_u5, path = "u5.rs")] | ||||
| #[cfg_attr(flash_h50, path = "h50.rs")] | ||||
| #[cfg_attr(flash_u0, path = "u0.rs")] | ||||
| #[cfg_attr(
 | ||||
|     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_g4, flash_h7, flash_h7ab, flash_u5, flash_h50 | ||||
|         flash_g4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0 | ||||
|     )), | ||||
|     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))); | ||||
| 
 | ||||
|     #[cfg(pwr_h5)] | ||||
|  | ||||
| @ -107,14 +107,14 @@ const EP_COUNT: usize = 8; | ||||
| 
 | ||||
| #[cfg(any(usbram_16x1_512, usbram_16x2_512))] | ||||
| const USBRAM_SIZE: usize = 512; | ||||
| #[cfg(usbram_16x2_1024)] | ||||
| #[cfg(any(usbram_16x2_1024, usbram_32_1024))] | ||||
| const USBRAM_SIZE: usize = 1024; | ||||
| #[cfg(usbram_32_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; | ||||
| #[cfg(usbram_32_2048)] | ||||
| #[cfg(any(usbram_32_2048, usbram_32_1024))] | ||||
| const USBRAM_ALIGN: usize = 4; | ||||
| 
 | ||||
| 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 { | ||||
|     use super::*; | ||||
| 
 | ||||
| @ -180,7 +180,7 @@ mod btable { | ||||
|         USBRAM.mem(index * 4 + 3).read() | ||||
|     } | ||||
| } | ||||
| #[cfg(usbram_32_2048)] | ||||
| #[cfg(any(usbram_32_2048, usbram_32_1024))] | ||||
| mod btable { | ||||
|     use super::*; | ||||
| 
 | ||||
| @ -224,9 +224,9 @@ impl<T: Instance> EndpointBuffer<T> { | ||||
|             let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); | ||||
|             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); | ||||
|             #[cfg(usbram_32_2048)] | ||||
|             #[cfg(any(usbram_32_2048, usbram_32_1024))] | ||||
|             let val = u32::from_le_bytes(val); | ||||
|             USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val); | ||||
|         } | ||||
|  | ||||
| @ -6,10 +6,11 @@ license = "MIT OR Apache-2.0" | ||||
| 
 | ||||
| [dependencies] | ||||
| # 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-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-usb = { version = "0.1.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } | ||||
| 
 | ||||
| defmt = "0.3" | ||||
| 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"] } | ||||
| heapless = { version = "0.8", default-features = false } | ||||
| 
 | ||||
| micromath = "2.0.0" | ||||
| chrono = { version = "0.4.38", default-features = false } | ||||
| 
 | ||||
| [profile.release] | ||||
| 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