diff --git a/src/platforms/common/stm32/timing_stm32.c b/src/platforms/common/stm32/timing_stm32.c index 69c9a0475cc..d1525fa429a 100644 --- a/src/platforms/common/stm32/timing_stm32.c +++ b/src/platforms/common/stm32/timing_stm32.c @@ -22,12 +22,21 @@ #include #include #include +#include bool running_status = false; static volatile uint32_t time_ms = 0; uint32_t swd_delay_cnt = 0; static size_t morse_tick = 0; +#ifdef PLATFORM_HAS_POWER_SWITCH +static uint8_t monitor_ticks = 0; + +/* Derived from calculating (1.2V / 3.0V) * 4096 */ +#define ADC_VREFINT_MAX 1638U +/* Derived from calculating (1.2V / 3.6V) * 4096 */ +#define ADC_VREFINT_MIN 1365U +#endif void platform_timing_init(void) { @@ -60,6 +69,45 @@ void sys_tick_handler(void) morse_tick = 0; } else ++morse_tick; + +#ifdef PLATFORM_HAS_POWER_SWITCH + /* First check if target power is presently enabled */ + if (platform_target_get_power()) { + /* + * Every 10 systicks, set up an ADC conversion on the 9th tick, then + * read back the value on the 10th, checking the internal bandgap reference + * is still sat in the correct range. If it diverges down, this indicates + * backfeeding and that VCC is being pulled higher than 3.3V. If it diverges + * up, this indicates either backfeeding or overcurrent and that VCC is being + * pulled below 3.3V. In either case, for safety, disable tpwr and set + * a morse error of "TPWR ERROR" + */ + + /* If we're on the 9th tick, start the bandgap conversion */ + if (monitor_ticks == 8U) { + uint8_t channel = ADC_CHANNEL_VREF; + adc_set_regular_sequence(ADC1, 1, &channel); + adc_start_conversion_direct(ADC1); + } + + /* If we're on the 10th tick, check the result of bandgap conversion */ + if (monitor_ticks == 9U) { + const uint32_t ref = adc_read_regular(ADC1); + /* Clear EOC bit. The GD32F103 does not automatically reset it on ADC read. */ + ADC_SR(ADC1) &= ~ADC_SR_EOC; + monitor_ticks = 0; + + /* Now compare the reference against the known good range */ + if (ref > ADC_VREFINT_MAX || ref < ADC_VREFINT_MIN) { + /* Something's wrong, so turn tpwr off and set the morse blink pattern */ + platform_target_set_power(false); + morse("TPWR ERROR", true); + } + } else + ++monitor_ticks; + } else + monitor_ticks = 0; +#endif } uint32_t platform_time_ms(void) diff --git a/src/platforms/native/platform.c b/src/platforms/native/platform.c index 22e3a5a6b9f..46669fef640 100644 --- a/src/platforms/native/platform.c +++ b/src/platforms/native/platform.c @@ -275,7 +275,7 @@ static void adc_init(void) adc_disable_external_trigger_regular(ADC1); adc_set_right_aligned(ADC1); adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_239DOT5CYC); - + adc_enable_temperature_sensor(); adc_power_on(ADC1); /* Wait for the ADC to finish starting up */