Skip to content

Commit a8cf5d9

Browse files
⛙ Merge w/Marlin
2 parents 8064f3a + 12ac094 commit a8cf5d9

File tree

87 files changed

+1305
-1293
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+1305
-1293
lines changed

Marlin/Configuration_adv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,6 +1803,8 @@
18031803
#define POWER_LOSS_RECOVERY // (3400 bytes of flash)
18041804
#if ENABLED(POWER_LOSS_RECOVERY)
18051805
#define PLR_ENABLED_DEFAULT false // Power-Loss Recovery enabled by default. (Set with 'M413 Sn' & M500)
1806+
//#define PLR_HEAT_BED_ON_REBOOT // Heat up bed immediately on reboot to mitigate object detaching/warping.
1807+
//#define PLR_HEAT_BED_EXTRA 0 // (°C) Relative increase of bed temperature for better adhesion (limited by max temp).
18061808
//#define PLR_BED_THRESHOLD BED_MAXTEMP // (°C) Skip user confirmation at or above this bed temperature (0 to disable)
18071809

18081810
//#define POWER_LOSS_PIN 44 // Pin to detect power-loss. Set to -1 to disable default pin on boards without module, or comment to use board default.

Marlin/Version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
* here we define this default string as the date where the latest release
4242
* version was tagged.
4343
*/
44-
//#define STRING_DISTRIBUTION_DATE "2025-11-25"
44+
//#define STRING_DISTRIBUTION_DATE "2025-11-28"
4545

4646
#define STRING_DISTRIBUTION_DATE __DATE__
4747
#define STRING_DISTRIBUTION_TIME __TIME__

Marlin/src/HAL/RP2040/HAL.cpp

Lines changed: 142 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,123 @@
3232
extern "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+
46152
volatile 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-
135258
void 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

144267
void 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

151277
void 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
172289
void flashFirmware(const int16_t) { hal.reboot(); }
173290

Marlin/src/HAL/RP2040/HAL.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@
4040
#include "msc_sd.h"
4141
#endif
4242

43+
// ADC index 4 is the MCU temperature
44+
#define HAL_ADC_MCU_TEMP_DUMMY_PIN 127
45+
#define TEMP_SOC_PIN HAL_ADC_MCU_TEMP_DUMMY_PIN // ADC4 is internal temp sensor
46+
#include "temp_soc.h"
47+
4348
//
4449
// Serial Ports
4550
//
@@ -85,8 +90,6 @@ typedef libServo hal_servo_t;
8590
#else
8691
#define HAL_ADC_RESOLUTION 12
8792
#endif
88-
// ADC index 4 is the MCU temperature
89-
#define HAL_ADC_MCU_TEMP_DUMMY_PIN 127
9093

9194
//
9295
// Pin Mapping for M42, M43, M226
@@ -164,9 +167,6 @@ class MarlinHAL {
164167
// Begin ADC sampling on the given pin. Called from Temperature::isr!
165168
static void adc_start(const pin_t pin);
166169

167-
// This ADC runs a periodic task
168-
static void adc_exclusive_handler();
169-
170170
// Is the ADC ready for reading?
171171
static volatile bool adc_has_result;
172172
static bool adc_ready() { return adc_has_result; }

Marlin/src/HAL/RP2040/eeprom/eeprom_flash.cpp

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,28 +31,48 @@
3131

3232
// NOTE: The Bigtreetech SKR Pico has an onboard W25Q16 flash module
3333

34-
// Use EEPROM.h for compatibility, for now.
35-
#include <EEPROM.h>
34+
// RP2040 Flash-based EEPROM emulation using internal flash memory
35+
#include <hardware/flash.h>
36+
#include <hardware/sync.h>
3637

37-
static bool eeprom_data_written = false;
38+
// Flash sector size is already defined in hardware/flash.h as FLASH_SECTOR_SIZE
39+
// Place EEPROM emulation at the end of flash, before the filesystem
40+
// This assumes 2MB flash, adjust if using different flash size
41+
#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES - FLASH_SECTOR_SIZE)
3842

3943
#ifndef MARLIN_EEPROM_SIZE
4044
#define MARLIN_EEPROM_SIZE size_t(E2END + 1)
4145
#endif
46+
47+
static uint8_t eeprom_buffer[MARLIN_EEPROM_SIZE];
48+
static bool eeprom_data_written = false;
49+
static bool eeprom_initialized = false;
4250
size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; }
4351

4452
bool PersistentStore::access_start() {
45-
EEPROM.begin(); // Avoid EEPROM.h warning (do nothing)
46-
eeprom_buffer_fill();
53+
if (!eeprom_initialized) {
54+
// Read from flash into buffer
55+
const uint8_t *flash_data = (const uint8_t *)(XIP_BASE + FLASH_TARGET_OFFSET);
56+
memcpy(eeprom_buffer, flash_data, MARLIN_EEPROM_SIZE);
57+
eeprom_initialized = true;
58+
}
4759
return true;
4860
}
4961

5062
bool PersistentStore::access_finish() {
5163
if (eeprom_data_written) {
5264
TERN_(HAS_PAUSE_SERVO_OUTPUT, PAUSE_SERVO_OUTPUT());
53-
hal.isr_off();
54-
eeprom_buffer_flush();
55-
hal.isr_on();
65+
66+
// Disable interrupts during flash write
67+
const uint32_t intstate = save_and_disable_interrupts();
68+
69+
// Erase and program the sector
70+
flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE);
71+
flash_range_program(FLASH_TARGET_OFFSET, eeprom_buffer, MARLIN_EEPROM_SIZE);
72+
73+
// Restore interrupts
74+
restore_interrupts(intstate);
75+
5676
TERN_(HAS_PAUSE_SERVO_OUTPUT, RESUME_SERVO_OUTPUT());
5777
eeprom_data_written = false;
5878
}
@@ -62,8 +82,8 @@ bool PersistentStore::access_finish() {
6282
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
6383
while (size--) {
6484
uint8_t v = *value;
65-
if (v != eeprom_buffered_read_byte(pos)) {
66-
eeprom_buffered_write_byte(pos, v);
85+
if (pos < (int)MARLIN_EEPROM_SIZE && v != eeprom_buffer[pos]) {
86+
eeprom_buffer[pos] = v;
6787
eeprom_data_written = true;
6888
}
6989
crc16(crc, &v, 1);
@@ -75,7 +95,7 @@ bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, ui
7595

7696
bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
7797
do {
78-
const uint8_t c = eeprom_buffered_read_byte(pos);
98+
const uint8_t c = (pos < (int)MARLIN_EEPROM_SIZE) ? eeprom_buffer[pos] : 0xFF;
7999
if (writing) *value = c;
80100
crc16(crc, &c, 1);
81101
pos++;

0 commit comments

Comments
 (0)