3232extern " C" {
3333 #include " pico/bootrom.h"
3434 #include " hardware/watchdog.h"
35+ #include " pico/multicore.h"
36+ #include " hardware/adc.h"
37+ #include " pico/time.h"
3538}
3639
3740#if HAS_SD_HOST_DRIVE
3841 #include " msc_sd.h"
39- #include " usbd_cdc_if.h"
4042#endif
4143
44+ // Core 1 watchdog configuration
45+ #define CORE1_MAX_RESETS 5 // Maximum number of Core 1 resets before halting system
46+
4247// ------------------------
4348// Public Variables
4449// ------------------------
4550
51+ volatile uint32_t adc_accumulators[5 ] = {0 }; // Accumulators for oversampling (sum of readings)
52+ volatile uint8_t adc_counts[5 ] = {0 }; // Count of readings accumulated per channel
53+ volatile uint16_t adc_values[5 ] = {512 , 512 , 512 , 512 , 512 }; // Final oversampled ADC values (averages) - initialized to mid-range
54+
55+ // Core 1 watchdog monitoring
56+ volatile uint32_t core1_last_heartbeat = 0 ; // Timestamp of Core 1's last activity
57+ volatile bool core1_watchdog_triggered = false ; // Flag to indicate Core 1 reset
58+ volatile uint8_t core1_reset_count = 0 ; // Count of Core 1 resets - halt system if >= CORE1_MAX_RESETS
59+ volatile uint8_t current_pin;
60+ volatile bool MarlinHAL::adc_has_result;
61+ volatile uint8_t adc_channels_enabled[5 ] = {false }; // Track which ADC channels are enabled
62+
63+ // Helper function for LED blinking patterns
64+ void blink_led_pattern (uint8_t blink_count, uint32_t blink_duration_us = 100000 ) {
65+ #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED)
66+ for (uint8_t i = 0 ; i < blink_count; i++) {
67+ WRITE (LED_PIN, HIGH);
68+ busy_wait_us (blink_duration_us);
69+ WRITE (LED_PIN, LOW);
70+ if (i < blink_count - 1 ) { // Don't delay after the last blink
71+ busy_wait_us (blink_duration_us);
72+ }
73+ }
74+ #endif
75+ }
76+
77+ // Core 1 ADC reading task - dynamically reads all enabled channels with oversampling
78+ void core1_adc_task () {
79+ static uint32_t last_led_toggle = 0 ;
80+ const uint8_t OVERSAMPLENR = 16 ; // Standard Marlin oversampling count
81+
82+ // Signal successful Core 1 startup/restart
83+ SERIAL_ECHO_MSG (" Core 1 ADC task started" );
84+
85+ while (true ) {
86+ // Update heartbeat timestamp at start of each scan cycle
87+ core1_last_heartbeat = time_us_32 ();
88+
89+ // Scan all enabled ADC channels
90+ for (uint8_t channel = 0 ; channel < 5 ; channel++) {
91+ if (!adc_channels_enabled[channel]) continue ;
92+
93+ // Enable temperature sensor if reading channel 4
94+ if (channel == 4 ) {
95+ adc_set_temp_sensor_enabled (true );
96+ }
97+
98+ // Select and read the channel
99+ adc_select_input (channel);
100+ busy_wait_us (100 ); // Settling delay
101+ adc_fifo_drain ();
102+ adc_run (true );
103+
104+ // Wait for conversion with timeout
105+ uint32_t timeout = 10000 ;
106+ while (adc_fifo_is_empty () && timeout--) {
107+ busy_wait_us (1 );
108+ }
109+
110+ adc_run (false );
111+ uint16_t reading = adc_fifo_is_empty () ? 0 : adc_fifo_get ();
112+
113+ // Accumulate readings for oversampling
114+ adc_accumulators[channel] += reading;
115+ adc_counts[channel]++;
116+
117+ // Update the averaged value with current accumulation (provides immediate valid data)
118+ adc_values[channel] = adc_accumulators[channel] / adc_counts[channel];
119+
120+ // When we reach the full oversampling count, reset accumulator for next cycle
121+ if (adc_counts[channel] >= OVERSAMPLENR) {
122+ adc_accumulators[channel] = 0 ;
123+ adc_counts[channel] = 0 ;
124+ }
125+
126+ // Disable temp sensor after reading to save power
127+ if (channel == 4 ) {
128+ adc_set_temp_sensor_enabled (false );
129+ }
130+ }
131+
132+ // Core 1 LED indicator: Double blink every 2 seconds to show Core 1 is active
133+ uint32_t now = time_us_32 ();
134+ if (now - last_led_toggle >= 2000000 ) { // 2 seconds
135+ last_led_toggle = now;
136+ #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED)
137+ // Triple blink pattern if watchdog was triggered (shows Core 1 was reset)
138+ if (core1_watchdog_triggered) {
139+ core1_watchdog_triggered = false ; // Clear flag
140+ blink_led_pattern (3 ); // Triple blink for watchdog reset
141+ } else {
142+ blink_led_pattern (2 ); // Normal double blink
143+ }
144+ #endif
145+ }
146+
147+ // Delay between full scan cycles
148+ busy_wait_us (10000 ); // 10ms between scans
149+ }
150+ }
151+
46152volatile uint16_t adc_result;
47153
48154// ------------------------
@@ -118,9 +224,28 @@ void MarlinHAL::reboot() { watchdog_reboot(0, 0, 1); }
118224 }
119225
120226 void MarlinHAL::watchdog_refresh () {
227+ // If Core 1 has reset CORE1_MAX_RESETS+ times, stop updating watchdog to halt system
228+ if (core1_reset_count >= CORE1_MAX_RESETS) {
229+ SERIAL_ECHO_MSG (" Core 1 reset limit exceeded (" , core1_reset_count, " resets) - halting system for safety" );
230+ return ; // Don't update watchdog - system will halt
231+ }
232+
121233 watchdog_update ();
234+
235+ // Check Core 1 watchdog (15 second timeout)
236+ uint32_t now = time_us_32 ();
237+ if (now - core1_last_heartbeat > 15000000 ) { // 15 seconds
238+ // Core 1 appears stuck - reset it
239+ multicore_reset_core1 ();
240+ multicore_launch_core1 (core1_adc_task);
241+ core1_watchdog_triggered = true ; // Signal for LED indicator
242+ core1_reset_count++; // Increment reset counter
243+ SERIAL_ECHO_MSG (" Core 1 ADC watchdog triggered - resetting Core 1 (attempt " , core1_reset_count, " )" );
244+ }
245+
122246 #if DISABLED(PINS_DEBUGGING) && PIN_EXISTS(LED)
123- TOGGLE (LED_PIN); // heartbeat indicator
247+ // Core 0 LED indicator: Single toggle every watchdog refresh (shows Core 0 activity)
248+ TOGGLE (LED_PIN);
124249 #endif
125250 }
126251
@@ -130,44 +255,36 @@ void MarlinHAL::reboot() { watchdog_reboot(0, 0, 1); }
130255// ADC
131256// ------------------------
132257
133- volatile bool MarlinHAL::adc_has_result = false ;
134-
135258void MarlinHAL::adc_init () {
136259 analogReadResolution (HAL_ADC_RESOLUTION);
137260 ::adc_init ();
138261 adc_fifo_setup (true , false , 1 , false , false );
139- irq_set_exclusive_handler (ADC_IRQ_FIFO, adc_exclusive_handler);
140- irq_set_enabled (ADC_IRQ_FIFO, true );
141- adc_irq_set_enabled ( true );
262+ // Launch Core 1 for continuous ADC reading
263+ multicore_launch_core1 (core1_adc_task );
264+ adc_has_result = true ; // Results are always available with continuous sampling
142265}
143266
144267void MarlinHAL::adc_enable (const pin_t pin) {
145- if (pin >= A0 && pin <= A3)
268+ if (pin >= A0 && pin <= A3) {
146269 adc_gpio_init (pin);
147- else if (pin == HAL_ADC_MCU_TEMP_DUMMY_PIN)
148- adc_set_temp_sensor_enabled (true );
270+ adc_channels_enabled[pin - A0] = true ; // Mark this channel as enabled
271+ }
272+ else if (pin == HAL_ADC_MCU_TEMP_DUMMY_PIN) {
273+ adc_channels_enabled[4 ] = true ; // Mark MCU temp channel as enabled
274+ }
149275}
150276
151277void MarlinHAL::adc_start (const pin_t pin) {
152- adc_has_result = false ;
153- // Select an ADC input. 0...3 are GPIOs 26...29 respectively.
154- adc_select_input (pin == HAL_ADC_MCU_TEMP_DUMMY_PIN ? 4 : pin - A0);
155- adc_run (true );
278+ // Just store which pin we need to read - values are continuously updated by Core 1
279+ current_pin = pin;
156280}
157281
158- void MarlinHAL::adc_exclusive_handler () {
159- adc_run (false ); // Disable since we only want one result
160- irq_clear (ADC_IRQ_FIFO); // Clear the IRQ
161-
162- if (adc_fifo_get_level () >= 1 ) {
163- adc_result = adc_fifo_get (); // Pop the result
164- adc_fifo_drain ();
165- adc_has_result = true ; // Signal the end of the conversion
166- }
282+ uint16_t MarlinHAL::adc_value () {
283+ // Return the latest ADC value from Core 1's continuous readings
284+ const uint8_t channel = (current_pin == HAL_ADC_MCU_TEMP_DUMMY_PIN) ? 4 : (current_pin - A0);
285+ return adc_values[channel];
167286}
168287
169- uint16_t MarlinHAL::adc_value () { return adc_result; }
170-
171288// Reset the system to initiate a firmware flash
172289void flashFirmware (const int16_t ) { hal.reboot (); }
173290
0 commit comments