update code base to Marlin 2.0.9.2

This commit is contained in:
Stefan Kalscheuer
2021-10-03 18:57:12 +02:00
parent b9d7ba838e
commit 7077da3591
2617 changed files with 332093 additions and 103438 deletions

View File

@@ -0,0 +1,176 @@
/**
* 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
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 ");
SERIAL_ECHOPGM_P(name);
SERIAL_ECHOLNPGM(" for ", cycles);
SERIAL_ECHOPGM_P(unit);
SERIAL_ECHOLNPGM(" took: ", total);
SERIAL_ECHOPGM_P(unit);
if (do_flush) SERIAL_FLUSHTX();
};
uint32_t s, e;
SERIAL_ECHOLNPGM("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() { SERIAL_ECHOPGM_P(PSTR("N/A on this platform")); }
#endif
#endif

249
Marlin/src/HAL/shared/Delay.h Executable file → Normal file
View File

@@ -16,11 +16,13 @@
* 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 <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../../inc/MarlinConfigPre.h"
/**
* Busy wait delay cycles routines:
*
@@ -31,131 +33,176 @@
#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
// http://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__)
#define nop() __asm__ __volatile__("nop;\n\t":::)
FORCE_INLINE static void __delay_4cycles(uint8_t cy) {
__asm__ __volatile__(
L("1")
A("dec %[cnt]")
A("nop")
A("brne 1b")
: [cnt] "+r"(cy) // output: +r means input+output
: // input:
: "cc" // clobbers:
);
FORCE_INLINE static void __delay_up_to_3c(uint8_t cycles) {
switch (cycles) {
case 3:
__asm__ __volatile__(A("RJMP .+0") A("NOP"));
break;
case 2:
__asm__ __volatile__(A("RJMP .+0"));
break;
case 1:
__asm__ __volatile__(A("NOP"));
break;
}
}
// Delay in cycles
FORCE_INLINE static void DELAY_CYCLES(uint16_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(); }
FORCE_INLINE static void DELAY_CYCLES(uint16_t cycles) {
if (__builtin_constant_p(cycles)) {
if (cycles <= 3) {
__delay_up_to_3c(cycles);
}
else if (cycles == 4) {
__delay_up_to_3c(2);
__delay_up_to_3c(2);
}
else {
const uint32_t rem = (x) % (MAXNOPS);
switch (rem) { case 3: nop(); case 2: nop(); case 1: nop(); }
if ((x = (x) / (MAXNOPS)))
__delay_4cycles(x); // if need more then 4 nop loop is more optimal
cycles -= 1 + 4; // Compensate for the first LDI (1) and the first round (4)
__delay_up_to_3c(cycles % 4);
cycles /= 4;
// The following code burns [1 + 4 * (rounds+1)] cycles
uint16_t dummy;
__asm__ __volatile__(
// "manually" load counter from constants, otherwise the compiler may optimize this part away
A("LDI %A[rounds], %[l]") // 1c
A("LDI %B[rounds], %[h]") // 1c (compensating the non branching BRCC)
L("1")
A("SBIW %[rounds], 1") // 2c
A("BRCC 1b") // 2c when branching, else 1c (end of loop)
: // Outputs ...
[rounds] "=w" (dummy) // Restrict to a wo (=) 16 bit register pair (w)
: // Inputs ...
[l] "M" (cycles%256), // Restrict to 0..255 constant (M)
[h] "M" (cycles/256) // Restrict to 0..255 constant (M)
:// Clobbers ...
"cc" // Indicate we are modifying flags like Carry (cc)
);
}
#undef MAXNOPS
}
else if ((x >>= 2))
__delay_4cycles(x);
else {
__asm__ __volatile__(
L("1")
A("SBIW %[cycles], 4") // 2c
A("BRCC 1b") // 2c when branching, else 1c (end of loop)
: [cycles] "+w" (cycles) // output: Restrict to a rw (+) 16 bit register pair (w)
: // input: -
: "cc" // clobbers: We are modifying flags like Carry (cc)
);
}
}
#undef nop
#elif defined(__PLAT_LINUX__) || defined(ESP32)
// Delay in microseconds
#define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
// specified inside platform
#elif defined(ESP32) || defined(__PLAT_LINUX__) || defined(__PLAT_NATIVE_SIM__)
// DELAY_CYCLES specified inside platform
// Delay in microseconds
#define DELAY_US(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL))
#else
#error "Unsupported MCU architecture"
#endif
// Delay in nanoseconds
#define DELAY_NS(x) DELAY_CYCLES( (x) * (F_CPU / 1000000UL) / 1000UL )
/**************************************************************
* Delay in nanoseconds. Requires the F_CPU macro.
* These macros follow avr-libc delay conventions.
*
* For AVR there are three possible operation modes, due to its
* slower clock speeds and thus coarser delay resolution. For
* example, when F_CPU = 16000000 the resolution is 62.5ns.
*
* Round up (default)
* Round up the delay according to the CPU clock resolution.
* e.g., 100 will give a delay of 2 cycles (125ns).
*
* Round down (DELAY_NS_ROUND_DOWN)
* Round down the delay according to the CPU clock resolution.
* e.g., 100 will be rounded down to 1 cycle (62.5ns).
*
* Nearest (DELAY_NS_ROUND_CLOSEST)
* Round the delay to the nearest number of clock cycles.
* e.g., 165 will be rounded up to 3 cycles (187.5ns) because
* it's closer to the requested delay than 2 cycle (125ns).
*/
// Delay in microseconds
#define DELAY_US(x) DELAY_CYCLES( (x) * (F_CPU / 1000000UL) )
#ifndef __AVR__
#undef DELAY_NS_ROUND_DOWN
#undef DELAY_NS_ROUND_CLOSEST
#endif
#if ENABLED(DELAY_NS_ROUND_DOWN)
#define DELAY_NS(x) DELAY_CYCLES((x) * ((F_CPU) / 1000000UL) / 1000UL) // floor
#elif ENABLED(DELAY_NS_ROUND_CLOSEST)
#define DELAY_NS(x) DELAY_CYCLES(((x) * ((F_CPU) / 1000000UL) + 500) / 1000UL) // round
#else
#define DELAY_NS(x) DELAY_CYCLES(((x) * ((F_CPU) / 1000000UL) + 999) / 1000UL) // "ceil"
#endif

View File

@@ -0,0 +1,33 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "HAL_MinSerial.h"
#if ENABLED(POSTMORTEM_DEBUGGING)
void HAL_min_serial_init_default() {}
void HAL_min_serial_out_default(char ch) { SERIAL_CHAR(ch); }
void (*HAL_min_serial_init)() = &HAL_min_serial_init_default;
void (*HAL_min_serial_out)(char) = &HAL_min_serial_out_default;
bool MinSerial::force_using_default_output = false;
#endif

View File

@@ -0,0 +1,79 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../../core/serial.h"
#include <stdint.h>
// Serial stuff here
// Inside an exception handler, the CPU state is not safe, we can't expect the handler to resume
// and the software to continue. UART communication can't rely on later callback/interrupt as it might never happen.
// So, you need to provide some method to send one byte to the usual UART with the interrupts disabled
// By default, the method uses SERIAL_CHAR but it's 100% guaranteed to break (couldn't be worse than nothing...)7
extern void (*HAL_min_serial_init)();
extern void (*HAL_min_serial_out)(char ch);
struct MinSerial {
static bool force_using_default_output;
// Serial output
static void TX(char ch) {
if (force_using_default_output)
SERIAL_CHAR(ch);
else
HAL_min_serial_out(ch);
}
// Send String through UART
static void TX(const char *s) { while (*s) TX(*s++); }
// Send a digit through UART
static void TXDigit(uint32_t d) {
if (d < 10) TX((char)(d+'0'));
else if (d < 16) TX((char)(d+'A'-10));
else TX('?');
}
// Send Hex number through UART
static void TXHex(uint32_t v) {
TX("0x");
for (uint8_t i = 0; i < 8; i++, v <<= 4)
TXDigit((v >> 28) & 0xF);
}
// Send Decimal number through UART
static void TXDec(uint32_t v) {
if (!v) {
TX('0');
return;
}
char nbrs[14];
char *p = &nbrs[0];
while (v != 0) {
*p++ = '0' + (v % 10);
v /= 10;
}
do {
p--;
TX(*p);
} while (p != &nbrs[0]);
}
static void init() { if (!force_using_default_output) HAL_min_serial_init(); }
};

8
Marlin/src/HAL/shared/HAL_SPI.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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 <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -71,10 +71,10 @@ void spiSend(uint8_t b);
uint8_t spiRec();
// Read from SPI into buffer
void spiRead(uint8_t* buf, uint16_t nbyte);
void spiRead(uint8_t *buf, uint16_t nbyte);
// Write token and then write from 512 byte buffer to SPI (for SD card)
void spiSendBlock(uint8_t token, const uint8_t* buf);
void spiSendBlock(uint8_t token, const uint8_t *buf);
// Begin SPI transaction, set clock, bit order, data mode
void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode);
@@ -87,7 +87,7 @@ void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode);
void spiSend(uint32_t chan, byte b);
// Write buffer to specified SPI channel
void spiSend(uint32_t chan, const uint8_t* buf, size_t n);
void spiSend(uint32_t chan, const uint8_t *buf, size_t n);
// Read single byte from specified SPI channel
uint8_t spiRec(uint32_t chan);

4
Marlin/src/HAL/shared/HAL_ST7920.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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 <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -27,7 +27,7 @@
* (bypassing U8G), it will allow the LIGHTWEIGHT_UI to operate.
*/
#if HAS_GRAPHICAL_LCD && ENABLED(LIGHTWEIGHT_UI)
#if BOTH(HAS_MARLINUI_U8GLIB, LIGHTWEIGHT_UI)
void ST7920_cs();
void ST7920_ncs();
void ST7920_set_cmd();

2
Marlin/src/HAL/shared/HAL_spi_L6470.cpp Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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 <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/

24
Marlin/src/HAL/shared/Marduino.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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 <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -28,9 +28,9 @@
#undef DISABLED // Redefined by ESP32
#undef M_PI // Redefined by all
#undef _BV // Redefined by some
#undef sq // Redefined by teensy3/wiring.h
#undef SBI // Redefined by arduino/const_functions.h
#undef CBI // Redefined by arduino/const_functions.h
#undef sq // Redefined by teensy3/wiring.h
#undef UNUSED // Redefined by stm32f4xx_hal_def.h
#include <Arduino.h> // NOTE: If included earlier then this line is a NOOP
@@ -40,18 +40,16 @@
#undef _BV
#define _BV(b) (1UL << (b))
#ifndef SBI
#define SBI(A,B) (A |= _BV(B))
#endif
#ifndef CBI
#define CBI(A,B) (A &= ~_BV(B))
#endif
#undef sq
#define sq(x) ((x)*(x))
#ifndef SBI
#define SBI(A,B) (A |= (1 << (B)))
#endif
#ifndef CBI
#define CBI(A,B) (A &= ~(1 << (B)))
#endif
#ifndef __AVR__
#ifndef strchr_P // Some platforms define a macro (DUE, teensy35)
inline const char* strchr_P(const char *s, int c) { return strchr(s,c); }
@@ -83,3 +81,9 @@
#ifndef UNUSED
#define UNUSED(x) ((void)(x))
#endif
#ifndef FORCE_INLINE
#define FORCE_INLINE inline __attribute__((always_inline))
#endif
#include "progmem.h"

35
Marlin/src/HAL/shared/backtrace/backtrace.cpp Executable file → Normal file
View File

@@ -16,40 +16,41 @@
* 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 <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#if defined(__arm__) || defined(__thumb__)
#include "backtrace.h"
#include "unwinder.h"
#include "unwmemaccess.h"
#include "../../../core/serial.h"
#include "../HAL_MinSerial.h"
#include <stdarg.h>
// Dump a backtrace entry
static bool UnwReportOut(void* ctx, const UnwReport* bte) {
static bool UnwReportOut(void *ctx, const UnwReport *bte) {
int *p = (int*)ctx;
(*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;
}
#ifdef UNW_DEBUG
void UnwPrintf(const char* format, ...) {
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]);
MinSerial::TX(&dest[0]);
}
#endif
@@ -64,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__ (
@@ -80,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;
@@ -87,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);
}
@@ -96,4 +103,4 @@ void backtrace() {
void backtrace() {}
#endif
#endif // __arm__ || __thumb__

5
Marlin/src/HAL/shared/backtrace/backtrace.h Executable file → Normal file
View File

@@ -16,10 +16,13 @@
* 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 <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// 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);

2
Marlin/src/HAL/shared/backtrace/unwarm.cpp Executable file → Normal file
View File

@@ -7,7 +7,7 @@
* for free and use it as they wish, with or without modifications, and in
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liability for it's use or misuse - this software is without warranty.
* liability for its use or misuse - this software is without warranty.
***************************************************************************
* File Description: Utility functions and glue for ARM unwinding sub-modules.
**************************************************************************/

4
Marlin/src/HAL/shared/backtrace/unwarm.h Executable file → Normal file
View File

@@ -4,9 +4,9 @@
* This program is PUBLIC DOMAIN.
* This means that there is no copyright and anyone is able to take a copy
* for free and use it as they wish, with or without modifications, and in
* any context, commerically or otherwise. The only limitation is that I
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liablity for it's use or misuse - this software is without warranty.
* liability for its use or misuse - this software is without warranty.
***************************************************************************
* File Description: Internal interface between the ARM unwinding sub-modules.
**************************************************************************/

7
Marlin/src/HAL/shared/backtrace/unwarm_arm.cpp Executable file → Normal file
View File

@@ -7,7 +7,7 @@
* for free and use it as they wish, with or without modifications, and in
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liability for it's use or misuse - this software is without warranty.
* liability for its use or misuse - this software is without warranty.
***************************************************************************
* File Description: Abstract interpreter for ARM mode.
**************************************************************************/
@@ -43,10 +43,9 @@ static bool isDataProc(uint32_t instr) {
}
UnwResult UnwStartArm(UnwState * const state) {
bool found = false;
uint16_t t = UNW_MAX_INSTR_COUNT;
do {
for (;;) {
uint32_t instr;
/* Attempt to read the instruction */
@@ -527,7 +526,7 @@ UnwResult UnwStartArm(UnwState * const state) {
if (--t == 0) return UNWIND_EXHAUSTED;
} while (!found);
}
return UNWIND_UNSUPPORTED;
}

9
Marlin/src/HAL/shared/backtrace/unwarm_thumb.cpp Executable file → Normal file
View File

@@ -7,7 +7,7 @@
* for free and use it as they wish, with or without modifications, and in
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liability for it's use or misuse - this software is without warranty.
* liability for its use or misuse - this software is without warranty.
***************************************************************************
* File Description: Abstract interpretation for Thumb mode.
**************************************************************************/
@@ -30,12 +30,11 @@ static int32_t signExtend11(const uint16_t value) {
}
UnwResult UnwStartThumb(UnwState * const state) {
bool found = false;
uint16_t t = UNW_MAX_INSTR_COUNT;
uint32_t lastJumpAddr = 0; // Last JUMP address, to try to detect infinite loops
bool loopDetected = false; // If a loop was detected
do {
for (;;) {
uint16_t instr;
/* Attempt to read the instruction */
@@ -807,7 +806,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
case 2: /* MOV */
UnwPrintd5("MOV r%d, r%d\t; r%d %s", rhd, rhs, rhd, M_Origin2Str(state->regData[rhs].o));
state->regData[rhd].v = state->regData[rhs].v;
state->regData[rhd].o = state->regData[rhd].o;
state->regData[rhd].o = state->regData[rhs].o;
break;
case 3: /* BX */
@@ -1059,7 +1058,7 @@ UnwResult UnwStartThumb(UnwState * const state) {
if (--t == 0) return UNWIND_EXHAUSTED;
} while (!found);
}
return UNWIND_SUCCESS;
}

71
Marlin/src/HAL/shared/backtrace/unwarmbytab.cpp Executable file → Normal file
View File

@@ -4,7 +4,7 @@
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* file, You can obtain one at https://www.mozilla.org/en-US/MPL/2.0/
*
* This library was modified, some bugs fixed, stack address validated
* and adapted to be used in Marlin 3D printer firmware as backtracer
@@ -128,11 +128,8 @@ static UnwResult UnwTabStateInit(const UnwindCallbacks *cb, UnwTabState *ucb, ui
* Execute unwinding instructions
*/
static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabState *ucb) {
int instruction;
uint32_t mask;
uint32_t reg;
uint32_t vsp;
uint32_t mask, reg, vsp;
/* Consume all instruction byte */
while ((instruction = UnwTabGetNextInstruction(cb, ucb)) != -1) {
@@ -140,12 +137,12 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
if ((instruction & 0xC0) == 0x00) { // ARM_EXIDX_CMD_DATA_POP
/* vsp = vsp + (xxxxxx << 2) + 4 */
ucb->vrs[13] += ((instruction & 0x3F) << 2) + 4;
} else
if ((instruction & 0xC0) == 0x40) { // ARM_EXIDX_CMD_DATA_PUSH
}
else if ((instruction & 0xC0) == 0x40) { // ARM_EXIDX_CMD_DATA_PUSH
/* vsp = vsp - (xxxxxx << 2) - 4 */
ucb->vrs[13] -= ((instruction & 0x3F) << 2) - 4;
} else
if ((instruction & 0xF0) == 0x80) {
}
else if ((instruction & 0xF0) == 0x80) {
/* pop under mask {r15-r12},{r11-r4} or refuse to unwind */
instruction = instruction << 8 | UnwTabGetNextInstruction(cb, ucb);
@@ -171,17 +168,17 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
}
/* Patch up the vrs sp if it was in the mask */
if ((instruction & (1 << (13 - 4))) != 0)
if (instruction & (1 << (13 - 4)))
ucb->vrs[13] = vsp;
} else
if ((instruction & 0xF0) == 0x90 && // ARM_EXIDX_CMD_REG_TO_SP
instruction != 0x9D &&
instruction != 0x9F) {
}
else if ((instruction & 0xF0) == 0x90 // ARM_EXIDX_CMD_REG_TO_SP
&& instruction != 0x9D
&& instruction != 0x9F
) {
/* vsp = r[nnnn] */
ucb->vrs[13] = ucb->vrs[instruction & 0x0F];
} else
if ((instruction & 0xF0) == 0xA0) { // ARM_EXIDX_CMD_REG_POP
}
else if ((instruction & 0xF0) == 0xA0) { // ARM_EXIDX_CMD_REG_POP
/* pop r4-r[4+nnn] or pop r4-r[4+nnn], r14*/
vsp = ucb->vrs[13];
@@ -204,8 +201,8 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
ucb->vrs[13] = vsp;
} else
if (instruction == 0xB0) { // ARM_EXIDX_CMD_FINISH
}
else if (instruction == 0xB0) { // ARM_EXIDX_CMD_FINISH
/* finished */
if (ucb->vrs[15] == 0)
ucb->vrs[15] = ucb->vrs[14];
@@ -213,8 +210,8 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
/* All done unwinding */
return UNWIND_SUCCESS;
} else
if (instruction == 0xB1) { // ARM_EXIDX_CMD_REG_POP
}
else if (instruction == 0xB1) { // ARM_EXIDX_CMD_REG_POP
/* pop register under mask {r3,r2,r1,r0} */
vsp = ucb->vrs[13];
mask = UnwTabGetNextInstruction(cb, ucb);
@@ -234,16 +231,15 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
}
ucb->vrs[13] = (uint32_t)vsp;
} else
if (instruction == 0xB2) { // ARM_EXIDX_CMD_DATA_POP
}
else if (instruction == 0xB2) { // ARM_EXIDX_CMD_DATA_POP
/* vps = vsp + 0x204 + (uleb128 << 2) */
ucb->vrs[13] += 0x204 + (UnwTabGetNextInstruction(cb, ucb) << 2);
} else
if (instruction == 0xB3 || // ARM_EXIDX_CMD_VFP_POP
instruction == 0xC8 ||
instruction == 0xC9) {
}
else if (instruction == 0xB3 // ARM_EXIDX_CMD_VFP_POP
|| instruction == 0xC8
|| instruction == 0xC9
) {
/* pop VFP double-precision registers */
vsp = ucb->vrs[13];
@@ -266,27 +262,20 @@ static UnwResult UnwTabExecuteInstructions(const UnwindCallbacks *cb, UnwTabStat
}
ucb->vrs[13] = vsp;
} else
if ((instruction & 0xF8) == 0xB8 ||
(instruction & 0xF8) == 0xD0) {
}
else if ((instruction & 0xF8) == 0xB8 || (instruction & 0xF8) == 0xD0) {
/* Pop VFP double precision registers D[8]-D[8+nnn] */
ucb->vrs[14] = 0x80 | (instruction & 0x07);
if ((instruction & 0xF8) == 0xD0) {
if ((instruction & 0xF8) == 0xD0)
ucb->vrs[14] = 1 << 17;
}
} else
}
else
return UNWIND_UNSUPPORTED_DWARF_INSTR;
}
return UNWIND_SUCCESS;
}
static inline __attribute__((always_inline)) uint32_t read_psp() {
/* Read the current PSP and return its value as a pointer */
uint32_t psp;

4
Marlin/src/HAL/shared/backtrace/unwarmbytab.h Executable file → Normal file
View File

@@ -5,9 +5,9 @@
* This program is PUBLIC DOMAIN.
* This means that there is no copyright and anyone is able to take a copy
* for free and use it as they wish, with or without modifications, and in
* any context, commerically or otherwise. The only limitation is that I
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liablity for it's use or misuse - this software is without warranty.
* liability for its use or misuse - this software is without warranty.
***************************************************************************
* File Description: Interface to the memory tracking sub-system.
**************************************************************************/

4
Marlin/src/HAL/shared/backtrace/unwarmmem.cpp Executable file → Normal file
View File

@@ -5,9 +5,9 @@
* This program is PUBLIC DOMAIN.
* This means that there is no copyright and anyone is able to take a copy
* for free and use it as they wish, with or without modifications, and in
* any context, commerically or otherwise. The only limitation is that I
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liablity for it's use or misuse - this software is without warranty.
* liability for its use or misuse - this software is without warranty.
***************************************************************************
* File Description: Implementation of the memory tracking sub-system.
**************************************************************************/

4
Marlin/src/HAL/shared/backtrace/unwarmmem.h Executable file → Normal file
View File

@@ -5,9 +5,9 @@
* This program is PUBLIC DOMAIN.
* This means that there is no copyright and anyone is able to take a copy
* for free and use it as they wish, with or without modifications, and in
* any context, commerically or otherwise. The only limitation is that I
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liablity for it's use or misuse - this software is without warranty.
* liability for its use or misuse - this software is without warranty.
***************************************************************************
* File Description: Interface to the memory tracking sub-system.
**************************************************************************/

4
Marlin/src/HAL/shared/backtrace/unwinder.cpp Executable file → Normal file
View File

@@ -7,7 +7,7 @@
* for free and use it as they wish, with or without modifications, and in
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liability for it's use or misuse - this software is without warranty.
* liability for its use or misuse - this software is without warranty.
***************************************************************************
* File Description: Implementation of the interface into the ARM unwinder.
**************************************************************************/
@@ -28,7 +28,7 @@ extern "C" const UnwTabEntry __exidx_end[];
// Detect if unwind information is present or not
static int HasUnwindTableInfo() {
// > 16 because there are default entries we can't supress
// > 16 because there are default entries we can't suppress
return ((char*)(&__exidx_end) - (char*)(&__exidx_start)) > 16 ? 1 : 0;
}

6
Marlin/src/HAL/shared/backtrace/unwinder.h Executable file → Normal file
View File

@@ -5,9 +5,9 @@
* This program is PUBLIC DOMAIN.
* This means that there is no copyright and anyone is able to take a copy
* for free and use it as they wish, with or without modifications, and in
* any context, commerically or otherwise. The only limitation is that I
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liablity for it's use or misuse - this software is without warranty.
* liability for its use or misuse - this software is without warranty.
**************************************************************************/
/** \file
* Interface to the ARM stack unwinding module.
@@ -114,7 +114,7 @@ typedef struct {
* report function maybe called again in future. If false is returned,
* unwinding will stop with UnwindStart() returning UNWIND_TRUNCATED.
*/
typedef bool (*UnwindReportFunc)(void* data, const UnwReport* bte);
typedef bool (*UnwindReportFunc)(void *data, const UnwReport *bte);
/** Structure that holds memory callback function pointers.
*/

292
Marlin/src/HAL/shared/backtrace/unwmemaccess.cpp Executable file → Normal file
View File

@@ -7,7 +7,7 @@
* for free and use it as they wish, with or without modifications, and in
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liability for it's use or misuse - this software is without warranty.
* liability for its use or misuse - this software is without warranty.
***************************************************************************
* File Description: Utility functions to access memory
**************************************************************************/
@@ -20,139 +20,169 @@
/* Validate address */
#ifdef ARDUINO_ARCH_SAM
// For DUE, valid address ranges are
// SRAM (0x20070000 - 0x20088000) (96kb)
// FLASH (0x00080000 - 0x00100000) (512kb)
//
#define START_SRAM_ADDR 0x20070000
#define END_SRAM_ADDR 0x20088000
#define START_FLASH_ADDR 0x00080000
#define END_FLASH_ADDR 0x00100000
// For DUE, valid address ranges are
// SRAM (0x20070000 - 0x20088000) (96kb)
// FLASH (0x00080000 - 0x00100000) (512kb)
//
#define START_SRAM_ADDR 0x20070000
#define END_SRAM_ADDR 0x20088000
#define START_FLASH_ADDR 0x00080000
#define END_FLASH_ADDR 0x00100000
#elif defined(TARGET_LPC1768)
// For LPC1769:
// SRAM (0x10000000 - 0x10008000) (32kb)
// FLASH (0x00000000 - 0x00080000) (512kb)
//
#define START_SRAM_ADDR 0x10000000
#define END_SRAM_ADDR 0x10008000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00080000
#elif defined(__STM32F1__) || defined(STM32F1xx) || defined(STM32F0xx)
// For STM32F103ZET6/STM32F103VET6/STM32F0xx
// SRAM (0x20000000 - 0x20010000) (64kb)
// FLASH (0x08000000 - 0x08080000) (512kb)
//
#define START_SRAM_ADDR 0x20000000
#define END_SRAM_ADDR 0x20010000
#define START_FLASH_ADDR 0x08000000
#define END_FLASH_ADDR 0x08080000
#elif defined(STM32F4) || defined(STM32F4xx)
// For STM32F407VET
// SRAM (0x20000000 - 0x20030000) (192kb)
// FLASH (0x08000000 - 0x08080000) (512kb)
//
#define START_SRAM_ADDR 0x20000000
#define END_SRAM_ADDR 0x20030000
#define START_FLASH_ADDR 0x08000000
#define END_FLASH_ADDR 0x08080000
#elif MB(REMRAM_V1, NUCLEO_F767ZI)
// For STM32F765VI in RemRam v1
// SRAM (0x20000000 - 0x20080000) (512kb)
// FLASH (0x08000000 - 0x08200000) (2048kb)
//
#define START_SRAM_ADDR 0x20000000
#define END_SRAM_ADDR 0x20080000
#define START_FLASH_ADDR 0x08000000
#define END_FLASH_ADDR 0x08200000
#elif defined(__MK20DX256__)
// For MK20DX256 in TEENSY 3.1 or TEENSY 3.2
// SRAM (0x1FFF8000 - 0x20008000) (64kb)
// FLASH (0x00000000 - 0x00040000) (256kb)
//
#define START_SRAM_ADDR 0x1FFF8000
#define END_SRAM_ADDR 0x20008000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00040000
#elif defined(__MK64FX512__)
// For MK64FX512 in TEENSY 3.5
// SRAM (0x1FFF0000 - 0x20020000) (192kb)
// FLASH (0x00000000 - 0x00080000) (512kb)
//
#define START_SRAM_ADDR 0x1FFF0000
#define END_SRAM_ADDR 0x20020000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00080000
#elif defined(__MK66FX1M0__)
// For MK66FX1M0 in TEENSY 3.6
// SRAM (0x1FFF0000 - 0x20030000) (256kb)
// FLASH (0x00000000 - 0x00140000) (1.25Mb)
//
#define START_SRAM_ADDR 0x1FFF0000
#define END_SRAM_ADDR 0x20030000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00140000
#elif defined(__IMXRT1062__)
// For IMXRT1062 in TEENSY 4.0/4/1
// ITCM (rwx): ORIGIN = 0x00000000, LENGTH = 512K
// DTCM (rwx): ORIGIN = 0x20000000, LENGTH = 512K
// RAM (rwx): ORIGIN = 0x20200000, LENGTH = 512K
// FLASH (rwx): ORIGIN = 0x60000000, LENGTH = 1984K
//
#define START_SRAM_ADDR 0x00000000
#define END_SRAM_ADDR 0x20280000
#define START_FLASH_ADDR 0x60000000
#define END_FLASH_ADDR 0x601F0000
#elif defined(__SAMD51P20A__)
// For SAMD51x20, valid address ranges are
// SRAM (0x20000000 - 0x20040000) (256kb)
// FLASH (0x00000000 - 0x00100000) (1024kb)
//
#define START_SRAM_ADDR 0x20000000
#define END_SRAM_ADDR 0x20040000
#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
#ifdef TARGET_LPC1768
// For LPC1769:
// SRAM (0x10000000 - 0x10008000) (32kb)
// FLASH (0x00000000 - 0x00080000) (512kb)
//
#define START_SRAM_ADDR 0x10000000
#define END_SRAM_ADDR 0x10008000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00080000
#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;
// Or in FLASH range
if (addr >= START_FLASH_ADDR && addr < END_FLASH_ADDR)
return true;
return false;
}
#endif
#if 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
#endif
#if defined(__STM32F1__) || defined(STM32F1xx) || defined(STM32F0xx)
// For STM32F103ZET6/STM32F103VET6/STM32F0xx
// SRAM (0x20000000 - 0x20010000) (64kb)
// FLASH (0x00000000 - 0x00080000) (512kb)
//
#define START_SRAM_ADDR 0x20000000
#define END_SRAM_ADDR 0x20010000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00080000
#endif
#if defined(STM32F4) || defined(STM32F4xx)
// For STM32F407VET
// SRAM (0x20000000 - 0x20030000) (192kb)
// FLASH (0x08000000 - 0x08080000) (512kb)
//
#define START_SRAM_ADDR 0x20000000
#define END_SRAM_ADDR 0x20030000
#define START_FLASH_ADDR 0x08000000
#define END_FLASH_ADDR 0x08080000
#endif
#if MB(THE_BORG)
// For STM32F765 in BORG
// SRAM (0x20000000 - 0x20080000) (512kb)
// FLASH (0x08000000 - 0x08100000) (1024kb)
//
#define START_SRAM_ADDR 0x20000000
#define END_SRAM_ADDR 0x20080000
#define START_FLASH_ADDR 0x08000000
#define END_FLASH_ADDR 0x08100000
#endif
#if MB(REMRAM_V1)
// For STM32F765VI in RemRam v1
// SRAM (0x20000000 - 0x20080000) (512kb)
// FLASH (0x08000000 - 0x08200000) (2048kb)
//
#define START_SRAM_ADDR 0x20000000
#define END_SRAM_ADDR 0x20080000
#define START_FLASH_ADDR 0x08000000
#define END_FLASH_ADDR 0x08200000
#endif
#ifdef __MK20DX256__
// For MK20DX256 in TEENSY 3.1 or TEENSY 3.2
// SRAM (0x1FFF8000 - 0x20008000) (64kb)
// FLASH (0x00000000 - 0x00040000) (256kb)
//
#define START_SRAM_ADDR 0x1FFF8000
#define END_SRAM_ADDR 0x20008000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00040000
#endif
#ifdef __MK64FX512__
// For MK64FX512 in TEENSY 3.5
// SRAM (0x1FFF0000 - 0x20020000) (192kb)
// FLASH (0x00000000 - 0x00080000) (512kb)
//
#define START_SRAM_ADDR 0x1FFF0000
#define END_SRAM_ADDR 0x20020000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00080000
#endif
#ifdef __MK66FX1M0__
// For MK66FX1M0 in TEENSY 3.6
// SRAM (0x1FFF0000 - 0x20030000) (256kb)
// FLASH (0x00000000 - 0x00140000) (1.25Mb)
//
#define START_SRAM_ADDR 0x1FFF0000
#define END_SRAM_ADDR 0x20030000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00140000
#endif
#ifdef __SAMD51P20A__
// For SAMD51x20, valid address ranges are
// SRAM (0x20000000 - 0x20040000) (256kb)
// FLASH (0x00000000 - 0x00100000) (1024kb)
//
#define START_SRAM_ADDR 0x20000000
#define END_SRAM_ADDR 0x20040000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00100000
#endif
static bool validate_addr(uint32_t addr) {
// 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;
return false;
}
bool UnwReadW(const uint32_t a, uint32_t *v) {
if (!validate_addr(a))
return false;
@@ -177,4 +207,4 @@ bool UnwReadB(const uint32_t a, uint8_t *v) {
return true;
}
#endif
#endif // __arm__ || __thumb__

4
Marlin/src/HAL/shared/backtrace/unwmemaccess.h Executable file → Normal file
View File

@@ -5,9 +5,9 @@
* This program is PUBLIC DOMAIN.
* This means that there is no copyright and anyone is able to take a copy
* for free and use it as they wish, with or without modifications, and in
* any context, commerically or otherwise. The only limitation is that I
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liablity for it's use or misuse - this software is without warranty.
* liability for its use or misuse - this software is without warranty.
***************************************************************************
* File Description: Utility functions to access memory
**************************************************************************/

View File

@@ -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_ECHOPGM("Vector table addr: ");
SERIAL_PRINTLN(get_vtor(), PrintBase::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 alignment is required for writing the VTOR register
alignas(128) static unsigned long vectable[VECTOR_TABLE_SENTINEL];
SERIAL_ECHOPGM("Detected vector table size: ");
SERIAL_PRINTLN(vec_size, PrintBase::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_ECHOLNPGM("Installed fault handlers");
#endif
}
#endif // __arm__ || __thumb__

View File

@@ -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() {}

View File

@@ -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();

2
Marlin/src/HAL/shared/eeprom_api.cpp Executable file → Normal file
View File

@@ -17,7 +17,7 @@
* 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 <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "../../inc/MarlinConfigPre.h"

32
Marlin/src/HAL/shared/eeprom_api.h Executable file → Normal file
View File

@@ -17,7 +17,7 @@
* 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 <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -29,21 +29,39 @@
class PersistentStore {
public:
static bool access_start();
static bool access_finish();
static bool write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc);
static bool read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc, const bool writing=true);
// Total available persistent storage space (in bytes)
static size_t capacity();
static inline bool write_data(const int pos, const uint8_t* value, const size_t size=sizeof(uint8_t)) {
// Prepare to read or write
static bool access_start();
// Housecleaning after read or write
static bool access_finish();
// Write one or more bytes of data and update the CRC
// Return 'true' on write error
static bool write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc);
// Read one or more bytes of data and update the CRC
// Return 'true' on read error
static bool read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing=true);
// Write one or more bytes of data
// Return 'true' on write error
static inline bool write_data(const int pos, const uint8_t *value, const size_t size=sizeof(uint8_t)) {
int data_pos = pos;
uint16_t crc = 0;
return write_data(data_pos, value, size, &crc);
}
// Write a single byte of data
// Return 'true' on write error
static inline bool write_data(const int pos, const uint8_t value) { return write_data(pos, &value); }
static inline bool read_data(const int pos, uint8_t* value, const size_t size=1) {
// Read one or more bytes of data
// Return 'true' on read error
static inline bool read_data(const int pos, uint8_t *value, const size_t size=1) {
int data_pos = pos;
uint16_t crc = 0;
return read_data(data_pos, value, size, &crc);

View File

@@ -1,123 +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 <http://www.gnu.org/licenses/>.
*
*/
/**
* Description: functions for I2C connected external EEPROM.
* Not platform dependent.
*
* TODO: Some platform Arduino libraries define these functions
* so Marlin needs to add a glue layer to prevent the conflict.
*/
#include "../../inc/MarlinConfig.h"
#if ENABLED(I2C_EEPROM)
#include "../HAL.h"
#include <Wire.h>
// ------------------------
// Private Variables
// ------------------------
static uint8_t eeprom_device_address = 0x50;
// ------------------------
// Public functions
// ------------------------
static void eeprom_init() {
Wire.begin();
}
void eeprom_write_byte(uint8_t *pos, unsigned char value) {
unsigned eeprom_address = (unsigned) pos;
eeprom_init();
Wire.beginTransmission(I2C_ADDRESS(eeprom_device_address));
Wire.write((int)(eeprom_address >> 8)); // MSB
Wire.write((int)(eeprom_address & 0xFF)); // LSB
Wire.write(value);
Wire.endTransmission();
// wait for write cycle to complete
// this could be done more efficiently with "acknowledge polling"
delay(5);
}
// WARNING: address is a page address, 6-bit end will wrap around
// also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes
void eeprom_update_block(const void *pos, void* eeprom_address, size_t n) {
eeprom_init();
Wire.beginTransmission(I2C_ADDRESS(eeprom_device_address));
Wire.write((int)((unsigned)eeprom_address >> 8)); // MSB
Wire.write((int)((unsigned)eeprom_address & 0xFF)); // LSB
Wire.endTransmission();
uint8_t *ptr = (uint8_t*)pos;
uint8_t flag = 0;
Wire.requestFrom(eeprom_device_address, (byte)n);
for (byte c = 0; c < n && Wire.available(); c++)
flag |= Wire.read() ^ ptr[c];
if (flag) {
Wire.beginTransmission(I2C_ADDRESS(eeprom_device_address));
Wire.write((int)((unsigned)eeprom_address >> 8)); // MSB
Wire.write((int)((unsigned)eeprom_address & 0xFF)); // LSB
Wire.write((uint8_t*)pos, n);
Wire.endTransmission();
// wait for write cycle to complete
// this could be done more efficiently with "acknowledge polling"
delay(5);
}
}
uint8_t eeprom_read_byte(uint8_t *pos) {
unsigned eeprom_address = (unsigned)pos;
eeprom_init();
Wire.beginTransmission(I2C_ADDRESS(eeprom_device_address));
Wire.write((int)(eeprom_address >> 8)); // MSB
Wire.write((int)(eeprom_address & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(eeprom_device_address, (byte)1);
return Wire.available() ? Wire.read() : 0xFF;
}
// Don't read more than 30..32 bytes at a time!
void eeprom_read_block(void* pos, const void* eeprom_address, size_t n) {
eeprom_init();
Wire.beginTransmission(I2C_ADDRESS(eeprom_device_address));
Wire.write((int)((unsigned)eeprom_address >> 8)); // MSB
Wire.write((int)((unsigned)eeprom_address & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(eeprom_device_address, (byte)n);
for (byte c = 0; c < n; c++ )
if (Wire.available()) *((uint8_t*)pos + c) = Wire.read();
}
#endif // I2C_EEPROM

View File

@@ -0,0 +1,29 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
*
* 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
//
// EEPROM
//
void eeprom_init();
void eeprom_write_byte(uint8_t *pos, uint8_t value);
uint8_t eeprom_read_byte(uint8_t *pos);

View File

@@ -0,0 +1,102 @@
/**
* 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/>.
*
*/
/**
* Platform-independent Arduino functions for I2C EEPROM.
* Enable USE_SHARED_EEPROM if not supplied by the framework.
*/
#include "../../inc/MarlinConfig.h"
#if ENABLED(I2C_EEPROM)
#include "eeprom_if.h"
#if ENABLED(SOFT_I2C_EEPROM)
#include <SlowSoftWire.h>
SlowSoftWire Wire = SlowSoftWire(I2C_SDA_PIN, I2C_SCL_PIN, true);
#else
#include <Wire.h>
#endif
void eeprom_init() {
Wire.begin(
#if PINS_EXIST(I2C_SCL, I2C_SDA) && DISABLED(SOFT_I2C_EEPROM)
uint8_t(I2C_SDA_PIN), uint8_t(I2C_SCL_PIN)
#endif
);
}
#if ENABLED(USE_SHARED_EEPROM)
#ifndef EEPROM_WRITE_DELAY
#define EEPROM_WRITE_DELAY 5
#endif
#ifndef EEPROM_DEVICE_ADDRESS
#define EEPROM_DEVICE_ADDRESS 0x50
#endif
static constexpr uint8_t eeprom_device_address = I2C_ADDRESS(EEPROM_DEVICE_ADDRESS);
// ------------------------
// Public functions
// ------------------------
#define SMALL_EEPROM (MARLIN_EEPROM_SIZE <= 2048)
// Combine Address high bits into the device address on <=16Kbit (2K) and >512Kbit (64K) EEPROMs.
// Note: MARLIN_EEPROM_SIZE is specified in bytes, whereas EEPROM model numbers refer to bits.
// e.g., The "16" in BL24C16 indicates a 16Kbit (2KB) size.
static uint8_t _eeprom_calc_device_address(uint8_t * const pos) {
const unsigned eeprom_address = (unsigned)pos;
return (SMALL_EEPROM || MARLIN_EEPROM_SIZE > 65536)
? uint8_t(eeprom_device_address | ((eeprom_address >> (SMALL_EEPROM ? 8 : 16)) & 0x07))
: eeprom_device_address;
}
static void _eeprom_begin(uint8_t * const pos) {
const unsigned eeprom_address = (unsigned)pos;
Wire.beginTransmission(_eeprom_calc_device_address(pos));
if (!SMALL_EEPROM)
Wire.write(uint8_t((eeprom_address >> 8) & 0xFF)); // Address High, if needed
Wire.write(uint8_t(eeprom_address & 0xFF)); // Address Low
}
void eeprom_write_byte(uint8_t *pos, uint8_t value) {
_eeprom_begin(pos);
Wire.write(value);
Wire.endTransmission();
// wait for write cycle to complete
// this could be done more efficiently with "acknowledge polling"
delay(EEPROM_WRITE_DELAY);
}
uint8_t eeprom_read_byte(uint8_t *pos) {
_eeprom_begin(pos);
Wire.endTransmission();
Wire.requestFrom(_eeprom_calc_device_address(pos), (byte)1);
return Wire.available() ? Wire.read() : 0xFF;
}
#endif // USE_SHARED_EEPROM
#endif // I2C_EEPROM

View File

@@ -0,0 +1,84 @@
/**
* 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/>.
*
*/
/**
* Platform-independent Arduino functions for SPI EEPROM.
* Enable USE_SHARED_EEPROM if not supplied by the framework.
*/
#include "../../inc/MarlinConfig.h"
#if ENABLED(SPI_EEPROM)
#include "eeprom_if.h"
void eeprom_init() {}
#if ENABLED(USE_SHARED_EEPROM)
#define CMD_WREN 6 // WREN
#define CMD_READ 2 // WRITE
#define CMD_WRITE 2 // WRITE
#ifndef EEPROM_WRITE_DELAY
#define EEPROM_WRITE_DELAY 7
#endif
static void _eeprom_begin(uint8_t * const pos, const uint8_t cmd) {
const uint8_t eeprom_temp[3] = {
cmd,
(unsigned(pos) >> 8) & 0xFF, // Address High
unsigned(pos) & 0xFF // Address Low
};
WRITE(SPI_EEPROM1_CS_PIN, HIGH); // Usually free already
WRITE(SPI_EEPROM1_CS_PIN, LOW); // Activate the Bus
spiSend(SPI_CHAN_EEPROM1, eeprom_temp, 3);
// Leave the Bus in-use
}
uint8_t eeprom_read_byte(uint8_t *pos) {
_eeprom_begin(pos, CMD_READ); // Set read location and begin transmission
const uint8_t v = spiRec(SPI_CHAN_EEPROM1); // After READ a value sits on the Bus
WRITE(SPI_EEPROM1_CS_PIN, HIGH); // Done with device
return v;
}
void eeprom_write_byte(uint8_t *pos, uint8_t value) {
const uint8_t eeprom_temp = CMD_WREN;
WRITE(SPI_EEPROM1_CS_PIN, LOW);
spiSend(SPI_CHAN_EEPROM1, &eeprom_temp, 1); // Write Enable
WRITE(SPI_EEPROM1_CS_PIN, HIGH); // Done with the Bus
delay(1); // For a small amount of time
_eeprom_begin(pos, CMD_WRITE); // Set write address and begin transmission
spiSend(SPI_CHAN_EEPROM1, value); // Send the value to be written
WRITE(SPI_EEPROM1_CS_PIN, HIGH); // Done with the Bus
delay(EEPROM_WRITE_DELAY); // Give page write time to complete
}
#endif // USE_SHARED_EEPROM
#endif // I2C_EEPROM

View File

@@ -1,118 +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 <http://www.gnu.org/licenses/>.
*
*/
/**
* Description: functions for SPI connected external EEPROM.
* Not platform dependent.
*/
#include "../../inc/MarlinConfig.h"
#if ENABLED(SPI_EEPROM)
#include "../HAL.h"
#define CMD_WREN 6 // WREN
#define CMD_READ 2 // WRITE
#define CMD_WRITE 2 // WRITE
uint8_t eeprom_read_byte(uint8_t* pos) {
uint8_t v;
uint8_t eeprom_temp[3];
// set read location
// begin transmission from device
eeprom_temp[0] = CMD_READ;
eeprom_temp[1] = ((unsigned)pos>>8) & 0xFF; // addr High
eeprom_temp[2] = (unsigned)pos& 0xFF; // addr Low
WRITE(SPI_EEPROM1_CS, HIGH);
WRITE(SPI_EEPROM1_CS, LOW);
spiSend(SPI_CHAN_EEPROM1, eeprom_temp, 3);
v = spiRec(SPI_CHAN_EEPROM1);
WRITE(SPI_EEPROM1_CS, HIGH);
return v;
}
void eeprom_read_block(void* dest, const void* eeprom_address, size_t n) {
uint8_t eeprom_temp[3];
// set read location
// begin transmission from device
eeprom_temp[0] = CMD_READ;
eeprom_temp[1] = ((unsigned)eeprom_address>>8) & 0xFF; // addr High
eeprom_temp[2] = (unsigned)eeprom_address& 0xFF; // addr Low
WRITE(SPI_EEPROM1_CS, HIGH);
WRITE(SPI_EEPROM1_CS, LOW);
spiSend(SPI_CHAN_EEPROM1, eeprom_temp, 3);
uint8_t *p_dest = (uint8_t *)dest;
while (n--)
*p_dest++ = spiRec(SPI_CHAN_EEPROM1);
WRITE(SPI_EEPROM1_CS, HIGH);
}
void eeprom_write_byte(uint8_t* pos, uint8_t value) {
uint8_t eeprom_temp[3];
/*write enable*/
eeprom_temp[0] = CMD_WREN;
WRITE(SPI_EEPROM1_CS, LOW);
spiSend(SPI_CHAN_EEPROM1, eeprom_temp, 1);
WRITE(SPI_EEPROM1_CS, HIGH);
delay(1);
/*write addr*/
eeprom_temp[0] = CMD_WRITE;
eeprom_temp[1] = ((unsigned)pos>>8) & 0xFF; //addr High
eeprom_temp[2] = (unsigned)pos & 0xFF; //addr Low
WRITE(SPI_EEPROM1_CS, LOW);
spiSend(SPI_CHAN_EEPROM1, eeprom_temp, 3);
spiSend(SPI_CHAN_EEPROM1, value);
WRITE(SPI_EEPROM1_CS, HIGH);
delay(7); // wait for page write to complete
}
void eeprom_update_block(const void* src, void* eeprom_address, size_t n) {
uint8_t eeprom_temp[3];
/*write enable*/
eeprom_temp[0] = CMD_WREN;
WRITE(SPI_EEPROM1_CS, LOW);
spiSend(SPI_CHAN_EEPROM1, eeprom_temp, 1);
WRITE(SPI_EEPROM1_CS, HIGH);
delay(1);
/*write addr*/
eeprom_temp[0] = CMD_WRITE;
eeprom_temp[1] = ((unsigned)eeprom_address>>8) & 0xFF; //addr High
eeprom_temp[2] = (unsigned)eeprom_address & 0xFF; //addr Low
WRITE(SPI_EEPROM1_CS, LOW);
spiSend(SPI_CHAN_EEPROM1, eeprom_temp, 3);
spiSend(SPI_CHAN_EEPROM1, (const uint8_t*)src, n);
WRITE(SPI_EEPROM1_CS, HIGH);
delay(7); // wait for page write to complete
}
#endif // SPI_EEPROM

View File

@@ -0,0 +1,43 @@
/**
* 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 "../../inc/MarlinConfig.h"
#include "Delay.h"
void esp_wifi_init(void) { // init ESP01 WIFI module pins
#if PIN_EXISTS(ESP_WIFI_MODULE_GPIO0)
OUT_WRITE(ESP_WIFI_MODULE_GPIO0_PIN, HIGH);
#endif
#if PIN_EXISTS(ESP_WIFI_MODULE_GPIO2)
OUT_WRITE(ESP_WIFI_MODULE_GPIO2_PIN, HIGH);
#endif
#if PIN_EXISTS(ESP_WIFI_MODULE_RESET)
delay(1); // power up delay (0.1mS minimum)
OUT_WRITE(ESP_WIFI_MODULE_RESET_PIN, LOW);
delay(1);
OUT_WRITE(ESP_WIFI_MODULE_RESET_PIN, HIGH);
#endif
#if PIN_EXISTS(ESP_WIFI_MODULE_ENABLE)
delay(1); // delay after reset released (0.1mS minimum)
OUT_WRITE(ESP_WIFI_MODULE_ENABLE_PIN, HIGH);
#endif
}

View File

@@ -0,0 +1,24 @@
/**
* 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/>.
*
*/
#pragma once
void esp_wifi_init();

2
Marlin/src/HAL/shared/math_32bit.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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 <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once

View File

@@ -0,0 +1,189 @@
/**
* 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/>.
*
*/
#pragma once
#ifndef __AVR__
#ifndef __PGMSPACE_H_
// This define should prevent reading the system pgmspace.h if included elsewhere
// This is not normally needed.
#define __PGMSPACE_H_ 1
#endif
#ifndef PROGMEM
#define PROGMEM
#endif
#ifndef PGM_P
#define PGM_P const char *
#endif
#ifndef PSTR
#define PSTR(str) (str)
#endif
#ifndef F
#define F(str) (str)
#endif
#ifndef _SFR_BYTE
#define _SFR_BYTE(n) (n)
#endif
#ifndef memchr_P
#define memchr_P(str, c, len) memchr((str), (c), (len))
#endif
#ifndef memcmp_P
#define memcmp_P(a, b, n) memcmp((a), (b), (n))
#endif
#ifndef memcpy_P
#define memcpy_P(dest, src, num) memcpy((dest), (src), (num))
#endif
#ifndef memmem_P
#define memmem_P(a, alen, b, blen) memmem((a), (alen), (b), (blen))
#endif
#ifndef memrchr_P
#define memrchr_P(str, val, len) memrchr((str), (val), (len))
#endif
#ifndef strcat_P
#define strcat_P(dest, src) strcat((dest), (src))
#endif
#ifndef strchr_P
#define strchr_P(str, c) strchr((str), (c))
#endif
#ifndef strchrnul_P
#define strchrnul_P(str, c) strchrnul((str), (c))
#endif
#ifndef strcmp_P
#define strcmp_P(a, b) strcmp((a), (b))
#endif
#ifndef strcpy_P
#define strcpy_P(dest, src) strcpy((dest), (src))
#endif
#ifndef strcasecmp_P
#define strcasecmp_P(a, b) strcasecmp((a), (b))
#endif
#ifndef strcasestr_P
#define strcasestr_P(a, b) strcasestr((a), (b))
#endif
#ifndef strlcat_P
#define strlcat_P(dest, src, len) strlcat((dest), (src), (len))
#endif
#ifndef strlcpy_P
#define strlcpy_P(dest, src, len) strlcpy((dest), (src), (len))
#endif
#ifndef strlen_P
#define strlen_P(s) strlen((const char *)(s))
#endif
#ifndef strnlen_P
#define strnlen_P(str, len) strnlen((str), (len))
#endif
#ifndef strncmp_P
#define strncmp_P(a, b, n) strncmp((a), (b), (n))
#endif
#ifndef strncasecmp_P
#define strncasecmp_P(a, b, n) strncasecmp((a), (b), (n))
#endif
#ifndef strncat_P
#define strncat_P(a, b, n) strncat((a), (b), (n))
#endif
#ifndef strncpy_P
#define strncpy_P(a, b, n) strncpy((a), (b), (n))
#endif
#ifndef strpbrk_P
#define strpbrk_P(str, chrs) strpbrk((str), (chrs))
#endif
#ifndef strrchr_P
#define strrchr_P(str, c) strrchr((str), (c))
#endif
#ifndef strsep_P
#define strsep_P(strp, delim) strsep((strp), (delim))
#endif
#ifndef strspn_P
#define strspn_P(str, chrs) strspn((str), (chrs))
#endif
#ifndef strstr_P
#define strstr_P(a, b) strstr((a), (b))
#endif
#ifndef sprintf_P
#define sprintf_P(s, ...) sprintf((s), __VA_ARGS__)
#endif
#ifndef vfprintf_P
#define vfprintf_P(s, ...) vfprintf((s), __VA_ARGS__)
#endif
#ifndef printf_P
#define printf_P(...) printf(__VA_ARGS__)
#endif
#ifndef snprintf_P
#define snprintf_P(s, n, ...) snprintf((s), (n), __VA_ARGS__)
#endif
#ifndef vsprintf_P
#define vsprintf_P(s, ...) vsprintf((s),__VA_ARGS__)
#endif
#ifndef vsnprintf_P
#define vsnprintf_P(s, n, ...) vsnprintf((s), (n),__VA_ARGS__)
#endif
#ifndef fprintf_P
#define fprintf_P(s, ...) fprintf((s), __VA_ARGS__)
#endif
#ifndef pgm_read_byte
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#endif
#ifndef pgm_read_word
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
#endif
#ifndef pgm_read_dword
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
#endif
#ifndef pgm_read_float
#define pgm_read_float(addr) (*(const float *)(addr))
#endif
#ifndef pgm_read_byte_near
#define pgm_read_byte_near(addr) pgm_read_byte(addr)
#endif
#ifndef pgm_read_word_near
#define pgm_read_word_near(addr) pgm_read_word(addr)
#endif
#ifndef pgm_read_dword_near
#define pgm_read_dword_near(addr) pgm_read_dword(addr)
#endif
#ifndef pgm_read_float_near
#define pgm_read_float_near(addr) pgm_read_float(addr)
#endif
#ifndef pgm_read_byte_far
#define pgm_read_byte_far(addr) pgm_read_byte(addr)
#endif
#ifndef pgm_read_word_far
#define pgm_read_word_far(addr) pgm_read_word(addr)
#endif
#ifndef pgm_read_dword_far
#define pgm_read_dword_far(addr) pgm_read_dword(addr)
#endif
#ifndef pgm_read_float_far
#define pgm_read_float_far(addr) pgm_read_float(addr)
#endif
#ifndef pgm_read_pointer
#define pgm_read_pointer
#endif
// Fix bug in pgm_read_ptr
#undef pgm_read_ptr
#define pgm_read_ptr(addr) (*((void**)(addr)))
#endif // __AVR__

7
Marlin/src/HAL/shared/servo.cpp Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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 <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -48,7 +48,6 @@
* readMicroseconds() - Get the last-written servo pulse width in microseconds.
* attached() - Return true if a servo is attached.
* detach() - Stop an attached servo from pulsing its i/o pin.
*
*/
#include "../../inc/MarlinConfig.h"
@@ -150,9 +149,7 @@ void Servo::move(const int value) {
if (attach(0) >= 0) {
write(value);
safe_delay(servo_delay[servoIndex]);
#if ENABLED(DEACTIVATE_SERVOS_AFTER_MOVE)
detach();
#endif
TERN_(DEACTIVATE_SERVOS_AFTER_MOVE, detach());
}
}

7
Marlin/src/HAL/shared/servo.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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 <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -41,7 +41,6 @@
*/
/**
*
* A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method.
* The servos are pulsed in the background using the value most recently written using the write() method
*
@@ -71,12 +70,12 @@
#include "../TEENSY31_32/Servo.h"
#elif IS_TEENSY35 || IS_TEENSY36
#include "../TEENSY35_36/Servo.h"
#elif IS_TEENSY40 || IS_TEENSY41
#include "../TEENSY40_41/Servo.h"
#elif defined(TARGET_LPC1768)
#include "../LPC1768/Servo.h"
#elif defined(__STM32F1__) || defined(TARGET_STM32F1)
#include "../STM32F1/Servo.h"
#elif defined(STM32GENERIC) && defined(STM32F4)
#include "../STM32_F4_F7/Servo.h"
#elif defined(ARDUINO_ARCH_STM32)
#include "../STM32/Servo.h"
#elif defined(ARDUINO_ARCH_ESP32)

2
Marlin/src/HAL/shared/servo_private.h Executable file → Normal file
View File

@@ -16,7 +16,7 @@
* 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 <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once