Merge pull request #3157 from wavexx/improve_d2

Add extra debugging functions & crash analysis
This commit is contained in:
DRracer 2021-06-22 07:37:30 +02:00 committed by GitHub
commit 6188870c2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 812 additions and 177 deletions

View File

@ -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

View File

@ -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".

View File

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

View File

@ -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
/*!

View File

@ -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.
*

View File

@ -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
View 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

View File

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

View File

@ -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"

View File

@ -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

View File

@ -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 !!!!!
// !!!!!

View File

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

View File

@ -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>

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
#include "Configuration.h"
#include "ultralcd.h"
#include "menu.h"
#include "sound.h"
#include "language.h"
#include "util.h"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

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

View File

@ -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
View 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
View 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
View 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

View File

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

View File

@ -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