|  | @@ -7,6 +7,7 @@
 | 
											
												
													
														|  |  #include <hardware/gpio.h>
 |  |  #include <hardware/gpio.h>
 | 
											
												
													
														|  |  #include <hardware/uart.h>
 |  |  #include <hardware/uart.h>
 | 
											
												
													
														|  |  #include <hardware/spi.h>
 |  |  #include <hardware/spi.h>
 | 
											
												
													
														|  | 
 |  | +#include <hardware/adc.h>
 | 
											
												
													
														|  |  #include <hardware/flash.h>
 |  |  #include <hardware/flash.h>
 | 
											
												
													
														|  |  #include <hardware/structs/xip_ctrl.h>
 |  |  #include <hardware/structs/xip_ctrl.h>
 | 
											
												
													
														|  |  #include <hardware/structs/usb.h>
 |  |  #include <hardware/structs/usb.h>
 | 
											
										
											
												
													
														|  | @@ -352,6 +353,51 @@ static void usb_log_poll()
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +// Use ADC to implement supply voltage monitoring for the +3.0V rail.
 | 
											
												
													
														|  | 
 |  | +// This works by sampling the temperature sensor channel, which has
 | 
											
												
													
														|  | 
 |  | +// a voltage of 0.7 V, allowing to calculate the VDD voltage.
 | 
											
												
													
														|  | 
 |  | +static void adc_poll()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +#if PLATFORM_VDD_WARNING_LIMIT_mV > 0
 | 
											
												
													
														|  | 
 |  | +    static bool initialized = false;
 | 
											
												
													
														|  | 
 |  | +    static int lowest_vdd_seen = PLATFORM_VDD_WARNING_LIMIT_mV;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (!initialized)
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +        adc_init();
 | 
											
												
													
														|  | 
 |  | +        adc_set_temp_sensor_enabled(true);
 | 
											
												
													
														|  | 
 |  | +        adc_set_clkdiv(65535); // Lowest samplerate, about 2 kHz
 | 
											
												
													
														|  | 
 |  | +        adc_select_input(4);
 | 
											
												
													
														|  | 
 |  | +        adc_fifo_setup(true, false, 0, false, false);
 | 
											
												
													
														|  | 
 |  | +        adc_run(true);
 | 
											
												
													
														|  | 
 |  | +        initialized = true;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    int adc_value_max = 0;
 | 
											
												
													
														|  | 
 |  | +    while (!adc_fifo_is_empty())
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +        int adc_value = adc_fifo_get();
 | 
											
												
													
														|  | 
 |  | +        if (adc_value > adc_value_max) adc_value_max = adc_value;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // adc_value = 700mV * 4096 / Vdd
 | 
											
												
													
														|  | 
 |  | +    // => Vdd = 700mV * 4096 / adc_value
 | 
											
												
													
														|  | 
 |  | +    // To avoid wasting time on division, compare against
 | 
											
												
													
														|  | 
 |  | +    // limit directly.
 | 
											
												
													
														|  | 
 |  | +    const int limit = (700 * 4096) / PLATFORM_VDD_WARNING_LIMIT_mV;
 | 
											
												
													
														|  | 
 |  | +    if (adc_value_max > limit)
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +        // Warn once, and then again if we detect even a lower drop.
 | 
											
												
													
														|  | 
 |  | +        int vdd_mV = (700 * 4096) / adc_value_max;
 | 
											
												
													
														|  | 
 |  | +        if (vdd_mV < lowest_vdd_seen)
 | 
											
												
													
														|  | 
 |  | +        {
 | 
											
												
													
														|  | 
 |  | +            log("WARNING: Detected supply voltage drop to ", vdd_mV, "mV. Verify power supply is adequate.");
 | 
											
												
													
														|  | 
 |  | +            lowest_vdd_seen = vdd_mV - 50; // Small hysteresis to avoid excessive warnings
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +#endif
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  // This function is called for every log message.
 |  |  // This function is called for every log message.
 | 
											
												
													
														|  |  void platform_log(const char *s)
 |  |  void platform_log(const char *s)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
										
											
												
													
														|  | @@ -444,6 +490,8 @@ void platform_reset_watchdog()
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      usb_log_poll();
 |  |      usb_log_poll();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    adc_poll();
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  /*****************************************/
 |  |  /*****************************************/
 |