Merge branch 'bugfix-2.0.x' into Raptor_2.0.X_Devel
This commit is contained in:
+27
-9
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
//
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
// ------------------------
|
||||
|
||||
@@ -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!
|
||||
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
@@ -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
|
||||
|
||||
@@ -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__
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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))
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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(); }
|
||||
};
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 { \
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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("]");
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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())));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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, ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Executable → Regular
+2
-2
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user