Merge pull request #3157 from wavexx/improve_d2
Add extra debugging functions & crash analysis
This commit is contained in:
commit
6188870c2e
@ -23,28 +23,25 @@ void print_hex_byte(uint8_t val)
|
||||
print_hex_nibble(val & 15);
|
||||
}
|
||||
|
||||
void print_hex_word(uint16_t val)
|
||||
{
|
||||
print_hex_byte(val >> 8);
|
||||
print_hex_byte(val & 255);
|
||||
}
|
||||
// debug range address type (fits all SRAM/PROGMEM/XFLASH memory ranges)
|
||||
#if defined(DEBUG_DCODE6) || defined(DEBUG_DCODES) || defined(XFLASH_DUMP)
|
||||
#include "xflash.h"
|
||||
#include "xflash_layout.h"
|
||||
|
||||
void print_eeprom(uint16_t address, uint16_t count, uint8_t countperline = 16)
|
||||
#define DADDR_SIZE 32
|
||||
typedef uint32_t daddr_t; // XFLASH requires 24 bits
|
||||
#else
|
||||
#define DADDR_SIZE 16
|
||||
typedef uint16_t daddr_t;
|
||||
#endif
|
||||
|
||||
void print_hex_word(daddr_t val)
|
||||
{
|
||||
while (count)
|
||||
{
|
||||
print_hex_word(address);
|
||||
putchar(' ');
|
||||
uint8_t count_line = countperline;
|
||||
while (count && count_line)
|
||||
{
|
||||
putchar(' ');
|
||||
print_hex_byte(eeprom_read_byte((uint8_t*)address++));
|
||||
count_line--;
|
||||
count--;
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
#if DADDR_SIZE > 16
|
||||
print_hex_byte((val >> 16) & 0xFF);
|
||||
#endif
|
||||
print_hex_byte((val >> 8) & 0xFF);
|
||||
print_hex_byte(val & 0xFF);
|
||||
}
|
||||
|
||||
int parse_hex(char* hex, uint8_t* data, int count)
|
||||
@ -71,12 +68,16 @@ int parse_hex(char* hex, uint8_t* data, int count)
|
||||
}
|
||||
|
||||
|
||||
void print_mem(uint32_t address, uint16_t count, uint8_t type, uint8_t countperline = 16)
|
||||
enum class dcode_mem_t:uint8_t { sram, eeprom, progmem, xflash };
|
||||
|
||||
void print_mem(daddr_t address, daddr_t count, dcode_mem_t type, uint8_t countperline = 16)
|
||||
{
|
||||
#if defined(DEBUG_DCODE6) || defined(DEBUG_DCODES) || defined(XFLASH_DUMP)
|
||||
if(type == dcode_mem_t::xflash)
|
||||
XFLASH_SPI_ENTER();
|
||||
#endif
|
||||
while (count)
|
||||
{
|
||||
if (type == 2)
|
||||
print_hex_nibble(address >> 16);
|
||||
print_hex_word(address);
|
||||
putchar(' ');
|
||||
uint8_t count_line = countperline;
|
||||
@ -85,19 +86,75 @@ void print_mem(uint32_t address, uint16_t count, uint8_t type, uint8_t countperl
|
||||
uint8_t data = 0;
|
||||
switch (type)
|
||||
{
|
||||
case 0: data = *((uint8_t*)address++); break;
|
||||
case 1: data = eeprom_read_byte((uint8_t*)address++); break;
|
||||
case 2: data = pgm_read_byte_far((uint8_t*)address++); break;
|
||||
case dcode_mem_t::sram: data = *((uint8_t*)address); break;
|
||||
case dcode_mem_t::eeprom: data = eeprom_read_byte((uint8_t*)address); break;
|
||||
case dcode_mem_t::progmem: break;
|
||||
#if defined(DEBUG_DCODE6) || defined(DEBUG_DCODES) || defined(XFLASH_DUMP)
|
||||
case dcode_mem_t::xflash: xflash_rd_data(address, &data, 1); break;
|
||||
#else
|
||||
case dcode_mem_t::xflash: break;
|
||||
#endif
|
||||
}
|
||||
++address;
|
||||
putchar(' ');
|
||||
print_hex_byte(data);
|
||||
count_line--;
|
||||
count--;
|
||||
|
||||
// sporadically call manage_heater, but only when interrupts are enabled (meaning
|
||||
// print_mem is called by D2). Don't do anything otherwise: we are inside a crash
|
||||
// handler where memory & stack needs to be preserved!
|
||||
if((SREG & (1 << SREG_I)) && !((uint16_t)count % 8192))
|
||||
manage_heater();
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this only handles SRAM/EEPROM 16bit addresses
|
||||
void write_mem(uint16_t address, uint16_t count, const uint8_t* data, const dcode_mem_t type)
|
||||
{
|
||||
for (uint16_t i = 0; i < count; i++)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case dcode_mem_t::sram: *((uint8_t*)address) = data[i]; break;
|
||||
case dcode_mem_t::eeprom: eeprom_write_byte((uint8_t*)address, data[i]); break;
|
||||
case dcode_mem_t::progmem: break;
|
||||
case dcode_mem_t::xflash: break;
|
||||
}
|
||||
++address;
|
||||
}
|
||||
}
|
||||
|
||||
void dcode_core(daddr_t addr_start, const daddr_t addr_end, const dcode_mem_t type,
|
||||
uint8_t dcode, const char* type_desc)
|
||||
{
|
||||
KEEPALIVE_STATE(NOT_BUSY);
|
||||
DBG(_N("D%d - Read/Write %S\n"), dcode, type_desc);
|
||||
daddr_t count = -1; // RW the entire space by default
|
||||
if (code_seen('A'))
|
||||
addr_start = (strchr_pointer[1] == 'x')?strtol(strchr_pointer + 2, 0, 16):(int)code_value();
|
||||
if (code_seen('C'))
|
||||
count = code_value_long();
|
||||
if (addr_start > addr_end)
|
||||
addr_start = addr_end;
|
||||
if ((addr_start + count) > addr_end || (addr_start + count) < addr_start)
|
||||
count = addr_end - addr_start;
|
||||
if (code_seen('X'))
|
||||
{
|
||||
uint8_t data[16];
|
||||
count = parse_hex(strchr_pointer + 1, data, 16);
|
||||
write_mem(addr_start, count, data, type);
|
||||
#if DADDR_SIZE > 16
|
||||
DBG(_N("%lu bytes written to %S at address 0x%04lx\n"), count, type_desc, addr_start);
|
||||
#else
|
||||
DBG(_N("%u bytes written to %S at address 0x%08x\n"), count, type_desc, addr_start);
|
||||
#endif
|
||||
}
|
||||
print_mem(addr_start, count, type);
|
||||
}
|
||||
|
||||
#if defined DEBUG_DCODE3 || defined DEBUG_DCODES
|
||||
#define EEPROM_SIZE 0x1000
|
||||
/*!
|
||||
@ -120,46 +177,7 @@ void print_mem(uint32_t address, uint16_t count, uint8_t type, uint8_t countperl
|
||||
*/
|
||||
void dcode_3()
|
||||
{
|
||||
DBG(_N("D3 - Read/Write EEPROM\n"));
|
||||
uint16_t address = 0x0000; //default 0x0000
|
||||
uint16_t count = EEPROM_SIZE; //default 0x1000 (entire eeprom)
|
||||
if (code_seen('A')) // Address (0x0000-0x0fff)
|
||||
address = (strchr_pointer[1] == 'x')?strtol(strchr_pointer + 2, 0, 16):(int)code_value();
|
||||
if (code_seen('C')) // Count (0x0001-0x1000)
|
||||
count = (int)code_value();
|
||||
address &= 0x1fff;
|
||||
if (count > EEPROM_SIZE) count = EEPROM_SIZE;
|
||||
if ((address + count) > EEPROM_SIZE) count = EEPROM_SIZE - address;
|
||||
if (code_seen('X')) // Data
|
||||
{
|
||||
uint8_t data[16];
|
||||
count = parse_hex(strchr_pointer + 1, data, 16);
|
||||
if (count > 0)
|
||||
{
|
||||
for (uint16_t i = 0; i < count; i++)
|
||||
eeprom_write_byte((uint8_t*)(address + i), data[i]);
|
||||
printf_P(_N("%d bytes written to EEPROM at address 0x%04x"), count, address);
|
||||
putchar('\n');
|
||||
}
|
||||
else
|
||||
count = 0;
|
||||
}
|
||||
print_mem(address, count, 1);
|
||||
/* while (count)
|
||||
{
|
||||
print_hex_word(address);
|
||||
putchar(' ');
|
||||
uint8_t countperline = 16;
|
||||
while (count && countperline)
|
||||
{
|
||||
uint8_t data = eeprom_read_byte((uint8_t*)address++);
|
||||
putchar(' ');
|
||||
print_hex_byte(data);
|
||||
countperline--;
|
||||
count--;
|
||||
}
|
||||
putchar('\n');
|
||||
}*/
|
||||
dcode_core(0, EEPROM_SIZE, dcode_mem_t::eeprom, 3, _N("EEPROM"));
|
||||
}
|
||||
#endif //DEBUG_DCODE3
|
||||
|
||||
@ -239,7 +257,9 @@ void dcode_1()
|
||||
eeprom_write_byte((unsigned char*)i, (unsigned char)0xff);
|
||||
softReset();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined DEBUG_DCODE2 || defined DEBUG_DCODES
|
||||
/*!
|
||||
### D2 - Read/Write RAM <a href="https://reprap.org/wiki/G-code#D2:_Read.2FWrite_RAM">D3: Read/Write RAM</a>
|
||||
This command can be used without any additional parameters. It will read the entire RAM.
|
||||
@ -248,8 +268,8 @@ void dcode_1()
|
||||
D2 [ A | C | X ]
|
||||
|
||||
#### Parameters
|
||||
- `A` - Address (x0000-x1fff)
|
||||
- `C` - Count (1-8192)
|
||||
- `A` - Address (x0000-x21ff)
|
||||
- `C` - Count (1-8704)
|
||||
- `X` - Data
|
||||
|
||||
#### Notes
|
||||
@ -260,47 +280,11 @@ void dcode_1()
|
||||
*/
|
||||
void dcode_2()
|
||||
{
|
||||
LOG("D2 - Read/Write RAM\n");
|
||||
uint16_t address = 0x0000; //default 0x0000
|
||||
uint16_t count = 0x2000; //default 0x2000 (entire ram)
|
||||
if (code_seen('A')) // Address (0x0000-0x1fff)
|
||||
address = (strchr_pointer[1] == 'x')?strtol(strchr_pointer + 2, 0, 16):(int)code_value();
|
||||
if (code_seen('C')) // Count (0x0001-0x2000)
|
||||
count = (int)code_value();
|
||||
address &= 0x1fff;
|
||||
if (count > 0x2000) count = 0x2000;
|
||||
if ((address + count) > 0x2000) count = 0x2000 - address;
|
||||
if (code_seen('X')) // Data
|
||||
{
|
||||
uint8_t data[16];
|
||||
count = parse_hex(strchr_pointer + 1, data, 16);
|
||||
if (count > 0)
|
||||
{
|
||||
for (uint16_t i = 0; i < count; i++)
|
||||
*((uint8_t*)(address + i)) = data[i];
|
||||
LOG("%d bytes written to RAM at address %04x", count, address);
|
||||
}
|
||||
else
|
||||
count = 0;
|
||||
}
|
||||
print_mem(address, count, 0);
|
||||
/* while (count)
|
||||
{
|
||||
print_hex_word(address);
|
||||
putchar(' ');
|
||||
uint8_t countperline = 16;
|
||||
while (count && countperline)
|
||||
{
|
||||
uint8_t data = *((uint8_t*)address++);
|
||||
putchar(' ');
|
||||
print_hex_byte(data);
|
||||
countperline--;
|
||||
count--;
|
||||
}
|
||||
putchar('\n');
|
||||
}*/
|
||||
dcode_core(RAMSTART, RAMEND+1, dcode_mem_t::sram, 2, _N("SRAM"));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_DCODES
|
||||
/*!
|
||||
|
||||
### D4 - Read/Write PIN <a href="https://reprap.org/wiki/G-code#D4:_Read.2FWrite_PIN">D4: Read/Write PIN</a>
|
||||
@ -425,17 +409,32 @@ void dcode_5()
|
||||
}
|
||||
#endif //DEBUG_DCODE5
|
||||
|
||||
#ifdef DEBUG_DCODES
|
||||
|
||||
#if defined(XFLASH) && (defined DEBUG_DCODE6 || defined DEBUG_DCODES)
|
||||
/*!
|
||||
### D6 - Read/Write external FLASH <a href="https://reprap.org/wiki/G-code#D6:_Read.2FWrite_external_FLASH">D6: Read/Write external Flash</a>
|
||||
Reserved
|
||||
This command can be used without any additional parameters. It will read the entire XFLASH.
|
||||
#### Usage
|
||||
|
||||
D6 [ A | C | X ]
|
||||
|
||||
#### Parameters
|
||||
- `A` - Address (x0000-x3ffff)
|
||||
- `C` - Count (1-262144)
|
||||
- `X` - Data
|
||||
|
||||
#### Notes
|
||||
- The hex address needs to be lowercase without the 0 before the x
|
||||
- Count is decimal
|
||||
- The hex data needs to be lowercase
|
||||
- Writing is currently not implemented
|
||||
*/
|
||||
void dcode_6()
|
||||
{
|
||||
LOG("D6 - Read/Write external FLASH\n");
|
||||
dcode_core(0x0, XFLASH_SIZE, dcode_mem_t::xflash, 6, _N("XFLASH"));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_DCODES
|
||||
/*!
|
||||
### D7 - Read/Write Bootloader <a href="https://reprap.org/wiki/G-code#D7:_Read.2FWrite_Bootloader">D7: Read/Write Bootloader</a>
|
||||
Reserved
|
||||
@ -927,5 +926,87 @@ void dcode_9125()
|
||||
}
|
||||
#endif //PAT9125
|
||||
|
||||
|
||||
#endif //DEBUG_DCODES
|
||||
|
||||
#ifdef XFLASH_DUMP
|
||||
#include "xflash_dump.h"
|
||||
|
||||
void dcode_20()
|
||||
{
|
||||
if(code_seen('E'))
|
||||
xfdump_full_dump_and_reset();
|
||||
else
|
||||
{
|
||||
unsigned long ts = _millis();
|
||||
xfdump_dump();
|
||||
ts = _millis() - ts;
|
||||
DBG(_N("dump completed in %lums\n"), ts);
|
||||
}
|
||||
}
|
||||
|
||||
void dcode_21()
|
||||
{
|
||||
if(!xfdump_check_state())
|
||||
DBG(_N("no dump available\n"));
|
||||
else
|
||||
{
|
||||
KEEPALIVE_STATE(NOT_BUSY);
|
||||
DBG(_N("D21 - read crash dump\n"));
|
||||
print_mem(DUMP_OFFSET, sizeof(dump_t), dcode_mem_t::xflash);
|
||||
}
|
||||
}
|
||||
|
||||
void dcode_22()
|
||||
{
|
||||
if(!xfdump_check_state())
|
||||
DBG(_N("no dump available\n"));
|
||||
else
|
||||
{
|
||||
xfdump_reset();
|
||||
DBG(_N("dump cleared\n"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EMERGENCY_SERIAL_DUMP
|
||||
#include "asm.h"
|
||||
#include "xflash_dump.h"
|
||||
|
||||
bool emergency_serial_dump = false;
|
||||
|
||||
void __attribute__((noinline)) serial_dump_and_reset(dump_crash_reason reason)
|
||||
{
|
||||
uint16_t sp;
|
||||
uint32_t pc;
|
||||
|
||||
// we're being called from a live state, so shut off interrupts ...
|
||||
cli();
|
||||
|
||||
// sample SP/PC
|
||||
sp = SP;
|
||||
GETPC(&pc);
|
||||
|
||||
// extend WDT long enough to allow writing the entire stream
|
||||
wdt_enable(WDTO_8S);
|
||||
|
||||
// ... and heaters
|
||||
WRITE(FAN_PIN, HIGH);
|
||||
disable_heater();
|
||||
|
||||
// this function can also be called from within a corrupted state, so not use
|
||||
// printf family of functions that use the heap or grow the stack.
|
||||
SERIAL_ECHOLNPGM("D23 - emergency serial dump");
|
||||
SERIAL_ECHOPGM("error: ");
|
||||
MYSERIAL.print((uint8_t)reason, DEC);
|
||||
SERIAL_ECHOPGM(" 0x");
|
||||
MYSERIAL.print(pc, HEX);
|
||||
SERIAL_ECHOPGM(" 0x");
|
||||
MYSERIAL.println(sp, HEX);
|
||||
|
||||
print_mem(0, RAMEND+1, dcode_mem_t::sram);
|
||||
SERIAL_ECHOLNRPGM(MSG_OK);
|
||||
|
||||
// reset soon
|
||||
softReset();
|
||||
}
|
||||
#endif
|
||||
|
@ -4,7 +4,10 @@
|
||||
extern void dcode__1(); //D-1 - Endless loop (to simulate deadlock)
|
||||
extern void dcode_0(); //D0 - Reset
|
||||
extern void dcode_1(); //D1 - Clear EEPROM
|
||||
|
||||
#if defined DEBUG_DCODE2 || defined DEBUG_DCODES
|
||||
extern void dcode_2(); //D2 - Read/Write RAM
|
||||
#endif
|
||||
|
||||
#if defined DEBUG_DCODE3 || defined DEBUG_DCODES
|
||||
extern void dcode_3(); //D3 - Read/Write EEPROM
|
||||
@ -16,13 +19,28 @@ extern void dcode_4(); //D4 - Read/Write PIN
|
||||
extern void dcode_5(); //D5 - Read/Write FLASH
|
||||
#endif //DEBUG_DCODE5
|
||||
|
||||
#if defined DEBUG_DCODE6 || defined DEBUG_DCODES
|
||||
extern void dcode_6(); //D6 - Read/Write external FLASH
|
||||
#endif
|
||||
|
||||
extern void dcode_7(); //D7 - Read/Write Bootloader
|
||||
extern void dcode_8(); //D8 - Read/Write PINDA
|
||||
extern void dcode_9(); //D9 - Read/Write ADC (Write=enable simulated, Read=disable simulated)
|
||||
extern void dcode_10(); //D10 - XYZ calibration = OK
|
||||
extern void dcode_12(); //D12 - Log time. Writes the current time in the log file.
|
||||
|
||||
#ifdef XFLASH_DUMP
|
||||
extern void dcode_20(); //D20 - Generate an offline crash dump
|
||||
extern void dcode_21(); //D21 - Print crash dump to serial
|
||||
extern void dcode_22(); //D22 - Clear crash dump state
|
||||
#endif
|
||||
|
||||
#ifdef EMERGENCY_SERIAL_DUMP
|
||||
#include "xflash_dump.h"
|
||||
extern bool emergency_serial_dump;
|
||||
extern void serial_dump_and_reset(dump_crash_reason);
|
||||
#endif
|
||||
|
||||
#ifdef HEATBED_ANALYSIS
|
||||
extern void dcode_80(); //D80 - Bed check. This command will log data to SD card file "mesh.txt".
|
||||
extern void dcode_81(); //D81 - Bed analysis. This command will log data to SD card file "wldsd.txt".
|
||||
|
@ -497,6 +497,7 @@ void marlin_wait_for_click();
|
||||
void raise_z_above(float target, bool plan=true);
|
||||
|
||||
extern "C" void softReset();
|
||||
void stack_error();
|
||||
|
||||
extern uint32_t IP_address;
|
||||
|
||||
|
@ -66,6 +66,7 @@
|
||||
|
||||
#include "menu.h"
|
||||
#include "ultralcd.h"
|
||||
#include "conv2str.h"
|
||||
#include "backlight.h"
|
||||
|
||||
#include "planner.h"
|
||||
@ -108,6 +109,8 @@
|
||||
#include "optiboot_xflash.h"
|
||||
#endif //XFLASH
|
||||
|
||||
#include "xflash_dump.h"
|
||||
|
||||
#ifdef BLINKM
|
||||
#include "BlinkM.h"
|
||||
#include "Wire.h"
|
||||
@ -994,6 +997,58 @@ void list_sec_lang_from_external_flash()
|
||||
#endif //(LANG_MODE != 0)
|
||||
|
||||
|
||||
static void fw_crash_init()
|
||||
{
|
||||
#ifdef XFLASH_DUMP
|
||||
dump_crash_reason crash_reason;
|
||||
if(xfdump_check_state(&crash_reason))
|
||||
{
|
||||
// always signal to the host that a dump is available for retrieval
|
||||
puts_P(_N("// action:dump_available"));
|
||||
|
||||
#ifdef EMERGENCY_DUMP
|
||||
if(crash_reason != dump_crash_reason::manual &&
|
||||
eeprom_read_byte((uint8_t*)EEPROM_FW_CRASH_FLAG) != 0xFF)
|
||||
{
|
||||
lcd_show_fullscreen_message_and_wait_P(
|
||||
_i("FIRMWARE CRASH!\n"
|
||||
"Debug data available for analysis. "
|
||||
"Contact support to submit details."));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else //XFLASH_DUMP
|
||||
dump_crash_reason crash_reason = (dump_crash_reason)eeprom_read_byte((uint8_t*)EEPROM_FW_CRASH_FLAG);
|
||||
if(crash_reason != dump_crash_reason::manual && (uint8_t)crash_reason != 0xFF)
|
||||
{
|
||||
lcd_beeper_quick_feedback();
|
||||
lcd_clear();
|
||||
|
||||
lcd_puts_P(_i("FIRMWARE CRASH!\nCrash reason:\n"));
|
||||
switch(crash_reason)
|
||||
{
|
||||
case dump_crash_reason::stack_error:
|
||||
lcd_puts_P(_i("Static memory has\nbeen overwritten"));
|
||||
break;
|
||||
case dump_crash_reason::watchdog:
|
||||
lcd_puts_P(_i("Watchdog timeout"));
|
||||
break;
|
||||
case dump_crash_reason::bad_isr:
|
||||
lcd_puts_P(_i("Bad interrupt"));
|
||||
break;
|
||||
default:
|
||||
lcd_print((uint8_t)crash_reason);
|
||||
break;
|
||||
}
|
||||
lcd_wait_for_click();
|
||||
}
|
||||
#endif //XFLASH_DUMP
|
||||
|
||||
// prevent crash prompts to reappear once acknowledged
|
||||
eeprom_update_byte((uint8_t*)EEPROM_FW_CRASH_FLAG, 0xFF);
|
||||
}
|
||||
|
||||
|
||||
static void xflash_err_msg()
|
||||
{
|
||||
lcd_clear();
|
||||
@ -1612,6 +1667,9 @@ void setup()
|
||||
if (tmc2130_home_enabled == 0xff) tmc2130_home_enabled = 0;
|
||||
#endif //TMC2130
|
||||
|
||||
// report crash failures
|
||||
fw_crash_init();
|
||||
|
||||
#ifdef UVLO_SUPPORT
|
||||
if (eeprom_read_byte((uint8_t*)EEPROM_UVLO) != 0) { //previous print was terminated by UVLO
|
||||
/*
|
||||
@ -1657,10 +1715,45 @@ void setup()
|
||||
KEEPALIVE_STATE(NOT_BUSY);
|
||||
#ifdef WATCHDOG
|
||||
wdt_enable(WDTO_4S);
|
||||
#ifdef EMERGENCY_HANDLERS
|
||||
WDTCSR |= (1 << WDIE);
|
||||
#endif //EMERGENCY_HANDLERS
|
||||
#endif //WATCHDOG
|
||||
}
|
||||
|
||||
|
||||
static inline void crash_and_burn(dump_crash_reason reason)
|
||||
{
|
||||
WRITE(BEEPER, HIGH);
|
||||
eeprom_update_byte((uint8_t*)EEPROM_FW_CRASH_FLAG, (uint8_t)reason);
|
||||
#ifdef EMERGENCY_DUMP
|
||||
xfdump_full_dump_and_reset(reason);
|
||||
#elif defined(EMERGENCY_SERIAL_DUMP)
|
||||
if(emergency_serial_dump)
|
||||
serial_dump_and_reset(reason);
|
||||
#endif
|
||||
softReset();
|
||||
}
|
||||
|
||||
#ifdef EMERGENCY_HANDLERS
|
||||
#ifdef WATCHDOG
|
||||
ISR(WDT_vect)
|
||||
{
|
||||
crash_and_burn(dump_crash_reason::watchdog);
|
||||
}
|
||||
#endif
|
||||
|
||||
ISR(BADISR_vect)
|
||||
{
|
||||
crash_and_burn(dump_crash_reason::bad_isr);
|
||||
}
|
||||
#endif //EMERGENCY_HANDLERS
|
||||
|
||||
void stack_error() {
|
||||
crash_and_burn(dump_crash_reason::stack_error);
|
||||
}
|
||||
|
||||
|
||||
void trace();
|
||||
|
||||
#define CHUNK_SIZE 64 // bytes
|
||||
@ -9080,7 +9173,9 @@ Sigma_Exit:
|
||||
*/
|
||||
case 1:
|
||||
dcode_1(); break;
|
||||
#endif
|
||||
|
||||
#if defined DEBUG_DCODE2 || defined DEBUG_DCODES
|
||||
/*!
|
||||
### D2 - Read/Write RAM <a href="https://reprap.org/wiki/G-code#D2:_Read.2FWrite_RAM">D3: Read/Write RAM</a>
|
||||
This command can be used without any additional parameters. It will read the entire RAM.
|
||||
@ -9167,7 +9262,7 @@ Sigma_Exit:
|
||||
case 5:
|
||||
dcode_5(); break;
|
||||
#endif //DEBUG_DCODE5
|
||||
#ifdef DEBUG_DCODES
|
||||
#if defined DEBUG_DCODE6 || defined DEBUG_DCODES
|
||||
|
||||
/*!
|
||||
### D6 - Read/Write external FLASH <a href="https://reprap.org/wiki/G-code#D6:_Read.2FWrite_external_FLASH">D6: Read/Write external Flash</a>
|
||||
@ -9175,6 +9270,8 @@ Sigma_Exit:
|
||||
*/
|
||||
case 6:
|
||||
dcode_6(); break;
|
||||
#endif
|
||||
#ifdef DEBUG_DCODES
|
||||
|
||||
/*!
|
||||
### D7 - Read/Write Bootloader <a href="https://reprap.org/wiki/G-code#D7:_Read.2FWrite_Bootloader">D7: Read/Write Bootloader</a>
|
||||
@ -9228,8 +9325,72 @@ Sigma_Exit:
|
||||
### D12 - Time <a href="https://reprap.org/wiki/G-code#D12:_Time">D12: Time</a>
|
||||
Writes the current time in the log file.
|
||||
*/
|
||||
|
||||
#endif //DEBUG_DCODES
|
||||
|
||||
#ifdef XFLASH_DUMP
|
||||
/*!
|
||||
### D20 - Generate an offline crash dump
|
||||
Generate a crash dump for later retrival.
|
||||
#### Usage
|
||||
|
||||
D20 [E]
|
||||
|
||||
### Parameters
|
||||
- `E` - Perform an emergency crash dump (resets the printer).
|
||||
### Notes
|
||||
- A crash dump can be later recovered with D21, or cleared with D22.
|
||||
- An emergency crash dump includes register data, but will cause the printer to reset after the dump
|
||||
is completed.
|
||||
*/
|
||||
case 20: {
|
||||
dcode_20();
|
||||
break;
|
||||
};
|
||||
|
||||
/*!
|
||||
### D21 - Print crash dump to serial
|
||||
Output the complete crash dump (if present) to the serial.
|
||||
#### Usage
|
||||
|
||||
D21
|
||||
|
||||
### Notes
|
||||
- The starting address can vary between builds, but it's always at the beginning of the data section.
|
||||
*/
|
||||
case 21: {
|
||||
dcode_21();
|
||||
break;
|
||||
};
|
||||
|
||||
/*!
|
||||
### D22 - Clear crash dump state
|
||||
Clear an existing internal crash dump.
|
||||
#### Usage
|
||||
|
||||
D22
|
||||
*/
|
||||
case 22: {
|
||||
dcode_22();
|
||||
break;
|
||||
};
|
||||
#endif //XFLASH_DUMP
|
||||
|
||||
#ifdef EMERGENCY_SERIAL_DUMP
|
||||
/*!
|
||||
### D23 - Request emergency dump on serial
|
||||
On boards without offline dump support, request online dumps to the serial port on firmware faults.
|
||||
When online dumps are enabled, the FW will dump memory on the serial before resetting.
|
||||
#### Usage
|
||||
|
||||
D23 [R]
|
||||
#### Parameters
|
||||
- `R` - Disable online dumps.
|
||||
*/
|
||||
case 23: {
|
||||
emergency_serial_dump = !code_seen('R');
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef HEATBED_ANALYSIS
|
||||
|
||||
/*!
|
||||
|
@ -48,24 +48,16 @@ void SdFatUtil::set_stack_guard()
|
||||
{
|
||||
uint32_t *stack_guard;
|
||||
|
||||
stack_guard = (uint32_t*)&__bss_end;
|
||||
stack_guard = (uint32_t*)(&__bss_end + STACK_GUARD_MARGIN);
|
||||
*stack_guard = STACK_GUARD_TEST_VALUE;
|
||||
}
|
||||
|
||||
bool SdFatUtil::test_stack_integrity()
|
||||
{
|
||||
uint32_t* stack_guard = (uint32_t*)&__bss_end;
|
||||
uint32_t* stack_guard = (uint32_t*)(&__bss_end + STACK_GUARD_MARGIN);
|
||||
return (*stack_guard == STACK_GUARD_TEST_VALUE);
|
||||
}
|
||||
|
||||
uint32_t SdFatUtil::get_stack_guard_test_value()
|
||||
{
|
||||
uint32_t* stack_guard;
|
||||
uint32_t output;
|
||||
stack_guard = (uint32_t*)&__bss_end;
|
||||
output = *stack_guard;
|
||||
return(output);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** %Print a string in flash memory.
|
||||
*
|
||||
|
@ -41,7 +41,6 @@ namespace SdFatUtil {
|
||||
void SerialPrintln_P(PGM_P str);
|
||||
void set_stack_guard();
|
||||
bool test_stack_integrity();
|
||||
uint32_t get_stack_guard_test_value();
|
||||
}
|
||||
|
||||
using namespace SdFatUtil; // NOLINT
|
||||
|
24
Firmware/asm.h
Normal file
24
Firmware/asm.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __AVR_ATmega2560__
|
||||
|
||||
// return the current PC (on AVRs with 22bit PC)
|
||||
static inline void GETPC(uint32_t* v)
|
||||
{
|
||||
uint8_t a, b, c;
|
||||
asm
|
||||
(
|
||||
"rcall .\n"
|
||||
"pop %2\n"
|
||||
"pop %1\n"
|
||||
"pop %0\n"
|
||||
: "=r" (a), "=r" (b), "=r" (c)
|
||||
);
|
||||
((uint8_t*)v)[0] = a;
|
||||
((uint8_t*)v)[1] = b;
|
||||
((uint8_t*)v)[2] = c;
|
||||
((uint8_t*)v)[3] = 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -3,10 +3,11 @@
|
||||
#define BOOTAPP_H
|
||||
|
||||
#include "config.h"
|
||||
#include <avr/io.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
|
||||
#define RAMSIZE 0x2000
|
||||
#define RAMSIZE (RAMEND+1-RAMSTART)
|
||||
#define boot_src_addr (*((uint32_t*)(RAMSIZE - 16)))
|
||||
#define boot_dst_addr (*((uint32_t*)(RAMSIZE - 12)))
|
||||
#define boot_copy_size (*((uint16_t*)(RAMSIZE - 8)))
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include "cmdqueue.h"
|
||||
#include "cardreader.h"
|
||||
#include "ultralcd.h"
|
||||
#include "conv2str.h"
|
||||
#include "menu.h"
|
||||
#include "stepper.h"
|
||||
#include "temperature.h"
|
||||
#include "language.h"
|
||||
|
@ -68,4 +68,25 @@
|
||||
#define COMMUNITY_LANG_SUPPORT
|
||||
#endif
|
||||
|
||||
// Sanity checks for correct configuration of XFLASH_DUMP options
|
||||
#if defined(XFLASH_DUMP) && !defined(XFLASH)
|
||||
#error "XFLASH_DUMP requires XFLASH support"
|
||||
#endif
|
||||
#if (defined(MENU_DUMP) || defined(EMERGENCY_DUMP)) && !defined(XFLASH_DUMP)
|
||||
#error "MENU_DUMP and EMERGENCY_DUMP require XFLASH_DUMP"
|
||||
#endif
|
||||
|
||||
// Support for serial dumps is mutually exclusive with XFLASH_DUMP features
|
||||
#if defined(EMERGENCY_DUMP) && defined(EMERGENCY_SERIAL_DUMP)
|
||||
#error "EMERGENCY_DUMP and EMERGENCY_SERIAL_DUMP are mutually exclusive"
|
||||
#endif
|
||||
#if defined(MENU_DUMP) && defined(MENU_SERIAL_DUMP)
|
||||
#error "MENU_DUMP and MENU_SERIAL_DUMP are mutually exclusive"
|
||||
#endif
|
||||
|
||||
// Reduce internal duplication
|
||||
#if defined(EMERGENCY_DUMP) || defined(EMERGENCY_SERIAL_DUMP)
|
||||
#define EMERGENCY_HANDLERS
|
||||
#endif
|
||||
|
||||
#endif //_CONFIG_H
|
||||
|
@ -325,8 +325,9 @@ static_assert(sizeof(Sheets) == EEPROM_SHEETS_SIZEOF, "Sizeof(Sheets) is not EEP
|
||||
| 0x0D0D 3341 | float | EEPROM_UVLO_RETRACT_ACCELL | ??? | ff ff ff ffh | Power panic saved retract acceleration | ??? | D3 Ax0d0d C4
|
||||
| 0x0D09 3337 | float | EEPROM_UVLO_TRAVEL_ACCELL | ??? | ff ff ff ffh | Power panic saved travel acceleration | ??? | D3 Ax0d09 C4
|
||||
| 0x0D05 3333 | uint32_t | EEPROM_JOB_ID | ??? | 00 00 00 00h | Job ID used by host software | D3 only | D3 Ax0d05 C4
|
||||
| 0x0D01 3329 | uint8_t | EEPROM_ECOOL_ENABLE | ffh 255 | ^ | Disable extruder motor scaling for non-farm print | LCD menu | D3 Ax0d01 FF
|
||||
| ^ | ^ | ^ | 2ah 42 | ^ | Enable extruder motor scaling for non-farm print | ^ | D3 Ax0d01 42
|
||||
| 0x0D04 3332 | uint8_t | EEPROM_ECOOL_ENABLE | ffh 255 | ^ | Disable extruder motor scaling for non-farm print | LCD menu | D3 Ax0d04 C1
|
||||
| ^ | ^ | ^ | 2ah 42 | ^ | Enable extruder motor scaling for non-farm print | ^ | D3 Ax0d04 C1
|
||||
| 0x0D03 3321 | uint8_t | EEPROM_FW_CRASH_FLAG | 01h 1 | ff/00 | Last FW crash reason (dump_crash_reason) | D21/D22 | D3 Ax0d03 C1
|
||||
|
||||
| Address begin | Bit/Type | Name | Valid values | Default/FactoryReset | Description | Gcode/Function| Debug code
|
||||
| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--:
|
||||
@ -541,9 +542,10 @@ static Sheets * const EEPROM_Sheets_base = (Sheets*)(EEPROM_SHEETS_BASE);
|
||||
#define EEPROM_JOB_ID (EEPROM_UVLO_TRAVEL_ACCELL-4) //uint32_t
|
||||
|
||||
#define EEPROM_ECOOL_ENABLE (EEPROM_JOB_ID-1) // uint8_t
|
||||
#define EEPROM_FW_CRASH_FLAG (EEPROM_ECOOL_ENABLE-1) // uint8_t
|
||||
|
||||
//This is supposed to point to last item to allow EEPROM overrun check. Please update when adding new items.
|
||||
#define EEPROM_LAST_ITEM EEPROM_ECOOL_ENABLE
|
||||
#define EEPROM_LAST_ITEM EEPROM_FW_CRASH_FLAG
|
||||
// !!!!!
|
||||
// !!!!! this is end of EEPROM section ... all updates MUST BE inserted before this mark !!!!!
|
||||
// !!!!!
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#ifdef XFLASH
|
||||
#include "xflash.h"
|
||||
#include "xflash_layout.h"
|
||||
#endif //XFLASH
|
||||
|
||||
// Currently active language selection.
|
||||
@ -110,7 +111,7 @@ uint8_t lang_get_count()
|
||||
#ifdef XFLASH
|
||||
XFLASH_SPI_ENTER();
|
||||
uint8_t count = 2; //count = 1+n (primary + secondary + all in xflash)
|
||||
uint32_t addr = 0x00000; //start of xflash
|
||||
uint32_t addr = LANG_OFFSET;
|
||||
lang_table_header_t header; //table header structure
|
||||
while (1)
|
||||
{
|
||||
@ -143,7 +144,7 @@ uint8_t lang_get_header(uint8_t lang, lang_table_header_t* header, uint32_t* off
|
||||
return (header->magic == LANG_MAGIC)?1:0; //return 1 if magic valid
|
||||
}
|
||||
XFLASH_SPI_ENTER();
|
||||
uint32_t addr = 0x00000; //start of xflash
|
||||
uint32_t addr = LANG_OFFSET;
|
||||
lang--;
|
||||
while (1)
|
||||
{
|
||||
@ -176,7 +177,7 @@ uint16_t lang_get_code(uint8_t lang)
|
||||
return pgm_read_word(((uint32_t*)(ui + 10))); //return lang code from progmem
|
||||
}
|
||||
XFLASH_SPI_ENTER();
|
||||
uint32_t addr = 0x00000; //start of xflash
|
||||
uint32_t addr = LANG_OFFSET;
|
||||
lang_table_header_t header; //table header structure
|
||||
lang--;
|
||||
while (1)
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "cardreader.h"
|
||||
#include "cmdqueue.h"
|
||||
#include "ultralcd.h"
|
||||
#include "menu.h"
|
||||
#include "sound.h"
|
||||
#include "printers.h"
|
||||
#include <avr/pgmspace.h>
|
||||
|
@ -32,11 +32,13 @@
|
||||
#include "Marlin.h"
|
||||
#include "cmdqueue.h"
|
||||
#include "ultralcd.h"
|
||||
#include "menu.h"
|
||||
#include "conv2str.h"
|
||||
#include "sound.h"
|
||||
#include "temperature.h"
|
||||
#include "cardreader.h"
|
||||
|
||||
#include "Sd2PinMap.h"
|
||||
#include "SdFatUtil.h"
|
||||
|
||||
#include <avr/wdt.h>
|
||||
#include "adc.h"
|
||||
@ -2060,6 +2062,9 @@ FORCE_INLINE static void temperature_isr()
|
||||
}
|
||||
#endif //BABYSTEPPING
|
||||
|
||||
// Check if a stack overflow happened
|
||||
if (!SdFatUtil::test_stack_integrity()) stack_error();
|
||||
|
||||
#if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1))
|
||||
check_fans();
|
||||
#endif //(defined(TACH_0))
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "temperature.h"
|
||||
#include "ultralcd.h"
|
||||
#include "conv2str.h"
|
||||
#include "fsensor.h"
|
||||
#include "Marlin.h"
|
||||
#include "language.h"
|
||||
@ -28,8 +29,6 @@
|
||||
//#include "Configuration.h"
|
||||
#include "cmdqueue.h"
|
||||
|
||||
#include "SdFatUtil.h"
|
||||
|
||||
#ifdef FILAMENT_SENSOR
|
||||
#include "pat9125.h"
|
||||
#include "fsensor.h"
|
||||
@ -1806,6 +1805,61 @@ static void lcd_preheat_menu()
|
||||
lcd_generic_preheat_menu();
|
||||
}
|
||||
|
||||
|
||||
#ifdef MENU_DUMP
|
||||
#include "xflash_dump.h"
|
||||
|
||||
static void lcd_dump_memory()
|
||||
{
|
||||
lcd_beeper_quick_feedback();
|
||||
xfdump_dump();
|
||||
lcd_return_to_status();
|
||||
}
|
||||
#endif //MENU_DUMP
|
||||
#ifdef MENU_SERIAL_DUMP
|
||||
#include "Dcodes.h"
|
||||
|
||||
static void lcd_serial_dump()
|
||||
{
|
||||
serial_dump_and_reset(dump_crash_reason::manual);
|
||||
}
|
||||
#endif //MENU_SERIAL_DUMP
|
||||
|
||||
#if defined(DEBUG_BUILD) && defined(EMERGENCY_HANDLERS)
|
||||
#include <avr/wdt.h>
|
||||
|
||||
#ifdef WATCHDOG
|
||||
static void lcd_wdr_crash()
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint8_t lcd_stack_crash_(uint8_t arg, uint32_t sp = 0)
|
||||
{
|
||||
// populate the stack with an increasing value for ease of testing
|
||||
volatile uint16_t tmp __attribute__((unused)) = sp;
|
||||
|
||||
_delay(arg);
|
||||
uint8_t ret = lcd_stack_crash_(arg, SP);
|
||||
|
||||
// required to avoid tail call elimination and to slow down the stack growth
|
||||
_delay(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void lcd_stack_crash()
|
||||
{
|
||||
#ifdef WATCHDOG
|
||||
wdt_disable();
|
||||
#endif
|
||||
// delay choosen in order to hit the stack-check in the temperature isr reliably
|
||||
lcd_stack_crash_(10);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//! @brief Show Support Menu
|
||||
//!
|
||||
//! @code{.unparsed}
|
||||
@ -1997,8 +2051,20 @@ static void lcd_support_menu()
|
||||
MENU_ITEM_SUBMENU_P(_i("Voltages"), lcd_menu_voltages);////MSG_MENU_VOLTAGES c=18
|
||||
#endif //defined VOLT_BED_PIN || defined VOLT_PWR_PIN
|
||||
|
||||
|
||||
#ifdef MENU_DUMP
|
||||
MENU_ITEM_FUNCTION_P(_i("Dump memory"), lcd_dump_memory);
|
||||
#endif //MENU_DUMP
|
||||
#ifdef MENU_SERIAL_DUMP
|
||||
if (emergency_serial_dump)
|
||||
MENU_ITEM_FUNCTION_P(_i("Dump to serial"), lcd_serial_dump);
|
||||
#endif
|
||||
#ifdef DEBUG_BUILD
|
||||
#ifdef EMERGENCY_HANDLERS
|
||||
#ifdef WATCHDOG
|
||||
MENU_ITEM_FUNCTION_P(PSTR("WDR crash"), lcd_wdr_crash);
|
||||
#endif //WATCHDOG
|
||||
MENU_ITEM_FUNCTION_P(PSTR("Stack crash"), lcd_stack_crash);
|
||||
#endif //EMERGENCY_HANDLERS
|
||||
MENU_ITEM_SUBMENU_P(PSTR("Debug"), lcd_menu_debug);////MSG_DEBUG c=18
|
||||
#endif /* DEBUG_BUILD */
|
||||
|
||||
@ -6695,12 +6761,6 @@ static void lcd_main_menu()
|
||||
|
||||
}
|
||||
|
||||
void stack_error() {
|
||||
Sound_MakeCustom(1000,0,true);
|
||||
lcd_display_message_fullscreen_P(_i("Error - static memory has been overwritten"));////MSG_STACK_ERROR c=20 r=4
|
||||
//err_triggered = 1;
|
||||
while (1) delay_keep_alive(1000);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_STEPPER_TIMER_MISSED
|
||||
bool stepper_timer_overflow_state = false;
|
||||
@ -8928,7 +8988,6 @@ void menu_lcd_lcdupdate_func(void)
|
||||
if (lcd_draw_update) lcd_draw_update--;
|
||||
lcd_next_update_millis = _millis() + LCD_UPDATE_INTERVAL;
|
||||
}
|
||||
if (!SdFatUtil::test_stack_integrity()) stack_error();
|
||||
lcd_ping(); //check that we have received ping command if we are in farm mode
|
||||
lcd_send_status();
|
||||
if (lcd_commands_type == LcdCommands::Layer1Cal) lcd_commands();
|
||||
|
@ -1,15 +1,9 @@
|
||||
#ifndef ULTRALCD_H
|
||||
#define ULTRALCD_H
|
||||
|
||||
#include "Marlin.h"
|
||||
#include "lcd.h"
|
||||
#include "conv2str.h"
|
||||
#include "menu.h"
|
||||
#include "mesh_bed_calibration.h"
|
||||
#include "config.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
extern void menu_lcd_longpress_func(void);
|
||||
extern void menu_lcd_charsetup_func(void);
|
||||
extern void menu_lcd_lcdupdate_func(void);
|
||||
@ -200,7 +194,6 @@ void mFilamentItemForce();
|
||||
void lcd_generic_preheat_menu();
|
||||
void unload_filament(bool automatic = false);
|
||||
|
||||
void stack_error();
|
||||
void lcd_printer_connected();
|
||||
void lcd_ping();
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "Configuration.h"
|
||||
|
||||
#include "ultralcd.h"
|
||||
#include "menu.h"
|
||||
#include "sound.h"
|
||||
#include "language.h"
|
||||
#include "util.h"
|
||||
|
@ -418,6 +418,7 @@ THERMISTORS SETTINGS
|
||||
#endif
|
||||
|
||||
#define STACK_GUARD_TEST_VALUE 0xA2A2
|
||||
#define STACK_GUARD_MARGIN 32
|
||||
|
||||
#define MAX_BED_TEMP_CALIBRATION 50
|
||||
#define MAX_HOTEND_TEMP_CALIBRATION 50
|
||||
|
@ -407,6 +407,7 @@ THERMISTORS SETTINGS
|
||||
#endif
|
||||
|
||||
#define STACK_GUARD_TEST_VALUE 0xA2A2
|
||||
#define STACK_GUARD_MARGIN 32
|
||||
|
||||
#define MAX_BED_TEMP_CALIBRATION 50
|
||||
#define MAX_HOTEND_TEMP_CALIBRATION 50
|
||||
|
@ -119,11 +119,15 @@
|
||||
#define DEFAULT_SAFETYTIMER_TIME_MINS 30
|
||||
#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
|
||||
|
||||
// Online crash dumper
|
||||
#define EMERGENCY_SERIAL_DUMP // Request dump via serial on stack corruption and WDR
|
||||
#define MENU_SERIAL_DUMP // Enable "Memory dump" in Settings menu
|
||||
|
||||
// Filament sensor
|
||||
#define FILAMENT_SENSOR
|
||||
#define PAT9125
|
||||
|
||||
|
||||
#define DEBUG_DCODE2
|
||||
#define DEBUG_DCODE3
|
||||
|
||||
//#define DEBUG_BUILD
|
||||
@ -469,6 +473,7 @@
|
||||
#define TEMP_SENSOR_PINDA 1
|
||||
|
||||
#define STACK_GUARD_TEST_VALUE 0xA2A2
|
||||
#define STACK_GUARD_MARGIN 32
|
||||
|
||||
#define MAX_BED_TEMP_CALIBRATION 50
|
||||
#define MAX_HOTEND_TEMP_CALIBRATION 50
|
||||
|
@ -120,11 +120,15 @@
|
||||
#define DEFAULT_SAFETYTIMER_TIME_MINS 30
|
||||
#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
|
||||
|
||||
// Online crash dumper
|
||||
#define EMERGENCY_SERIAL_DUMP // Request dump via serial on stack corruption and WDR
|
||||
#define MENU_SERIAL_DUMP // Enable "Memory dump" in Settings menu
|
||||
|
||||
// Filament sensor
|
||||
#define FILAMENT_SENSOR
|
||||
#define PAT9125
|
||||
|
||||
|
||||
#define DEBUG_DCODE2
|
||||
#define DEBUG_DCODE3
|
||||
|
||||
//#define DEBUG_BUILD
|
||||
@ -470,6 +474,7 @@
|
||||
#define TEMP_SENSOR_PINDA 1
|
||||
|
||||
#define STACK_GUARD_TEST_VALUE 0xA2A2
|
||||
#define STACK_GUARD_MARGIN 32
|
||||
|
||||
#define MAX_BED_TEMP_CALIBRATION 50
|
||||
#define MAX_HOTEND_TEMP_CALIBRATION 50
|
||||
|
@ -119,11 +119,15 @@
|
||||
#define DEFAULT_SAFETYTIMER_TIME_MINS 30
|
||||
#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
|
||||
|
||||
// Online crash dumper
|
||||
#define EMERGENCY_SERIAL_DUMP // Request dump via serial on stack corruption and WDR
|
||||
#define MENU_SERIAL_DUMP // Enable "Memory dump" in Settings menu
|
||||
|
||||
// Filament sensor
|
||||
#define FILAMENT_SENSOR
|
||||
#define IR_SENSOR
|
||||
|
||||
|
||||
#define DEBUG_DCODE2
|
||||
#define DEBUG_DCODE3
|
||||
|
||||
//#define DEBUG_BUILD
|
||||
@ -469,6 +473,7 @@
|
||||
#define TEMP_SENSOR_PINDA 1
|
||||
|
||||
#define STACK_GUARD_TEST_VALUE 0xA2A2
|
||||
#define STACK_GUARD_MARGIN 32
|
||||
|
||||
#define MAX_BED_TEMP_CALIBRATION 50
|
||||
#define MAX_HOTEND_TEMP_CALIBRATION 50
|
||||
|
@ -120,11 +120,15 @@
|
||||
#define DEFAULT_SAFETYTIMER_TIME_MINS 30
|
||||
#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
|
||||
|
||||
// Online crash dumper
|
||||
#define EMERGENCY_SERIAL_DUMP // Request dump via serial on stack corruption and WDR
|
||||
#define MENU_SERIAL_DUMP // Enable "Memory dump" in Settings menu
|
||||
|
||||
// Filament sensor
|
||||
#define FILAMENT_SENSOR
|
||||
#define IR_SENSOR
|
||||
|
||||
|
||||
#define DEBUG_DCODE2
|
||||
#define DEBUG_DCODE3
|
||||
|
||||
//#define DEBUG_BUILD
|
||||
@ -470,6 +474,7 @@
|
||||
#define TEMP_SENSOR_PINDA 1
|
||||
|
||||
#define STACK_GUARD_TEST_VALUE 0xA2A2
|
||||
#define STACK_GUARD_MARGIN 32
|
||||
|
||||
#define MAX_BED_TEMP_CALIBRATION 50
|
||||
#define MAX_HOTEND_TEMP_CALIBRATION 50
|
||||
|
@ -139,6 +139,15 @@
|
||||
#define DEFAULT_SAFETYTIMER_TIME_MINS 30
|
||||
#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
|
||||
|
||||
// Offline crash dumper
|
||||
#define XFLASH_DUMP // enable dump functionality (including D20/D21/D22)
|
||||
#define MENU_DUMP // enable "Memory dump" in Settings menu
|
||||
#define EMERGENCY_DUMP // trigger crash on stack corruption and WDR
|
||||
|
||||
// Online crash dumper
|
||||
//#define EMERGENCY_SERIAL_DUMP // Request dump via serial on stack corruption and WDR
|
||||
//#define MENU_SERIAL_DUMP // Enable "Memory dump" in Settings menu
|
||||
|
||||
// Filament sensor
|
||||
#define FILAMENT_SENSOR
|
||||
#define PAT9125
|
||||
@ -155,7 +164,9 @@
|
||||
#define MINTEMP_MINAMBIENT 10
|
||||
#define MINTEMP_MINAMBIENT_RAW 1002
|
||||
|
||||
#define DEBUG_DCODE2
|
||||
#define DEBUG_DCODE3
|
||||
#define DEBUG_DCODE6
|
||||
|
||||
//#define DEBUG_BUILD
|
||||
//#define DEBUG_SEC_LANG //secondary language debug output at startup
|
||||
@ -591,6 +602,7 @@
|
||||
#define TEMP_SENSOR_AMBIENT 2000
|
||||
|
||||
#define STACK_GUARD_TEST_VALUE 0xA2A2
|
||||
#define STACK_GUARD_MARGIN 32
|
||||
|
||||
#define MAX_BED_TEMP_CALIBRATION 50
|
||||
#define MAX_HOTEND_TEMP_CALIBRATION 50
|
||||
|
@ -141,6 +141,15 @@
|
||||
#define DEFAULT_SAFETYTIMER_TIME_MINS 30
|
||||
#define FARM_DEFAULT_SAFETYTIMER_TIME_ms (45*60*1000ul)
|
||||
|
||||
// Offline crash dumper
|
||||
#define XFLASH_DUMP // enable dump functionality (including D20/D21/D22)
|
||||
#define MENU_DUMP // enable "Memory dump" in Settings menu
|
||||
#define EMERGENCY_DUMP // trigger crash on stack corruption and WDR
|
||||
|
||||
// Online crash dumper
|
||||
//#define EMERGENCY_SERIAL_DUMP // Request dump via serial on stack corruption and WDR
|
||||
//#define MENU_SERIAL_DUMP // Enable "Memory dump" in Settings menu
|
||||
|
||||
// Filament sensor
|
||||
#define FILAMENT_SENSOR
|
||||
#define IR_SENSOR
|
||||
@ -157,7 +166,9 @@
|
||||
#define MINTEMP_MINAMBIENT 10
|
||||
#define MINTEMP_MINAMBIENT_RAW 1002
|
||||
|
||||
#define DEBUG_DCODE2
|
||||
#define DEBUG_DCODE3
|
||||
#define DEBUG_DCODE6
|
||||
|
||||
//#define DEBUG_BUILD
|
||||
//#define DEBUG_SEC_LANG //secondary language debug output at startup
|
||||
@ -595,6 +606,7 @@
|
||||
#define TEMP_SENSOR_AMBIENT 2000
|
||||
|
||||
#define STACK_GUARD_TEST_VALUE 0xA2A2
|
||||
#define STACK_GUARD_MARGIN 32
|
||||
|
||||
#define MAX_BED_TEMP_CALIBRATION 50
|
||||
#define MAX_HOTEND_TEMP_CALIBRATION 50
|
||||
|
@ -90,13 +90,18 @@ void w25x20cl_wr_status_reg(uint8_t val)
|
||||
}
|
||||
#endif
|
||||
|
||||
void xflash_rd_data(uint32_t addr, uint8_t* data, uint16_t cnt)
|
||||
static void xflash_send_cmdaddr(uint8_t cmd, uint32_t addr)
|
||||
{
|
||||
_CS_LOW();
|
||||
_SPI_TX(_CMD_RD_DATA); // send command 0x03
|
||||
_SPI_TX(cmd); // send command 0x03
|
||||
_SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23
|
||||
_SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15
|
||||
_SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7
|
||||
}
|
||||
|
||||
void xflash_rd_data(uint32_t addr, uint8_t* data, uint16_t cnt)
|
||||
{
|
||||
_CS_LOW();
|
||||
xflash_send_cmdaddr(_CMD_RD_DATA, addr);
|
||||
while (cnt--) // receive data
|
||||
*(data++) = _SPI_RX();
|
||||
_CS_HIGH();
|
||||
@ -105,22 +110,38 @@ void xflash_rd_data(uint32_t addr, uint8_t* data, uint16_t cnt)
|
||||
void xflash_page_program(uint32_t addr, uint8_t* data, uint16_t cnt)
|
||||
{
|
||||
_CS_LOW();
|
||||
_SPI_TX(_CMD_PAGE_PROGRAM); // send command 0x02
|
||||
_SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23
|
||||
_SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15
|
||||
_SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7
|
||||
xflash_send_cmdaddr(_CMD_PAGE_PROGRAM, addr);
|
||||
while (cnt--) // send data
|
||||
_SPI_TX(*(data++));
|
||||
_CS_HIGH();
|
||||
}
|
||||
|
||||
void xflash_multipage_program(uint32_t addr, uint8_t* data, uint16_t cnt)
|
||||
{
|
||||
while(cnt)
|
||||
{
|
||||
xflash_enable_wr();
|
||||
_CS_LOW();
|
||||
xflash_send_cmdaddr(_CMD_PAGE_PROGRAM, addr);
|
||||
while(1)
|
||||
{
|
||||
// send data
|
||||
_SPI_TX(*(data++));
|
||||
if(!--cnt || !(++addr & 0xFF))
|
||||
{
|
||||
// on a page boundary or end of write
|
||||
_CS_HIGH();
|
||||
xflash_wait_busy();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void xflash_page_program_P(uint32_t addr, uint8_t* data, uint16_t cnt)
|
||||
{
|
||||
_CS_LOW();
|
||||
_SPI_TX(_CMD_PAGE_PROGRAM); // send command 0x02
|
||||
_SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23
|
||||
_SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15
|
||||
_SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7
|
||||
xflash_send_cmdaddr(_CMD_PAGE_PROGRAM, addr);
|
||||
while (cnt--) // send data
|
||||
_SPI_TX(pgm_read_byte(data++));
|
||||
_CS_HIGH();
|
||||
@ -129,10 +150,7 @@ void xflash_page_program_P(uint32_t addr, uint8_t* data, uint16_t cnt)
|
||||
void xflash_erase(uint8_t cmd, uint32_t addr)
|
||||
{
|
||||
_CS_LOW();
|
||||
_SPI_TX(cmd); // send command 0x20
|
||||
_SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23
|
||||
_SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15
|
||||
_SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7
|
||||
xflash_send_cmdaddr(cmd, addr);
|
||||
_CS_HIGH();
|
||||
}
|
||||
|
||||
|
@ -34,16 +34,25 @@ extern uint8_t xflash_rd_status_reg(void);
|
||||
extern void w25x20cl_wr_status_reg(uint8_t val);
|
||||
#endif
|
||||
extern void xflash_rd_data(uint32_t addr, uint8_t* data, uint16_t cnt);
|
||||
extern void xflash_page_program(uint32_t addr, uint8_t* data, uint16_t cnt);
|
||||
extern void xflash_page_program_P(uint32_t addr, uint8_t* data, uint16_t cnt);
|
||||
|
||||
extern void xflash_sector_erase(uint32_t addr);
|
||||
extern void xflash_block32_erase(uint32_t addr);
|
||||
extern void xflash_block64_erase(uint32_t addr);
|
||||
extern void xflash_chip_erase(void);
|
||||
extern void xflash_page_program(uint32_t addr, uint8_t* data, uint16_t cnt);
|
||||
extern void xflash_rd_uid(uint8_t* uid);
|
||||
extern void xflash_wait_busy(void);
|
||||
|
||||
// write up to a single page of data (256bytes)
|
||||
extern void xflash_page_program(uint32_t addr, uint8_t* data, uint16_t cnt);
|
||||
|
||||
// write up to a single page of data from program memory
|
||||
extern void xflash_page_program_P(uint32_t addr, uint8_t* data, uint16_t cnt);
|
||||
|
||||
// xflash_multipage_program: high-level interface for multi-page writes.
|
||||
// Write any amount of data, chunking writes to page boundaries as needed.
|
||||
// Automatically enables writes and waits for completion.
|
||||
extern void xflash_multipage_program(uint32_t addr, uint8_t* data, uint16_t cnt);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif //defined(__cplusplus)
|
||||
|
109
Firmware/xflash_dump.cpp
Normal file
109
Firmware/xflash_dump.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include <avr/wdt.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "xflash_dump.h"
|
||||
#ifdef XFLASH_DUMP
|
||||
#include "asm.h"
|
||||
#include "xflash.h"
|
||||
#include "Marlin.h" // for softReset
|
||||
|
||||
bool xfdump_check_state(dump_crash_reason* reason)
|
||||
{
|
||||
uint32_t magic;
|
||||
|
||||
XFLASH_SPI_ENTER();
|
||||
xflash_rd_data(DUMP_OFFSET + offsetof(dump_t, header.magic),
|
||||
(uint8_t*)&magic, sizeof(magic));
|
||||
if (magic != DUMP_MAGIC)
|
||||
return false;
|
||||
|
||||
if (reason)
|
||||
{
|
||||
xflash_rd_data(DUMP_OFFSET + offsetof(dump_t, header.crash_reason),
|
||||
(uint8_t*)reason, sizeof(*reason));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void xfdump_reset()
|
||||
{
|
||||
XFLASH_SPI_ENTER();
|
||||
xflash_enable_wr();
|
||||
xflash_sector_erase(DUMP_OFFSET + offsetof(dump_t, header.magic));
|
||||
xflash_wait_busy();
|
||||
}
|
||||
|
||||
|
||||
static void xfdump_erase()
|
||||
{
|
||||
for(uint32_t addr = DUMP_OFFSET;
|
||||
addr < DUMP_OFFSET + DUMP_SIZE;
|
||||
addr += 4096)
|
||||
{
|
||||
xflash_enable_wr();
|
||||
xflash_sector_erase(DUMP_OFFSET);
|
||||
xflash_wait_busy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void __attribute__((noinline)) xfdump_dump_core(dump_header_t& hdr, uint32_t addr, uint8_t* buf, uint16_t cnt)
|
||||
{
|
||||
XFLASH_SPI_ENTER();
|
||||
|
||||
// start by clearing all sectors (we need all of them in any case)
|
||||
xfdump_erase();
|
||||
|
||||
// sample SP/PC
|
||||
hdr.sp = SP;
|
||||
GETPC(&hdr.pc);
|
||||
|
||||
// write header
|
||||
static_assert(sizeof(hdr) <= 256, "header is larger than a single page write");
|
||||
xflash_enable_wr();
|
||||
xflash_page_program(DUMP_OFFSET, (uint8_t*)&hdr, sizeof(hdr));
|
||||
xflash_wait_busy();
|
||||
|
||||
// write data
|
||||
static_assert(sizeof(dump_t::data) <= RAMEND+1, "dump area size insufficient");
|
||||
xflash_multipage_program(addr, buf, cnt);
|
||||
}
|
||||
|
||||
|
||||
void xfdump_dump()
|
||||
{
|
||||
dump_header_t buf;
|
||||
buf.magic = DUMP_MAGIC;
|
||||
buf.regs_present = false;
|
||||
buf.crash_reason = (uint8_t)dump_crash_reason::manual;
|
||||
|
||||
// write sram only
|
||||
xfdump_dump_core(buf, DUMP_OFFSET + offsetof(dump_t, data.sram),
|
||||
(uint8_t*)RAMSTART, RAMSIZE);
|
||||
}
|
||||
|
||||
|
||||
void xfdump_full_dump_and_reset(dump_crash_reason reason)
|
||||
{
|
||||
dump_header_t buf;
|
||||
buf.magic = DUMP_MAGIC;
|
||||
buf.regs_present = true;
|
||||
buf.crash_reason = (uint8_t)reason;
|
||||
|
||||
// disable interrupts for a cleaner register dump
|
||||
cli();
|
||||
|
||||
// ensure there's always enough time (with some margin) to dump
|
||||
// dump time on w25x20cl: ~150ms
|
||||
wdt_enable(WDTO_500MS);
|
||||
|
||||
// write all addressable ranges (this will trash bidirectional registers)
|
||||
xfdump_dump_core(buf, DUMP_OFFSET + offsetof(dump_t, data), 0, RAMEND+1);
|
||||
|
||||
// force a reset even sooner
|
||||
softReset();
|
||||
}
|
||||
#endif
|
22
Firmware/xflash_dump.h
Normal file
22
Firmware/xflash_dump.h
Normal file
@ -0,0 +1,22 @@
|
||||
// XFLASH dumper
|
||||
#pragma once
|
||||
#include "xflash_layout.h"
|
||||
|
||||
enum class dump_crash_reason : uint8_t
|
||||
{
|
||||
manual = 0,
|
||||
stack_error,
|
||||
watchdog,
|
||||
bad_isr,
|
||||
};
|
||||
|
||||
#ifdef XFLASH_DUMP
|
||||
void xfdump_reset(); // reset XFLASH dump state
|
||||
void xfdump_dump(); // create a new SRAM memory dump
|
||||
|
||||
// return true if a dump is present, save type in "reason" if provided
|
||||
bool xfdump_check_state(dump_crash_reason* reason = NULL);
|
||||
|
||||
// create a new dump containing registers and SRAM, then reset
|
||||
void xfdump_full_dump_and_reset(dump_crash_reason crash = dump_crash_reason::manual);
|
||||
#endif
|
51
Firmware/xflash_layout.h
Normal file
51
Firmware/xflash_layout.h
Normal file
@ -0,0 +1,51 @@
|
||||
// XFLASH memory layout
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "bootapp.h" // for RAMSIZE
|
||||
#include "config.h"
|
||||
|
||||
#define XFLASH_SIZE 0x40000ul // size of XFLASH
|
||||
#define LANG_OFFSET 0x0 // offset for language data
|
||||
|
||||
#ifndef XFLASH_DUMP
|
||||
#define LANG_SIZE XFLASH_SIZE
|
||||
#else
|
||||
|
||||
#define DUMP_MAGIC 0x55525547ul
|
||||
|
||||
struct dump_header_t
|
||||
{
|
||||
// start with a magic value to indicate the presence of a dump, so that clearing
|
||||
// a single page is sufficient for resetting the state
|
||||
uint32_t magic;
|
||||
|
||||
uint8_t regs_present; // true when the lower segment containing registers is present
|
||||
uint8_t crash_reason; // uses values from dump_crash_source
|
||||
|
||||
uint32_t pc; // PC nearby the crash location
|
||||
uint16_t sp; // SP nearby the crash location
|
||||
};
|
||||
|
||||
struct dump_data_t
|
||||
{
|
||||
// contiguous region containing all addressable ranges
|
||||
uint8_t regs[RAMSTART];
|
||||
uint8_t sram[RAMSIZE];
|
||||
};
|
||||
|
||||
struct dump_t
|
||||
{
|
||||
struct dump_header_t header;
|
||||
|
||||
// data is page aligned (no real space waste, due to the larger
|
||||
// alignment required for the whole dump)
|
||||
struct dump_data_t __attribute__((aligned(256))) data;
|
||||
};
|
||||
|
||||
// dump offset must be aligned to lower 4kb sector boundary
|
||||
#define DUMP_OFFSET ((XFLASH_SIZE - sizeof(dump_t)) & ~0xFFFul)
|
||||
|
||||
#define DUMP_SIZE (XFLASH_SIZE - DUMP_OFFSET) // effective dump size area
|
||||
#define LANG_SIZE DUMP_OFFSET // available language space
|
||||
|
||||
#endif
|
@ -163,6 +163,9 @@ void xyzcal_meassure_leave(void)
|
||||
ENABLE_STEPPER_DRIVER_INTERRUPT();
|
||||
#ifdef WATCHDOG
|
||||
wdt_enable(WDTO_4S);
|
||||
#ifdef EMERGENCY_HANDLERS
|
||||
WDTCSR |= (1 << WDIE);
|
||||
#endif //EMERGENCY_HANDLERS
|
||||
#endif //WATCHDOG
|
||||
sm4_stop_cb = 0;
|
||||
sm4_update_pos_cb = 0;
|
||||
|
@ -198,6 +198,21 @@ if [ -e lang_nl.bin ]; then cat lang_nl.bin >> lang.bin; fi
|
||||
## New language
|
||||
#if [ -e lang_qr.bin ]; then cat lang_qr.bin >> lang.bin; fi
|
||||
|
||||
# Check that the language data doesn't exceed the reserved XFLASH space
|
||||
echo " checking language data size:"
|
||||
lang_size=$(wc -c lang.bin | cut -f1 -d' ')
|
||||
lang_size_pad=$(( ($lang_size+4096-1) / 4096 * 4096 ))
|
||||
|
||||
# TODO: hard-coded! get value by preprocessing LANG_SIZE from xflash_layout.h!
|
||||
lang_reserved=249856
|
||||
|
||||
echo " total size usage: $lang_size_pad ($lang_size)"
|
||||
echo " reserved size: $lang_reserved"
|
||||
if [ $lang_size_pad -gt $lang_reserved ]; then
|
||||
echo "NG! - language data too large" >&2
|
||||
finish 1
|
||||
fi
|
||||
|
||||
#convert lang.bin to lang.hex
|
||||
echo -n " converting to hex..." >&2
|
||||
$OBJCOPY -I binary -O ihex ./lang.bin ./lang.hex
|
||||
|
Loading…
Reference in New Issue
Block a user