@@ -22,7 +22,7 @@ use stm32f0xx_hal::{
2222 gpio:: { Alternate , Floating , Input , Output , PullDown , PullUp , PushPull , AF1 } ,
2323 pac,
2424 prelude:: * ,
25- serial,
25+ rcc , serial,
2626} ;
2727
2828use neotron_bmc_commands:: Command ;
@@ -80,6 +80,10 @@ mod app {
8080 Ps2Data1 ( u16 ) ,
8181 /// Message from SPI bus
8282 SpiRequest ( neotron_bmc_protocol:: Request ) ,
83+ /// SPI CS went low (active)
84+ SpiEnable ,
85+ /// SPI CS went high (inactive)
86+ SpiDisable ,
8387 /// The power button was given a press
8488 PowerButtonShortPress ,
8589 /// The power button was held down
@@ -159,6 +163,8 @@ mod app {
159163 press_button_power_long : debouncr:: Debouncer < u16 , debouncr:: Repeat16 > ,
160164 /// Tracks reset button state for short presses. 75ms x 2 = 150ms is a long press
161165 press_button_reset_short : debouncr:: Debouncer < u8 , debouncr:: Repeat2 > ,
166+ /// Run-time Clock Control (required for resetting peripheral blocks)
167+ rcc : Option < rcc:: Rcc > ,
162168 }
163169
164170 #[ monotonic( binds = SysTick , default = true ) ]
@@ -281,7 +287,6 @@ mod app {
281287 let spi = neotron_bmc_pico:: spi:: SpiPeripheral :: new (
282288 dp. SPI1 ,
283289 ( pin_sck, pin_cipo, pin_copi) ,
284- 2_000_000 ,
285290 & mut rcc,
286291 ) ;
287292
@@ -339,6 +344,7 @@ mod app {
339344 press_button_power_short : debouncr:: debounce_2 ( false ) ,
340345 press_button_power_long : debouncr:: debounce_16 ( false ) ,
341346 press_button_reset_short : debouncr:: debounce_2 ( false ) ,
347+ rcc : Some ( rcc) ,
342348 } ;
343349 let init = init:: Monotonics ( mono) ;
344350 ( shared_resources, local_resources, init)
@@ -347,14 +353,15 @@ mod app {
347353 /// Our idle task.
348354 ///
349355 /// This task is called when there is nothing else to do.
350- #[ idle( shared = [ msg_q_out, msg_q_in, spi, state_dc_power_enabled, pin_dc_on, pin_sys_reset, pin_cs ] ) ]
356+ #[ idle( shared = [ msg_q_out, msg_q_in, spi, state_dc_power_enabled, pin_dc_on, pin_sys_reset] , local = [ rcc ] ) ]
351357 fn idle ( mut ctx : idle:: Context ) -> ! {
352358 // TODO: Get this from the VERSION static variable or from PKG_VERSION
353359 let mut register_state = RegisterState {
354360 firmware_version : * b"Neotron BMC v0.4.1-alpha\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 " ,
355361 ..Default :: default ( )
356362 } ;
357-
363+ // Take this out of the `local` object to avoid sharing issues.
364+ let mut rcc = ctx. local . rcc . take ( ) . unwrap ( ) ;
358365 defmt:: info!( "Idle is running..." ) ;
359366 loop {
360367 match ctx. shared . msg_q_out . dequeue ( ) {
@@ -377,36 +384,46 @@ mod app {
377384 }
378385 Some ( Message :: PowerButtonLongPress ) => {
379386 if ctx. shared . state_dc_power_enabled . lock ( |r| * r) == DcPowerState :: On {
380- defmt:: info!( "Power button held whilst on. " ) ;
387+ defmt:: info!( "Power off requested! " ) ;
381388 ctx. shared
382389 . state_dc_power_enabled
383390 . lock ( |r| * r = DcPowerState :: Off ) ;
384- defmt:: info!( "Power off!" ) ;
391+ // Stop any SPI stuff that's currently going on (the host is about to be powered off)
392+ ctx. shared . spi . lock ( |s| s. stop ( ) ) ;
393+ // Put the host into reset
385394 ctx. shared . pin_sys_reset . lock ( |pin| pin. set_low ( ) . unwrap ( ) ) ;
395+ // Shut off the 5V power
386396 ctx. shared . pin_dc_on . set_low ( ) . unwrap ( ) ;
387- ctx. shared . spi . lock ( |s| s. disable ( ) ) ;
388397 // Start LED blinking again
389398 led_power_blink:: spawn ( ) . unwrap ( ) ;
390399 }
391400 }
392401 Some ( Message :: PowerButtonShortPress ) => {
393402 if ctx. shared . state_dc_power_enabled . lock ( |r| * r) == DcPowerState :: Off {
394- defmt:: info!( "Power button pressed whilst off. Powering up." ) ;
395- // Button pressed - power on system
403+ defmt:: info!( "Power up requested!" ) ;
404+ // Button pressed - power on system.
405+ // Step 1 - Note our new power state
396406 ctx. shared
397407 . state_dc_power_enabled
398408 . lock ( |r| * r = DcPowerState :: Starting ) ;
409+ // Step 2 - Hold reset line (active) low
410+ ctx. shared . pin_sys_reset . lock ( |pin| pin. set_low ( ) . unwrap ( ) ) ;
411+ // Step 3 - Turn on PSU
399412 ctx. shared . pin_dc_on . set_high ( ) . unwrap ( ) ;
413+ // Step 4 - Leave it in reset for a while.
400414 // TODO: Start monitoring 3.3V and 5.0V rails here
401415 // TODO: Take system out of reset when 3.3V and 5.0V are good
402- ctx . shared . pin_sys_reset . lock ( |pin| pin . set_high ( ) . unwrap ( ) ) ;
403- ctx . shared . spi . lock ( |s| s . enable ( ) ) ;
416+ // Returns an error if it's already scheduled (but we don't care)
417+ let _ = exit_reset :: spawn_after ( RESET_DURATION_MS . millis ( ) ) ;
404418 }
405419 }
406420 Some ( Message :: PowerButtonRelease ) => {
407421 if ctx. shared . state_dc_power_enabled . lock ( |r| * r) == DcPowerState :: Starting {
408422 defmt:: info!( "Power button released." ) ;
409- // Button released after power on
423+ // Button released after power on. Change the power
424+ // state machine t "On". We were in 'Starting' to ignore
425+ // any further button events until the button had been
426+ // released.
410427 ctx. shared
411428 . state_dc_power_enabled
412429 . lock ( |r| * r = DcPowerState :: On ) ;
@@ -417,10 +434,25 @@ mod app {
417434 if ctx. shared . state_dc_power_enabled . lock ( |r| * r) == DcPowerState :: On {
418435 defmt:: info!( "Reset!" ) ;
419436 ctx. shared . pin_sys_reset . lock ( |pin| pin. set_low ( ) . unwrap ( ) ) ;
420- // Returns an error if it's already scheduled
437+ ctx. shared . spi . lock ( |s| s. reset ( & mut rcc) ) ;
438+ // Returns an error if it's already scheduled (but we don't care)
421439 let _ = exit_reset:: spawn_after ( RESET_DURATION_MS . millis ( ) ) ;
422440 }
423441 }
442+ Some ( Message :: SpiEnable ) => {
443+ if ctx. shared . state_dc_power_enabled . lock ( |r| * r) != DcPowerState :: Off {
444+ // Turn on the SPI peripheral
445+ ctx. shared . spi . lock ( |s| s. start ( ) ) ;
446+ } else {
447+ // Ignore message - it'll be the CS line being pulled low when the host is powered off
448+ defmt:: info!( "Ignoring spurious CS low" ) ;
449+ }
450+ }
451+ Some ( Message :: SpiDisable ) => {
452+ // Turn off the SPI peripheral. Don't need to check power state for this.
453+ ctx. shared . spi . lock ( |s| s. stop ( ) ) ;
454+ defmt:: trace!( "SPI Disable" ) ;
455+ }
424456 Some ( Message :: SpiRequest ( req) ) => {
425457 process_command ( req, & mut register_state, |rsp| {
426458 ctx. shared . spi . lock ( |spi| {
@@ -487,7 +519,7 @@ mod app {
487519 #[ task(
488520 binds = EXTI4_15 ,
489521 priority = 4 ,
490- shared = [ ps2_clk0, msg_q_in, ps2_dat0, exti, spi , pin_cs, kb_decoder] ,
522+ shared = [ ps2_clk0, msg_q_in, ps2_dat0, exti, pin_cs, kb_decoder] ,
491523 ) ]
492524 fn exti4_15_interrupt ( mut ctx : exti4_15_interrupt:: Context ) {
493525 let pr = ctx. shared . exti . pr . read ( ) ;
@@ -511,12 +543,15 @@ mod app {
511543 }
512544
513545 if pr. pr4 ( ) . bit_is_set ( ) {
514- if ctx. shared . pin_cs . lock ( |pin| pin. is_low ( ) . unwrap ( ) ) {
515- // If incoming Chip Select is low, turn on the SPI engine
516- ctx . shared . spi . lock ( |s| s . start ( ) ) ;
546+ let msg = if ctx. shared . pin_cs . lock ( |pin| pin. is_low ( ) . unwrap ( ) ) {
547+ // If incoming Chip Select is low, tell the main thread to turn on the SPI engine
548+ Message :: SpiEnable
517549 } else {
518- // If incoming Chip Select is high, turn off the SPI engine
519- ctx. shared . spi . lock ( |s| s. stop ( ) ) ;
550+ // If incoming Chip Select is high, tell the main thread to turn off the SPI engine
551+ Message :: SpiDisable
552+ } ;
553+ if ctx. shared . msg_q_in . lock ( |q| q. enqueue ( msg) ) . is_err ( ) {
554+ panic ! ( "queue full" ) ;
520555 }
521556 // Clear the pending flag for this pin
522557 ctx. shared . exti . pr . write ( |w| w. pr4 ( ) . set_bit ( ) ) ;
@@ -663,7 +698,8 @@ mod app {
663698 #[ task( shared = [ pin_sys_reset, state_dc_power_enabled] ) ]
664699 fn exit_reset ( mut ctx : exit_reset:: Context ) {
665700 defmt:: debug!( "End reset" ) ;
666- if ctx. shared . state_dc_power_enabled . lock ( |r| * r) == DcPowerState :: On {
701+ if ctx. shared . state_dc_power_enabled . lock ( |r| * r) != DcPowerState :: Off {
702+ // Raising the reset line takes the rest of the system out of reset
667703 ctx. shared . pin_sys_reset . lock ( |pin| pin. set_high ( ) . unwrap ( ) ) ;
668704 }
669705 }
0 commit comments