@@ -63,6 +63,7 @@ use prio::realtime_priority;
63
63
const MAX_AGE : Duration = Duration :: from_millis ( 300 ) ;
64
64
const THREAD_INTERVAL : Duration = Duration :: from_millis ( 100 ) ;
65
65
const TASK_INTERVAL : Duration = Duration :: from_millis ( 200 ) ;
66
+ const TURN_ON_ERROR_GRACE_PERIOD : Duration = Duration :: from_millis ( 600 ) ;
66
67
const MAX_CURRENT : f32 = 5.0 ;
67
68
const MAX_VOLTAGE : f32 = 48.0 ;
68
69
const MIN_VOLTAGE : f32 = -1.0 ;
@@ -353,6 +354,12 @@ impl DutPwrThread {
353
354
}
354
355
} ;
355
356
357
+ // The grace period contains the number of loop iterations until
358
+ // we start handling over/under voltage and overcurrent events.
359
+ // This counts down to zero after turning on the output.
360
+ // And is kept at TURN_ON_ERROR_GRACE_PERIOD while the output is off.
361
+ let mut grace_period = TURN_ON_ERROR_GRACE_PERIOD ;
362
+
356
363
// Run as long as there is a strong reference to `tick`.
357
364
// As tick is a private member of the struct this is equivalent
358
365
// to running as long as the DutPwrThread was not dropped.
@@ -413,10 +420,29 @@ impl DutPwrThread {
413
420
. swap ( OutputRequest :: Idle as u8 , Ordering :: Relaxed )
414
421
. into ( ) ;
415
422
416
- {
417
- // Don't even look at the requests if there is an ongoing
418
- // overvoltage condition. Instead turn the output off and
419
- // go back to measuring.
423
+ // Checking for MAX_VOLTAGE, MIN_VOLTAGE, MAX_CURRENT error conditions while
424
+ // the DUT power switch is off does not make a lot of sense,
425
+ // considering the way we measure these values right now (behind the DUT power switch).
426
+ // And what would we even do in this case? Turn the output even more off?
427
+ // If we see one of these error conditions while the output is off it is
428
+ // likely due to our high-impedance measurements and not due to a real error.
429
+ // Ignore these kinds of errors while the output is off and for a few
430
+ // THREAD_INTERVALs after turning it on.
431
+ grace_period = match state. load ( Ordering :: Relaxed ) . into ( ) {
432
+ OutputState :: On => grace_period. saturating_sub ( THREAD_INTERVAL ) ,
433
+ OutputState :: Off
434
+ | OutputState :: OffFloating
435
+ | OutputState :: Changing
436
+ | OutputState :: InvertedPolarity
437
+ | OutputState :: OverCurrent
438
+ | OutputState :: OverVoltage
439
+ | OutputState :: RealtimeViolation => TURN_ON_ERROR_GRACE_PERIOD ,
440
+ } ;
441
+
442
+ if grace_period == Duration :: ZERO {
443
+ // At this point the output is on and has been on for
444
+ // TURN_ON_ERROR_GRACE_PERIOD, so we start checking for error conditions.
445
+
420
446
if volt > MAX_VOLTAGE {
421
447
turn_off_with_reason (
422
448
OutputState :: OverVoltage ,
@@ -428,9 +454,6 @@ impl DutPwrThread {
428
454
continue ;
429
455
}
430
456
431
- // Don't even look at the requests if there is an ongoin
432
- // polarity inversion. Turn off, go back to start, do not
433
- // collect $200.
434
457
if volt < MIN_VOLTAGE {
435
458
turn_off_with_reason (
436
459
OutputState :: InvertedPolarity ,
@@ -442,8 +465,6 @@ impl DutPwrThread {
442
465
continue ;
443
466
}
444
467
445
- // Don't even look at the requests if there is an ongoin
446
- // overcurrent condition.
447
468
if curr > MAX_CURRENT {
448
469
turn_off_with_reason (
449
470
OutputState :: OverCurrent ,
@@ -744,4 +765,61 @@ mod tests {
744
765
assert_eq ! ( pwr_line. stub_get( ) , 1 - PWR_LINE_ASSERTED ) ;
745
766
assert_eq ! ( discharge_line. stub_get( ) , DISCHARGE_LINE_ASSERTED ) ;
746
767
}
768
+
769
+ #[ test]
770
+ fn grace_period ( ) {
771
+ let mut wtb = WatchedTasksBuilder :: new ( ) ;
772
+ let pwr_line = find_line ( "DUT_PWR_EN" ) . unwrap ( ) ;
773
+ let discharge_line = find_line ( "DUT_PWR_DISCH" ) . unwrap ( ) ;
774
+
775
+ let ( adc, dut_pwr) = {
776
+ let mut bb = BrokerBuilder :: new ( ) ;
777
+ let adc = block_on ( Adc :: new ( & mut bb, & mut wtb) ) . unwrap ( ) ;
778
+ let led = Topic :: anonymous ( None ) ;
779
+
780
+ let dut_pwr = block_on ( DutPwrThread :: new (
781
+ & mut bb,
782
+ & mut wtb,
783
+ adc. pwr_volt . clone ( ) ,
784
+ adc. pwr_curr . clone ( ) ,
785
+ led,
786
+ ) )
787
+ . unwrap ( ) ;
788
+
789
+ ( adc, dut_pwr)
790
+ } ;
791
+
792
+ // Set acceptable voltage / current
793
+ adc. pwr_volt . fast . set ( MAX_VOLTAGE * 0.99 ) ;
794
+ adc. pwr_curr . fast . set ( MAX_CURRENT * 0.99 ) ;
795
+
796
+ println ! ( "Turn Off" ) ;
797
+ dut_pwr. request . set ( OutputRequest :: Off ) ;
798
+ block_on ( sleep ( Duration :: from_millis ( 500 ) ) ) ;
799
+ assert_eq ! ( pwr_line. stub_get( ) , 1 - PWR_LINE_ASSERTED ) ;
800
+ assert_eq ! ( discharge_line. stub_get( ) , DISCHARGE_LINE_ASSERTED ) ;
801
+ assert_eq ! ( block_on( dut_pwr. state. get( ) ) , OutputState :: Off ) ;
802
+
803
+ println ! ( "Set overvoltage" ) ;
804
+ adc. pwr_volt . fast . set ( MAX_VOLTAGE * 1.01 ) ;
805
+ block_on ( sleep ( Duration :: from_millis ( 500 ) ) ) ;
806
+
807
+ println ! ( "Check if output stays off and does not go into error state" ) ;
808
+ assert_eq ! ( pwr_line. stub_get( ) , 1 - PWR_LINE_ASSERTED ) ;
809
+ assert_eq ! ( discharge_line. stub_get( ) , DISCHARGE_LINE_ASSERTED ) ;
810
+ assert_eq ! ( block_on( dut_pwr. state. get( ) ) , OutputState :: Off ) ;
811
+
812
+ println ! ( "Turn On (with overvoltage applied)" ) ;
813
+ dut_pwr. request . set ( OutputRequest :: On ) ;
814
+ block_on ( sleep ( Duration :: from_millis ( 400 ) ) ) ;
815
+ assert_eq ! ( pwr_line. stub_get( ) , PWR_LINE_ASSERTED ) ;
816
+ assert_eq ! ( discharge_line. stub_get( ) , 1 - DISCHARGE_LINE_ASSERTED ) ;
817
+ assert_eq ! ( block_on( dut_pwr. state. get( ) ) , OutputState :: On ) ;
818
+
819
+ println ! ( "Go into overvoltage error" ) ;
820
+ block_on ( sleep ( Duration :: from_millis ( 500 ) ) ) ;
821
+ assert_eq ! ( pwr_line. stub_get( ) , 1 - PWR_LINE_ASSERTED ) ;
822
+ assert_eq ! ( discharge_line. stub_get( ) , DISCHARGE_LINE_ASSERTED ) ;
823
+ assert_eq ! ( block_on( dut_pwr. state. get( ) ) , OutputState :: OverVoltage ) ;
824
+ }
747
825
}
0 commit comments