aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-06-28 22:55:11 +0000
committerGitHub <[email protected]>2023-06-28 22:55:11 +0000
commit8cbe5b8e20999d77f032ee14f77d4f2c07a38088 (patch)
tree2f86425f8ead9b10872bf82a2ef71834e1ff2171
parent2eb7a67c7027c6768fa95031caf60bcd0eade1ad (diff)
parent5666c569033d59fc894230ed4161e6c686733b2d (diff)
Merge pull request #1592 from kevswims/feature/stm32g4-usb-crs
WIP: Working CRS USB Example
-rw-r--r--embassy-stm32/src/rcc/g4.rs77
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs28
2 files changed, 95 insertions, 10 deletions
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index 9401af4c3..ff8f97541 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -3,6 +3,7 @@ use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw};
3use stm32_metapac::FLASH; 3use stm32_metapac::FLASH;
4 4
5use crate::pac::{PWR, RCC}; 5use crate::pac::{PWR, RCC};
6use crate::rcc::sealed::RccPeripheral;
6use crate::rcc::{set_freqs, Clocks}; 7use crate::rcc::{set_freqs, Clocks};
7use crate::time::Hertz; 8use crate::time::Hertz;
8 9
@@ -316,6 +317,27 @@ impl Into<Hpre> for AHBPrescaler {
316 } 317 }
317} 318}
318 319
320/// Sets the source for the 48MHz clock to the USB and RNG peripherals.
321pub enum Clock48MhzSrc {
322 /// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the
323 /// oscillator to comply with the USB specification for oscillator tolerance.
324 Hsi48(Option<CrsConfig>),
325 /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. For USB usage the
326 /// PLL needs to be using the HSE source to comply with the USB specification for oscillator
327 /// tolerance.
328 PllQ,
329}
330
331/// Sets the sync source for the Clock Recovery System (CRS).
332pub enum CrsSyncSource {
333 /// Use an external GPIO to sync the CRS.
334 Gpio,
335 /// Use the Low Speed External oscillator to sync the CRS.
336 Lse,
337 /// Use the USB SOF to sync the CRS.
338 Usb,
339}
340
319/// Clocks configutation 341/// Clocks configutation
320pub struct Config { 342pub struct Config {
321 pub mux: ClockSrc, 343 pub mux: ClockSrc,
@@ -326,6 +348,14 @@ pub struct Config {
326 /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration 348 /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration
327 /// MUST turn on the PLLR output. 349 /// MUST turn on the PLLR output.
328 pub pll: Option<Pll>, 350 pub pll: Option<Pll>,
351 /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
352 pub clock_48mhz_src: Option<Clock48MhzSrc>,
353}
354
355/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
356pub struct CrsConfig {
357 /// Sync source for the CRS.
358 pub sync_src: CrsSyncSource,
329} 359}
330 360
331impl Default for Config { 361impl Default for Config {
@@ -338,6 +368,7 @@ impl Default for Config {
338 apb2_pre: APBPrescaler::NotDivided, 368 apb2_pre: APBPrescaler::NotDivided,
339 low_power_run: false, 369 low_power_run: false,
340 pll: None, 370 pll: None,
371 clock_48mhz_src: None,
341 } 372 }
342 } 373 }
343} 374}
@@ -430,7 +461,7 @@ pub(crate) unsafe fn init(config: Config) {
430 assert!(pll_freq.is_some()); 461 assert!(pll_freq.is_some());
431 assert!(pll_freq.as_ref().unwrap().pll_r.is_some()); 462 assert!(pll_freq.as_ref().unwrap().pll_r.is_some());
432 463
433 let freq = pll_freq.unwrap().pll_r.unwrap().0; 464 let freq = pll_freq.as_ref().unwrap().pll_r.unwrap().0;
434 465
435 assert!(freq <= 170_000_000); 466 assert!(freq <= 170_000_000);
436 467
@@ -497,6 +528,50 @@ pub(crate) unsafe fn init(config: Config) {
497 } 528 }
498 }; 529 };
499 530
531 // Setup the 48 MHz clock if needed
532 if let Some(clock_48mhz_src) = config.clock_48mhz_src {
533 let source = match clock_48mhz_src {
534 Clock48MhzSrc::PllQ => {
535 // Make sure the PLLQ is enabled and running at 48Mhz
536 let pllq_freq = pll_freq.as_ref().and_then(|f| f.pll_q);
537 assert!(pllq_freq.is_some() && pllq_freq.unwrap().0 == 48_000_000);
538
539 crate::pac::rcc::vals::Clk48sel::PLLQCLK
540 }
541 Clock48MhzSrc::Hsi48(crs_config) => {
542 // Enable HSI48
543 RCC.crrcr().modify(|w| w.set_hsi48on(true));
544 // Wait for HSI48 to turn on
545 while RCC.crrcr().read().hsi48rdy() == false {}
546
547 // Enable and setup CRS if needed
548 if let Some(crs_config) = crs_config {
549 crate::peripherals::CRS::enable();
550
551 let sync_src = match crs_config.sync_src {
552 CrsSyncSource::Gpio => crate::pac::crs::vals::Syncsrc::GPIO,
553 CrsSyncSource::Lse => crate::pac::crs::vals::Syncsrc::LSE,
554 CrsSyncSource::Usb => crate::pac::crs::vals::Syncsrc::USB,
555 };
556
557 crate::pac::CRS.cfgr().modify(|w| {
558 w.set_syncsrc(sync_src);
559 });
560
561 // These are the correct settings for standard USB operation. If other settings
562 // are needed there will need to be additional config options for the CRS.
563 crate::pac::CRS.cr().modify(|w| {
564 w.set_autotrimen(true);
565 w.set_cen(true);
566 });
567 }
568 crate::pac::rcc::vals::Clk48sel::HSI48
569 }
570 };
571
572 RCC.ccipr().modify(|w| w.set_clk48sel(source));
573 }
574
500 if config.low_power_run { 575 if config.low_power_run {
501 assert!(sys_clk <= 2_000_000); 576 assert!(sys_clk <= 2_000_000);
502 PWR.cr1().modify(|w| w.set_lpr(true)); 577 PWR.cr1().modify(|w| w.set_lpr(true));
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index 289d0ed86..77cfa67d3 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -4,10 +4,10 @@
4 4
5use defmt::{panic, *}; 5use defmt::{panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllQ, PllR, PllSrc}; 7use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, CrsConfig, CrsSyncSource, Pll, PllM, PllN, PllQ, PllR, PllSrc};
8use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
9use embassy_stm32::usb::{self, Driver, Instance}; 9use embassy_stm32::usb::{self, Driver, Instance};
10use embassy_stm32::{bind_interrupts, pac, peripherals, Config}; 10use embassy_stm32::{bind_interrupts, peripherals, Config};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError; 12use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder; 13use embassy_usb::Builder;
@@ -22,25 +22,35 @@ bind_interrupts!(struct Irqs {
22async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
23 let mut config = Config::default(); 23 let mut config = Config::default();
24 24
25 // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE.
26 const USE_HSI48: bool = true;
27
28 let pllq_div = if USE_HSI48 { None } else { Some(PllQ::Div6) };
29
25 config.rcc.pll = Some(Pll { 30 config.rcc.pll = Some(Pll {
26 source: PllSrc::HSE(Hertz(8000000)), 31 source: PllSrc::HSE(Hertz(8_000_000)),
27 prediv_m: PllM::Div2, 32 prediv_m: PllM::Div2,
28 mul_n: PllN::Mul72, 33 mul_n: PllN::Mul72,
29 div_p: None, 34 div_p: None,
30 // USB and CAN at 48 MHz 35 div_q: pllq_div,
31 div_q: Some(PllQ::Div6),
32 // Main system clock at 144 MHz 36 // Main system clock at 144 MHz
33 div_r: Some(PllR::Div2), 37 div_r: Some(PllR::Div2),
34 }); 38 });
35 39
36 config.rcc.mux = ClockSrc::PLL; 40 config.rcc.mux = ClockSrc::PLL;
37 41
42 if USE_HSI48 {
43 // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
44 config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Some(CrsConfig {
45 sync_src: CrsSyncSource::Usb,
46 })));
47 } else {
48 config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ);
49 }
50
38 let p = embassy_stm32::init(config); 51 let p = embassy_stm32::init(config);
39 info!("Hello World!");
40 52
41 pac::RCC.ccipr().write(|w| { 53 info!("Hello World!");
42 w.set_clk48sel(pac::rcc::vals::Clk48sel::PLLQCLK);
43 });
44 54
45 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); 55 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
46 56