Merge branch 'bugfix-2.0.x' into Raptor_2.0.X_Devel

This commit is contained in:
InsanityAutomation
2021-02-24 09:51:58 -05:00
399 changed files with 9081 additions and 4929 deletions
+27 -9
View File
@@ -146,15 +146,19 @@
//===========================================================================
/**
* Here are some standard links for getting your machine calibrated:
* Here are some useful links to help get your machine configured and calibrated:
*
* https://reprap.org/wiki/Calibration
* https://youtu.be/wAL9d7FgInk
* http://calculator.josefprusa.cz
* https://reprap.org/wiki/Triffid_Hunter%27s_Calibration_Guide
* https://www.thingiverse.com/thing:5573
* https://sites.google.com/site/repraplogphase/calibration-of-your-reprap
* https://www.thingiverse.com/thing:298812
* Example Configs: https://github.com/MarlinFirmware/Configurations/branches/all
*
* Průša Calculator: https://blog.prusaprinters.org/calculator_3416/
*
* Calibration Guides: https://reprap.org/wiki/Calibration
* https://reprap.org/wiki/Triffid_Hunter%27s_Calibration_Guide
* https://sites.google.com/site/repraplogphase/calibration-of-your-reprap
* https://youtu.be/wAL9d7FgInk
*
* Calibration Objects: https://www.thingiverse.com/thing:5573
* https://www.thingiverse.com/thing:1278865
*/
//===========================================================================
@@ -1924,7 +1928,9 @@
// @section temperature
// Preheat Constants
//
// Preheat Constants - Up to 5 are supported without changes
//
#define PREHEAT_1_LABEL "PLA"
#define PREHEAT_1_TEMP_HOTEND 180
#define PREHEAT_1_TEMP_BED 70
@@ -2257,6 +2263,14 @@
//
//#define REPRAP_DISCOUNT_SMART_CONTROLLER
//
// GT2560 (YHCB2004) LCD Display
//
// Requires Testato, Koepel softwarewire library and
// Andriy Golovnya's LiquidCrystal_AIP31068 library.
//
//#define YHCB2004
//
// Original RADDS LCD Display+Encoder+SDCardReader
// http://doku.radds.org/dokumentation/lcd-display/
@@ -2767,6 +2781,10 @@
//#define TOUCH_OFFSET_Y 257
//#define TOUCH_ORIENTATION TOUCH_LANDSCAPE
#if BOTH(TOUCH_SCREEN_CALIBRATION, EEPROM_SETTINGS)
#define TOUCH_CALIBRATION_AUTO_SAVE // Auto save successful calibration values to EEPROM
#endif
#if ENABLED(TFT_COLOR_UI)
//#define SINGLE_TOUCH_NAVIGATION
#endif
+17 -3
View File
@@ -113,6 +113,12 @@
#define CHAMBER_BETA 3950 // Beta value
#endif
#if TEMP_SENSOR_PROBE == 1000
#define PROBE_PULLUP_RESISTOR_OHMS 4700 // Pullup resistor
#define PROBE_RESISTANCE_25C_OHMS 100000 // Resistance at 25C
#define PROBE_BETA 3950 // Beta value
#endif
//
// Hephestos 2 24V heated bed upgrade kit.
// https://store.bq.com/en/heated-bed-kit-hephestos2
@@ -331,7 +337,7 @@
* High Temperature Thermistor Support
*
* Thermistors able to support high temperature tend to have a hard time getting
* good readings at room and lower temperatures. This means HEATER_X_RAW_LO_TEMP
* good readings at room and lower temperatures. This means TEMP_SENSOR_X_RAW_LO_TEMP
* will probably be caught when the heating element first turns on during the
* preheating process, which will trigger a min_temp_error as a safety measure
* and force stop everything.
@@ -1552,7 +1558,7 @@
//
// Specify additional languages for the UI. Default specified by LCD_LANGUAGE.
//
#if EITHER(DOGLCD, TOUCH_UI_FTDI_EVE)
#if ANY(DOGLCD, TFT_COLOR_UI, TOUCH_UI_FTDI_EVE)
//#define LCD_LANGUAGE_2 fr
//#define LCD_LANGUAGE_3 de
//#define LCD_LANGUAGE_4 es
@@ -3404,7 +3410,8 @@
#endif
/**
* User-defined menu items that execute custom GCode
* User-defined menu items to run custom G-code.
* Up to 25 may be defined, but the actual number is LCD-dependent.
*/
#define CUSTOM_USER_MENUS
@@ -3800,3 +3807,10 @@
// Enable Marlin dev mode which adds some special commands
//#define MARLIN_DEV_MODE
/**
* Postmortem Debugging captures misbehavior and outputs the CPU status and backtrace to serial.
* When running in the debugger it will break for debugging. This is useful to help understand
* a crash from a remote location. Requires ~400 bytes of SRAM and 5Kb of flash.
*/
//#define POSTMORTEM_DEBUGGING
+2 -2
View File
@@ -82,14 +82,14 @@ typedef int8_t pin_t;
// Serial ports
#ifdef USBCON
#include "../../core/serial_hook.h"
#include "../../core/serial_hook.h"
typedef ForwardSerial0Type< decltype(Serial) > DefaultSerial;
extern DefaultSerial MSerial;
#ifdef BLUETOOTH
typedef ForwardSerial0Type< decltype(bluetoothSerial) > BTSerial;
extern BTSerial btSerial;
#endif
#define MYSERIAL0 TERN(BLUETOOTH, btSerial, MSerial)
#else
#if !WITHIN(SERIAL_PORT, -1, 3)
+3 -3
View File
@@ -566,7 +566,7 @@ ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _UDRE_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::_tx_udr_empty_irq();
}
// Because of the template definition above, it's required to instantiate the template to have all method generated
// Because of the template definition above, it's required to instantiate the template to have all methods generated
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT> >;
MSerialT customizedSerial1(MSerialT::HasEmergencyParser);
@@ -595,7 +595,7 @@ MSerialT customizedSerial1(MSerialT::HasEmergencyParser);
MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>>::_tx_udr_empty_irq();
}
template class MarlinSerial< MarlinSerialCfg<MMU2_SERIAL_PORT> >;
template class MarlinSerial< MMU2SerialCfg<MMU2_SERIAL_PORT> >;
MSerialT3 mmuSerial(MSerialT3::HasEmergencyParser);
#endif
@@ -611,7 +611,7 @@ MSerialT customizedSerial1(MSerialT::HasEmergencyParser);
template class MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> >;
MSerialT4 lcdSerial(MSerialT4::HasEmergencyParser);
#if HAS_DGUS_LCD
template<typename Cfg>
typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::get_tx_buffer_free() {
+5 -5
View File
@@ -238,11 +238,11 @@
static constexpr bool MAX_RX_QUEUED = ENABLED(SERIAL_STATS_MAX_RX_QUEUED);
};
typedef Serial0Type< MarlinSerial< MarlinSerialCfg<SERIAL_PORT> > > MSerialT;
typedef Serial0Type< MarlinSerial< MarlinSerialCfg<SERIAL_PORT> > > MSerialT;
extern MSerialT customizedSerial1;
#ifdef SERIAL_PORT_2
typedef Serial0Type< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> > > MSerialT2;
typedef Serial0Type< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> > > MSerialT2;
extern MSerialT2 customizedSerial2;
#endif
@@ -262,8 +262,8 @@
static constexpr bool RX_OVERRUNS = false;
};
typedef Serial0Type< MarlinSerial< MMU2SerialCfg<MMU2_SERIAL_PORT> > > MSerialT3;
extern MSerial3 mmuSerial;
typedef Serial0Type< MarlinSerial< MMU2SerialCfg<MMU2_SERIAL_PORT> > > MSerialT3;
extern MSerialT3 mmuSerial;
#endif
#ifdef LCD_SERIAL_PORT
@@ -292,7 +292,7 @@
};
typedef Serial0Type< MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> > > MSerialT4;
typedef Serial0Type< MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> > > MSerialT4;
extern MSerialT4 lcdSerial;
#endif
+7
View File
@@ -56,3 +56,10 @@
#if BOTH(HAS_TMC_SW_SERIAL, MONITOR_DRIVER_STATUS)
#error "MONITOR_DRIVER_STATUS causes performance issues when used with SoftwareSerial-connected drivers. Disable MONITOR_DRIVER_STATUS or use hardware serial to continue."
#endif
/**
* Postmortem debugging
*/
#if ENABLED(POSTMORTEM_DEBUGGING)
#error "POSTMORTEM_DEBUGGING is not supported on AVR boards."
#endif
+7 -15
View File
@@ -235,8 +235,8 @@ static void print_is_also_tied() { SERIAL_ECHOPGM(" is also tied to this pin");
inline void com_print(const uint8_t N, const uint8_t Z) {
const uint8_t *TCCRA = (uint8_t*)TCCR_A(N);
SERIAL_ECHOPGM(" COM");
SERIAL_CHAR('0' + N, Z);
SERIAL_ECHOPAIR(" COM", AS_CHAR('0' + N));
SERIAL_CHAR(Z);
SERIAL_ECHOPAIR(": ", int((*TCCRA >> (6 - Z * 2)) & 0x03));
}
@@ -247,8 +247,8 @@ void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N -
uint8_t WGM = (((*TCCRB & _BV(WGM_2)) >> 1) | (*TCCRA & (_BV(WGM_0) | _BV(WGM_1))));
if (N == 4) WGM |= ((*TCCRB & _BV(WGM_3)) >> 1);
SERIAL_ECHOPGM(" TIMER");
SERIAL_CHAR(T + '0', L);
SERIAL_ECHOPAIR(" TIMER", AS_CHAR(T + '0'));
SERIAL_CHAR(L);
SERIAL_ECHO_SP(3);
if (N == 3) {
@@ -262,19 +262,11 @@ void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N -
SERIAL_ECHOPAIR(" WGM: ", WGM);
com_print(T,L);
SERIAL_ECHOPAIR(" CS: ", (*TCCRB & (_BV(CS_0) | _BV(CS_1) | _BV(CS_2)) ));
SERIAL_ECHOPGM(" TCCR");
SERIAL_CHAR(T + '0');
SERIAL_ECHOPAIR("A: ", *TCCRA);
SERIAL_ECHOPGM(" TCCR");
SERIAL_CHAR(T + '0');
SERIAL_ECHOPAIR("B: ", *TCCRB);
SERIAL_ECHOPAIR(" TCCR", AS_CHAR(T + '0'), "A: ", *TCCRA);
SERIAL_ECHOPAIR(" TCCR", AS_CHAR(T + '0'), "B: ", *TCCRB);
const uint8_t *TMSK = (uint8_t*)TIMSK(T);
SERIAL_ECHOPGM(" TIMSK");
SERIAL_CHAR(T + '0');
SERIAL_ECHOPAIR(": ", *TMSK);
SERIAL_ECHOPAIR(" TIMSK", AS_CHAR(T + '0'), ": ", *TMSK);
const uint8_t OCIE = L - 'A' + 1;
if (N == 3) { if (WGM == 0 || WGM == 2 || WGM == 4 || WGM == 6) err_is_counter(); }
-342
View File
@@ -1,342 +0,0 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../core/macros.h"
#include "../../core/serial.h"
#include "../shared/backtrace/unwinder.h"
#include "../shared/backtrace/unwmemaccess.h"
#include <stdarg.h>
// Debug monitor that dumps to the Programming port all status when
// an exception or WDT timeout happens - And then resets the board
// All the Monitor routines must run with interrupts disabled and
// under an ISR execution context. That is why we cannot reuse the
// Serial interrupt routines or any C runtime, as we don't know the
// state we are when running them
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() __asm__ volatile("": : :"memory");
// (re)initialize UART0 as a monitor output to 250000,n,8,1
static void TXBegin() {
// Disable UART interrupt in NVIC
NVIC_DisableIRQ( UART_IRQn );
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();
// Disable clock
pmc_disable_periph_clk( ID_UART );
// Configure PMC
pmc_enable_periph_clk( ID_UART );
// Disable PDC channel
UART->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
// Reset and disable receiver and transmitter
UART->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS;
// Configure mode: 8bit, No parity, 1 bit stop
UART->UART_MR = UART_MR_CHMODE_NORMAL | US_MR_CHRL_8_BIT | US_MR_NBSTOP_1_BIT | UART_MR_PAR_NO;
// Configure baudrate (asynchronous, no oversampling) to BAUDRATE bauds
UART->UART_BRGR = (SystemCoreClock / (BAUDRATE << 4));
// Enable receiver and transmitter
UART->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
}
// Send character through UART with no interrupts
static void TX(char c) {
while (!(UART->UART_SR & UART_SR_TXRDY)) { WDT_Restart(WDT); sw_barrier(); };
UART->UART_THR = c;
}
// Send String through UART
static void TX(const char* s) {
while (*s) TX(*s++);
}
static void TXDigit(uint32_t d) {
if (d < 10) TX((char)(d+'0'));
else if (d < 16) TX((char)(d+'A'-10));
else TX('?');
}
// Send Hex number thru UART
static void TXHex(uint32_t v) {
TX("0x");
for (uint8_t i = 0; i < 8; i++, v <<= 4)
TXDigit((v >> 28) & 0xF);
}
// Send Decimal number thru UART
static void TXDec(uint32_t v) {
if (!v) {
TX('0');
return;
}
char nbrs[14];
char *p = &nbrs[0];
while (v != 0) {
*p++ = '0' + (v % 10);
v /= 10;
}
do {
p--;
TX(*p);
} while (p != &nbrs[0]);
}
// Dump a backtrace entry
static bool UnwReportOut(void* ctx, const UnwReport* bte) {
int* p = (int*)ctx;
(*p)++;
TX('#'); TXDec(*p); TX(" : ");
TX(bte->name?bte->name:"unknown"); TX('@'); TXHex(bte->function);
TX('+'); TXDec(bte->address - bte->function);
TX(" PC:");TXHex(bte->address); TX('\n');
return true;
}
#ifdef UNW_DEBUG
void UnwPrintf(const char* format, ...) {
char dest[256];
va_list argptr;
va_start(argptr, format);
vsprintf(dest, format, argptr);
va_end(argptr);
TX(&dest[0]);
}
#endif
/* Table of function pointers for passing to the unwinder */
static const UnwindCallbacks UnwCallbacks = {
UnwReportOut,
UnwReadW,
UnwReadH,
UnwReadB
#ifdef UNW_DEBUG
, UnwPrintf
#endif
};
/**
* HardFaultHandler_C:
* This is called from the HardFault_HandlerAsm with a pointer the Fault stack
* as the parameter. We can then read the values from the stack and place them
* into local variables for ease of reading.
* We then read the various Fault Status and Address Registers to help decode
* cause of the fault.
* The function ends with a BKPT instruction to force control back into the debugger
*/
extern "C"
void HardFault_HandlerC(unsigned long *sp, unsigned long lr, unsigned long cause) {
static const char* causestr[] = {
"NMI","Hard","Mem","Bus","Usage","Debug","WDT","RSTC"
};
UnwindFrame btf;
// Dump report to the Programming port (interrupts are DISABLED)
TXBegin();
TX("\n\n## Software Fault detected ##\n");
TX("Cause: "); TX(causestr[cause]); TX('\n');
TX("R0 : "); TXHex(((unsigned long)sp[0])); TX('\n');
TX("R1 : "); TXHex(((unsigned long)sp[1])); TX('\n');
TX("R2 : "); TXHex(((unsigned long)sp[2])); TX('\n');
TX("R3 : "); TXHex(((unsigned long)sp[3])); TX('\n');
TX("R12 : "); TXHex(((unsigned long)sp[4])); TX('\n');
TX("LR : "); TXHex(((unsigned long)sp[5])); TX('\n');
TX("PC : "); TXHex(((unsigned long)sp[6])); TX('\n');
TX("PSR : "); TXHex(((unsigned long)sp[7])); TX('\n');
// Configurable Fault Status Register
// Consists of MMSR, BFSR and UFSR
TX("CFSR : "); TXHex((*((volatile unsigned long *)(0xE000ED28)))); TX('\n');
// Hard Fault Status Register
TX("HFSR : "); TXHex((*((volatile unsigned long *)(0xE000ED2C)))); TX('\n');
// Debug Fault Status Register
TX("DFSR : "); TXHex((*((volatile unsigned long *)(0xE000ED30)))); TX('\n');
// Auxiliary Fault Status Register
TX("AFSR : "); TXHex((*((volatile unsigned long *)(0xE000ED3C)))); TX('\n');
// Read the Fault Address Registers. These may not contain valid values.
// Check BFARVALID/MMARVALID to see if they are valid values
// MemManage Fault Address Register
TX("MMAR : "); TXHex((*((volatile unsigned long *)(0xE000ED34)))); TX('\n');
// Bus Fault Address Register
TX("BFAR : "); TXHex((*((volatile unsigned long *)(0xE000ED38)))); TX('\n');
TX("ExcLR: "); TXHex(lr); TX('\n');
TX("ExcSP: "); TXHex((unsigned long)sp); TX('\n');
btf.sp = ((unsigned long)sp) + 8*4; // The original stack pointer
btf.fp = btf.sp;
btf.lr = ((unsigned long)sp[5]);
btf.pc = ((unsigned long)sp[6]) | 1; // Force Thumb, as CORTEX only support it
// Perform a backtrace
TX("\nBacktrace:\n\n");
int ctr = 0;
UnwindStart(&btf, &UnwCallbacks, &ctr);
// Disable all NVIC interrupts
NVIC->ICER[0] = 0xFFFFFFFF;
NVIC->ICER[1] = 0xFFFFFFFF;
// Relocate VTOR table to default position
SCB->VTOR = 0;
// Disable USB
otg_disable();
// Restart watchdog
WDT_Restart(WDT);
// Reset controller
NVIC_SystemReset();
for (;;) WDT_Restart(WDT);
}
__attribute__((naked)) void NMI_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#0")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void HardFault_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#1")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void MemManage_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#2")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void BusFault_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#3")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void UsageFault_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#4")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void DebugMon_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#5")
A("b HardFault_HandlerC")
);
}
/* This is NOT an exception, it is an interrupt handler - Nevertheless, the framing is the same */
__attribute__((naked)) void WDT_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#6")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void RSTC_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#7")
A("b HardFault_HandlerC")
);
}
#endif // ARDUINO_ARCH_SAM
+16 -6
View File
@@ -40,6 +40,8 @@ uint16_t HAL_adc_result;
// Public functions
// ------------------------
TERN_(POSTMORTEM_DEBUGGING, extern void install_min_serial());
// HAL initialization task
void HAL_init() {
// Initialize the USB stack
@@ -47,6 +49,7 @@ void HAL_init() {
OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up
#endif
usb_task_init();
TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler
}
// HAL idle task
@@ -102,11 +105,18 @@ uint16_t HAL_adc_get_result() {
return HAL_adc_result;
}
// Forward the default serial port
DefaultSerial MSerial(false, Serial);
DefaultSerial1 MSerial1(false, Serial1);
DefaultSerial2 MSerial2(false, Serial2);
DefaultSerial3 MSerial3(false, Serial3);
// Forward the default serial ports
#if ANY_SERIAL_IS(0)
DefaultSerial MSerial(false, Serial);
#endif
#if ANY_SERIAL_IS(1)
DefaultSerial1 MSerial1(false, Serial1);
#endif
#if ANY_SERIAL_IS(2)
DefaultSerial2 MSerial2(false, Serial2);
#endif
#if ANY_SERIAL_IS(3)
DefaultSerial3 MSerial3(false, Serial3);
#endif
#endif // ARDUINO_ARCH_SAM
+2 -2
View File
@@ -37,12 +37,12 @@
#include <stdint.h>
#include "../../core/serial_hook.h"
typedef ForwardSerial0Type< decltype(Serial) > DefaultSerial;
extern DefaultSerial MSerial;
typedef ForwardSerial0Type< decltype(Serial) > DefaultSerial;
typedef ForwardSerial0Type< decltype(Serial1) > DefaultSerial1;
typedef ForwardSerial0Type< decltype(Serial2) > DefaultSerial2;
typedef ForwardSerial0Type< decltype(Serial3) > DefaultSerial3;
extern DefaultSerial MSerial;
extern DefaultSerial1 MSerial1;
extern DefaultSerial2 MSerial2;
extern DefaultSerial3 MSerial3;
+91
View File
@@ -0,0 +1,91 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(POSTMORTEM_DEBUGGING)
#include "../shared/HAL_MinSerial.h"
#include <stdarg.h>
static void TXBegin() {
// Disable UART interrupt in NVIC
NVIC_DisableIRQ( UART_IRQn );
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();
// Disable clock
pmc_disable_periph_clk( ID_UART );
// Configure PMC
pmc_enable_periph_clk( ID_UART );
// Disable PDC channel
UART->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
// Reset and disable receiver and transmitter
UART->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS;
// Configure mode: 8bit, No parity, 1 bit stop
UART->UART_MR = UART_MR_CHMODE_NORMAL | US_MR_CHRL_8_BIT | US_MR_NBSTOP_1_BIT | UART_MR_PAR_NO;
// Configure baudrate (asynchronous, no oversampling) to BAUDRATE bauds
UART->UART_BRGR = (SystemCoreClock / (BAUDRATE << 4));
// Enable receiver and transmitter
UART->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
}
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() __asm__ volatile("": : :"memory");
static void TX(char c) {
while (!(UART->UART_SR & UART_SR_TXRDY)) { WDT_Restart(WDT); sw_barrier(); };
UART->UART_THR = c;
}
void install_min_serial() {
HAL_min_serial_init = &TXBegin;
HAL_min_serial_out = &TX;
}
#if DISABLED(DYNAMIC_VECTORTABLE)
extern "C" {
__attribute__((naked)) void JumpHandler_ASM() {
__asm__ __volatile__ (
"b CommonHandler_ASM\n"
);
}
void __attribute__((naked, alias("JumpHandler_ASM"))) HardFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"))) BusFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"))) UsageFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"))) MemManage_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"))) NMI_Handler();
}
#endif
#endif // POSTMORTEM_DEBUGGING
#endif // ARDUINO_ARCH_SAM
+4 -4
View File
@@ -240,7 +240,7 @@
}
// all the others
static uint32_t spiDelayCyclesX4 = (F_CPU) / 1000000; // 4µs => 125khz
static uint32_t spiDelayCyclesX4 = 4 * (F_CPU) / 1000000; // 4µs => 125khz
static uint8_t spiTransferX(uint8_t b) { // using Mode 0
int bits = 8;
@@ -249,12 +249,12 @@
b <<= 1; // little setup time
WRITE(SD_SCK_PIN, HIGH);
__delay_4cycles(spiDelayCyclesX4);
DELAY_CYCLES(spiDelayCyclesX4);
b |= (READ(SD_MISO_PIN) != 0);
WRITE(SD_SCK_PIN, LOW);
__delay_4cycles(spiDelayCyclesX4);
DELAY_CYCLES(spiDelayCyclesX4);
} while (--bits);
return b;
}
@@ -510,7 +510,7 @@
spiRxBlock = (pfnSpiRxBlock)spiRxBlockX;
break;
default:
spiDelayCyclesX4 = ((F_CPU) / 1000000) >> (6 - spiRate);
spiDelayCyclesX4 = ((F_CPU) / 1000000) >> (6 - spiRate) << 2; // spiRate of 2 gives the maximum error with current CPU
spiTransferTx = (pfnSpiTransfer)spiTransferX;
spiTransferRx = (pfnSpiTransfer)spiTransferX;
spiTxBlock = (pfnSpiTxBlock)spiTxBlockX;
+2 -7
View File
@@ -33,10 +33,6 @@
#include "MarlinSerialUSB.h"
#if ENABLED(EMERGENCY_PARSER)
#include "../../feature/e_parser.h"
#endif
// Imports from Atmel USB Stack/CDC implementation
extern "C" {
bool usb_task_cdc_isenabled();
@@ -69,7 +65,7 @@ int MarlinSerialUSB::peek() {
pending_char = udi_cdc_getc();
TERN_(EMERGENCY_PARSER, emergency_parser.update(emergency_state, (char)pending_char));
TERN_(EMERGENCY_PARSER, emergency_parser.update(static_cast<MSerialT*>(this)->emergency_state, (char)pending_char));
return pending_char;
}
@@ -91,7 +87,7 @@ int MarlinSerialUSB::read() {
int c = udi_cdc_getc();
TERN_(EMERGENCY_PARSER, emergency_parser.update(emergency_state, (char)c));
TERN_(EMERGENCY_PARSER, emergency_parser.update(static_cast<MSerialT*>(this)->emergency_state, (char)c));
return c;
}
@@ -105,7 +101,6 @@ bool MarlinSerialUSB::available() {
}
void MarlinSerialUSB::flush() { }
void MarlinSerialUSB::flushTX() { }
size_t MarlinSerialUSB::write(const uint8_t c) {
+9 -10
View File
@@ -34,21 +34,20 @@
struct MarlinSerialUSB {
static void begin(const long);
static void end();
static int peek();
static int read();
static void flush();
static void flushTX();
static bool available();
static size_t write(const uint8_t c);
void begin(const long);
void end();
int peek();
int read();
void flush();
bool available();
size_t write(const uint8_t c);
#if ENABLED(SERIAL_STATS_DROPPED_RX)
FORCE_INLINE static uint32_t dropped() { return 0; }
FORCE_INLINE uint32_t dropped() { return 0; }
#endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
FORCE_INLINE static int rxMaxEnqueued() { return 0; }
FORCE_INLINE int rxMaxEnqueued() { return 0; }
#endif
};
typedef Serial0Type<MarlinSerialUSB> MSerialT;
@@ -59,6 +59,7 @@
#if ENABLED(U8GLIB_ST7920)
#include "../../../inc/MarlinConfig.h"
#include "../../shared/Delay.h"
#include <U8glib.h>
@@ -59,6 +59,7 @@
#if HAS_MARLINUI_U8GLIB
#include "../../../inc/MarlinConfig.h"
#include "../../shared/Delay.h"
#include <U8glib.h>
+1 -1
View File
@@ -57,5 +57,5 @@
#endif
#if HAS_TMC_SW_SERIAL
#error "TMC220x Software Serial is not supported on this platform."
#error "TMC220x Software Serial is not supported on the DUE platform."
#endif
+4 -2
View File
@@ -90,8 +90,6 @@ volatile int numPWMUsed = 0,
#endif
void HAL_init() { TERN_(I2S_STEPPER_STREAM, i2s_init()); }
void HAL_init_board() {
#if ENABLED(ESP3D_WIFISUPPORT)
@@ -126,6 +124,10 @@ void HAL_init_board() {
#endif
#endif
// Initialize the i2s peripheral only if the I2S stepper stream is enabled.
// The following initialization is performed after Serial1 and Serial2 are defined as
// their native pins might conflict with the i2s stream even when they are remapped.
TERN_(I2S_STEPPER_STREAM, i2s_init());
}
void HAL_idletask() {
+1 -1
View File
@@ -139,7 +139,7 @@ void HAL_adc_start_conversion(const uint8_t adc_pin);
#define HAL_IDLETASK 1
#define BOARD_INIT() HAL_init_board();
void HAL_idletask();
void HAL_init();
inline void HAL_init() {}
void HAL_init_board();
//
+5 -1
View File
@@ -30,9 +30,13 @@
#endif
#if HAS_TMC_SW_SERIAL
#error "TMC220x Software Serial is not supported on this platform."
#error "TMC220x Software Serial is not supported on ESP32."
#endif
#if BOTH(WIFISUPPORT, ESP3D_WIFISUPPORT)
#error "Only enable one WiFi option, either WIFISUPPORT or ESP3D_WIFISUPPORT."
#endif
#if ENABLED(POSTMORTEM_DEBUGGING)
#error "POSTMORTEM_DEBUGGING is not yet supported on ESP32."
#endif
+5 -1
View File
@@ -35,5 +35,9 @@
#endif
#if HAS_TMC_SW_SERIAL
#error "TMC220x Software Serial is not supported on this platform."
#error "TMC220x Software Serial is not supported on LINUX."
#endif
#if ENABLED(POSTMORTEM_DEBUGGING)
#error "POSTMORTEM_DEBUGGING is not yet supported on LINUX."
#endif
-322
View File
@@ -1,322 +0,0 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef TARGET_LPC1768
#include "../../core/macros.h"
#include "../../core/serial.h"
#include <stdarg.h>
#include "../shared/backtrace/unwinder.h"
#include "../shared/backtrace/unwmemaccess.h"
#include "watchdog.h"
#include <debug_frmwrk.h>
// Debug monitor that dumps to the Programming port all status when
// an exception or WDT timeout happens - And then resets the board
// All the Monitor routines must run with interrupts disabled and
// under an ISR execution context. That is why we cannot reuse the
// Serial interrupt routines or any C runtime, as we don't know the
// state we are when running them
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() __asm__ volatile("": : :"memory");
// (re)initialize UART0 as a monitor output to 250000,n,8,1
static void TXBegin() {
}
// Send character through UART with no interrupts
static void TX(char c) {
_DBC(c);
}
// Send String through UART
static void TX(const char* s) {
while (*s) TX(*s++);
}
static void TXDigit(uint32_t d) {
if (d < 10) TX((char)(d+'0'));
else if (d < 16) TX((char)(d+'A'-10));
else TX('?');
}
// Send Hex number thru UART
static void TXHex(uint32_t v) {
TX("0x");
for (uint8_t i = 0; i < 8; i++, v <<= 4)
TXDigit((v >> 28) & 0xF);
}
// Send Decimal number thru UART
static void TXDec(uint32_t v) {
if (!v) {
TX('0');
return;
}
char nbrs[14];
char *p = &nbrs[0];
while (v != 0) {
*p++ = '0' + (v % 10);
v /= 10;
}
do {
p--;
TX(*p);
} while (p != &nbrs[0]);
}
// Dump a backtrace entry
static bool UnwReportOut(void* ctx, const UnwReport* bte) {
int* p = (int*)ctx;
(*p)++;
TX('#'); TXDec(*p); TX(" : ");
TX(bte->name?bte->name:"unknown"); TX('@'); TXHex(bte->function);
TX('+'); TXDec(bte->address - bte->function);
TX(" PC:");TXHex(bte->address); TX('\n');
return true;
}
#ifdef UNW_DEBUG
void UnwPrintf(const char* format, ...) {
char dest[256];
va_list argptr;
va_start(argptr, format);
vsprintf(dest, format, argptr);
va_end(argptr);
TX(&dest[0]);
}
#endif
/* Table of function pointers for passing to the unwinder */
static const UnwindCallbacks UnwCallbacks = {
UnwReportOut,
UnwReadW,
UnwReadH,
UnwReadB
#ifdef UNW_DEBUG
,UnwPrintf
#endif
};
/**
* HardFaultHandler_C:
* This is called from the HardFault_HandlerAsm with a pointer the Fault stack
* as the parameter. We can then read the values from the stack and place them
* into local variables for ease of reading.
* We then read the various Fault Status and Address Registers to help decode
* cause of the fault.
* The function ends with a BKPT instruction to force control back into the debugger
*/
extern "C"
void HardFault_HandlerC(unsigned long *sp, unsigned long lr, unsigned long cause) {
static const char* causestr[] = {
"NMI","Hard","Mem","Bus","Usage","Debug","WDT","RSTC"
};
UnwindFrame btf;
// Dump report to the Programming port (interrupts are DISABLED)
TXBegin();
TX("\n\n## Software Fault detected ##\n");
TX("Cause: "); TX(causestr[cause]); TX('\n');
TX("R0 : "); TXHex(((unsigned long)sp[0])); TX('\n');
TX("R1 : "); TXHex(((unsigned long)sp[1])); TX('\n');
TX("R2 : "); TXHex(((unsigned long)sp[2])); TX('\n');
TX("R3 : "); TXHex(((unsigned long)sp[3])); TX('\n');
TX("R12 : "); TXHex(((unsigned long)sp[4])); TX('\n');
TX("LR : "); TXHex(((unsigned long)sp[5])); TX('\n');
TX("PC : "); TXHex(((unsigned long)sp[6])); TX('\n');
TX("PSR : "); TXHex(((unsigned long)sp[7])); TX('\n');
// Configurable Fault Status Register
// Consists of MMSR, BFSR and UFSR
TX("CFSR : "); TXHex((*((volatile unsigned long *)(0xE000ED28)))); TX('\n');
// Hard Fault Status Register
TX("HFSR : "); TXHex((*((volatile unsigned long *)(0xE000ED2C)))); TX('\n');
// Debug Fault Status Register
TX("DFSR : "); TXHex((*((volatile unsigned long *)(0xE000ED30)))); TX('\n');
// Auxiliary Fault Status Register
TX("AFSR : "); TXHex((*((volatile unsigned long *)(0xE000ED3C)))); TX('\n');
// Read the Fault Address Registers. These may not contain valid values.
// Check BFARVALID/MMARVALID to see if they are valid values
// MemManage Fault Address Register
TX("MMAR : "); TXHex((*((volatile unsigned long *)(0xE000ED34)))); TX('\n');
// Bus Fault Address Register
TX("BFAR : "); TXHex((*((volatile unsigned long *)(0xE000ED38)))); TX('\n');
TX("ExcLR: "); TXHex(lr); TX('\n');
TX("ExcSP: "); TXHex((unsigned long)sp); TX('\n');
btf.sp = ((unsigned long)sp) + 8*4; // The original stack pointer
btf.fp = btf.sp;
btf.lr = ((unsigned long)sp[5]);
btf.pc = ((unsigned long)sp[6]) | 1; // Force Thumb, as CORTEX only support it
// Perform a backtrace
TX("\nBacktrace:\n\n");
int ctr = 0;
UnwindStart(&btf, &UnwCallbacks, &ctr);
// Disable all NVIC interrupts
NVIC->ICER[0] = 0xFFFFFFFF;
NVIC->ICER[1] = 0xFFFFFFFF;
// Relocate VTOR table to default position
SCB->VTOR = 0;
// Clear cause of reset to prevent entering smoothie bootstrap
HAL_clear_reset_source();
// Restart watchdog
#if ENABLED(USE_WATCHDOG)
//WDT_Restart(WDT);
watchdog_init();
#endif
// Reset controller
NVIC_SystemReset();
// Nothing below here is compiled because NVIC_SystemReset loops forever
for (;;) { TERN_(USE_WATCHDOG, watchdog_init()); }
}
extern "C" {
__attribute__((naked)) void NMI_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#0")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void HardFault_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#1")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void MemManage_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#2")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void BusFault_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#3")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void UsageFault_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#4")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void DebugMon_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#5")
A("b HardFault_HandlerC")
);
}
/* This is NOT an exception, it is an interrupt handler - Nevertheless, the framing is the same */
__attribute__((naked)) void WDT_IRQHandler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#6")
A("b HardFault_HandlerC")
);
}
__attribute__((naked)) void RSTC_Handler() {
__asm__ __volatile__ (
".syntax unified" "\n\t"
A("tst lr, #4")
A("ite eq")
A("mrseq r0, msp")
A("mrsne r0, psp")
A("mov r1,lr")
A("mov r2,#7")
A("b HardFault_HandlerC")
);
}
}
#endif // TARGET_LPC1768
+6 -1
View File
@@ -63,7 +63,12 @@ int16_t PARSED_PIN_INDEX(const char code, const int16_t dval) {
return ind > -1 ? ind : dval;
}
void flashFirmware(const int16_t) { NVIC_SystemReset(); }
void flashFirmware(const int16_t) {
delay(500); // Give OS time to disconnect
USB_Connect(false); // USB clear connection
delay(1000); // Give OS time to notice
NVIC_SystemReset();
}
void HAL_clear_reset_source(void) {
TERN_(USE_WATCHDOG, watchdog_clear_timeout_flag());
+50
View File
@@ -0,0 +1,50 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef TARGET_LPC1768
#include "HAL.h"
#if ENABLED(POSTMORTEM_DEBUGGING)
#include "../shared/HAL_MinSerial.h"
#include <debug_frmwrk.h>
static void TX(char c) { _DBC(c); }
void install_min_serial() { HAL_min_serial_out = &TX; }
#if DISABLED(DYNAMIC_VECTORTABLE)
extern "C" {
__attribute__((naked)) void JumpHandler_ASM() {
__asm__ __volatile__ (
"b CommonHandler_ASM\n"
);
}
void __attribute__((naked, alias("JumpHandler_ASM"))) HardFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"))) BusFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"))) UsageFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"))) MemManage_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"))) NMI_Handler();
}
#endif
#endif // POSTMORTEM_DEBUGGING
#endif // TARGET_LPC1768
+4 -4
View File
@@ -24,19 +24,19 @@
#include "../../inc/MarlinConfigPre.h"
#include "MarlinSerial.h"
#if USING_SERIAL_0
#if ANY_SERIAL_IS(0)
MSerialT MSerial(true, LPC_UART0);
extern "C" void UART0_IRQHandler() { MSerial.IRQHandler(); }
#endif
#if USING_SERIAL_1
#if ANY_SERIAL_IS(1)
MSerialT MSerial1(true, (LPC_UART_TypeDef *) LPC_UART1);
extern "C" void UART1_IRQHandler() { MSerial1.IRQHandler(); }
#endif
#if USING_SERIAL_2
#if ANY_SERIAL_IS(2)
MSerialT MSerial2(true, LPC_UART2);
extern "C" void UART2_IRQHandler() { MSerial2.IRQHandler(); }
#endif
#if USING_SERIAL_3
#if ANY_SERIAL_IS(3)
MSerialT MSerial3(true, LPC_UART3);
extern "C" void UART3_IRQHandler() { MSerial3.IRQHandler(); }
#endif
+3 -3
View File
@@ -84,16 +84,16 @@ static void debug_rw(const bool write, int &pos, const uint8_t *value, const siz
PGM_P const rw_str = write ? PSTR("write") : PSTR("read");
SERIAL_CHAR(' ');
serialprintPGM(rw_str);
SERIAL_ECHOLNPAIR("_data(", pos, ",", int(value), ",", int(size), ", ...)");
SERIAL_ECHOLNPAIR("_data(", pos, ",", value, ",", size, ", ...)");
if (total) {
SERIAL_ECHOPGM(" f_");
serialprintPGM(rw_str);
SERIAL_ECHOPAIR("()=", int(s), "\n size=", int(size), "\n bytes_");
SERIAL_ECHOPAIR("()=", s, "\n size=", size, "\n bytes_");
serialprintPGM(write ? PSTR("written=") : PSTR("read="));
SERIAL_ECHOLN(total);
}
else
SERIAL_ECHOLNPAIR(" f_lseek()=", int(s));
SERIAL_ECHOLNPAIR(" f_lseek()=", s);
}
// File function return codes for type FRESULT. This goes away soon, but
+7 -7
View File
@@ -31,7 +31,7 @@
/**
* Detect an old pins file by checking for old ADC pins values.
*/
#define _OLD_TEMP_PIN(P) PIN_EXISTS(P) && _CAT(P,_PIN) <= 7 && _CAT(P,_PIN) != 2 && _CAT(P,_PIN) != 3
#define _OLD_TEMP_PIN(P) PIN_EXISTS(P) && _CAT(P,_PIN) <= 7 && !WITHIN(_CAT(P,_PIN), TERN(LPC1768_IS_SKRV1_3, 0, 2), 3) // Include P0_00 and P0_01 for SKR V1.3 board
#if _OLD_TEMP_PIN(TEMP_BED)
#error "TEMP_BED_PIN must be defined using the Pn_nn or Pn_nn_An format. (See the included pins files)."
#elif _OLD_TEMP_PIN(TEMP_0)
@@ -92,7 +92,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o
#define ANY_TX(N,V...) DO(IS_TX##N,||,V)
#define ANY_RX(N,V...) DO(IS_RX##N,||,V)
#if USING_SERIAL_0
#if ANY_SERIAL_IS(0)
#define IS_TX0(P) (P == P0_02)
#define IS_RX0(P) (P == P0_03)
#if IS_TX0(TMC_SW_MISO) || IS_RX0(TMC_SW_MOSI)
@@ -106,7 +106,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o
#undef IS_RX0
#endif
#if USING_SERIAL_1
#if ANY_SERIAL_IS(1)
#define IS_TX1(P) (P == P0_15)
#define IS_RX1(P) (P == P0_16)
#define _IS_TX1_1 IS_TX1
@@ -127,7 +127,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o
#undef _IS_RX1_1
#endif
#if USING_SERIAL_2
#if ANY_SERIAL_IS(2)
#define IS_TX2(P) (P == P0_10)
#define IS_RX2(P) (P == P0_11)
#define _IS_TX2_1 IS_TX2
@@ -161,7 +161,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o
#undef _IS_RX2_1
#endif
#if USING_SERIAL_3
#if ANY_SERIAL_IS(3)
#define PIN_IS_TX3(P) (PIN_EXISTS(P) && P##_PIN == P0_00)
#define PIN_IS_RX3(P) (P##_PIN == P0_01)
#if PIN_IS_TX3(X_MIN) || PIN_IS_RX3(X_MAX)
@@ -270,7 +270,7 @@ static_assert(DISABLED(BAUD_RATE_GCODE), "BAUD_RATE_GCODE is not yet supported o
#endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
#error "SERIAL_STATS_MAX_RX_QUEUED is not supported on this platform."
#error "SERIAL_STATS_MAX_RX_QUEUED is not supported on LPC176x."
#elif ENABLED(SERIAL_STATS_DROPPED_RX)
#error "SERIAL_STATS_DROPPED_RX is not supported on this platform."
#error "SERIAL_STATS_DROPPED_RX is not supported on LPX176x."
#endif
+7 -5
View File
@@ -46,6 +46,8 @@ extern "C" {
void SysTick_Callback() { disk_timerproc(); }
TERN_(POSTMORTEM_DEBUGGING, extern void install_min_serial());
void HAL_init() {
// Init LEDs
@@ -119,13 +121,11 @@ void HAL_init() {
#endif
USB_Init(); // USB Initialization
USB_Connect(FALSE); // USB clear connection
USB_Connect(false); // USB clear connection
delay(1000); // Give OS time to notice
USB_Connect(TRUE);
USB_Connect(true);
#if HAS_SD_HOST_DRIVE
MSC_SD_Init(0); // Enable USB SD card access
#endif
TERN_(HAS_SD_HOST_DRIVE, MSC_SD_Init(0)); // Enable USB SD card access
const millis_t usb_timeout = millis() + 2000;
while (!USB_Configuration && PENDING(millis(), usb_timeout)) {
@@ -137,6 +137,8 @@ void HAL_init() {
}
HAL_timer_init();
TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler
}
// HAL idle task
+15 -2
View File
@@ -25,8 +25,21 @@
#include <wiring_private.h>
#ifdef ADAFRUIT_GRAND_CENTRAL_M4
DefaultSerial MSerial(false, Serial);
DefaultSerial1 MSerial1(false, Serial1);
#if ANY_SERIAL_IS(-1)
DefaultSerial MSerial(false, Serial);
#endif
#if ANY_SERIAL_IS(0)
DefaultSerial1 MSerial1(false, Serial1);
#endif
#if ANY_SERIAL_IS(1)
DefaultSerial2 MSerial2(false, Serial2);
#endif
#if ANY_SERIAL_IS(2)
DefaultSerial3 MSerial3(false, Serial3);
#endif
#if ANY_SERIAL_IS(3)
DefaultSerial4 MSerial4(false, Serial4);
#endif
#endif
// ------------------------
+7 -1
View File
@@ -33,9 +33,15 @@
// Serial ports
typedef ForwardSerial0Type< decltype(Serial) > DefaultSerial;
extern DefaultSerial MSerial;
typedef ForwardSerial0Type< decltype(Serial1) > DefaultSerial1;
typedef ForwardSerial0Type< decltype(Serial2) > DefaultSerial2;
typedef ForwardSerial0Type< decltype(Serial3) > DefaultSerial3;
typedef ForwardSerial0Type< decltype(Serial4) > DefaultSerial4;
extern DefaultSerial MSerial;
extern DefaultSerial1 MSerial1;
extern DefaultSerial2 MSerial2;
extern DefaultSerial3 MSerial3;
extern DefaultSerial4 MSerial4;
// MYSERIAL0 required before MarlinSerial includes!
+3 -3
View File
@@ -27,7 +27,7 @@
#include "../../inc/MarlinConfig.h"
#if USING_SERIAL_1
#if ANY_SERIAL_IS(1)
UartT Serial2(false, &sercom4, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX);
void SERCOM4_0_Handler() { Serial2.IrqHandler(); }
void SERCOM4_1_Handler() { Serial2.IrqHandler(); }
@@ -35,7 +35,7 @@
void SERCOM4_3_Handler() { Serial2.IrqHandler(); }
#endif
#if USING_SERIAL_2
#if ANY_SERIAL_IS(2)
UartT Serial3(false, &sercom1, PIN_SERIAL3_RX, PIN_SERIAL3_TX, PAD_SERIAL3_RX, PAD_SERIAL3_TX);
void SERCOM1_0_Handler() { Serial3.IrqHandler(); }
void SERCOM1_1_Handler() { Serial3.IrqHandler(); }
@@ -43,7 +43,7 @@
void SERCOM1_3_Handler() { Serial3.IrqHandler(); }
#endif
#if USING_SERIAL_3
#if ANY_SERIAL_IS(3)
UartT Serial4(false, &sercom5, PIN_SERIAL4_RX, PIN_SERIAL4_TX, PAD_SERIAL4_RX, PAD_SERIAL4_TX);
void SERCOM5_0_Handler() { Serial4.IrqHandler(); }
void SERCOM5_1_Handler() { Serial4.IrqHandler(); }
+21 -10
View File
@@ -42,6 +42,11 @@
#endif
#endif
#if HAS_SD_HOST_DRIVE
#include "msc_sd.h"
#include "usbd_cdc_if.h"
#endif
// ------------------------
// Public Variables
// ------------------------
@@ -52,16 +57,7 @@ uint16_t HAL_adc_result;
// Public functions
// ------------------------
// Needed for DELAY_NS() / DELAY_US() on CORTEX-M7
#if (defined(__arm__) || defined(__thumb__)) && __CORTEX_M == 7
// HAL pre-initialization task
// Force the preinit function to run between the premain() and main() function
// of the STM32 arduino core
__attribute__((constructor (102)))
void HAL_preinit() {
enableCycleCounter();
}
#endif
TERN_(POSTMORTEM_DEBUGGING, extern void install_min_serial());
// HAL initialization task
void HAL_init() {
@@ -88,6 +84,21 @@ void HAL_init() {
#if ENABLED(EMERGENCY_PARSER) && USBD_USE_CDC
USB_Hook_init();
#endif
TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler
#if HAS_SD_HOST_DRIVE
MSC_SD_init(); // Enable USB SD card access
#endif
}
// HAL idle task
void HAL_idletask() {
#if HAS_SHARED_MEDIA
// Stm32duino currently doesn't have a "loop/idle" method
CDC_resume_receive();
CDC_continue_transmit();
#endif
}
void HAL_clear_reset_source() { __HAL_RCC_CLEAR_RESET_FLAGS(); }
+4 -1
View File
@@ -39,7 +39,7 @@
#ifdef USBCON
#include <USBSerial.h>
#include "../../core/serial_hook.h"
#include "../../core/serial_hook.h"
typedef ForwardSerial0Type< decltype(SerialUSB) > DefaultSerial;
extern DefaultSerial MSerial;
#endif
@@ -135,6 +135,8 @@ extern uint16_t HAL_adc_result;
// Enable hooks into setup for HAL
void HAL_init();
#define HAL_IDLETASK 1
void HAL_idletask();
// Clear reset reason
void HAL_clear_reset_source();
@@ -192,6 +194,7 @@ void flashFirmware(const int16_t);
typedef void (*systickCallback_t)(void);
void systick_attach_callback(systickCallback_t cb);
void HAL_SYSTICK_Callback();
extern volatile uint32_t systick_uptime_millis;
#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
+152
View File
@@ -0,0 +1,152 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
* Copyright (c) 2017 Victor Perez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(POSTMORTEM_DEBUGGING)
#include "../shared/HAL_MinSerial.h"
#include "watchdog.h"
/* Instruction Synchronization Barrier */
#define isb() __asm__ __volatile__ ("isb" : : : "memory")
/* Data Synchronization Barrier */
#define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
// Dumb mapping over the registers of a USART device on STM32
struct USARTMin {
volatile uint32_t SR;
volatile uint32_t DR;
volatile uint32_t BRR;
volatile uint32_t CR1;
volatile uint32_t CR2;
};
#if WITHIN(SERIAL_PORT, 1, 6)
// Depending on the CPU, the serial port is different for USART1
static const uintptr_t regsAddr[] = {
TERN(STM32F1xx, 0x40013800, 0x40011000), // USART1
0x40004400, // USART2
0x40004800, // USART3
0x40004C00, // UART4_BASE
0x40005000, // UART5_BASE
0x40011400 // USART6
};
static USARTMin * regs = (USARTMin*)regsAddr[SERIAL_PORT - 1];
#endif
static void TXBegin() {
#if !WITHIN(SERIAL_PORT, 1, 6)
#warning "Using POSTMORTEM_DEBUGGING requires a physical U(S)ART hardware in case of severe error."
#warning "Disabling the severe error reporting feature currently because the used serial port is not a HW port."
#else
// This is common between STM32F1/STM32F2 and STM32F4
const int nvicUART[] = { /* NVIC_USART1 */ 37, /* NVIC_USART2 */ 38, /* NVIC_USART3 */ 39, /* NVIC_UART4 */ 52, /* NVIC_UART5 */ 53, /* NVIC_USART6 */ 71 };
int nvicIndex = nvicUART[SERIAL_PORT - 1];
struct NVICMin {
volatile uint32_t ISER[32];
volatile uint32_t ICER[32];
};
NVICMin * nvicBase = (NVICMin*)0xE000E100;
nvicBase->ICER[nvicIndex / 32] |= _BV32(nvicIndex % 32);
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
dsb();
isb();
// Example for USART1 disable: (RCC->APB2ENR &= ~(RCC_APB2ENR_USART1EN))
// Too difficult to reimplement here, let's query the STM32duino macro here
#if SERIAL_PORT == 1
__HAL_RCC_USART1_CLK_DISABLE();
__HAL_RCC_USART1_CLK_ENABLE();
#elif SERIAL_PORT == 2
__HAL_RCC_USART2_CLK_DISABLE();
__HAL_RCC_USART2_CLK_ENABLE();
#elif SERIAL_PORT == 3
__HAL_RCC_USART3_CLK_DISABLE();
__HAL_RCC_USART3_CLK_ENABLE();
#elif SERIAL_PORT == 4
__HAL_RCC_UART4_CLK_DISABLE(); // BEWARE: UART4 and not USART4 here
__HAL_RCC_UART4_CLK_ENABLE();
#elif SERIAL_PORT == 5
__HAL_RCC_UART5_CLK_DISABLE(); // BEWARE: UART5 and not USART5 here
__HAL_RCC_UART5_CLK_ENABLE();
#elif SERIAL_PORT == 6
__HAL_RCC_USART6_CLK_DISABLE();
__HAL_RCC_USART6_CLK_ENABLE();
#endif
uint32_t brr = regs->BRR;
regs->CR1 = 0; // Reset the USART
regs->CR2 = 0; // 1 stop bit
// If we don't touch the BRR (baudrate register), we don't need to recompute.
regs->BRR = brr;
regs->CR1 = _BV(3) | _BV(13); // 8 bits, no parity, 1 stop bit (TE | UE)
#endif
}
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() __asm__ volatile("": : :"memory");
static void TX(char c) {
#if WITHIN(SERIAL_PORT, 1, 6)
constexpr uint32_t usart_sr_txe = _BV(7);
while (!(regs->SR & usart_sr_txe)) {
TERN_(USE_WATCHDOG, HAL_watchdog_refresh());
sw_barrier();
}
regs->DR = c;
#else
// Let's hope a mystical guru will fix this, one day by writting interrupt-free USB CDC ACM code (or, at least, by polling the registers since interrupt will be queued but will never trigger)
// For now, it's completely lost to oblivion.
#endif
}
void install_min_serial() {
HAL_min_serial_init = &TXBegin;
HAL_min_serial_out = &TX;
}
#if DISABLED(DYNAMIC_VECTORTABLE) && DISABLED(STM32F0xx) // Cortex M0 can't jump to a symbol that's too far from the current function, so we work around this in exception_arm.cpp
extern "C" {
__attribute__((naked)) void JumpHandler_ASM() {
__asm__ __volatile__ (
"b CommonHandler_ASM\n"
);
}
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) HardFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) BusFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) UsageFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) MemManage_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) NMI_Handler();
}
#endif
#endif // POSTMORTEM_DEBUGGING
#endif // ARDUINO_ARCH_STM32
+20 -10
View File
@@ -51,18 +51,28 @@ static SPISettings spiConfig;
OUT_WRITE(SD_MOSI_PIN, HIGH);
}
static uint16_t delay_STM32_soft_spi;
// Use function with compile-time value so we can actually reach the desired frequency
// Need to adjust this a little bit: on a 72MHz clock, we have 14ns/clock
// and we'll use ~3 cycles to jump to the method and going back, so it'll take ~40ns from the given clock here
#define CALLING_COST_NS (3U * 1000000000U) / (F_CPU)
void (*delaySPIFunc)();
void delaySPI_125() { DELAY_NS(125 - CALLING_COST_NS); }
void delaySPI_250() { DELAY_NS(250 - CALLING_COST_NS); }
void delaySPI_500() { DELAY_NS(500 - CALLING_COST_NS); }
void delaySPI_1000() { DELAY_NS(1000 - CALLING_COST_NS); }
void delaySPI_2000() { DELAY_NS(2000 - CALLING_COST_NS); }
void delaySPI_4000() { DELAY_NS(4000 - CALLING_COST_NS); }
void spiInit(uint8_t spiRate) {
// Use datarates Marlin uses
switch (spiRate) {
case SPI_FULL_SPEED: delay_STM32_soft_spi = 125; break; // desired: 8,000,000 actual: ~1.1M
case SPI_HALF_SPEED: delay_STM32_soft_spi = 125; break; // desired: 4,000,000 actual: ~1.1M
case SPI_QUARTER_SPEED:delay_STM32_soft_spi = 250; break; // desired: 2,000,000 actual: ~890K
case SPI_EIGHTH_SPEED: delay_STM32_soft_spi = 500; break; // desired: 1,000,000 actual: ~590K
case SPI_SPEED_5: delay_STM32_soft_spi = 1000; break; // desired: 500,000 actual: ~360K
case SPI_SPEED_6: delay_STM32_soft_spi = 2000; break; // desired: 250,000 actual: ~210K
default: delay_STM32_soft_spi = 4000; break; // desired: 125,000 actual: ~123K
case SPI_FULL_SPEED: delaySPIFunc = &delaySPI_125; break; // desired: 8,000,000 actual: ~1.1M
case SPI_HALF_SPEED: delaySPIFunc = &delaySPI_125; break; // desired: 4,000,000 actual: ~1.1M
case SPI_QUARTER_SPEED:delaySPIFunc = &delaySPI_250; break; // desired: 2,000,000 actual: ~890K
case SPI_EIGHTH_SPEED: delaySPIFunc = &delaySPI_500; break; // desired: 1,000,000 actual: ~590K
case SPI_SPEED_5: delaySPIFunc = &delaySPI_1000; break; // desired: 500,000 actual: ~360K
case SPI_SPEED_6: delaySPIFunc = &delaySPI_2000; break; // desired: 250,000 actual: ~210K
default: delaySPIFunc = &delaySPI_4000; break; // desired: 125,000 actual: ~123K
}
SPI.begin();
}
@@ -75,9 +85,9 @@ static SPISettings spiConfig;
WRITE(SD_SCK_PIN, LOW);
WRITE(SD_MOSI_PIN, b & 0x80);
DELAY_NS(delay_STM32_soft_spi);
delaySPIFunc();
WRITE(SD_SCK_PIN, HIGH);
DELAY_NS(delay_STM32_soft_spi);
delaySPIFunc();
b <<= 1; // little setup time
b |= (READ(SD_MISO_PIN) != 0);
+1 -1
View File
@@ -81,7 +81,7 @@ void MarlinSerial::_rx_complete_irq(serial_t *obj) {
}
#if ENABLED(EMERGENCY_PARSER)
emergency_parser.update(emergency_state, c);
emergency_parser.update(static_cast<MSerialT*>(this)->emergency_state, c);
#endif
}
}
@@ -163,7 +163,6 @@
GPIO_InitStruct.Pin = GPIO_PIN_2;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
#if DISABLED(STM32F1xx)
// TODO: use __HAL_RCC_SDIO_RELEASE_RESET() and __HAL_RCC_SDIO_CLK_ENABLE();
RCC->APB2RSTR &= ~RCC_APB2RSTR_SDIORST_Msk; // take SDIO out of reset
+1 -1
View File
@@ -21,6 +21,6 @@
*/
#pragma once
#if defined(USBD_USE_CDC_COMPOSITE) && DISABLED(NO_SD_HOST_DRIVE)
#if defined(USBD_USE_CDC_MSC) && DISABLED(NO_SD_HOST_DRIVE)
#define HAS_SD_HOST_DRIVE 1
#endif
+2 -2
View File
@@ -47,9 +47,9 @@
#endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
#error "SERIAL_STATS_MAX_RX_QUEUED is not supported on this platform."
#error "SERIAL_STATS_MAX_RX_QUEUED is not supported on STM32."
#elif ENABLED(SERIAL_STATS_DROPPED_RX)
#error "SERIAL_STATS_DROPPED_RX is not supported on this platform."
#error "SERIAL_STATS_DROPPED_RX is not supported on STM32."
#endif
#if ANY(TFT_COLOR_UI, TFT_LVGL_UI, TFT_CLASSIC_UI) && NOT_TARGET(STM32F4xx, STM32F1xx)
+112
View File
@@ -0,0 +1,112 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech]
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "../../inc/MarlinConfigPre.h"
#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC) && HAS_SD_HOST_DRIVE
#include "msc_sd.h"
#include "../shared/Marduino.h"
#include "usbd_core.h"
#include <USB.h>
#include <USBMscHandler.h>
#define BLOCK_SIZE 512
#define PRODUCT_ID 0x29
#include "../../sd/cardreader.h"
class Sd2CardUSBMscHandler : public USBMscHandler {
public:
bool GetCapacity(uint32_t *pBlockNum, uint16_t *pBlockSize) {
*pBlockNum = card.getSd2Card().cardSize();
*pBlockSize = BLOCK_SIZE;
return true;
}
bool Write(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) {
auto sd2card = card.getSd2Card();
// single block
if (blkLen == 1) {
watchdog_refresh();
sd2card.writeBlock(blkAddr, pBuf);
return true;
}
// multi block optmization
sd2card.writeStart(blkAddr, blkLen);
while (blkLen--) {
watchdog_refresh();
sd2card.writeData(pBuf);
pBuf += BLOCK_SIZE;
}
sd2card.writeStop();
return true;
}
bool Read(uint8_t *pBuf, uint32_t blkAddr, uint16_t blkLen) {
auto sd2card = card.getSd2Card();
// single block
if (blkLen == 1) {
watchdog_refresh();
sd2card.readBlock(blkAddr, pBuf);
return true;
}
// multi block optmization
sd2card.readStart(blkAddr);
while (blkLen--) {
watchdog_refresh();
sd2card.readData(pBuf);
pBuf += BLOCK_SIZE;
}
sd2card.readStop();
return true;
}
bool IsReady() {
return card.isMounted();
}
};
Sd2CardUSBMscHandler usbMscHandler;
/* USB Mass storage Standard Inquiry Data */
uint8_t Marlin_STORAGE_Inquirydata[] = { /* 36 */
/* LUN 0 */
0x00,
0x80,
0x02,
0x02,
(STANDARD_INQUIRY_DATA_LEN - 5),
0x00,
0x00,
0x00,
'M', 'A', 'R', 'L', 'I', 'N', ' ', ' ', /* Manufacturer : 8 bytes */
'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product : 16 Bytes */
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
'0', '.', '0', '1', /* Version : 4 Bytes */
};
USBMscHandler *pSingleMscHandler = &usbMscHandler;
void MSC_SD_init() {
USBDevice.end();
delay(200);
USBDevice.begin();
USBDevice.registerMscHandlers(1, &pSingleMscHandler, Marlin_STORAGE_Inquirydata);
}
#endif // __STM32F1__ && HAS_SD_HOST_DRIVE
+18
View File
@@ -0,0 +1,18 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2019 BigTreeTech [https://github.com/bigtreetech]
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
void MSC_SD_init();
+31 -1
View File
@@ -84,7 +84,32 @@
#if defined(SERIAL_USB) && !HAS_SD_HOST_DRIVE
USBSerial SerialUSB;
DefaultSerial MSerial(false, SerialUSB);
DefaultSerial MSerial(true, SerialUSB);
#if ENABLED(EMERGENCY_PARSER)
#include "../libmaple/usb/stm32f1/usb_reg_map.h"
#include "libmaple/usb_cdcacm.h"
// The original callback is not called (no way to retrieve address).
// That callback detects a special STM32 reset sequence: this functionality is not essential
// as M997 achieves the same.
void my_rx_callback(unsigned int, void*) {
// max length of 16 is enough to contain all emergency commands
uint8 buf[16];
//rx is usbSerialPart.endpoints[2]
uint16 len = usb_get_ep_rx_count(USB_CDCACM_RX_ENDP);
uint32 total = usb_cdcacm_data_available();
if (len == 0 || total == 0 || !WITHIN(total, len, COUNT(buf)))
return;
// cannot get character by character due to bug in composite_cdcacm_peek_ex
len = usb_cdcacm_peek(buf, total);
for (uint32 i = 0; i < len; i++)
emergency_parser.update(MSerial.emergency_state, buf[i + total - len]);
}
#endif
#endif
uint16_t HAL_adc_result;
@@ -247,6 +272,8 @@ static void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) {
} }
#endif
TERN_(POSTMORTEM_DEBUGGING, extern void install_min_serial());
void HAL_init() {
NVIC_SetPriorityGrouping(0x3);
#if PIN_EXISTS(LED)
@@ -254,12 +281,15 @@ void HAL_init() {
#endif
#if HAS_SD_HOST_DRIVE
MSC_SD_init();
#elif BOTH(SERIAL_USB, EMERGENCY_PARSER)
usb_cdcacm_set_hooks(USB_CDCACM_HOOK_RX, my_rx_callback);
#endif
#if PIN_EXISTS(USB_CONNECT)
OUT_WRITE(USB_CONNECT_PIN, !USB_CONNECT_INVERTING); // USB clear connection
delay(1000); // Give OS time to notice
OUT_WRITE(USB_CONNECT_PIN, USB_CONNECT_INVERTING);
#endif
TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the minimal serial handler
}
// HAL idle task
+118
View File
@@ -0,0 +1,118 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
* Copyright (c) 2017 Victor Perez
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef __STM32F1__
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(POSTMORTEM_DEBUGGING)
#include "../shared/HAL_MinSerial.h"
#include "watchdog.h"
#include <libmaple/usart.h>
#include <libmaple/rcc.h>
#include <libmaple/nvic.h>
/* Instruction Synchronization Barrier */
#define isb() __asm__ __volatile__ ("isb" : : : "memory")
/* Data Synchronization Barrier */
#define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
static void TXBegin() {
#if !WITHIN(SERIAL_PORT, 1, 6)
#warning "Using POSTMORTEM_DEBUGGING requires a physical U(S)ART hardware in case of severe error."
#warning "Disabling the severe error reporting feature currently because the used serial port is not a HW port."
#else
// We use MYSERIAL0 here, so we need to figure out how to get the linked register
struct usart_dev* dev = MYSERIAL0.c_dev();
// Or use this if removing libmaple
// int irq = dev->irq_num;
// int nvicUART[] = { NVIC_USART1 /* = 37 */, NVIC_USART2 /* = 38 */, NVIC_USART3 /* = 39 */, NVIC_UART4 /* = 52 */, NVIC_UART5 /* = 53 */ };
// Disabling irq means setting the bit in the NVIC ICER register located at
// Disable UART interrupt in NVIC
nvic_irq_disable(dev->irq_num);
// Use this if removing libmaple
//NVIC_BASE->ICER[1] |= _BV(irq - 32);
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
dsb();
isb();
rcc_clk_disable(dev->clk_id);
rcc_clk_enable(dev->clk_id);
usart_reg_map *regs = dev->regs;
regs->CR1 = 0; // Reset the USART
regs->CR2 = 0; // 1 stop bit
// If we don't touch the BRR (baudrate register), we don't need to recompute. Else we would need to call
usart_set_baud_rate(dev, 0, BAUDRATE);
regs->CR1 = (USART_CR1_TE | USART_CR1_UE); // 8 bits, no parity, 1 stop bit
#endif
}
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() __asm__ volatile("": : :"memory");
static void TX(char c) {
#if WITHIN(SERIAL_PORT, 1, 6)
struct usart_dev* dev = MYSERIAL0.c_dev();
while (!(dev->regs->SR & USART_SR_TXE)) {
TERN_(USE_WATCHDOG, HAL_watchdog_refresh());
sw_barrier();
}
dev->regs->DR = c;
#endif
}
void install_min_serial() {
HAL_min_serial_init = &TXBegin;
HAL_min_serial_out = &TX;
}
#if DISABLED(DYNAMIC_VECTORTABLE) && DISABLED(STM32F0xx) // Cortex M0 can't branch to a symbol that's too far, so we have a specific hack for them
extern "C" {
__attribute__((naked)) void JumpHandler_ASM() {
__asm__ __volatile__ (
"b CommonHandler_ASM\n"
);
}
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __exc_hardfault();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __exc_busfault();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __exc_usagefault();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __exc_memmanage();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __exc_nmi();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __stm32reservedexception7();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __stm32reservedexception8();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __stm32reservedexception9();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __stm32reservedexception10();
void __attribute__((naked, alias("JumpHandler_ASM"), nothrow)) __stm32reservedexception13();
}
#endif
#endif // POSTMORTEM_DEBUGGING
#endif // __STM32F1__
+2 -2
View File
@@ -34,9 +34,9 @@
#endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
#error "SERIAL_STATS_MAX_RX_QUEUED is not supported on this platform."
#error "SERIAL_STATS_MAX_RX_QUEUED is not supported on the STM32F1 platform."
#elif ENABLED(SERIAL_STATS_DROPPED_RX)
#error "SERIAL_STATS_DROPPED_RX is not supported on this platform."
#error "SERIAL_STATS_DROPPED_RX is not supported on the STM32F1 platform."
#endif
#if ENABLED(NEOPIXEL_LED)
+22 -10
View File
@@ -19,6 +19,7 @@
#include "msc_sd.h"
#include "SPI.h"
#include "usb_reg_map.h"
#define PRODUCT_ID 0x29
@@ -41,14 +42,27 @@ Serial0Type<USBCompositeSerial> MarlinCompositeSerial(true);
#endif
#if ENABLED(EMERGENCY_PARSER)
void (*real_rx_callback)(void);
void my_rx_callback(void) {
real_rx_callback();
int len = MarlinCompositeSerial.available();
while (len-- > 0) // >0 because available() may return a negative value
emergency_parser.update(MarlinCompositeSerial.emergency_state, MarlinCompositeSerial.peek());
}
// The original callback is not called (no way to retrieve address).
// That callback detects a special STM32 reset sequence: this functionality is not essential
// as M997 achieves the same.
void my_rx_callback(unsigned int, void*) {
// max length of 16 is enough to contain all emergency commands
uint8 buf[16];
//rx is usbSerialPart.endpoints[2]
uint16 len = usb_get_ep_rx_count(usbSerialPart.endpoints[2].address);
uint32 total = composite_cdcacm_data_available();
if (len == 0 || total == 0 || !WITHIN(total, len, COUNT(buf)))
return;
// cannot get character by character due to bug in composite_cdcacm_peek_ex
len = composite_cdcacm_peek(buf, total);
for (uint32 i = 0; i < len; i++)
emergency_parser.update(MarlinCompositeSerial.emergency_state, buf[i+total-len]);
}
#endif
void MSC_SD_init() {
@@ -73,9 +87,7 @@ void MSC_SD_init() {
MarlinCompositeSerial.registerComponent();
USBComposite.begin();
#if ENABLED(EMERGENCY_PARSER)
//rx is usbSerialPart.endpoints[2]
real_rx_callback = usbSerialPart.endpoints[2].callback;
usbSerialPart.endpoints[2].callback = my_rx_callback;
composite_cdcacm_set_hooks(USBHID_CDCACM_HOOK_RX, my_rx_callback);
#endif
}
+5 -1
View File
@@ -34,5 +34,9 @@
#endif
#if HAS_TMC_SW_SERIAL
#error "TMC220x Software Serial is not supported on this platform."
#error "TMC220x Software Serial is not supported on Teensy 3.1/3.2."
#endif
#if ENABLED(POSTMORTEM_DEBUGGING)
#error "POSTMORTEM_DEBUGGING is not yet supported on Teensy 3.1/3.2."
#endif
+5 -1
View File
@@ -34,5 +34,9 @@
#endif
#if HAS_TMC_SW_SERIAL
#error "TMC220x Software Serial is not supported on this platform."
#error "TMC220x Software Serial is not supported on Teensy 3.5/3.6."
#endif
#if ENABLED(POSTMORTEM_DEBUGGING)
#error "POSTMORTEM_DEBUGGING is not yet supported on Teensy 3.5/3.6."
#endif
+5 -1
View File
@@ -34,5 +34,9 @@
#endif
#if HAS_TMC_SW_SERIAL
#error "TMC220x Software Serial is not supported on this platform."
#error "TMC220x Software Serial is not supported on Teensy 4.0/4.1."
#endif
#if ENABLED(POSTMORTEM_DEBUGGING)
#error "POSTMORTEM_DEBUGGING is not yet supported on Teensy 4.0/4.1."
#endif
+178
View File
@@ -0,0 +1,178 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "Delay.h"
#include "../../inc/MarlinConfig.h"
#if defined(__arm__) || defined(__thumb__)
static uint32_t ASM_CYCLES_PER_ITERATION = 4; // Initial bet which will be adjusted in calibrate_delay_loop
// Simple assembler loop counting down
void delay_asm(uint32_t cy) {
cy = _MAX(cy / ASM_CYCLES_PER_ITERATION, 1U); // Zero is forbidden here
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
L("1")
A("subs %[cnt],#1")
A("bne 1b")
: [cnt]"+r"(cy) // output: +r means input+output
: // input:
: "cc" // clobbers:
);
}
// We can't use CMSIS since it's not available on all platform, so fallback to hardcoded register values
#define HW_REG(X) *(volatile uint32_t *)(X)
#define _DWT_CTRL 0xE0001000
#define _DWT_CYCCNT 0xE0001004 // CYCCNT is 32bits, takes 37s or so to wrap.
#define _DEM_CR 0xE000EDFC
#define _LAR 0xE0001FB0
// Use hardware cycle counter instead, it's much safer
void delay_dwt(uint32_t count) {
// Reuse the ASM_CYCLES_PER_ITERATION variable to avoid wasting another useless variable
register uint32_t start = HW_REG(_DWT_CYCCNT) - ASM_CYCLES_PER_ITERATION, elapsed;
do {
elapsed = HW_REG(_DWT_CYCCNT) - start;
} while (elapsed < count);
}
// Pointer to asm function, calling the functions has a ~20 cycles overhead
DelayImpl DelayCycleFnc = delay_asm;
void calibrate_delay_loop() {
// Check if we have a working DWT implementation in the CPU (see https://developer.arm.com/documentation/ddi0439/b/Data-Watchpoint-and-Trace-Unit/DWT-Programmers-Model)
if (!HW_REG(_DWT_CTRL)) {
// No DWT present, so fallback to plain old ASM nop counting
// Unfortunately, we don't exactly know how many iteration it'll take to decrement a counter in a loop
// It depends on the CPU architecture, the code current position (flash vs SRAM)
// So, instead of wild guessing and making mistake, instead
// compute it once for all
ASM_CYCLES_PER_ITERATION = 1;
// We need to fetch some reference clock before waiting
cli();
uint32_t start = micros();
delay_asm(1000); // On a typical CPU running in MHz, waiting 1000 "unknown cycles" means it'll take between 1ms to 6ms, that's perfectly acceptable
uint32_t end = micros();
sei();
uint32_t expectedCycles = (end - start) * ((F_CPU) / 1000000UL); // Convert microseconds to cycles
// Finally compute the right scale
ASM_CYCLES_PER_ITERATION = (uint32_t)(expectedCycles / 1000);
// No DWT present, likely a Cortex M0 so NOP counting is our best bet here
DelayCycleFnc = delay_asm;
}
else {
// Enable DWT counter
// From https://stackoverflow.com/a/41188674/1469714
HW_REG(_DEM_CR) = HW_REG(_DEM_CR) | 0x01000000; // Enable trace
#if __CORTEX_M == 7
HW_REG(_LAR) = 0xC5ACCE55; // Unlock access to DWT registers, see https://developer.arm.com/documentation/ihi0029/e/ section B2.3.10
#endif
HW_REG(_DWT_CYCCNT) = 0; // Clear DWT cycle counter
HW_REG(_DWT_CTRL) = HW_REG(_DWT_CTRL) | 1; // Enable DWT cycle counter
// Then calibrate the constant offset from the counter
ASM_CYCLES_PER_ITERATION = 0;
uint32_t s = HW_REG(_DWT_CYCCNT);
uint32_t e = HW_REG(_DWT_CYCCNT); // (e - s) contains the number of cycle required to read the cycle counter
delay_dwt(0);
uint32_t f = HW_REG(_DWT_CYCCNT); // (f - e) contains the delay to call the delay function + the time to read the cycle counter
ASM_CYCLES_PER_ITERATION = (f - e) - (e - s);
// Use safer DWT function
DelayCycleFnc = delay_dwt;
}
}
#if ENABLED(MARLIN_DEV_MODE)
void dump_delay_accuracy_check() {
auto report_call_time = [](PGM_P const name, PGM_P const unit, const uint32_t cycles, const uint32_t total, const bool do_flush=true) {
SERIAL_ECHOPGM("Calling ");
serialprintPGM(name);
SERIAL_ECHOLNPAIR(" for ", cycles);
serialprintPGM(unit);
SERIAL_ECHOLNPAIR(" took: ", total);
serialprintPGM(unit);
if (do_flush) SERIAL_FLUSH();
};
uint32_t s, e;
SERIAL_ECHOLNPAIR("Computed delay calibration value: ", ASM_CYCLES_PER_ITERATION);
SERIAL_FLUSH();
// Display the results of the calibration above
constexpr uint32_t testValues[] = { 1, 5, 10, 20, 50, 100, 150, 200, 350, 500, 750, 1000 };
for (auto i : testValues) {
s = micros(); DELAY_US(i); e = micros();
report_call_time(PSTR("delay"), PSTR("us"), i, e - s);
}
if (HW_REG(_DWT_CTRL)) {
for (auto i : testValues) {
s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(i); e = HW_REG(_DWT_CYCCNT);
report_call_time(PSTR("runtime delay"), PSTR("cycles"), i, e - s);
}
// Measure the delay to call a real function compared to a function pointer
s = HW_REG(_DWT_CYCCNT); delay_dwt(1); e = HW_REG(_DWT_CYCCNT);
report_call_time(PSTR("delay_dwt"), PSTR("cycles"), 1, e - s);
static PGMSTR(dcd, "DELAY_CYCLES directly ");
s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES( 1); e = HW_REG(_DWT_CYCCNT);
report_call_time(dcd, PSTR("cycles"), 1, e - s, false);
s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES( 5); e = HW_REG(_DWT_CYCCNT);
report_call_time(dcd, PSTR("cycles"), 5, e - s, false);
s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(10); e = HW_REG(_DWT_CYCCNT);
report_call_time(dcd, PSTR("cycles"), 10, e - s, false);
s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(20); e = HW_REG(_DWT_CYCCNT);
report_call_time(dcd, PSTR("cycles"), 20, e - s, false);
s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(50); e = HW_REG(_DWT_CYCCNT);
report_call_time(dcd, PSTR("cycles"), 50, e - s, false);
s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(100); e = HW_REG(_DWT_CYCCNT);
report_call_time(dcd, PSTR("cycles"), 100, e - s, false);
s = HW_REG(_DWT_CYCCNT); DELAY_CYCLES(200); e = HW_REG(_DWT_CYCCNT);
report_call_time(dcd, PSTR("cycles"), 200, e - s, false);
}
}
#endif // MARLIN_DEV_MODE
#else
void calibrate_delay_loop() {}
#if ENABLED(MARLIN_DEV_MODE)
void dump_delay_accuracy_check() {
static PGMSTR(none, "N/A on this platform");
serialprintPGM(none);
}
#endif
#endif
+64 -68
View File
@@ -21,6 +21,8 @@
*/
#pragma once
#include "../../inc/MarlinConfigPre.h"
/**
* Busy wait delay cycles routines:
*
@@ -31,79 +33,68 @@
#include "../../core/macros.h"
void calibrate_delay_loop();
#if defined(__arm__) || defined(__thumb__)
#if __CORTEX_M == 7
// We want to have delay_cycle function with the lowest possible overhead, so we adjust at the function at runtime based on the current CPU best feature
typedef void (*DelayImpl)(uint32_t);
extern DelayImpl DelayCycleFnc;
// Cortex-M3 through M7 can use the cycle counter of the DWT unit
// https://www.anthonyvh.com/2017/05/18/cortex_m-cycle_counter/
// I've measured 36 cycles on my system to call the cycle waiting method, but it shouldn't change much to have a bit more margin, it only consume a bit more flash
#define TRIP_POINT_FOR_CALLING_FUNCTION 40
FORCE_INLINE static void enableCycleCounter() {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
#if __CORTEX_M == 7
DWT->LAR = 0xC5ACCE55; // Unlock DWT on the M7
#endif
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
// A simple recursive template class that output exactly one 'nop' of code per recursion
template <int N> struct NopWriter {
FORCE_INLINE static void build() {
__asm__ __volatile__("nop");
NopWriter<N-1>::build();
}
};
// End the loop
template <> struct NopWriter<0> { FORCE_INLINE static void build() {} };
FORCE_INLINE volatile uint32_t getCycleCount() { return DWT->CYCCNT; }
FORCE_INLINE static void DELAY_CYCLES(const uint32_t x) {
const uint32_t endCycles = getCycleCount() + x;
while (PENDING(getCycleCount(), endCycles)) {}
}
#else
// https://blueprints.launchpad.net/gcc-arm-embedded/+spec/delay-cycles
#define nop() __asm__ __volatile__("nop;\n\t":::)
FORCE_INLINE static void __delay_4cycles(uint32_t cy) { // +1 cycle
#if ARCH_PIPELINE_RELOAD_CYCLES < 2
#define EXTRA_NOP_CYCLES A("nop")
#else
#define EXTRA_NOP_CYCLES ""
#endif
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
L("1")
A("subs %[cnt],#1")
EXTRA_NOP_CYCLES
A("bne 1b")
: [cnt]"+r"(cy) // output: +r means input+output
: // input:
: "cc" // clobbers:
);
}
// Delay in cycles
FORCE_INLINE static void DELAY_CYCLES(uint32_t x) {
if (__builtin_constant_p(x)) {
#define MAXNOPS 4
if (x <= (MAXNOPS)) {
switch (x) { case 4: nop(); case 3: nop(); case 2: nop(); case 1: nop(); }
}
else { // because of +1 cycle inside delay_4cycles
const uint32_t rem = (x - 1) % (MAXNOPS);
switch (rem) { case 3: nop(); case 2: nop(); case 1: nop(); }
if ((x = (x - 1) / (MAXNOPS)))
__delay_4cycles(x); // if need more then 4 nop loop is more optimal
}
#undef MAXNOPS
namespace Private {
// Split recursing template in 2 different class so we don't reach the maximum template instantiation depth limit
template <bool belowTP, int N> struct Helper {
FORCE_INLINE static void build() {
DelayCycleFnc(N - 2); // Approximative cost of calling the function (might be off by one or 2 cycles)
}
else if ((x >>= 2))
__delay_4cycles(x);
}
#undef nop
};
#endif
template <int N> struct Helper<true, N> {
FORCE_INLINE static void build() {
NopWriter<N - 1>::build();
}
};
template <> struct Helper<true, 0> {
FORCE_INLINE static void build() {}
};
}
// Select a behavior based on the constexpr'ness of the parameter
// If called with a compile-time parameter, then write as many NOP as required to reach the asked cycle count
// (there is some tripping point here to start looping when it's more profitable than gruntly executing NOPs)
// If not called from a compile-time parameter, fallback to a runtime loop counting version instead
template <bool compileTime, int Cycles>
struct SmartDelay {
FORCE_INLINE SmartDelay(int) {
if (Cycles == 0) return;
Private::Helper<Cycles < TRIP_POINT_FOR_CALLING_FUNCTION, Cycles>::build();
}
};
// Runtime version below. There is no way this would run under less than ~TRIP_POINT_FOR_CALLING_FUNCTION cycles
template <int T>
struct SmartDelay<false, T> {
FORCE_INLINE SmartDelay(int v) { DelayCycleFnc(v); }
};
#define DELAY_CYCLES(X) do { SmartDelay<IS_CONSTEXPR(X), IS_CONSTEXPR(X) ? X : 0> _smrtdly_X(X); } while(0)
// For delay in microseconds, no smart delay selection is required, directly call the delay function
// Teensy compiler is too old and does not accept smart delay compile-time / run-time selection correctly
#define DELAY_US(x) DelayCycleFnc((x) * ((F_CPU) / 1000000UL))
#elif defined(__AVR__)
@@ -144,10 +135,15 @@
}
#undef nop
// Delay in microseconds
#define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
#elif defined(__PLAT_LINUX__) || defined(ESP32)
// specified inside platform
// DELAY_CYCLES specified inside platform
// Delay in microseconds
#define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
#else
#error "Unsupported MCU architecture"
@@ -157,5 +153,5 @@
// Delay in nanoseconds
#define DELAY_NS(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL) / 1000UL)
// Delay in microseconds
#define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
+33
View File
@@ -0,0 +1,33 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "HAL_MinSerial.h"
#if ENABLED(POSTMORTEM_DEBUGGING)
void HAL_min_serial_init_default() {}
void HAL_min_serial_out_default(char ch) { SERIAL_CHAR(ch); }
void (*HAL_min_serial_init)() = &HAL_min_serial_init_default;
void (*HAL_min_serial_out)(char) = &HAL_min_serial_out_default;
bool MinSerial::force_using_default_output = false;
#endif
+79
View File
@@ -0,0 +1,79 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../../core/serial.h"
#include <stdint.h>
// Serial stuff here
// Inside an exception handler, the CPU state is not safe, we can't expect the handler to resume
// and the software to continue. UART communication can't rely on later callback/interrupt as it might never happen.
// So, you need to provide some method to send one byte to the usual UART with the interrupts disabled
// By default, the method uses SERIAL_CHAR but it's 100% guaranteed to break (couldn't be worse than nothing...)7
extern void (*HAL_min_serial_init)();
extern void (*HAL_min_serial_out)(char ch);
struct MinSerial {
static bool force_using_default_output;
// Serial output
static void TX(char ch) {
if (force_using_default_output)
SERIAL_CHAR(ch);
else
HAL_min_serial_out(ch);
}
// Send String through UART
static void TX(const char* s) { while (*s) TX(*s++); }
// Send a digit through UART
static void TXDigit(uint32_t d) {
if (d < 10) TX((char)(d+'0'));
else if (d < 16) TX((char)(d+'A'-10));
else TX('?');
}
// Send Hex number through UART
static void TXHex(uint32_t v) {
TX("0x");
for (uint8_t i = 0; i < 8; i++, v <<= 4)
TXDigit((v >> 28) & 0xF);
}
// Send Decimal number through UART
static void TXDec(uint32_t v) {
if (!v) {
TX('0');
return;
}
char nbrs[14];
char *p = &nbrs[0];
while (v != 0) {
*p++ = '0' + (v % 10);
v /= 10;
}
do {
p--;
TX(*p);
} while (p != &nbrs[0]);
}
static void init() { if (!force_using_default_output) HAL_min_serial_init(); }
};
+18 -10
View File
@@ -25,7 +25,7 @@
#include "unwinder.h"
#include "unwmemaccess.h"
#include "../../../core/serial.h"
#include "../HAL_MinSerial.h"
#include <stdarg.h>
// Dump a backtrace entry
@@ -34,10 +34,12 @@ static bool UnwReportOut(void* ctx, const UnwReport* bte) {
(*p)++;
SERIAL_CHAR('#'); SERIAL_PRINT(*p, DEC); SERIAL_ECHOPGM(" : ");
SERIAL_ECHOPGM(bte->name ? bte->name : "unknown"); SERIAL_ECHOPGM("@0x"); SERIAL_PRINT(bte->function, HEX);
SERIAL_CHAR('+'); SERIAL_PRINT(bte->address - bte->function,DEC);
SERIAL_ECHOPGM(" PC:"); SERIAL_PRINT(bte->address,HEX); SERIAL_CHAR('\n');
const uint32_t a = bte->address, f = bte->function;
MinSerial::TX('#'); MinSerial::TXDec(*p); MinSerial::TX(" : ");
MinSerial::TX(bte->name?:"unknown"); MinSerial::TX('@'); MinSerial::TXHex(f);
MinSerial::TX('+'); MinSerial::TXDec(a - f);
MinSerial::TX(" PC:"); MinSerial::TXHex(a);
MinSerial::TX('\n');
return true;
}
@@ -48,7 +50,7 @@ static bool UnwReportOut(void* ctx, const UnwReport* bte) {
va_start(argptr, format);
vsprintf(dest, format, argptr);
va_end(argptr);
TX(&dest[0]);
MinSerial::TX(&dest[0]);
}
#endif
@@ -63,10 +65,10 @@ static const UnwindCallbacks UnwCallbacks = {
#endif
};
// Perform a backtrace to the serial port
void backtrace() {
UnwindFrame btf;
uint32_t sp = 0, lr = 0, pc = 0;
unsigned long sp = 0, lr = 0, pc = 0;
// Capture the values of the registers to perform the traceback
__asm__ __volatile__ (
@@ -79,6 +81,12 @@ void backtrace() {
::
);
backtrace_ex(sp, lr, pc);
}
void backtrace_ex(unsigned long sp, unsigned long lr, unsigned long pc) {
UnwindFrame btf;
// Fill the traceback structure
btf.sp = sp;
btf.fp = btf.sp;
@@ -86,7 +94,7 @@ void backtrace() {
btf.pc = pc | 1; // Force Thumb, as CORTEX only support it
// Perform a backtrace
SERIAL_ERROR_MSG("Backtrace:");
MinSerial::TX("Backtrace:");
int ctr = 0;
UnwindStart(&btf, &UnwCallbacks, &ctr);
}
@@ -95,4 +103,4 @@ void backtrace() {
void backtrace() {}
#endif
#endif // __arm__ || __thumb__
@@ -23,3 +23,6 @@
// Perform a backtrace to the serial port
void backtrace();
// Perform a backtrace to the serial port
void backtrace_ex(unsigned long sp, unsigned long lr, unsigned long pc);
@@ -41,27 +41,16 @@
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00080000
#elif 0
// For STM32F103CBT6
// SRAM (0x20000000 - 0x20005000) (20kb)
// FLASH (0x00000000 - 0x00020000) (128kb)
//
#define START_SRAM_ADDR 0x20000000
#define END_SRAM_ADDR 0x20005000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00020000
#elif defined(__STM32F1__) || defined(STM32F1xx) || defined(STM32F0xx)
// For STM32F103ZET6/STM32F103VET6/STM32F0xx
// SRAM (0x20000000 - 0x20010000) (64kb)
// FLASH (0x00000000 - 0x00080000) (512kb)
// FLASH (0x08000000 - 0x08080000) (512kb)
//
#define START_SRAM_ADDR 0x20000000
#define END_SRAM_ADDR 0x20010000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00080000
#define START_FLASH_ADDR 0x08000000
#define END_FLASH_ADDR 0x08080000
#elif defined(STM32F4) || defined(STM32F4xx)
@@ -142,20 +131,57 @@
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00100000
#else
// Generic ARM code, that's testing if an access to the given address would cause a fault or not
// It can't guarantee an address is in RAM or Flash only, but we usually don't care
#define NVIC_FAULT_STAT 0xE000ED28 // Configurable Fault Status Reg.
#define NVIC_CFG_CTRL 0xE000ED14 // Configuration Control Register
#define NVIC_FAULT_STAT_BFARV 0x00008000 // BFAR is valid
#define NVIC_CFG_CTRL_BFHFNMIGN 0x00000100 // Ignore bus fault in NMI/fault
#define HW_REG(X) (*((volatile unsigned long *)(X)))
static bool validate_addr(uint32_t read_address) {
bool works = true;
uint32_t intDisabled = 0;
// Read current interrupt state
__asm__ __volatile__ ("MRS %[result], PRIMASK\n\t" : [result]"=r"(intDisabled) :: ); // 0 is int enabled, 1 for disabled
// Clear bus fault indicator first (write 1 to clear)
HW_REG(NVIC_FAULT_STAT) |= NVIC_FAULT_STAT_BFARV;
// Ignore bus fault interrupt
HW_REG(NVIC_CFG_CTRL) |= NVIC_CFG_CTRL_BFHFNMIGN;
// Disable interrupts if not disabled previously
if (!intDisabled) __asm__ __volatile__ ("CPSID f");
// Probe address
*(volatile uint32_t*)read_address;
// Check if a fault happened
if ((HW_REG(NVIC_FAULT_STAT) & NVIC_FAULT_STAT_BFARV) != 0)
works = false;
// Enable interrupts again if previously disabled
if (!intDisabled) __asm__ __volatile__ ("CPSIE f");
// Enable fault interrupt flag
HW_REG(NVIC_CFG_CTRL) &= ~NVIC_CFG_CTRL_BFHFNMIGN;
return works;
}
#endif
static bool validate_addr(uint32_t addr) {
#ifdef START_SRAM_ADDR
static bool validate_addr(uint32_t addr) {
// Address must be in SRAM range
if (addr >= START_SRAM_ADDR && addr < END_SRAM_ADDR)
return true;
// Address must be in SRAM range
if (addr >= START_SRAM_ADDR && addr < END_SRAM_ADDR)
return true;
// Or in FLASH range
if (addr >= START_FLASH_ADDR && addr < END_FLASH_ADDR)
return true;
// Or in FLASH range
if (addr >= START_FLASH_ADDR && addr < END_FLASH_ADDR)
return true;
return false;
}
return false;
}
#endif
bool UnwReadW(const uint32_t a, uint32_t *v) {
if (!validate_addr(a))
@@ -0,0 +1,379 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
* Copyright (c) 2020 Cyril Russo
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/***************************************************************************
* ARM CPU Exception handler
***************************************************************************/
#if defined(__arm__) || defined(__thumb__)
/*
On ARM CPUs exception handling is quite powerful.
By default, upon a crash, the CPU enters the handlers that have a higher priority than any other interrupts,
so, in effect, no (real) interrupt can "interrupt" the handler (it's acting like if interrupts were disabled).
If the handler is not called as re-entrant (that is, if the crash is not happening inside an interrupt or an handler),
then it'll patch the return address to a dumping function (resume_from_fault) and save the crash state.
The CPU will exit the handler and, as such, re-allow the other interrupts, and jump to the dumping function.
In this function, the usual serial port (USB / HW) will be used to dump the crash (no special configuration required).
The only case where it requires hardware UART is when it's crashing in an interrupt or a crash handler.
In that case, instead of returning to the resume_from_fault function (and thus, re-enabling interrupts),
it jumps to this function directly (so with interrupts disabled), after changing the behavior of the serial output
wrapper to use the HW uart (and in effect, calling MinSerial::init which triggers a warning if you are using
a USB serial port).
In the case you have a USB serial port, this part will be disabled, and only that part (so that's the reason for
the warning).
This means that you can't have a crash report if the crash happens in an interrupt or an handler if you are using
a USB serial port since it's physically impossible.
You will get a crash report in all other cases.
*/
#include "exception_hook.h"
#include "../backtrace/backtrace.h"
#include "../HAL_MinSerial.h"
#define HW_REG(X) (*((volatile unsigned long *)(X)))
// Default function use the CPU VTOR register to get the vector table.
// Accessing the CPU VTOR register is done in assembly since it's the only way that's common to all current tool
unsigned long get_vtor() { return HW_REG(0xE000ED08); } // Even if it looks like an error, it is not an error
void * hook_get_hardfault_vector_address(unsigned vtor) { return (void*)(vtor + 0x03); }
void * hook_get_memfault_vector_address(unsigned vtor) { return (void*)(vtor + 0x04); }
void * hook_get_busfault_vector_address(unsigned vtor) { return (void*)(vtor + 0x05); }
void * hook_get_usagefault_vector_address(unsigned vtor) { return (void*)(vtor + 0x06); }
void * hook_get_reserved_vector_address(unsigned vtor) { return (void*)(vtor + 0x07); }
// Common exception frame for ARM, should work for all ARM CPU
// Described here (modified for convenience): https://interrupt.memfault.com/blog/cortex-m-fault-debug
struct __attribute__((packed)) ContextStateFrame {
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t lr;
uint32_t pc;
uint32_t xpsr;
};
struct __attribute__((packed)) ContextSavedFrame {
uint32_t R0;
uint32_t R1;
uint32_t R2;
uint32_t R3;
uint32_t R12;
uint32_t LR;
uint32_t PC;
uint32_t XPSR;
uint32_t CFSR;
uint32_t HFSR;
uint32_t DFSR;
uint32_t AFSR;
uint32_t MMAR;
uint32_t BFAR;
uint32_t ESP;
uint32_t ELR;
};
#if DISABLED(STM32F0xx)
extern "C"
__attribute__((naked)) void CommonHandler_ASM() {
__asm__ __volatile__ (
// Bit 2 of LR tells which stack pointer to use (either main or process, only main should be used anyway)
"tst lr, #4\n"
"ite eq\n"
"mrseq r0, msp\n"
"mrsne r0, psp\n"
// Save the LR in use when being interrupted
"mov r1, lr\n"
// Get the exception number from the ICSR register
"ldr r2, =0xE000ED00\n"
"ldr r2, [r2, #4]\n"
"b CommonHandler_C\n"
);
}
#else // Cortex M0 does not support conditional mov and testing with a constant, so let's have a specific handler for it
extern "C"
__attribute__((naked)) void CommonHandler_ASM() {
__asm__ __volatile__ (
".syntax unified\n"
// Save the LR in use when being interrupted
"mov r1, lr\n"
// Get the exception number from the ICSR register
"ldr r2, =0xE000ED00\n"
"ldr r2, [r2, #4]\n"
"movs r0, #4\n"
"tst r1, r0\n"
"beq _MSP\n"
"mrs r0, psp\n"
"b CommonHandler_C\n"
"_MSP:\n"
"mrs r0, msp\n"
"b CommonHandler_C\n"
);
}
#if DISABLED(DYNAMIC_VECTORTABLE) // Cortex M0 requires the handler's address to be within 32kB to the actual function to be able to branch to it
extern "C" {
void __attribute__((naked, alias("CommonHandler_ASM"), nothrow)) __exc_hardfault();
void __attribute__((naked, alias("CommonHandler_ASM"), nothrow)) __exc_busfault();
void __attribute__((naked, alias("CommonHandler_ASM"), nothrow)) __exc_usagefault();
void __attribute__((naked, alias("CommonHandler_ASM"), nothrow)) __exc_memmanage();
void __attribute__((naked, alias("CommonHandler_ASM"), nothrow)) __exc_nmi();
void __attribute__((naked, alias("CommonHandler_ASM"), nothrow)) __stm32reservedexception7();
void __attribute__((naked, alias("CommonHandler_ASM"), nothrow)) __stm32reservedexception8();
void __attribute__((naked, alias("CommonHandler_ASM"), nothrow)) __stm32reservedexception9();
void __attribute__((naked, alias("CommonHandler_ASM"), nothrow)) __stm32reservedexception10();
void __attribute__((naked, alias("CommonHandler_ASM"), nothrow)) __stm32reservedexception13();
}
//TODO When going off from libmaple, you'll need to replace those by the one from STM32/HAL_MinSerial.cpp
#endif
#endif
// Must be a macro to avoid creating a function frame
#define HALT_IF_DEBUGGING() \
do { \
if (HW_REG(0xE000EDF0) & _BV(0)) { \
__asm("bkpt 1"); \
} \
} while (0)
// Resume from a fault (if possible) so we can still use interrupt based code for serial output
// In that case, we will not jump back to the faulty code, but instead to a dumping code and then a
// basic loop with watchdog calling or manual resetting
static ContextSavedFrame savedFrame;
static uint8_t lastCause;
bool resume_from_fault() {
static const char* causestr[] = { "Thread", "Rsvd", "NMI", "Hard", "Mem", "Bus", "Usage", "7", "8", "9", "10", "SVC", "Dbg", "13", "PendSV", "SysTk", "IRQ" };
// Reinit the serial link (might only work if implemented in each of your boards)
MinSerial::init();
MinSerial::TX("\n\n## Software Fault detected ##\n");
MinSerial::TX("Cause: "); MinSerial::TX(causestr[min(lastCause, (uint8_t)16)]); MinSerial::TX('\n');
MinSerial::TX("R0 : "); MinSerial::TXHex(savedFrame.R0); MinSerial::TX('\n');
MinSerial::TX("R1 : "); MinSerial::TXHex(savedFrame.R1); MinSerial::TX('\n');
MinSerial::TX("R2 : "); MinSerial::TXHex(savedFrame.R2); MinSerial::TX('\n');
MinSerial::TX("R3 : "); MinSerial::TXHex(savedFrame.R3); MinSerial::TX('\n');
MinSerial::TX("R12 : "); MinSerial::TXHex(savedFrame.R12); MinSerial::TX('\n');
MinSerial::TX("LR : "); MinSerial::TXHex(savedFrame.LR); MinSerial::TX('\n');
MinSerial::TX("PC : "); MinSerial::TXHex(savedFrame.PC); MinSerial::TX('\n');
MinSerial::TX("PSR : "); MinSerial::TXHex(savedFrame.XPSR); MinSerial::TX('\n');
// Configurable Fault Status Register
// Consists of MMSR, BFSR and UFSR
MinSerial::TX("CFSR : "); MinSerial::TXHex(savedFrame.CFSR); MinSerial::TX('\n');
// Hard Fault Status Register
MinSerial::TX("HFSR : "); MinSerial::TXHex(savedFrame.HFSR); MinSerial::TX('\n');
// Debug Fault Status Register
MinSerial::TX("DFSR : "); MinSerial::TXHex(savedFrame.DFSR); MinSerial::TX('\n');
// Auxiliary Fault Status Register
MinSerial::TX("AFSR : "); MinSerial::TXHex(savedFrame.AFSR); MinSerial::TX('\n');
// Read the Fault Address Registers. These may not contain valid values.
// Check BFARVALID/MMARVALID to see if they are valid values
// MemManage Fault Address Register
MinSerial::TX("MMAR : "); MinSerial::TXHex(savedFrame.MMAR); MinSerial::TX('\n');
// Bus Fault Address Register
MinSerial::TX("BFAR : "); MinSerial::TXHex(savedFrame.BFAR); MinSerial::TX('\n');
MinSerial::TX("ExcLR: "); MinSerial::TXHex(savedFrame.ELR); MinSerial::TX('\n');
MinSerial::TX("ExcSP: "); MinSerial::TXHex(savedFrame.ESP); MinSerial::TX('\n');
// The stack pointer is pushed by 8 words upon entering an exception, so we need to revert this
backtrace_ex(savedFrame.ESP + 8*4, savedFrame.LR, savedFrame.PC);
// Call the last resort function here
hook_last_resort_func();
const uint32_t start = millis(), end = start + 100; // 100ms should be enough
// We need to wait for the serial buffers to be output but we don't know for how long
// So we'll just need to refresh the watchdog for a while and then stop for the system to reboot
uint32_t last = start;
while (PENDING(last, end)) {
watchdog_refresh();
while (millis() == last) { /* nada */ }
last = millis();
MinSerial::TX('.');
}
// Reset now by reinstantiating the bootloader's vector table
HW_REG(0xE000ED08) = 0;
// Restart watchdog
#if DISABLED(USE_WATCHDOG)
// No watchdog, let's perform ARMv7 reset instead by writing to AIRCR register with VECTKEY set to SYSRESETREQ
HW_REG(0xE000ED0C) = (HW_REG(0xE000ED0C) & 0x0000FFFF) | 0x05FA0004;
#endif
while(1) {} // Bad luck, nothing worked
}
// Make sure the compiler does not optimize the frame argument away
extern "C"
__attribute__((optimize("O0")))
void CommonHandler_C(ContextStateFrame * frame, unsigned long lr, unsigned long cause) {
// If you are using it'll stop here
HALT_IF_DEBUGGING();
// Save the state to backtrace later on (don't call memcpy here since the stack can be corrupted)
savedFrame.R0 = frame->r0;
savedFrame.R1 = frame->r1;
savedFrame.R2 = frame->r2;
savedFrame.R3 = frame->r3;
savedFrame.R12 = frame->r12;
savedFrame.LR = frame->lr;
savedFrame.PC = frame->pc;
savedFrame.XPSR= frame->xpsr;
lastCause = cause & 0x1FF;
volatile uint32_t &CFSR = HW_REG(0xE000ED28);
savedFrame.CFSR = CFSR;
savedFrame.HFSR = HW_REG(0xE000ED2C);
savedFrame.DFSR = HW_REG(0xE000ED30);
savedFrame.AFSR = HW_REG(0xE000ED3C);
savedFrame.MMAR = HW_REG(0xE000ED34);
savedFrame.BFAR = HW_REG(0xE000ED38);
savedFrame.ESP = (unsigned long)frame; // Even on return, this should not be overwritten by the CPU
savedFrame.ELR = lr;
// First check if we can resume from this exception to our own handler safely
// If we can, then we don't need to disable interrupts and the usual serial code
// can be used
//const uint32_t non_usage_fault_mask = 0x0000FFFF;
//const bool non_usage_fault_occurred = (CFSR & non_usage_fault_mask) != 0;
// the bottom 8 bits of the xpsr hold the exception number of the
// executing exception or 0 if the processor is in Thread mode
const bool faulted_from_exception = ((frame->xpsr & 0xFF) != 0);
if (!faulted_from_exception) { // Not sure about the non_usage_fault, we want to try anyway, don't we ? && !non_usage_fault_occurred)
// Try to resume to our handler here
CFSR |= CFSR; // The ARM programmer manual says you must write to 1 all fault bits to clear them so this instruction is correct
// The frame will not be valid when returning anymore, let's clean it
savedFrame.CFSR = 0;
frame->pc = (uint32_t)resume_from_fault; // Patch where to return to
frame->lr = 0xdeadbeef; // If our handler returns (it shouldn't), let's make it trigger an exception immediately
frame->xpsr = _BV(24); // Need to clean the PSR register to thumb II only
MinSerial::force_using_default_output = true;
return; // The CPU will resume in our handler hopefully, and we'll try to use default serial output
}
// Sorry, we need to emergency code here since the fault is too dangerous to recover from
MinSerial::force_using_default_output = false;
resume_from_fault();
}
void hook_cpu_exceptions() {
#if ENABLED(DYNAMIC_VECTORTABLE)
// On ARM 32bits CPU, the vector table is like this:
// 0x0C => Hardfault
// 0x10 => MemFault
// 0x14 => BusFault
// 0x18 => UsageFault
// Unfortunately, it's usually run from flash, and we can't write to flash here directly to hook our instruction
// We could set an hardware breakpoint, and hook on the fly when it's being called, but this
// is hard to get right and would probably break debugger when attached
// So instead, we'll allocate a new vector table filled with the previous value except
// for the fault we are interested in.
// Now, comes the issue to figure out what is the current vector table size
// There is nothing telling us what is the vector table as it's per-cpu vendor specific.
// BUT: we are being called at the end of the setup, so we assume the setup is done
// Thus, we can read the current vector table until we find an address that's not in flash, and it would mark the
// end of the vector table (skipping the fist entry obviously)
// The position of the program in flash is expected to be at 0x08xxx xxxx on all known platform for ARM and the
// flash size is available via register 0x1FFFF7E0 on STM32 family, but it's not the case for all ARM boards
// (accessing this register might trigger a fault if it's not implemented).
// So we'll simply mask the top 8 bits of the first handler as an hint of being in the flash or not -that's poor and will
// probably break if the flash happens to be more than 128MB, but in this case, we are not magician, we need help from outside.
unsigned long * vecAddr = (unsigned long*)get_vtor();
SERIAL_ECHO("Vector table addr: ");
SERIAL_PRINTLN(get_vtor(), HEX);
#ifdef VECTOR_TABLE_SIZE
uint32_t vec_size = VECTOR_TABLE_SIZE;
alignas(128) static unsigned long vectable[VECTOR_TABLE_SIZE] ;
#else
#ifndef IS_IN_FLASH
#define IS_IN_FLASH(X) (((unsigned long)X & 0xFF000000) == 0x08000000)
#endif
// When searching for the end of the vector table, this acts as a limit not to overcome
#ifndef VECTOR_TABLE_SENTINEL
#define VECTOR_TABLE_SENTINEL 80
#endif
// Find the vector table size
uint32_t vec_size = 1;
while (IS_IN_FLASH(vecAddr[vec_size]) && vec_size < VECTOR_TABLE_SENTINEL)
vec_size++;
// We failed to find a valid vector table size, let's abort hooking up
if (vec_size == VECTOR_TABLE_SENTINEL) return;
// Poor method that's wasting RAM here, but allocating with malloc and alignment would be worst
// 128 bytes alignement is required for writing the VTOR register
alignas(128) static unsigned long vectable[VECTOR_TABLE_SENTINEL];
SERIAL_ECHO("Detected vector table size: ");
SERIAL_PRINTLN(vec_size, HEX);
#endif
uint32_t defaultFaultHandler = vecAddr[(unsigned)7];
// Copy the current vector table into the new table
for (uint32_t i = 0; i < vec_size; i++) {
vectable[i] = vecAddr[i];
// Replace all default handler by our own handler
if (vectable[i] == defaultFaultHandler)
vectable[i] = (unsigned long)&CommonHandler_ASM;
}
// Let's hook now with our functions
vectable[(unsigned long)hook_get_hardfault_vector_address(0)] = (unsigned long)&CommonHandler_ASM;
vectable[(unsigned long)hook_get_memfault_vector_address(0)] = (unsigned long)&CommonHandler_ASM;
vectable[(unsigned long)hook_get_busfault_vector_address(0)] = (unsigned long)&CommonHandler_ASM;
vectable[(unsigned long)hook_get_usagefault_vector_address(0)] = (unsigned long)&CommonHandler_ASM;
// Finally swap with our own vector table
// This is supposed to be atomic, but let's do that with interrupt disabled
HW_REG(0xE000ED08) = (unsigned long)vectable | _BV32(29); // 29th bit is for telling the CPU the table is now in SRAM (should be present already)
SERIAL_ECHOLN("Installed fault handlers");
#endif
}
#endif // __arm__ || __thumb__
@@ -0,0 +1,28 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "exception_hook.h"
void * __attribute__((weak)) hook_get_hardfault_vector_address(unsigned) { return 0; }
void * __attribute__((weak)) hook_get_memfault_vector_address(unsigned) { return 0; }
void * __attribute__((weak)) hook_get_busfault_vector_address(unsigned) { return 0; }
void * __attribute__((weak)) hook_get_usagefault_vector_address(unsigned) { return 0; }
void __attribute__((weak)) hook_last_resort_func() {}
@@ -0,0 +1,54 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/* Here is the expected behavior of a system producing a CPU exception with this hook installed:
1. Before the system is crashed
1.1 Upon validation (not done yet in this code, but we could be using DEBUG flags here to allow/disallow hooking)
1.2 Install the hook by overwriting the vector table exception handler with the hooked function
2. Upon system crash (for example, by a dereference of a NULL pointer or anything else)
2.1 The CPU triggers its exception and jump into the vector table for the exception type
2.2 Instead of finding the default handler, it finds the updated pointer to our hook
2.3 The CPU jumps into our hook function (likely a naked function to keep all information about crash point intact)
2.4 The hook (naked) function saves the important registers (stack pointer, program counter, current mode) and jumps to a common exception handler (in C)
2.5 The common exception handler dumps the registers on the serial link and perform a backtrace around the crashing point
2.6 Once the backtrace is performed the last resort function is called (platform specific).
On some platform with a LCD screen, this might display the crash information as a QR code or as text for the
user to capture by taking a picture
2.7 The CPU is reset and/or halted by triggering a debug breakpoint if a debugger is attached */
// Hook into CPU exception interrupt table to call the backtracing code upon an exception
// Most platform will simply do nothing here, but those who can will install/overwrite the default exception handler
// with a more performant exception handler
void hook_cpu_exceptions();
// Some platform might deal without a hard fault handler, in that case, return 0 in your platform here or skip implementing it
void * __attribute__((weak)) hook_get_hardfault_vector_address(unsigned base_address);
// Some platform might deal without a memory management fault handler, in that case, return 0 in your platform here or skip implementing it
void * __attribute__((weak)) hook_get_memfault_vector_address(unsigned base_address);
// Some platform might deal without a bus fault handler, in that case, return 0 in your platform here or skip implementing it
void * __attribute__((weak)) hook_get_busfault_vector_address(unsigned base_address);
// Some platform might deal without a usage fault handler, in that case, return 0 in your platform here or skip implementing it
void * __attribute__((weak)) hook_get_usagefault_vector_address(unsigned base_address);
// Last resort function that can be called after the exception handler was called.
void __attribute__((weak)) hook_last_resort_func();
+24 -19
View File
@@ -36,6 +36,7 @@
#include "HAL/shared/Delay.h"
#include "HAL/shared/esp_wifi.h"
#include "HAL/shared/cpu_exception/exception_hook.h"
#ifdef ARDUINO
#include <pins_arduino.h>
@@ -419,8 +420,7 @@ inline void manage_inactivity(const bool ignore_stepper_queue=false) {
if (parked_or_ignoring) gcode.reset_stepper_timeout(ms);
if (gcode.stepper_max_timed_out(ms)) {
SERIAL_ERROR_START();
SERIAL_ECHOLNPAIR(STR_KILL_INACTIVE_TIME, parser.command_ptr);
SERIAL_ERROR_MSG(STR_KILL_INACTIVE_TIME, parser.command_ptr);
kill();
}
@@ -614,8 +614,8 @@ inline void manage_inactivity(const bool ignore_stepper_queue=false) {
*/
void idle(TERN_(ADVANCED_PAUSE_FEATURE, bool no_stepper_sleep/*=false*/)) {
#if ENABLED(MARLIN_DEV_MODE)
static uint8_t idle_depth = 0;
if (++idle_depth > 5) SERIAL_ECHOLNPAIR("idle() call depth: ", int(idle_depth));
static uint16_t idle_depth = 0;
if (++idle_depth > 5) SERIAL_ECHOLNPAIR("idle() call depth: ", idle_depth);
#endif
// Core Marlin activities
@@ -886,6 +886,17 @@ void setup() {
#endif
#define SETUP_RUN(C) do{ SETUP_LOG(STRINGIFY(C)); C; }while(0)
MYSERIAL0.begin(BAUDRATE);
millis_t serial_connect_timeout = millis() + 1000UL;
while (!MYSERIAL0.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
#if HAS_MULTI_SERIAL && !HAS_ETHERNET
MYSERIAL1.begin(BAUDRATE);
serial_connect_timeout = millis() + 1000UL;
while (!MYSERIAL1.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
#endif
SERIAL_ECHOLNPGM("start");
// Set up these pins early to prevent suicide
#if HAS_KILL
SETUP_LOG("KILL_PIN");
@@ -918,17 +929,6 @@ void setup() {
#endif
#endif
MYSERIAL0.begin(BAUDRATE);
millis_t serial_connect_timeout = millis() + 1000UL;
while (!MYSERIAL0.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
#if HAS_MULTI_SERIAL && !HAS_ETHERNET
MYSERIAL1.begin(BAUDRATE);
serial_connect_timeout = millis() + 1000UL;
while (!MYSERIAL1.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
#endif
SERIAL_ECHOLNPGM("start");
#if BOTH(HAS_TFT_LVGL_UI, MKS_WIFI_MODULE)
mks_esp_wifi_init();
WIFISERIAL.begin(WIFI_BAUDRATE);
@@ -936,13 +936,15 @@ void setup() {
while (/*!WIFISERIAL && */PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
#endif
TERN_(DYNAMIC_VECTORTABLE, hook_cpu_exceptions()); // If supported, install Marlin exception handlers at runtime
SETUP_RUN(HAL_init());
// Init and disable SPI thermocouples
#if HEATER_0_USES_MAX6675
// Init and disable SPI thermocouples; this is still needed
#if TEMP_SENSOR_0_IS_MAX_TC
OUT_WRITE(MAX6675_SS_PIN, HIGH); // Disable
#endif
#if HEATER_1_USES_MAX6675
#if TEMP_SENSOR_1_IS_MAX_TC
OUT_WRITE(MAX6675_SS2_PIN, HIGH); // Disable
#endif
@@ -1004,7 +1006,10 @@ void setup() {
);
#endif
SERIAL_ECHO_MSG("Compiled: " __DATE__);
SERIAL_ECHO_MSG(STR_FREE_MEMORY, freeMemory(), STR_PLANNER_BUFFER_BYTES, (int)sizeof(block_t) * (BLOCK_BUFFER_SIZE));
SERIAL_ECHO_MSG(STR_FREE_MEMORY, freeMemory(), STR_PLANNER_BUFFER_BYTES, sizeof(block_t) * (BLOCK_BUFFER_SIZE));
// Some HAL need precise delay adjustment
calibrate_delay_loop();
// Init buzzer pin(s)
#if USE_BEEPER
+1 -3
View File
@@ -327,7 +327,7 @@
#define BOARD_LONGER3D_LK 4034 // Alfawise U20/U20+/U30 (Longer3D LK1/2) / STM32F103VET6
#define BOARD_CCROBOT_MEEB_3DP 4035 // ccrobot-online.com MEEB_3DP (STM32F103RC)
#define BOARD_CHITU3D_V5 4036 // Chitu3D TronXY X5SA V5 Board
#define BOARD_CHITU3D_V6 4037 // Chitu3D TronXY X5SA V5 Board
#define BOARD_CHITU3D_V6 4037 // Chitu3D TronXY X5SA V6 Board
#define BOARD_CREALITY_V4 4038 // Creality v4.x (STM32F103RE)
#define BOARD_CREALITY_V427 4039 // Creality v4.2.7 (STM32F103RE)
#define BOARD_CREALITY_V4210 4040 // Creality v4.2.10 (STM32F103RE) as found in the CR-30
@@ -415,5 +415,3 @@
#define _MB_1(B) (defined(BOARD_##B) && MOTHERBOARD==BOARD_##B)
#define MB(V...) DO(MB,||,V)
#define IS_MELZI MB(MELZI, MELZI_CREALITY, MELZI_MAKR3D, MELZI_MALYAN, MELZI_TRONXY, MELZI_V2)
+14 -6
View File
@@ -61,6 +61,8 @@
#define _O2 __attribute__((optimize("O2")))
#define _O3 __attribute__((optimize("O3")))
#define IS_CONSTEXPR(...) __builtin_constant_p(__VA_ARGS__) // Only valid solution with C++14. Should use std::is_constant_evaluated() in C++20 instead
#ifndef UNUSED
#define UNUSED(x) ((void)(x))
#endif
@@ -128,20 +130,20 @@
#define NOLESS(v, n) \
do{ \
__typeof__(n) _n = (n); \
__typeof__(v) _n = (n); \
if (_n > v) v = _n; \
}while(0)
#define NOMORE(v, n) \
do{ \
__typeof__(n) _n = (n); \
__typeof__(v) _n = (n); \
if (_n < v) v = _n; \
}while(0)
#define LIMIT(v, n1, n2) \
do{ \
__typeof__(n1) _n1 = (n1); \
__typeof__(n2) _n2 = (n2); \
__typeof__(v) _n1 = (n1); \
__typeof__(v) _n2 = (n2); \
if (_n1 > v) v = _n1; \
else if (_n2 < v) v = _n2; \
}while(0)
@@ -319,9 +321,15 @@
namespace Private {
template<bool, typename _Tp = void> struct enable_if { };
template<typename _Tp> struct enable_if<true, _Tp> { typedef _Tp type; };
template<typename T, typename U> struct is_same { enum { value = false }; };
template<typename T> struct is_same<T, T> { enum { value = true }; };
template <typename T, typename ... Args> struct first_type_of { typedef T type; };
template <typename T> struct first_type_of<T> { typedef T type; };
}
// C++11 solution using SFINAE to detect the existance of a member in a class at compile time.
// It creates a HasMember<Type> structure containing 'value' set to true if the member exists
// C++11 solution using SFINAE to detect the existance of a member in a class at compile time.
// It creates a HasMember<Type> structure containing 'value' set to true if the member exists
#define HAS_MEMBER_IMPL(Member) \
namespace Private { \
template <typename Type, typename Yes=char, typename No=long> struct HasMember_ ## Member { \
+3 -1
View File
@@ -59,12 +59,14 @@ void serialprintPGM(PGM_P str) {
void serial_echo_start() { static PGMSTR(echomagic, "echo:"); serialprintPGM(echomagic); }
void serial_error_start() { static PGMSTR(errormagic, "Error:"); serialprintPGM(errormagic); }
void serial_echopair_PGM(PGM_P const s_P, serial_char_t v) { serialprintPGM(s_P); SERIAL_CHAR(v.c); }
void serial_echopair_PGM(PGM_P const s_P, const char *v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, char v) { serialprintPGM(s_P); SERIAL_CHAR(v); }
void serial_echopair_PGM(PGM_P const s_P, char v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, int v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, long v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, float v) { serialprintPGM(s_P); SERIAL_DECIMAL(v); }
void serial_echopair_PGM(PGM_P const s_P, double v) { serialprintPGM(s_P); SERIAL_DECIMAL(v); }
void serial_echopair_PGM(PGM_P const s_P, unsigned char v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, unsigned int v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, unsigned long v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
+79 -56
View File
@@ -62,6 +62,7 @@ typedef int8_t serial_index_t;
#define SERIAL_ALL 0x7F
#if HAS_MULTI_SERIAL
#define _PORT_REDIRECT(n,p) REMEMBER(n,multiSerial.portMask,p)
#define _PORT_RESTORE(n,p) RESTORE(n)
#define SERIAL_ASSERT(P) if(multiSerial.portMask!=(P)){ debugger(); }
#ifdef SERIAL_CATCHALL
typedef MultiSerial<decltype(MYSERIAL), decltype(SERIAL_CATCHALL), 0> SerialOutputT;
@@ -72,6 +73,7 @@ typedef int8_t serial_index_t;
#define SERIAL_IMPL multiSerial
#else
#define _PORT_REDIRECT(n,p) NOOP
#define _PORT_RESTORE(n) NOOP
#define SERIAL_ASSERT(P) NOOP
#define SERIAL_IMPL MYSERIAL0
#endif
@@ -79,39 +81,52 @@ typedef int8_t serial_index_t;
#define SERIAL_OUT(WHAT, V...) (void)SERIAL_IMPL.WHAT(V)
#define PORT_REDIRECT(p) _PORT_REDIRECT(1,p)
#define PORT_RESTORE() _PORT_RESTORE(1)
#define SERIAL_PORTMASK(P) _BV(P)
#define SERIAL_ECHO(x) SERIAL_OUT(print, x)
#define SERIAL_ECHO_F(V...) SERIAL_OUT(print, V)
#define SERIAL_ECHOLN(x) SERIAL_OUT(println, x)
#define SERIAL_PRINT(x,b) SERIAL_OUT(print, x, b)
#define SERIAL_PRINTLN(x,b) SERIAL_OUT(println, x, b)
#define SERIAL_FLUSH() SERIAL_OUT(flush)
//
// SERIAL_CHAR - Print one or more individual chars
//
inline void SERIAL_CHAR(char a) { SERIAL_IMPL.write(a); }
template <typename ... Args>
void SERIAL_CHAR(char a, Args ... args) { SERIAL_IMPL.write(a); SERIAL_CHAR(args ...); }
#ifdef ARDUINO_ARCH_STM32
#define SERIAL_FLUSHTX() SERIAL_OUT(flush)
#elif TX_BUFFER_SIZE > 0
#define SERIAL_FLUSHTX() SERIAL_OUT(flushTX)
#else
#define SERIAL_FLUSHTX()
#endif
/**
* SERIAL_ECHO - Print a single string or value.
* Any numeric parameter (including char) is printed as a base-10 number.
* A string pointer or literal will be output as a string.
*
* NOTE: Use SERIAL_CHAR to print char as a single character.
*/
template <typename T>
void SERIAL_ECHO(T x) { SERIAL_IMPL.print(x); }
// Print up to 10 chars from a list
#define __CHAR_N(N,V...) _CHAR_##N(V)
#define _CHAR_N(N,V...) __CHAR_N(N,V)
#define _CHAR_1(c) SERIAL_OUT(write, c)
#define _CHAR_2(a,b) do{ _CHAR_1(a); _CHAR_1(b); }while(0)
#define _CHAR_3(a,V...) do{ _CHAR_1(a); _CHAR_2(V); }while(0)
#define _CHAR_4(a,V...) do{ _CHAR_1(a); _CHAR_3(V); }while(0)
#define _CHAR_5(a,V...) do{ _CHAR_1(a); _CHAR_4(V); }while(0)
#define _CHAR_6(a,V...) do{ _CHAR_1(a); _CHAR_5(V); }while(0)
#define _CHAR_7(a,V...) do{ _CHAR_1(a); _CHAR_6(V); }while(0)
#define _CHAR_8(a,V...) do{ _CHAR_1(a); _CHAR_7(V); }while(0)
#define _CHAR_9(a,V...) do{ _CHAR_1(a); _CHAR_8(V); }while(0)
#define _CHAR_10(a,V...) do{ _CHAR_1(a); _CHAR_9(V); }while(0)
// Wrapper for ECHO commands to interpret a char
typedef struct SerialChar { char c; SerialChar(char n) : c(n) { } } serial_char_t;
inline void SERIAL_ECHO(serial_char_t x) { SERIAL_IMPL.write(x.c); }
#define AS_CHAR(C) serial_char_t(C)
#define SERIAL_CHAR(V...) _CHAR_N(NUM_ARGS(V),V)
// SERIAL_ECHO_F prints a floating point value with optional precision
inline void SERIAL_ECHO_F(EnsureDouble x, int digit = 2) { SERIAL_IMPL.print(x, digit); }
template <typename T>
void SERIAL_ECHOLN(T x) { SERIAL_IMPL.println(x); }
// SERIAL_PRINT works like SERIAL_ECHO but allow to specify the encoding base of the number printed
template <typename T, typename U>
void SERIAL_PRINT(T x, U y) { SERIAL_IMPL.print(x, y); }
template <typename T, typename U>
void SERIAL_PRINTLN(T x, U y) { SERIAL_IMPL.println(x, y); }
// Flush the serial port
inline void SERIAL_FLUSH() { SERIAL_IMPL.flush(); }
inline void SERIAL_FLUSHTX() { SERIAL_IMPL.flushTX(); }
// Print a single PROGMEM string to serial
void serialprintPGM(PGM_P str);
// SERIAL_ECHOPAIR / SERIAL_ECHOPAIR_P is used to output a key value pair. The key must be a string and the value can be anything
// Print up to 12 pairs of values. Odd elements auto-wrapped in PSTR().
#define __SEP_N(N,V...) _SEP_##N(V)
#define _SEP_N(N,V...) __SEP_N(N,V)
@@ -170,6 +185,7 @@ typedef int8_t serial_index_t;
#define _SEP_23_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_21_P(V); }while(0)
#define _SEP_24_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_22_P(V); }while(0)
// SERIAL_ECHOPAIR_P is used to output a key value pair. Unlike SERIAL_ECHOPAIR, the key must be a PGM string already and the value can be anything
#define SERIAL_ECHOPAIR_P(V...) _SEP_N_P(NUM_ARGS(V),V)
// Print up to 12 pairs of values followed by newline
@@ -244,32 +260,39 @@ typedef int8_t serial_index_t;
#define SERIAL_ECHOLNPAIR_P(V...) _SELP_N_P(NUM_ARGS(V),V)
// Print up to 20 comma-separated pairs of values
#define __SLST_N(N,V...) _SLST_##N(V)
#define _SLST_N(N,V...) __SLST_N(N,V)
#define _SLST_1(a) SERIAL_ECHO(a)
#define _SLST_2(a,b) do{ SERIAL_ECHO(a); SERIAL_ECHOPAIR(", ",b); }while(0)
#define _SLST_3(a,b,c) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_1(c); }while(0)
#define _SLST_4(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_2(V); }while(0)
#define _SLST_5(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_3(V); }while(0)
#define _SLST_6(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_4(V); }while(0)
#define _SLST_7(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_5(V); }while(0)
#define _SLST_8(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_6(V); }while(0)
#define _SLST_9(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_7(V); }while(0)
#define _SLST_10(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_8(V); }while(0)
#define _SLST_11(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_9(V); }while(0)
#define _SLST_12(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_10(V); }while(0)
#define _SLST_13(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_11(V); }while(0)
#define _SLST_14(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_12(V); }while(0)
#define _SLST_15(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_13(V); }while(0)
#define _SLST_16(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_14(V); }while(0)
#define _SLST_17(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_15(V); }while(0)
#define _SLST_18(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_16(V); }while(0)
#define _SLST_19(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_17(V); }while(0)
#define _SLST_20(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_18(V); }while(0) // Eat two args, pass the rest up
#ifdef AllowDifferentTypeInList
#define SERIAL_ECHOLIST(pre,V...) do{ SERIAL_ECHOPGM(pre); _SLST_N(NUM_ARGS(V),V); }while(0)
#define SERIAL_ECHOLIST_N(N,V...) _SLST_N(N,LIST_N(N,V))
inline void SERIAL_ECHOLIST_IMPL() {}
template <typename T>
void SERIAL_ECHOLIST_IMPL(T && t) { SERIAL_IMPL.print(t); }
template <typename T, typename ... Args>
void SERIAL_ECHOLIST_IMPL(T && t, Args && ... args) {
SERIAL_IMPL.print(t);
serialprintPGM(PSTR(", "));
SERIAL_ECHOLIST_IMPL(args...);
}
template <typename ... Args>
void SERIAL_ECHOLIST(PGM_P const str, Args && ... args) {
SERIAL_IMPL.print(str);
SERIAL_ECHOLIST_IMPL(args...);
}
#else // Optimization if the listed type are all the same (seems to be the case in the codebase so use that instead)
template <typename ... Args>
void SERIAL_ECHOLIST(PGM_P const str, Args && ... args) {
serialprintPGM(str);
typename Private::first_type_of<Args...>::type values[] = { args... };
constexpr size_t argsSize = sizeof...(args);
for (size_t i = 0; i < argsSize; i++) {
if (i) serialprintPGM(PSTR(", "));
SERIAL_IMPL.print(values[i]);
}
}
#endif
#define SERIAL_ECHOPGM_P(P) (serialprintPGM(P))
#define SERIAL_ECHOLNPGM_P(P) (serialprintPGM(P "\n"))
@@ -303,19 +326,19 @@ typedef int8_t serial_index_t;
//
// Functions for serial printing from PROGMEM. (Saves loads of SRAM.)
//
void serial_echopair_PGM(PGM_P const s_P, serial_char_t v);
void serial_echopair_PGM(PGM_P const s_P, const char *v);
void serial_echopair_PGM(PGM_P const s_P, char v);
void serial_echopair_PGM(PGM_P const s_P, int v);
void serial_echopair_PGM(PGM_P const s_P, unsigned int v);
void serial_echopair_PGM(PGM_P const s_P, long v);
void serial_echopair_PGM(PGM_P const s_P, unsigned long v);
void serial_echopair_PGM(PGM_P const s_P, float v);
void serial_echopair_PGM(PGM_P const s_P, double v);
inline void serial_echopair_PGM(PGM_P const s_P, uint8_t v) { serial_echopair_PGM(s_P, (int)v); }
void serial_echopair_PGM(PGM_P const s_P, unsigned char v);
void serial_echopair_PGM(PGM_P const s_P, unsigned int v);
void serial_echopair_PGM(PGM_P const s_P, unsigned long v);
inline void serial_echopair_PGM(PGM_P const s_P, bool v) { serial_echopair_PGM(s_P, (int)v); }
inline void serial_echopair_PGM(PGM_P const s_P, void *v) { serial_echopair_PGM(s_P, (uintptr_t)v); }
void serialprintPGM(PGM_P str);
void serial_echo_start();
void serial_error_start();
void serial_ternary(const bool onoff, PGM_P const pre, PGM_P const on, PGM_P const off, PGM_P const post=nullptr);
+78 -31
View File
@@ -22,25 +22,41 @@
#pragma once
#include "../inc/MarlinConfigPre.h"
#include "macros.h"
#if ENABLED(EMERGENCY_PARSER)
#include "../feature/e_parser.h"
#endif
#ifndef DEC
#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2
#endif
// flushTX is not implemented in all HAL, so use SFINAE to call the method where it is.
CALL_IF_EXISTS_IMPL(void, flushTX );
CALL_IF_EXISTS_IMPL(void, flushTX);
CALL_IF_EXISTS_IMPL(bool, connected, true);
// In order to catch usage errors in code, we make the base to encode number explicit
// If given a number (and not this enum), the compiler will reject the overload, falling back to the (double, digit) version
// We don't want hidden conversion of the first parameter to double, so it has to be as hard to do for the compiler as creating this enum
enum class PrintBase {
Dec = 10,
Hex = 16,
Oct = 8,
Bin = 2
};
// A simple forward struct that prevent the compiler to select print(double, int) as a default overload for any type different than
// double or float. For double or float, a conversion exists so the call will be transparent
struct EnsureDouble {
double a;
FORCE_INLINE operator double() { return a; }
// If the compiler breaks on ambiguity here, it's likely because you're calling print(X, base) with X not a double or a float, and a
// base that's not one of PrintBase's value. This exact code is made to detect such error, you NEED to set a base explicitely like this:
// SERIAL_PRINT(v, PrintBase::Hex)
FORCE_INLINE EnsureDouble(double a) : a(a) {}
FORCE_INLINE EnsureDouble(float a) : a(a) {}
};
// Using Curiously Recurring Template Pattern here to avoid virtual table cost when compiling.
// Since the real serial class is known at compile time, this results in compiler writing a completely
// efficient code
// Since the real serial class is known at compile time, this results in the compiler writing
// a completely efficient code.
template <class Child>
struct SerialBase {
#if ENABLED(EMERGENCY_PARSER)
@@ -78,26 +94,47 @@ struct SerialBase {
FORCE_INLINE void write(const char* str) { while (*str) write(*str++); }
FORCE_INLINE void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
FORCE_INLINE void print(const char* str) { write(str); }
NO_INLINE void print(char c, int base = 0) { print((long)c, base); }
NO_INLINE void print(unsigned char c, int base = 0) { print((unsigned long)c, base); }
NO_INLINE void print(int c, int base = DEC) { print((long)c, base); }
NO_INLINE void print(unsigned int c, int base = DEC) { print((unsigned long)c, base); }
void print(long c, int base = DEC) { if (!base) write(c); write((const uint8_t*)"-", c < 0); printNumber(c < 0 ? -c : c, base); }
void print(unsigned long c, int base = DEC) { printNumber(c, base); }
void print(double c, int digits = 2) { printFloat(c, digits); }
// No default argument to avoid ambiguity
NO_INLINE void print(char c, PrintBase base) { printNumber((signed long)c, (uint8_t)base); }
NO_INLINE void print(unsigned char c, PrintBase base) { printNumber((unsigned long)c, (uint8_t)base); }
NO_INLINE void print(int c, PrintBase base) { printNumber((signed long)c, (uint8_t)base); }
NO_INLINE void print(unsigned int c, PrintBase base) { printNumber((unsigned long)c, (uint8_t)base); }
void print(unsigned long c, PrintBase base) { printNumber((unsigned long)c, (uint8_t)base); }
void print(long c, PrintBase base) { printNumber((signed long)c, (uint8_t)base); }
void print(EnsureDouble c, int digits) { printFloat(c, digits); }
NO_INLINE void println(const char s[]) { print(s); println(); }
NO_INLINE void println(char c, int base = 0) { print(c, base); println(); }
NO_INLINE void println(unsigned char c, int base = 0) { print(c, base); println(); }
NO_INLINE void println(int c, int base = DEC) { print(c, base); println(); }
NO_INLINE void println(unsigned int c, int base = DEC) { print(c, base); println(); }
NO_INLINE void println(long c, int base = DEC) { print(c, base); println(); }
NO_INLINE void println(unsigned long c, int base = DEC) { print(c, base); println(); }
NO_INLINE void println(double c, int digits = 2) { print(c, digits); println(); }
NO_INLINE void println() { write('\r'); write('\n'); }
// Forward the call to the former's method
FORCE_INLINE void print(char c) { print(c, PrintBase::Dec); }
FORCE_INLINE void print(unsigned char c) { print(c, PrintBase::Dec); }
FORCE_INLINE void print(int c) { print(c, PrintBase::Dec); }
FORCE_INLINE void print(unsigned int c) { print(c, PrintBase::Dec); }
FORCE_INLINE void print(unsigned long c) { print(c, PrintBase::Dec); }
FORCE_INLINE void print(long c) { print(c, PrintBase::Dec); }
FORCE_INLINE void print(double c) { print(c, 2); }
FORCE_INLINE void println(const char s[]) { print(s); println(); }
FORCE_INLINE void println(char c, PrintBase base) { print(c, base); println(); }
FORCE_INLINE void println(unsigned char c, PrintBase base) { print(c, base); println(); }
FORCE_INLINE void println(int c, PrintBase base) { print(c, base); println(); }
FORCE_INLINE void println(unsigned int c, PrintBase base) { print(c, base); println(); }
FORCE_INLINE void println(long c, PrintBase base) { print(c, base); println(); }
FORCE_INLINE void println(unsigned long c, PrintBase base) { print(c, base); println(); }
FORCE_INLINE void println(double c, int digits) { print(c, digits); println(); }
FORCE_INLINE void println() { write('\r'); write('\n'); }
// Forward the call to the former's method
FORCE_INLINE void println(char c) { println(c, PrintBase::Dec); }
FORCE_INLINE void println(unsigned char c) { println(c, PrintBase::Dec); }
FORCE_INLINE void println(int c) { println(c, PrintBase::Dec); }
FORCE_INLINE void println(unsigned int c) { println(c, PrintBase::Dec); }
FORCE_INLINE void println(unsigned long c) { println(c, PrintBase::Dec); }
FORCE_INLINE void println(long c) { println(c, PrintBase::Dec); }
FORCE_INLINE void println(double c) { println(c, 2); }
// Print a number with the given base
void printNumber(unsigned long n, const uint8_t base) {
NO_INLINE void printNumber(unsigned long n, const uint8_t base) {
if (!base) return; // Hopefully, this should raise visible bug immediately
if (n) {
unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
int8_t i = 0;
@@ -109,9 +146,19 @@ struct SerialBase {
}
else write('0');
}
void printNumber(signed long n, const uint8_t base) {
if (base == 10 && n < 0) {
n = -n; // This works because all platforms Marlin's builds on are using 2-complement encoding for negative number
// On such CPU, changing the sign of a number is done by inverting the bits and adding one, so if n = 0x80000000 = -2147483648 then
// -n = 0x7FFFFFFF + 1 => 0x80000000 = 2147483648 (if interpreted as unsigned) or -2147483648 if interpreted as signed.
// On non 2-complement CPU, there would be no possible representation for 2147483648.
write('-');
}
printNumber((unsigned long)n , base);
}
// Print a decimal number
void printFloat(double number, uint8_t digits) {
NO_INLINE void printFloat(double number, uint8_t digits) {
// Handle negative numbers
if (number < 0.0) {
write('-');
@@ -134,7 +181,7 @@ struct SerialBase {
// Extract digits from the remainder one at a time
while (digits--) {
remainder *= 10.0;
int toPrint = int(remainder);
unsigned long toPrint = (unsigned long)remainder;
printNumber(toPrint, 10);
remainder -= toPrint;
}
@@ -142,5 +189,5 @@ struct SerialBase {
}
};
// All serial instances will be built by chaining the features required for the function in a form of a template
// type definition
// All serial instances will be built by chaining the features required
// for the function in the form of a template type definition.
+9 -3
View File
@@ -21,6 +21,7 @@
*/
#pragma once
#include "macros.h"
#include "serial_base.h"
// The most basic serial class: it dispatch to the base serial class with no hook whatsoever. This will compile to nothing but the base serial class
@@ -37,6 +38,8 @@ struct BaseSerial : public SerialBase< BaseSerial<SerialT> >, public SerialT {
bool available(uint8_t index) { return index == 0 && SerialT::available(); }
int read(uint8_t index) { return index == 0 ? SerialT::read() : -1; }
bool connected() { return CALL_IF_EXISTS(bool, static_cast<SerialT*>(this), connected);; }
void flushTX() { CALL_IF_EXISTS(void, static_cast<SerialT*>(this), flushTX); }
// We have 2 implementation of the same method in both base class, let's say which one we want
using SerialT::available;
using SerialT::read;
@@ -68,6 +71,7 @@ struct ConditionalSerial : public SerialBase< ConditionalSerial<SerialT> > {
void msgDone() {}
bool connected() { return CALL_IF_EXISTS(bool, &out, connected); }
void flushTX() { CALL_IF_EXISTS(void, &out, flushTX); }
bool available(uint8_t index) { return index == 0 && out.available(); }
int read(uint8_t index) { return index == 0 ? out.read() : -1; }
@@ -91,6 +95,7 @@ struct ForwardSerial : public SerialBase< ForwardSerial<SerialT> > {
void msgDone() {}
// Existing instances implement Arduino's operator bool, so use that if it's available
bool connected() { return Private::HasMember_connected<SerialT>::value ? CALL_IF_EXISTS(bool, &out, connected) : (bool)out; }
void flushTX() { CALL_IF_EXISTS(void, &out, flushTX); }
bool available(uint8_t index) { return index == 0 && out.available(); }
int read(uint8_t index) { return index == 0 ? out.read() : -1; }
@@ -132,9 +137,10 @@ struct RuntimeSerial : public SerialBase< RuntimeSerial<SerialT> >, public Seria
using BaseClassT::println;
// Underlying implementation might use Arduino's bool operator
bool connected() {
return Private::HasMember_connected<SerialT>::value ? CALL_IF_EXISTS(bool, static_cast<SerialT*>(this), connected) : static_cast<SerialT*>(this)->operator bool();
}
bool connected() {
return Private::HasMember_connected<SerialT>::value ? CALL_IF_EXISTS(bool, static_cast<SerialT*>(this), connected) : static_cast<SerialT*>(this)->operator bool();
}
void flushTX() { CALL_IF_EXISTS(void, static_cast<SerialT*>(this), flushTX); }
void setHook(WriteHook writeHook = 0, EndOfMessageHook eofHook = 0, void * userPointer = 0) {
// Order is important here as serial code can be called inside interrupts
+2 -2
View File
@@ -47,11 +47,11 @@ static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t
if (DEBUGGING(LEVELING)) {
DEBUG_ECHOPGM("Extrapolate [");
if (x < 10) DEBUG_CHAR(' ');
DEBUG_ECHO((int)x);
DEBUG_ECHO(x);
DEBUG_CHAR(xdir ? (xdir > 0 ? '+' : '-') : ' ');
DEBUG_CHAR(' ');
if (y < 10) DEBUG_CHAR(' ');
DEBUG_ECHO((int)y);
DEBUG_ECHO(y);
DEBUG_CHAR(ydir ? (ydir > 0 ? '+' : '-') : ' ');
DEBUG_ECHOLNPGM("]");
}
+3 -3
View File
@@ -160,7 +160,7 @@ void reset_bed_level() {
#ifndef SCAD_MESH_OUTPUT
LOOP_L_N(x, sx) {
serial_spaces(precision + (x < 10 ? 3 : 2));
SERIAL_ECHO(int(x));
SERIAL_ECHO(x);
}
SERIAL_EOL();
#endif
@@ -172,7 +172,7 @@ void reset_bed_level() {
SERIAL_ECHOPGM(" ["); // open sub-array
#else
if (y < 10) SERIAL_CHAR(' ');
SERIAL_ECHO(int(y));
SERIAL_ECHO(y);
#endif
LOOP_L_N(x, sx) {
SERIAL_CHAR(' ');
@@ -196,7 +196,7 @@ void reset_bed_level() {
#endif
}
#ifdef SCAD_MESH_OUTPUT
SERIAL_CHAR(' ', ']'); // close sub-array
SERIAL_ECHOPGM(" ]"); // close sub-array
if (y < sy - 1) SERIAL_CHAR(',');
#endif
SERIAL_EOL();
+2 -2
View File
@@ -50,7 +50,7 @@
GRID_LOOP(x, y)
if (!isnan(z_values[x][y])) {
SERIAL_ECHO_START();
SERIAL_ECHOPAIR(" M421 I", int(x), " J", int(y));
SERIAL_ECHOPAIR(" M421 I", x, " J", y);
SERIAL_ECHOLNPAIR_F_P(SP_Z_STR, z_values[x][y], 4);
serial_delay(75); // Prevent Printrun from exploding
}
@@ -214,7 +214,7 @@
else if (isnan(f))
serialprintPGM(human ? PSTR(" . ") : PSTR("NAN"));
else if (human || csv) {
if (human && f >= 0.0) SERIAL_CHAR(f > 0 ? '+' : ' '); // Space for positive ('-' for negative)
if (human && f >= 0.0) SERIAL_CHAR(f > 0 ? '+' : ' '); // Display sign also for positive numbers (' ' for 0)
SERIAL_ECHO_F(f, 3); // Positive: 5 digits, Negative: 6 digits
}
if (csv && i < GRID_MAX_POINTS_X - 1) SERIAL_CHAR('\t');
+4 -4
View File
@@ -742,7 +742,7 @@
if (do_ubl_mesh_map) display_map(g29_map_type);
const int point_num = (GRID_MAX_POINTS) - count + 1;
SERIAL_ECHOLNPAIR("\nProbing mesh point ", point_num, "/", int(GRID_MAX_POINTS), ".\n");
SERIAL_ECHOLNPAIR("Probing mesh point ", point_num, "/", GRID_MAX_POINTS, ".");
TERN_(HAS_DISPLAY, ui.status_printf_P(0, PSTR(S_FMT " %i/%i"), GET_TEXT(MSG_PROBING_MESH), point_num, int(GRID_MAX_POINTS)));
#if HAS_LCD_MENU
@@ -1694,7 +1694,7 @@
SERIAL_EOL();
#if HAS_KILL
SERIAL_ECHOLNPAIR("Kill pin on :", int(KILL_PIN), " state:", int(kill_state()));
SERIAL_ECHOLNPAIR("Kill pin on :", KILL_PIN, " state:", kill_state());
#endif
SERIAL_EOL();
@@ -1707,8 +1707,8 @@
SERIAL_ECHOLNPAIR("Meshes go from ", hex_address((void*)settings.meshes_start_index()), " to ", hex_address((void*)settings.meshes_end_index()));
serial_delay(50);
SERIAL_ECHOLNPAIR("sizeof(ubl) : ", (int)sizeof(ubl)); SERIAL_EOL();
SERIAL_ECHOLNPAIR("z_value[][] size: ", (int)sizeof(z_values)); SERIAL_EOL();
SERIAL_ECHOLNPAIR("sizeof(ubl) : ", sizeof(ubl)); SERIAL_EOL();
SERIAL_ECHOLNPAIR("z_value[][] size: ", sizeof(z_values)); SERIAL_EOL();
serial_delay(25);
SERIAL_ECHOLNPAIR("EEPROM free for UBL: ", hex_address((void*)(settings.meshes_end_index() - settings.meshes_start_index())));
+3 -6
View File
@@ -352,8 +352,7 @@ public:
}
}
else {
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR("Packet header(", packet.header.sync, "?) corrupt");
SERIAL_ECHO_MSG("Packet header(", packet.header.sync, "?) corrupt");
stream_state = StreamState::PACKET_RESEND;
}
}
@@ -387,8 +386,7 @@ public:
stream_state = StreamState::PACKET_PROCESS;
}
else {
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR("Packet(", packet.header.sync, ") payload corrupt");
SERIAL_ECHO_MSG("Packet(", packet.header.sync, ") payload corrupt");
stream_state = StreamState::PACKET_RESEND;
}
}
@@ -406,8 +404,7 @@ public:
if (packet_retries < MAX_RETRIES || MAX_RETRIES == 0) {
packet_retries++;
stream_state = StreamState::PACKET_RESET;
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR("Resend request ", int(packet_retries));
SERIAL_ECHO_MSG("Resend request ", packet_retries);
SERIAL_ECHOLNPAIR("rs", sync);
}
else
+3 -3
View File
@@ -64,7 +64,7 @@ void BLTouch::init(const bool set_voltage/*=false*/) {
#else
if (DEBUGGING(LEVELING)) {
DEBUG_ECHOLNPAIR("last_written_mode - ", (int)last_written_mode);
DEBUG_ECHOLNPAIR("last_written_mode - ", last_written_mode);
DEBUG_ECHOLNPGM("config mode - "
#if ENABLED(BLTOUCH_SET_5V_MODE)
"BLTOUCH_SET_5V_MODE"
@@ -175,7 +175,7 @@ bool BLTouch::status_proc() {
_set_SW_mode(); // Incidentally, _set_SW_mode() will also RESET any active alarm
const bool tr = triggered(); // If triggered in SW mode, the pin is up, it is STOWED
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("BLTouch is ", (int)tr);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("BLTouch is ", tr);
if (tr) _stow(); else _deploy(); // Turn off SW mode, reset any trigger, honor pin state
return !tr;
@@ -187,7 +187,7 @@ void BLTouch::mode_conv_proc(const bool M5V) {
* BLTOUCH V3.0: This will set the mode (twice) and sadly, a STOW is needed at the end, because of the deploy
* BLTOUCH V3.1: This will set the mode and store it in the eeprom. The STOW is not needed but does not hurt
*/
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("BLTouch Set Mode - ", (int)M5V);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("BLTouch Set Mode - ", M5V);
_deploy();
if (M5V) _set_5V_mode(); else _set_OD_mode();
_mode_store();
+2 -4
View File
@@ -66,10 +66,8 @@ void CancelObject::uncancel_object(const int8_t obj) {
}
void CancelObject::report() {
if (active_object >= 0) {
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR("Active Object: ", int(active_object));
}
if (active_object >= 0)
SERIAL_ECHO_MSG("Active Object: ", active_object);
if (canceled) {
SERIAL_ECHO_START();
+3 -3
View File
@@ -180,7 +180,7 @@ namespace DirectStepping {
if (!page_states_dirty) return;
page_states_dirty = false;
SERIAL_ECHO(Cfg::CONTROL_CHAR);
SERIAL_CHAR(Cfg::CONTROL_CHAR);
constexpr int state_bits = 2;
constexpr int n_bytes = Cfg::NUM_PAGES >> state_bits;
volatile uint8_t bits_b[n_bytes] = { 0 };
@@ -192,10 +192,10 @@ namespace DirectStepping {
uint8_t crc = 0;
for (uint8_t i = 0 ; i < n_bytes ; i++) {
crc ^= bits_b[i];
SERIAL_ECHO(bits_b[i]);
SERIAL_CHAR(bits_b[i]);
}
SERIAL_ECHO(crc);
SERIAL_CHAR(crc);
SERIAL_EOL();
}
+15 -16
View File
@@ -49,7 +49,7 @@ void I2CPositionEncoder::init(const uint8_t address, const AxisEnum axis) {
initialized++;
SERIAL_ECHOLNPAIR("Setting up encoder on ", axis_codes[encoderAxis], " axis, addr = ", address);
SERIAL_ECHOLNPAIR("Setting up encoder on ", AS_CHAR(axis_codes[encoderAxis]), " axis, addr = ", address);
position = get_position();
}
@@ -67,7 +67,7 @@ void I2CPositionEncoder::update() {
/*
if (trusted) { //commented out as part of the note below
trusted = false;
SERIAL_ECHOLMPAIR("Fault detected on ", axis_codes[encoderAxis], " axis encoder. Disengaging error correction until module is trusted again.");
SERIAL_ECHOLNPAIR("Fault detected on ", AS_CHAR(axis_codes[encoderAxis]), " axis encoder. Disengaging error correction until module is trusted again.");
}
*/
return;
@@ -92,7 +92,7 @@ void I2CPositionEncoder::update() {
if (millis() - lastErrorTime > I2CPE_TIME_TRUSTED) {
trusted = true;
SERIAL_ECHOLNPAIR("Untrusted encoder module on ", axis_codes[encoderAxis], " axis has been fault-free for set duration, reinstating error correction.");
SERIAL_ECHOLNPAIR("Untrusted encoder module on ", AS_CHAR(axis_codes[encoderAxis]), " axis has been fault-free for set duration, reinstating error correction.");
//the encoder likely lost its place when the error occured, so we'll reset and use the printer's
//idea of where it the axis is to re-initialize
@@ -172,7 +172,7 @@ void I2CPositionEncoder::update() {
float sumP = 0;
LOOP_L_N(i, I2CPE_ERR_PRST_ARRAY_SIZE) sumP += errPrst[i];
const int32_t errorP = int32_t(sumP * RECIPROCAL(I2CPE_ERR_PRST_ARRAY_SIZE));
SERIAL_ECHO(axis_codes[encoderAxis]);
SERIAL_CHAR(axis_codes[encoderAxis]);
SERIAL_ECHOLNPAIR(" : CORRECT ERR ", errorP * planner.steps_to_mm[encoderAxis], "mm");
babystep.add_steps(encoderAxis, -LROUND(errorP));
errPrstIdx = 0;
@@ -192,8 +192,8 @@ void I2CPositionEncoder::update() {
if (ABS(error) > I2CPE_ERR_CNT_THRESH * planner.settings.axis_steps_per_mm[encoderAxis]) {
const millis_t ms = millis();
if (ELAPSED(ms, nextErrorCountTime)) {
SERIAL_ECHO(axis_codes[encoderAxis]);
SERIAL_ECHOLNPAIR(" : LARGE ERR ", int(error), "; diffSum=", diffSum);
SERIAL_CHAR(axis_codes[encoderAxis]);
SERIAL_ECHOLNPAIR(" : LARGE ERR ", error, "; diffSum=", diffSum);
errorCount++;
nextErrorCountTime = ms + I2CPE_ERR_CNT_DEBOUNCE_MS;
}
@@ -213,7 +213,7 @@ void I2CPositionEncoder::set_homed() {
trusted++;
#ifdef I2CPE_DEBUG
SERIAL_ECHO(axis_codes[encoderAxis]);
SERIAL_CHAR(axis_codes[encoderAxis]);
SERIAL_ECHOLNPAIR(" axis encoder homed, offset of ", zeroOffset, " ticks.");
#endif
}
@@ -224,7 +224,7 @@ void I2CPositionEncoder::set_unhomed() {
homed = trusted = false;
#ifdef I2CPE_DEBUG
SERIAL_ECHO(axis_codes[encoderAxis]);
SERIAL_CHAR(axis_codes[encoderAxis]);
SERIAL_ECHOLNPGM(" axis encoder unhomed.");
#endif
}
@@ -232,7 +232,7 @@ void I2CPositionEncoder::set_unhomed() {
bool I2CPositionEncoder::passes_test(const bool report) {
if (report) {
if (H != I2CPE_MAG_SIG_GOOD) SERIAL_ECHOPGM("Warning. ");
SERIAL_ECHO(axis_codes[encoderAxis]);
SERIAL_CHAR(axis_codes[encoderAxis]);
serial_ternary(H == I2CPE_MAG_SIG_BAD, PSTR(" axis "), PSTR("magnetic strip "), PSTR("encoder "));
switch (H) {
case I2CPE_MAG_SIG_GOOD:
@@ -253,7 +253,7 @@ float I2CPositionEncoder::get_axis_error_mm(const bool report) {
error = ABS(diff) > 10000 ? 0 : diff; // Huge error is a bad reading
if (report) {
SERIAL_ECHO(axis_codes[encoderAxis]);
SERIAL_CHAR(axis_codes[encoderAxis]);
SERIAL_ECHOLNPAIR(" axis target=", target, "mm; actual=", actual, "mm; err=", error, "mm");
}
@@ -263,7 +263,7 @@ float I2CPositionEncoder::get_axis_error_mm(const bool report) {
int32_t I2CPositionEncoder::get_axis_error_steps(const bool report) {
if (!active) {
if (report) {
SERIAL_ECHO(axis_codes[encoderAxis]);
SERIAL_CHAR(axis_codes[encoderAxis]);
SERIAL_ECHOLNPGM(" axis encoder not active!");
}
return 0;
@@ -288,7 +288,7 @@ int32_t I2CPositionEncoder::get_axis_error_steps(const bool report) {
errorPrev = error;
if (report) {
SERIAL_ECHO(axis_codes[encoderAxis]);
SERIAL_CHAR(axis_codes[encoderAxis]);
SERIAL_ECHOLNPAIR(" axis target=", target, "; actual=", encoderCountInStepperTicksScaled, "; err=", error);
}
@@ -667,8 +667,7 @@ void I2CPositionEncodersMgr::report_position(const int8_t idx, const bool units,
else {
if (noOffset) {
const int32_t raw_count = encoders[idx].get_raw_count();
SERIAL_ECHO(axis_codes[encoders[idx].get_axis()]);
SERIAL_CHAR(' ');
SERIAL_CHAR(axis_codes[encoders[idx].get_axis()], ' ');
for (uint8_t j = 31; j > 0; j--)
SERIAL_ECHO((bool)(0x00000001 & (raw_count >> j)));
@@ -723,7 +722,7 @@ void I2CPositionEncodersMgr::change_module_address(const uint8_t oldaddr, const
// and enable it (it will likely have failed initialization on power-up, before the address change).
const int8_t idx = idx_from_addr(newaddr);
if (idx >= 0 && !encoders[idx].get_active()) {
SERIAL_ECHO(axis_codes[encoders[idx].get_axis()]);
SERIAL_CHAR(axis_codes[encoders[idx].get_axis()]);
SERIAL_ECHOLNPGM(" axis encoder was not detected on printer startup. Trying again.");
encoders[idx].set_active(encoders[idx].passes_test(true));
}
@@ -748,7 +747,7 @@ void I2CPositionEncodersMgr::report_module_firmware(const uint8_t address) {
if (Wire.requestFrom(I2C_ADDRESS(address), uint8_t(32))) {
char c;
while (Wire.available() > 0 && (c = (char)Wire.read()) > 0)
SERIAL_ECHO(c);
SERIAL_CHAR(c);
SERIAL_EOL();
}
+5 -5
View File
@@ -261,32 +261,32 @@ class I2CPositionEncodersMgr {
static void report_error_count(const int8_t idx, const AxisEnum axis) {
CHECK_IDX();
SERIAL_ECHOLNPAIR("Error count on ", axis_codes[axis], " axis is ", encoders[idx].get_error_count());
SERIAL_ECHOLNPAIR("Error count on ", AS_CHAR(axis_codes[axis]), " axis is ", encoders[idx].get_error_count());
}
static void reset_error_count(const int8_t idx, const AxisEnum axis) {
CHECK_IDX();
encoders[idx].set_error_count(0);
SERIAL_ECHOLNPAIR("Error count on ", axis_codes[axis], " axis has been reset.");
SERIAL_ECHOLNPAIR("Error count on ", AS_CHAR(axis_codes[axis]), " axis has been reset.");
}
static void enable_ec(const int8_t idx, const bool enabled, const AxisEnum axis) {
CHECK_IDX();
encoders[idx].set_ec_enabled(enabled);
SERIAL_ECHOPAIR("Error correction on ", axis_codes[axis]);
SERIAL_ECHOPAIR("Error correction on ", AS_CHAR(axis_codes[axis]));
SERIAL_ECHO_TERNARY(encoders[idx].get_ec_enabled(), " axis is ", "en", "dis", "abled.\n");
}
static void set_ec_threshold(const int8_t idx, const float newThreshold, const AxisEnum axis) {
CHECK_IDX();
encoders[idx].set_ec_threshold(newThreshold);
SERIAL_ECHOLNPAIR("Error correct threshold for ", axis_codes[axis], " axis set to ", newThreshold, "mm.");
SERIAL_ECHOLNPAIR("Error correct threshold for ", AS_CHAR(axis_codes[axis]), " axis set to ", newThreshold, "mm.");
}
static void get_ec_threshold(const int8_t idx, const AxisEnum axis) {
CHECK_IDX();
const float threshold = encoders[idx].get_ec_threshold();
SERIAL_ECHOLNPAIR("Error correct threshold for ", axis_codes[axis], " axis is ", threshold, "mm.");
SERIAL_ECHOLNPAIR("Error correct threshold for ", AS_CHAR(axis_codes[axis]), " axis is ", threshold, "mm.");
}
static int8_t idx_from_axis(const AxisEnum axis) {
+1 -1
View File
@@ -182,7 +182,7 @@ void host_action(PGM_P const pstr, const bool eol) {
break;
case PROMPT_PAUSE_RESUME:
msg = PSTR("LCD_PAUSE_RESUME");
#if ENABLED(ADVANCED_PAUSE_FEATURE)
#if BOTH(ADVANCED_PAUSE_FEATURE, SDSUPPORT)
extern const char M24_STR[];
queue.inject_P(M24_STR);
#endif
+7 -5
View File
@@ -147,11 +147,13 @@ void LEDLights::set_color(const LEDColor &incol
millis_t LEDLights::led_off_time; // = 0
void LEDLights::update_timeout(const bool power_on) {
const millis_t ms = millis();
if (power_on)
reset_timeout(ms);
else if (ELAPSED(ms, led_off_time))
set_off();
if (lights_on) {
const millis_t ms = millis();
if (power_on)
reset_timeout(ms);
else if (ELAPSED(ms, led_off_time))
set_off();
}
}
#endif
+1 -1
View File
@@ -203,7 +203,7 @@ public:
public:
static inline void reset_timeout(const millis_t &ms) {
led_off_time = ms + LED_BACKLIGHT_TIMEOUT;
if (!lights_on) set_default();
if (!lights_on) update();
}
static void update_timeout(const bool power_on);
#endif
+2 -2
View File
@@ -135,11 +135,11 @@ void Mixer::refresh_collector(const float proportion/*=1.0*/, const uint8_t t/*=
cmax = _MAX(cmax, v);
csum += v;
}
//SERIAL_ECHOPAIR("Mixer::refresh_collector(", proportion, ", ", int(t), ") cmax=", cmax, " csum=", csum, " color");
//SERIAL_ECHOPAIR("Mixer::refresh_collector(", proportion, ", ", t, ") cmax=", cmax, " csum=", csum, " color");
const float inv_prop = proportion / csum;
MIXER_STEPPER_LOOP(i) {
c[i] = color[t][i] * inv_prop;
//SERIAL_ECHOPAIR(" [", int(t), "][", int(i), "] = ", int(color[t][i]), " (", c[i], ") ");
//SERIAL_ECHOPAIR(" [", t, "][", i, "] = ", color[t][i], " (", c[i], ") ");
}
//SERIAL_EOL();
}
+7 -7
View File
@@ -139,9 +139,9 @@ class Mixer {
#ifdef MIXER_NORMALIZER_DEBUG
SERIAL_ECHOPGM("Mix [ ");
SERIAL_ECHOLIST_N(MIXING_STEPPERS, int(mix[0]), int(mix[1]), int(mix[2]), int(mix[3]), int(mix[4]), int(mix[5]));
SERIAL_ECHOLIST_N(MIXING_STEPPERS, mix[0], mix[1], mix[2], mix[3], mix[4], mix[5]);
SERIAL_ECHOPGM(" ] to Color [ ");
SERIAL_ECHOLIST_N(MIXING_STEPPERS, int(tcolor[0]), int(tcolor[1]), int(tcolor[2]), int(tcolor[3]), int(tcolor[4]), int(tcolor[5]));
SERIAL_ECHOLIST_N(MIXING_STEPPERS, tcolor[0], tcolor[1], tcolor[2], tcolor[3], tcolor[4], tcolor[5]);
SERIAL_ECHOLNPGM(" ]");
#endif
}
@@ -153,10 +153,10 @@ class Mixer {
MIXER_STEPPER_LOOP(i) mix[i] = mixer_perc_t(100.0f * color[j][i] / ctot);
#ifdef MIXER_NORMALIZER_DEBUG
SERIAL_ECHOPAIR("V-tool ", int(j), " [ ");
SERIAL_ECHOLIST_N(MIXING_STEPPERS, int(color[j][0]), int(color[j][1]), int(color[j][2]), int(color[j][3]), int(color[j][4]), int(color[j][5]));
SERIAL_ECHOPAIR("V-tool ", j, " [ ");
SERIAL_ECHOLIST_N(MIXING_STEPPERS, color[j][0], color[j][1], color[j][2], color[j][3], color[j][4], color[j][5]);
SERIAL_ECHOPGM(" ] to Mix [ ");
SERIAL_ECHOLIST_N(MIXING_STEPPERS, int(mix[0]), int(mix[1]), int(mix[2]), int(mix[3]), int(mix[4]), int(mix[5]));
SERIAL_ECHOLIST_N(MIXING_STEPPERS, mix[0], mix[1], mix[2], mix[3], mix[4], mix[5]);
SERIAL_ECHOLNPGM(" ]");
#endif
}
@@ -199,9 +199,9 @@ class Mixer {
#ifdef MIXER_NORMALIZER_DEBUG
SERIAL_ECHOPGM("Gradient [ ");
SERIAL_ECHOLIST_N(MIXING_STEPPERS, int(gradient.color[0]), int(gradient.color[1]), int(gradient.color[2]), int(gradient.color[3]), int(gradient.color[4]), int(gradient.color[5]));
SERIAL_ECHOLIST_N(MIXING_STEPPERS, gradient.color[0], gradient.color[1], gradient.color[2], gradient.color[3], gradient.color[4], gradient.color[5]);
SERIAL_ECHOPGM(" ] to Mix [ ");
SERIAL_ECHOLIST_N(MIXING_STEPPERS, int(mix[0]), int(mix[1]), int(mix[2]), int(mix[3]), int(mix[4]), int(mix[5]));
SERIAL_ECHOLIST_N(MIXING_STEPPERS, mix[0], mix[1], mix[2], mix[3], mix[4], mix[5]);
SERIAL_ECHOLNPGM(" ]");
#endif
}
+4 -9
View File
@@ -287,9 +287,7 @@ void MMU2::mmu_loop() {
else if (WITHIN(cmd, MMU_CMD_F0, MMU_CMD_F4)) {
// filament type
int filament = cmd - MMU_CMD_F0;
DEBUG_ECHOPAIR("MMU <= F", filament, " ");
DEBUG_ECHO_F(cmd_arg, DEC);
DEBUG_EOL();
DEBUG_ECHOLNPAIR("MMU <= F", filament, " ", cmd_arg);
tx_printf_P(PSTR("F%d %d\n"), filament, cmd_arg);
state = 3; // wait for response
}
@@ -514,8 +512,7 @@ static void mmu2_not_responding() {
extruder = index; // filament change is finished
active_extruder = 0;
ENABLE_AXIS_E0();
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR(STR_ACTIVE_EXTRUDER, int(extruder));
SERIAL_ECHO_MSG(STR_ACTIVE_EXTRUDER, extruder);
}
ui.reset_status();
}
@@ -602,8 +599,7 @@ static void mmu2_not_responding() {
active_extruder = 0;
ENABLE_AXIS_E0();
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR(STR_ACTIVE_EXTRUDER, int(extruder));
SERIAL_ECHO_MSG(STR_ACTIVE_EXTRUDER, extruder);
ui.reset_status();
}
@@ -698,8 +694,7 @@ static void mmu2_not_responding() {
extruder = index; //filament change is finished
active_extruder = 0;
ENABLE_AXIS_E0();
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR(STR_ACTIVE_EXTRUDER, int(extruder));
SERIAL_ECHO_MSG(STR_ACTIVE_EXTRUDER, extruder);
ui.reset_status();
}
+7 -7
View File
@@ -130,7 +130,7 @@ fil_change_settings_t fc_settings[EXTRUDERS];
*/
static bool ensure_safe_temperature(const bool wait=true, const PauseMode mode=PAUSE_MODE_SAME) {
DEBUG_SECTION(est, "ensure_safe_temperature", true);
DEBUG_ECHOLNPAIR("... wait:", int(wait), " mode:", int(mode));
DEBUG_ECHOLNPAIR("... wait:", wait, " mode:", mode);
#if ENABLED(PREVENT_COLD_EXTRUSION)
if (!DEBUGGING(DRYRUN) && thermalManager.targetTooColdToExtrude(active_extruder))
@@ -176,7 +176,7 @@ bool load_filament(const float &slow_load_length/*=0*/, const float &fast_load_l
DXC_ARGS
) {
DEBUG_SECTION(lf, "load_filament", true);
DEBUG_ECHOLNPAIR("... slowlen:", slow_load_length, " fastlen:", fast_load_length, " purgelen:", purge_length, " maxbeep:", int(max_beep_count), " showlcd:", int(show_lcd), " pauseforuser:", int(pause_for_user), " pausemode:", int(mode) DXC_SAY);
DEBUG_ECHOLNPAIR("... slowlen:", slow_load_length, " fastlen:", fast_load_length, " purgelen:", purge_length, " maxbeep:", max_beep_count, " showlcd:", show_lcd, " pauseforuser:", pause_for_user, " pausemode:", mode DXC_SAY);
if (!ensure_safe_temperature(false, mode)) {
if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_STATUS, mode);
@@ -309,7 +309,7 @@ bool unload_filament(const float &unload_length, const bool show_lcd/*=false*/,
#endif
) {
DEBUG_SECTION(uf, "unload_filament", true);
DEBUG_ECHOLNPAIR("... unloadlen:", unload_length, " showlcd:", int(show_lcd), " mode:", int(mode)
DEBUG_ECHOLNPAIR("... unloadlen:", unload_length, " showlcd:", show_lcd, " mode:", mode
#if BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER)
, " mixmult:", mix_multiplier
#endif
@@ -373,7 +373,7 @@ uint8_t did_pause_print = 0;
bool pause_print(const float &retract, const xyz_pos_t &park_point, const float &unload_length/*=0*/, const bool show_lcd/*=false*/ DXC_ARGS) {
DEBUG_SECTION(pp, "pause_print", true);
DEBUG_ECHOLNPAIR("... park.x:", park_point.x, " y:", park_point.y, " z:", park_point.z, " unloadlen:", unload_length, " showlcd:", int(show_lcd) DXC_SAY);
DEBUG_ECHOLNPAIR("... park.x:", park_point.x, " y:", park_point.y, " z:", park_point.z, " unloadlen:", unload_length, " showlcd:", show_lcd DXC_SAY);
UNUSED(show_lcd);
@@ -456,7 +456,7 @@ bool pause_print(const float &retract, const xyz_pos_t &park_point, const float
void show_continue_prompt(const bool is_reload) {
DEBUG_SECTION(scp, "pause_print", true);
DEBUG_ECHOLNPAIR("... is_reload:", int(is_reload));
DEBUG_ECHOLNPAIR("... is_reload:", is_reload);
ui.pause_show_message(is_reload ? PAUSE_MESSAGE_INSERT : PAUSE_MESSAGE_WAITING);
SERIAL_ECHO_START();
@@ -465,7 +465,7 @@ void show_continue_prompt(const bool is_reload) {
void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep_count/*=0*/ DXC_ARGS) {
DEBUG_SECTION(wfc, "wait_for_confirmation", true);
DEBUG_ECHOLNPAIR("... is_reload:", is_reload, " maxbeep:", int(max_beep_count) DXC_SAY);
DEBUG_ECHOLNPAIR("... is_reload:", is_reload, " maxbeep:", max_beep_count DXC_SAY);
bool nozzle_timed_out = false;
@@ -561,7 +561,7 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep
*/
void resume_print(const float &slow_load_length/*=0*/, const float &fast_load_length/*=0*/, const float &purge_length/*=ADVANCED_PAUSE_PURGE_LENGTH*/, const int8_t max_beep_count/*=0*/, int16_t targetTemp/*=0*/ DXC_ARGS) {
DEBUG_SECTION(rp, "resume_print", true);
DEBUG_ECHOLNPAIR("... slowlen:", slow_load_length, " fastlen:", fast_load_length, " purgelen:", purge_length, " maxbeep:", int(max_beep_count), " targetTemp:", targetTemp DXC_SAY);
DEBUG_ECHOLNPAIR("... slowlen:", slow_load_length, " fastlen:", fast_load_length, " purgelen:", purge_length, " maxbeep:", max_beep_count, " targetTemp:", targetTemp DXC_SAY);
/*
SERIAL_ECHOLNPAIR(
+6 -6
View File
@@ -532,7 +532,7 @@ void PrintJobRecovery::resume() {
void PrintJobRecovery::debug(PGM_P const prefix) {
DEBUG_PRINT_P(prefix);
DEBUG_ECHOLNPAIR(" Job Recovery Info...\nvalid_head:", int(info.valid_head), " valid_foot:", int(info.valid_foot));
DEBUG_ECHOLNPAIR(" Job Recovery Info...\nvalid_head:", info.valid_head, " valid_foot:", info.valid_foot);
if (info.valid_head) {
if (info.valid_head == info.valid_foot) {
DEBUG_ECHOPGM("current_position: ");
@@ -565,7 +565,7 @@ void PrintJobRecovery::resume() {
DEBUG_ECHOLNPAIR("feedrate: ", info.feedrate);
#if HAS_MULTI_EXTRUDER
DEBUG_ECHOLNPAIR("active_extruder: ", int(info.active_extruder));
DEBUG_ECHOLNPAIR("active_extruder: ", info.active_extruder);
#endif
#if HAS_HOTEND
@@ -584,14 +584,14 @@ void PrintJobRecovery::resume() {
#if HAS_FAN
DEBUG_ECHOPGM("fan_speed: ");
FANS_LOOP(i) {
DEBUG_ECHO(int(info.fan_speed[i]));
DEBUG_ECHO(info.fan_speed[i]);
if (i < FAN_COUNT - 1) DEBUG_CHAR(',');
}
DEBUG_EOL();
#endif
#if HAS_LEVELING
DEBUG_ECHOLNPAIR("leveling: ", int(info.flag.leveling), " fade: ", info.fade);
DEBUG_ECHOLNPAIR("leveling: ", info.flag.leveling, " fade: ", info.fade);
#endif
#if ENABLED(FWRETRACT)
DEBUG_ECHOPGM("retract: ");
@@ -605,8 +605,8 @@ void PrintJobRecovery::resume() {
DEBUG_ECHOLNPAIR("sd_filename: ", info.sd_filename);
DEBUG_ECHOLNPAIR("sdpos: ", info.sdpos);
DEBUG_ECHOLNPAIR("print_job_elapsed: ", info.print_job_elapsed);
DEBUG_ECHOLNPAIR("dryrun: ", int(info.flag.dryrun));
DEBUG_ECHOLNPAIR("allow_cold_extrusion: ", int(info.flag.allow_cold_extrusion));
DEBUG_ECHOLNPAIR("dryrun: ", info.flag.dryrun);
DEBUG_ECHOLNPAIR("allow_cold_extrusion: ", info.flag.allow_cold_extrusion);
}
else
DEBUG_ECHOLNPGM("INVALID DATA");
+3 -3
View File
@@ -43,7 +43,7 @@ void Repeat::add_marker(const uint32_t sdpos, const uint16_t count) {
marker[index].sdpos = sdpos;
marker[index].counter = count ?: -1;
index++;
DEBUG_ECHOLNPAIR("Add Marker ", int(index), " at ", sdpos, " (", count, ")");
DEBUG_ECHOLNPAIR("Add Marker ", index, " at ", sdpos, " (", count, ")");
}
}
@@ -53,14 +53,14 @@ void Repeat::loop() {
else {
const uint8_t ind = index - 1; // Active marker's index
if (!marker[ind].counter) { // Did its counter run out?
DEBUG_ECHOLNPAIR("Pass Marker ", int(index));
DEBUG_ECHOLNPAIR("Pass Marker ", index);
index--; // Carry on. Previous marker on the next 'M808'.
}
else {
card.setIndex(marker[ind].sdpos); // Loop back to the marker.
if (marker[ind].counter > 0) // Ignore a negative (or zero) counter.
--marker[ind].counter; // Decrement the counter. If zero this 'M808' will be skipped next time.
DEBUG_ECHOLNPAIR("Goto Marker ", int(index), " at ", marker[ind].sdpos, " (", marker[ind].counter, ")");
DEBUG_ECHOLNPAIR("Goto Marker ", index, " at ", marker[ind].sdpos, " (", marker[ind].counter, ")");
}
}
}
+32 -32
View File
@@ -233,10 +233,10 @@
void report_polled_driver_data(TMC &st, const TMC_driver_data &data) {
const uint32_t pwm_scale = get_pwm_scale(st);
st.printLabel();
SERIAL_CHAR(':'); SERIAL_PRINT(pwm_scale, DEC);
SERIAL_CHAR(':'); SERIAL_ECHO(pwm_scale);
#if ENABLED(TMC_DEBUG)
#if HAS_TMCX1X0 || HAS_TMC220x
SERIAL_CHAR('/'); SERIAL_PRINT(data.cs_actual, DEC);
SERIAL_CHAR('/'); SERIAL_ECHO(data.cs_actual);
#endif
#if HAS_STALLGUARD
SERIAL_CHAR('/');
@@ -257,7 +257,7 @@
#endif
if (st.flag_otpw) SERIAL_CHAR('F'); // otpw Flag
SERIAL_CHAR('|');
if (st.otpw_count > 0) SERIAL_PRINT(st.otpw_count, DEC);
if (st.otpw_count > 0) SERIAL_ECHO(st.otpw_count);
SERIAL_CHAR('\t');
}
@@ -551,8 +551,8 @@
#if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC5130)
static void _tmc_status(TMC2130Stepper &st, const TMC_debug_enum i) {
switch (i) {
case TMC_PWM_SCALE: SERIAL_PRINT(st.PWM_SCALE(), DEC); break;
case TMC_SGT: SERIAL_PRINT(st.sgt(), DEC); break;
case TMC_PWM_SCALE: SERIAL_ECHO(st.PWM_SCALE()); break;
case TMC_SGT: SERIAL_ECHO(st.sgt()); break;
case TMC_STEALTHCHOP: serialprint_truefalse(st.en_pwm_mode()); break;
case TMC_INTERPOLATE: serialprint_truefalse(st.intpol()); break;
default: break;
@@ -563,9 +563,9 @@
static void _tmc_parse_drv_status(TMC2130Stepper &st, const TMC_drv_status_enum i) {
switch (i) {
case TMC_STALLGUARD: if (st.stallguard()) SERIAL_CHAR('*'); break;
case TMC_SG_RESULT: SERIAL_PRINT(st.sg_result(), DEC); break;
case TMC_SG_RESULT: SERIAL_ECHO(st.sg_result()); break;
case TMC_FSACTIVE: if (st.fsactive()) SERIAL_CHAR('*'); break;
case TMC_DRV_CS_ACTUAL: SERIAL_PRINT(st.cs_actual(), DEC); break;
case TMC_DRV_CS_ACTUAL: SERIAL_ECHO(st.cs_actual()); break;
default: break;
}
}
@@ -580,13 +580,13 @@
static void _tmc_status(TMC2160Stepper &st, const TMC_debug_enum i) {
switch (i) {
case TMC_PWM_SCALE: SERIAL_PRINT(st.PWM_SCALE(), DEC); break;
case TMC_SGT: SERIAL_PRINT(st.sgt(), DEC); break;
case TMC_PWM_SCALE: SERIAL_ECHO(st.PWM_SCALE()); break;
case TMC_SGT: SERIAL_ECHO(st.sgt()); break;
case TMC_STEALTHCHOP: serialprint_truefalse(st.en_pwm_mode()); break;
case TMC_GLOBAL_SCALER:
{
uint16_t value = st.GLOBAL_SCALER();
SERIAL_PRINT(value ?: 256, DEC);
SERIAL_ECHO(value ? value : 256);
SERIAL_ECHOPGM("/256");
}
break;
@@ -599,10 +599,10 @@
#if HAS_TMC220x
static void _tmc_status(TMC2208Stepper &st, const TMC_debug_enum i) {
switch (i) {
case TMC_PWM_SCALE_SUM: SERIAL_PRINT(st.pwm_scale_sum(), DEC); break;
case TMC_PWM_SCALE_AUTO: SERIAL_PRINT(st.pwm_scale_auto(), DEC); break;
case TMC_PWM_OFS_AUTO: SERIAL_PRINT(st.pwm_ofs_auto(), DEC); break;
case TMC_PWM_GRAD_AUTO: SERIAL_PRINT(st.pwm_grad_auto(), DEC); break;
case TMC_PWM_SCALE_SUM: SERIAL_ECHO(st.pwm_scale_sum()); break;
case TMC_PWM_SCALE_AUTO: SERIAL_ECHO(st.pwm_scale_auto()); break;
case TMC_PWM_OFS_AUTO: SERIAL_ECHO(st.pwm_ofs_auto()); break;
case TMC_PWM_GRAD_AUTO: SERIAL_ECHO(st.pwm_grad_auto()); break;
case TMC_STEALTHCHOP: serialprint_truefalse(st.stealth()); break;
case TMC_INTERPOLATE: serialprint_truefalse(st.intpol()); break;
default: break;
@@ -613,8 +613,8 @@
template<char AXIS_LETTER, char DRIVER_ID, AxisEnum AXIS_ID>
static void _tmc_status(TMCMarlin<TMC2209Stepper, AXIS_LETTER, DRIVER_ID, AXIS_ID> &st, const TMC_debug_enum i) {
switch (i) {
case TMC_SGT: SERIAL_PRINT(st.SGTHRS(), DEC); break;
case TMC_UART_ADDR: SERIAL_PRINT(st.get_address(), DEC); break;
case TMC_SGT: SERIAL_ECHO(st.SGTHRS()); break;
case TMC_UART_ADDR: SERIAL_ECHO(st.get_address()); break;
default:
TMC2208Stepper *parent = &st;
_tmc_status(*parent, i);
@@ -631,7 +631,7 @@
case TMC_T120: if (st.t120()) SERIAL_CHAR('*'); break;
case TMC_S2VSA: if (st.s2vsa()) SERIAL_CHAR('*'); break;
case TMC_S2VSB: if (st.s2vsb()) SERIAL_CHAR('*'); break;
case TMC_DRV_CS_ACTUAL: SERIAL_PRINT(st.cs_actual(), DEC); break;
case TMC_DRV_CS_ACTUAL: SERIAL_ECHO(st.cs_actual()); break;
default: break;
}
}
@@ -639,7 +639,7 @@
#if HAS_DRIVER(TMC2209)
static void _tmc_parse_drv_status(TMC2209Stepper &st, const TMC_drv_status_enum i) {
switch (i) {
case TMC_SG_RESULT: SERIAL_PRINT(st.SG_RESULT(), DEC); break;
case TMC_SG_RESULT: SERIAL_ECHO(st.SG_RESULT()); break;
default: _tmc_parse_drv_status(static_cast<TMC2208Stepper &>(st), i); break;
}
}
@@ -666,15 +666,15 @@
case TMC_RMS_CURRENT: SERIAL_ECHO(st.rms_current()); break;
case TMC_MAX_CURRENT: SERIAL_PRINT((float)st.rms_current() * 1.41, 0); break;
case TMC_IRUN:
SERIAL_PRINT(st.irun(), DEC);
SERIAL_ECHO(st.irun());
SERIAL_ECHOPGM("/31");
break;
case TMC_IHOLD:
SERIAL_PRINT(st.ihold(), DEC);
SERIAL_ECHO(st.ihold());
SERIAL_ECHOPGM("/31");
break;
case TMC_CS_ACTUAL:
SERIAL_PRINT(st.cs_actual(), DEC);
SERIAL_ECHO(st.cs_actual());
SERIAL_ECHOPGM("/31");
break;
case TMC_VSENSE: print_vsense(st); break;
@@ -694,11 +694,11 @@
#if ENABLED(MONITOR_DRIVER_STATUS)
case TMC_OTPW_TRIGGERED: serialprint_truefalse(st.getOTPW()); break;
#endif
case TMC_TOFF: SERIAL_PRINT(st.toff(), DEC); break;
case TMC_TBL: SERIAL_PRINT(st.blank_time(), DEC); break;
case TMC_HEND: SERIAL_PRINT(st.hysteresis_end(), DEC); break;
case TMC_HSTRT: SERIAL_PRINT(st.hysteresis_start(), DEC); break;
case TMC_MSCNT: SERIAL_PRINT(st.get_microstep_counter(), DEC); break;
case TMC_TOFF: SERIAL_ECHO(st.toff()); break;
case TMC_TBL: SERIAL_ECHO(st.blank_time()); break;
case TMC_HEND: SERIAL_ECHO(st.hysteresis_end()); break;
case TMC_HSTRT: SERIAL_ECHO(st.hysteresis_start()); break;
case TMC_MSCNT: SERIAL_ECHO(st.get_microstep_counter()); break;
default: _tmc_status(st, i); break;
}
}
@@ -714,18 +714,18 @@
case TMC_RMS_CURRENT: SERIAL_ECHO(st.rms_current()); break;
case TMC_MAX_CURRENT: SERIAL_PRINT((float)st.rms_current() * 1.41, 0); break;
case TMC_IRUN:
SERIAL_PRINT(st.cs(), DEC);
SERIAL_ECHO(st.cs());
SERIAL_ECHOPGM("/31");
break;
case TMC_VSENSE: serialprintPGM(st.vsense() ? PSTR("1=.165") : PSTR("0=.310")); break;
case TMC_MICROSTEPS: SERIAL_ECHO(st.microsteps()); break;
//case TMC_OTPW: serialprint_truefalse(st.otpw()); break;
//case TMC_OTPW_TRIGGERED: serialprint_truefalse(st.getOTPW()); break;
case TMC_SGT: SERIAL_PRINT(st.sgt(), DEC); break;
case TMC_TOFF: SERIAL_PRINT(st.toff(), DEC); break;
case TMC_TBL: SERIAL_PRINT(st.blank_time(), DEC); break;
case TMC_HEND: SERIAL_PRINT(st.hysteresis_end(), DEC); break;
case TMC_HSTRT: SERIAL_PRINT(st.hysteresis_start(), DEC); break;
case TMC_SGT: SERIAL_ECHO(st.sgt()); break;
case TMC_TOFF: SERIAL_ECHO(st.toff()); break;
case TMC_TBL: SERIAL_ECHO(st.blank_time()); break;
case TMC_HEND: SERIAL_ECHO(st.hysteresis_end()); break;
case TMC_HSTRT: SERIAL_ECHO(st.hysteresis_start()); break;
default: break;
}
}
+1 -1
View File
@@ -537,7 +537,7 @@ void GcodeSuite::G26() {
if (bedtemp) {
if (!WITHIN(bedtemp, 40, BED_MAX_TARGET)) {
SERIAL_ECHOLNPAIR("?Specified bed temperature not plausible (40-", int(BED_MAX_TARGET), "C).");
SERIAL_ECHOLNPAIR("?Specified bed temperature not plausible (40-", BED_MAX_TARGET, "C).");
return;
}
g26_bed_temp = bedtemp;
+2 -2
View File
@@ -104,7 +104,7 @@ void GcodeSuite::G35() {
const float z_probed_height = probe.probe_at_point(screws_tilt_adjust_pos[i], PROBE_PT_RAISE, 0, true);
if (isnan(z_probed_height)) {
SERIAL_ECHOPAIR("G35 failed at point ", int(i), " (");
SERIAL_ECHOPAIR("G35 failed at point ", i, " (");
SERIAL_ECHOPGM_P((char *)pgm_read_ptr(&tramming_point_name[i]));
SERIAL_CHAR(')');
SERIAL_ECHOLNPAIR_P(SP_X_STR, screws_tilt_adjust_pos[i].x, SP_Y_STR, screws_tilt_adjust_pos[i].y);
@@ -113,7 +113,7 @@ void GcodeSuite::G35() {
}
if (DEBUGGING(LEVELING)) {
DEBUG_ECHOPAIR("Probing point ", int(i), " (");
DEBUG_ECHOPAIR("Probing point ", i, " (");
DEBUG_PRINT_P((char *)pgm_read_ptr(&tramming_point_name[i]));
DEBUG_CHAR(')');
DEBUG_ECHOLNPAIR_P(SP_X_STR, screws_tilt_adjust_pos[i].x, SP_Y_STR, screws_tilt_adjust_pos[i].y, SP_Z_STR, z_probed_height);
+2 -2
View File
@@ -637,7 +637,7 @@ G29_TYPE GcodeSuite::G29() {
// Avoid probing outside the round or hexagonal area
if (TERN0(IS_KINEMATIC, !probe.can_reach(probePos))) continue;
if (verbose_level) SERIAL_ECHOLNPAIR("Probing mesh point ", int(pt_index), "/", abl_points, ".");
if (verbose_level) SERIAL_ECHOLNPAIR("Probing mesh point ", pt_index, "/", abl_points, ".");
TERN_(HAS_DISPLAY, ui.status_printf_P(0, PSTR(S_FMT " %i/%i"), GET_TEXT(MSG_PROBING_MESH), int(pt_index), int(abl_points)));
measured_z = faux ? 0.001f * random(-100, 101) : probe.probe_at_point(probePos, raise_after, verbose_level);
@@ -682,7 +682,7 @@ G29_TYPE GcodeSuite::G29() {
// Probe at 3 arbitrary points
LOOP_L_N(i, 3) {
if (verbose_level) SERIAL_ECHOLNPAIR("Probing point ", int(i + 1), "/3.");
if (verbose_level) SERIAL_ECHOLNPAIR("Probing point ", i + 1, "/3.");
TERN_(HAS_DISPLAY, ui.status_printf_P(0, PSTR(S_FMT " %i/3"), GET_TEXT(MSG_PROBING_MESH), int(i + 1)));
// Retain the last probe position
+4 -8
View File
@@ -142,8 +142,7 @@ void GcodeSuite::G29() {
if (parser.seenval('I')) {
ix = parser.value_int();
if (!WITHIN(ix, 0, GRID_MAX_POINTS_X - 1)) {
SERIAL_ECHOPAIR("I out of range (0-", int(GRID_MAX_POINTS_X - 1));
SERIAL_ECHOLNPGM(")");
SERIAL_ECHOLNPAIR("I out of range (0-", GRID_MAX_POINTS_X - 1, ")");
return;
}
}
@@ -153,8 +152,7 @@ void GcodeSuite::G29() {
if (parser.seenval('J')) {
iy = parser.value_int();
if (!WITHIN(iy, 0, GRID_MAX_POINTS_Y - 1)) {
SERIAL_ECHOPAIR("J out of range (0-", int(GRID_MAX_POINTS_Y - 1));
SERIAL_ECHOLNPGM(")");
SERIAL_ECHOLNPAIR("J out of range (0-", GRID_MAX_POINTS_Y - 1, ")");
return;
}
}
@@ -182,10 +180,8 @@ void GcodeSuite::G29() {
} // switch(state)
if (state == MeshNext) {
SERIAL_ECHOPAIR("MBL G29 point ", _MIN(mbl_probe_index, GRID_MAX_POINTS));
SERIAL_ECHOLNPAIR(" of ", int(GRID_MAX_POINTS));
}
if (state == MeshNext)
SERIAL_ECHOLNPAIR("MBL G29 point ", _MIN(mbl_probe_index, GRID_MAX_POINTS), " of ", GRID_MAX_POINTS);
report_current_position();
}
+1 -1
View File
@@ -96,7 +96,7 @@
};
#endif
do_blocking_move_to_xy(1.5 * mlx * x_axis_home_dir, 1.5 * mly * home_dir(Y_AXIS), fr_mm_s);
do_blocking_move_to_xy(1.5 * mlx * x_axis_home_dir, 1.5 * mly * Y_HOME_DIR, fr_mm_s);
endstops.validate_homing_move();
+9 -9
View File
@@ -238,7 +238,7 @@ void GcodeSuite::G34() {
// the next iteration of probing. This allows adjustments to be made away from the bed.
z_measured[iprobe] = z_probed_height + Z_CLEARANCE_BETWEEN_PROBES;
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("> Z", int(iprobe + 1), " measured position is ", z_measured[iprobe]);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("> Z", iprobe + 1, " measured position is ", z_measured[iprobe]);
// Remember the minimum measurement to calculate the correction later on
z_measured_min = _MIN(z_measured_min, z_measured[iprobe]);
@@ -267,7 +267,7 @@ void GcodeSuite::G34() {
linear_fit_data lfd;
incremental_LSF_reset(&lfd);
LOOP_L_N(i, NUM_Z_STEPPER_DRIVERS) {
SERIAL_ECHOLNPAIR("PROBEPT_", int(i), ": ", z_measured[i]);
SERIAL_ECHOLNPAIR("PROBEPT_", i, ": ", z_measured[i]);
incremental_LSF(&lfd, z_stepper_align.xy[i], z_measured[i]);
}
finish_incremental_LSF(&lfd);
@@ -357,8 +357,8 @@ void GcodeSuite::G34() {
// Check for less accuracy compared to last move
if (decreasing_accuracy(last_z_align_move[zstepper], z_align_abs)) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("> Z", int(zstepper + 1), " last_z_align_move = ", last_z_align_move[zstepper]);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("> Z", int(zstepper + 1), " z_align_abs = ", z_align_abs);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("> Z", zstepper + 1, " last_z_align_move = ", last_z_align_move[zstepper]);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("> Z", zstepper + 1, " z_align_abs = ", z_align_abs);
adjustment_reverse = !adjustment_reverse;
}
@@ -370,7 +370,7 @@ void GcodeSuite::G34() {
// Stop early if all measured points achieve accuracy target
if (z_align_abs > z_auto_align_accuracy) success_break = false;
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("> Z", int(zstepper + 1), " corrected by ", z_align_move);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("> Z", zstepper + 1, " corrected by ", z_align_move);
// Lock all steppers except one
stepper.set_all_z_lock(true, zstepper);
@@ -380,7 +380,7 @@ void GcodeSuite::G34() {
// Will match reversed Z steppers on dual steppers. Triple will need more work to map.
if (adjustment_reverse) {
z_align_move = -z_align_move;
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("> Z", int(zstepper + 1), " correction reversed to ", z_align_move);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("> Z", zstepper + 1, " correction reversed to ", z_align_move);
}
#endif
@@ -406,7 +406,7 @@ void GcodeSuite::G34() {
if (err_break)
SERIAL_ECHOLNPGM("G34 aborted.");
else {
SERIAL_ECHOLNPAIR("Did ", int(iteration + (iteration != z_auto_align_iterations)), " of ", int(z_auto_align_iterations));
SERIAL_ECHOLNPAIR("Did ", iteration + (iteration != z_auto_align_iterations), " of ", z_auto_align_iterations);
SERIAL_ECHOLNPAIR_F("Accuracy: ", z_maxdiff);
}
@@ -467,10 +467,10 @@ void GcodeSuite::M422() {
if (!parser.seen_any()) {
LOOP_L_N(i, NUM_Z_STEPPER_DRIVERS)
SERIAL_ECHOLNPAIR_P(PSTR("M422 S"), int(i + 1), SP_X_STR, z_stepper_align.xy[i].x, SP_Y_STR, z_stepper_align.xy[i].y);
SERIAL_ECHOLNPAIR_P(PSTR("M422 S"), i + 1, SP_X_STR, z_stepper_align.xy[i].x, SP_Y_STR, z_stepper_align.xy[i].y);
#if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS)
LOOP_L_N(i, NUM_Z_STEPPER_DRIVERS)
SERIAL_ECHOLNPAIR_P(PSTR("M422 W"), int(i + 1), SP_X_STR, z_stepper_align.stepper_xy[i].x, SP_Y_STR, z_stepper_align.stepper_xy[i].y);
SERIAL_ECHOLNPAIR_P(PSTR("M422 W"), i + 1, SP_X_STR, z_stepper_align.stepper_xy[i].x, SP_Y_STR, z_stepper_align.stepper_xy[i].y);
#endif
return;
}
+2 -2
View File
@@ -375,7 +375,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
inline void report_measured_positional_error(const measurements_t &m) {
SERIAL_CHAR('T');
SERIAL_ECHO(int(active_extruder));
SERIAL_ECHO(active_extruder);
SERIAL_ECHOLNPGM(" Positional Error:");
#if HAS_X_CENTER
SERIAL_ECHOLNPAIR_P(SP_X_STR, m.pos_error.x);
@@ -408,7 +408,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
//
inline void report_hotend_offsets() {
LOOP_S_L_N(e, 1, HOTENDS)
SERIAL_ECHOLNPAIR_P(PSTR("T"), int(e), PSTR(" Hotend Offset X"), hotend_offset[e].x, SP_Y_STR, hotend_offset[e].y, SP_Z_STR, hotend_offset[e].z);
SERIAL_ECHOLNPAIR_P(PSTR("T"), e, PSTR(" Hotend Offset X"), hotend_offset[e].x, SP_Y_STR, hotend_offset[e].y, SP_Z_STR, hotend_offset[e].z);
}
#endif
+1 -1
View File
@@ -241,7 +241,7 @@ void GcodeSuite::M48() {
if (verbose_level > 1) {
SERIAL_ECHO(n + 1);
SERIAL_ECHOPAIR(" of ", int(n_samples));
SERIAL_ECHOPAIR(" of ", n_samples);
SERIAL_ECHOPAIR_F(": z: ", pz, 3);
SERIAL_CHAR(' ');
dev_report(verbose_level > 2, mean, sigma, min, max);
+1 -1
View File
@@ -47,7 +47,7 @@ void M217_report(const bool eeprom=false) {
" G", toolchange_settings.fan_time);
#if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
SERIAL_ECHOPAIR(" A", int(migration.automode));
SERIAL_ECHOPAIR(" A", migration.automode);
SERIAL_ECHOPAIR(" L", LINEAR_UNIT(migration.last));
#endif
+8 -8
View File
@@ -34,7 +34,9 @@
* U<angle> - Stowed Angle
*/
void GcodeSuite::M281() {
if (!parser.seenval('P')) return;
const int servo_index = parser.value_int();
if (WITHIN(servo_index, 0, NUM_SERVOS - 1)) {
#if ENABLED(BLTOUCH)
@@ -53,16 +55,14 @@ void GcodeSuite::M281() {
angle_change = true;
}
if (!angle_change) {
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR(" Servo ", servo_index,
" L", servo_angles[servo_index][0],
" U", servo_angles[servo_index][1]);
SERIAL_ECHO_MSG(" Servo ", servo_index,
" L", servo_angles[servo_index][0],
" U", servo_angles[servo_index][1]);
}
}
else {
SERIAL_ERROR_START();
SERIAL_ECHOLNPAIR("Servo ", servo_index, " out of range");
}
else
SERIAL_ERROR_MSG("Servo ", servo_index, " out of range");
}
#endif // EDITABLE_SERVO_ANGLES
+5 -4
View File
@@ -35,14 +35,15 @@
* D<dval> - Set the D value
*/
void GcodeSuite::M304() {
if (parser.seen('P')) thermalManager.temp_bed.pid.Kp = parser.value_float();
if (parser.seen('I')) thermalManager.temp_bed.pid.Ki = scalePID_i(parser.value_float());
if (parser.seen('D')) thermalManager.temp_bed.pid.Kd = scalePID_d(parser.value_float());
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR(" p:", thermalManager.temp_bed.pid.Kp,
" i:", unscalePID_i(thermalManager.temp_bed.pid.Ki),
" d:", unscalePID_d(thermalManager.temp_bed.pid.Kd));
SERIAL_ECHO_MSG(" p:", thermalManager.temp_bed.pid.Kp,
" i:", unscalePID_i(thermalManager.temp_bed.pid.Ki),
" d:", unscalePID_d(thermalManager.temp_bed.pid.Kd));
}
#endif // PIDTEMPBED
+2 -4
View File
@@ -49,10 +49,8 @@ void GcodeSuite::M305() {
const bool do_set = parser.seen("BCRT");
// A valid P index is required
if (t_index >= (USER_THERMISTORS) || (do_set && t_index < 0)) {
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR("!Invalid index. (0 <= P <= ", int(USER_THERMISTORS - 1), ")");
}
if (t_index >= (USER_THERMISTORS) || (do_set && t_index < 0))
SERIAL_ECHO_MSG("!Invalid index. (0 <= P <= ", USER_THERMISTORS - 1, ")");
else if (do_set) {
if (parser.seen('R')) // Pullup resistor value
if (!thermalManager.set_pull_up_res(t_index, parser.value_float()))
+3 -3
View File
@@ -131,7 +131,7 @@ inline void servo_probe_test() {
const uint8_t probe_index = parser.byteval('P', Z_PROBE_SERVO_NR);
SERIAL_ECHOLNPAIR("Servo probe test\n"
". using index: ", int(probe_index),
". using index: ", probe_index,
", deploy angle: ", servo_angles[probe_index][0],
", stow angle: ", servo_angles[probe_index][1]
);
@@ -143,7 +143,7 @@ inline void servo_probe_test() {
#define PROBE_TEST_PIN Z_MIN_PIN
constexpr bool probe_inverting = Z_MIN_ENDSTOP_INVERTING;
SERIAL_ECHOLNPAIR(". Probe Z_MIN_PIN: ", int(PROBE_TEST_PIN));
SERIAL_ECHOLNPAIR(". Probe Z_MIN_PIN: ", PROBE_TEST_PIN);
SERIAL_ECHOPGM(". Z_MIN_ENDSTOP_INVERTING: ");
#else
@@ -151,7 +151,7 @@ inline void servo_probe_test() {
#define PROBE_TEST_PIN Z_MIN_PROBE_PIN
constexpr bool probe_inverting = Z_MIN_PROBE_ENDSTOP_INVERTING;
SERIAL_ECHOLNPAIR(". Probe Z_MIN_PROBE_PIN: ", int(PROBE_TEST_PIN));
SERIAL_ECHOLNPAIR(". Probe Z_MIN_PROBE_PIN: ", PROBE_TEST_PIN);
SERIAL_ECHOPGM( ". Z_MIN_PROBE_ENDSTOP_INVERTING: ");
#endif
+1 -1
View File
@@ -37,7 +37,7 @@ void report_M92(const bool echo=true, const int8_t e=-1) {
LOOP_L_N(i, E_STEPPERS) {
if (e >= 0 && i != e) continue;
if (echo) SERIAL_ECHO_START(); else SERIAL_CHAR(' ');
SERIAL_ECHOLNPAIR_P(PSTR(" M92 T"), (int)i,
SERIAL_ECHOLNPAIR_P(PSTR(" M92 T"), i,
SP_E_STR, VOLUMETRIC_UNIT(planner.settings.axis_steps_per_mm[E_AXIS_N(i)]));
}
#endif
+7 -8
View File
@@ -31,7 +31,9 @@
* M280: Get or set servo position. P<index> [S<angle>]
*/
void GcodeSuite::M280() {
if (!parser.seen('P')) return;
const int servo_index = parser.value_int();
if (WITHIN(servo_index, 0, NUM_SERVOS - 1)) {
if (parser.seen('S')) {
@@ -41,15 +43,12 @@ void GcodeSuite::M280() {
else
MOVE_SERVO(servo_index, a);
}
else {
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR(" Servo ", servo_index, ": ", servo[servo_index].read());
}
}
else {
SERIAL_ERROR_START();
SERIAL_ECHOLNPAIR("Servo ", servo_index, " out of range");
else
SERIAL_ECHO_MSG(" Servo ", servo_index, ": ", servo[servo_index].read());
}
else
SERIAL_ERROR_MSG("Servo ", servo_index, " out of range");
}
#endif // HAS_SERVOS

Some files were not shown because too many files have changed in this diff Show More