M100: LPC1768 and DUE compatibility (#13962)
This commit is contained in:
parent
88bedf3a57
commit
fa3739aa23
|
@ -50,7 +50,7 @@
|
||||||
*
|
*
|
||||||
* Also, there are two support functions that can be called from a developer's C code.
|
* Also, there are two support functions that can be called from a developer's C code.
|
||||||
*
|
*
|
||||||
* uint16_t check_for_free_memory_corruption(PGM_P const ptr);
|
* uint16_t check_for_free_memory_corruption(PGM_P const free_memory_start);
|
||||||
* void M100_dump_routine(PGM_P const title, const char *start, const char *end);
|
* void M100_dump_routine(PGM_P const title, const char *start, const char *end);
|
||||||
*
|
*
|
||||||
* Initial version by Roxy-3D
|
* Initial version by Roxy-3D
|
||||||
|
@ -60,16 +60,57 @@
|
||||||
|
|
||||||
#define TEST_BYTE ((char) 0xE5)
|
#define TEST_BYTE ((char) 0xE5)
|
||||||
|
|
||||||
extern char* __brkval;
|
#if defined(__AVR__) || IS_32BIT_TEENSY
|
||||||
extern size_t __heap_start, __heap_end, __flp;
|
|
||||||
extern char __bss_end;
|
extern char __bss_end;
|
||||||
|
char* end_bss = &__bss_end;
|
||||||
|
char* free_memory_start = end_bss;
|
||||||
|
|
||||||
|
|
||||||
|
char* free_memory_end = 0;
|
||||||
|
char* stacklimit = 0;
|
||||||
|
char* heaplimit = 0;
|
||||||
|
|
||||||
|
#define MEMORY_END_CORRECTION 0
|
||||||
|
|
||||||
|
#elif defined(TARGET_LPC1768)
|
||||||
|
|
||||||
|
extern char __bss_end__;
|
||||||
|
extern char __StackLimit;
|
||||||
|
extern char __HeapLimit;
|
||||||
|
|
||||||
|
char* end_bss = &__bss_end__;
|
||||||
|
char* stacklimit = &__StackLimit;
|
||||||
|
char* heaplimit = &__HeapLimit ;
|
||||||
|
|
||||||
|
#define MEMORY_END_CORRECTION 0x200
|
||||||
|
|
||||||
|
char* free_memory_start = heaplimit;
|
||||||
|
char* free_memory_end = stacklimit - MEMORY_END_CORRECTION;
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(__SAM3X8E__)
|
||||||
|
|
||||||
|
extern char _ebss;
|
||||||
|
|
||||||
|
char* end_bss = &_ebss;
|
||||||
|
|
||||||
|
char* free_memory_start = end_bss;
|
||||||
|
|
||||||
|
char* free_memory_end = 0;
|
||||||
|
char* stacklimit = 0;
|
||||||
|
char* heaplimit = 0;
|
||||||
|
|
||||||
|
#define MEMORY_END_CORRECTION 0x10000 // need to stay well below 0x20080000 or M100 F crashes
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "M100 - unsupported CPU"
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// Utility functions
|
// Utility functions
|
||||||
//
|
//
|
||||||
|
|
||||||
#define END_OF_HEAP() (__brkval ? __brkval : &__bss_end)
|
|
||||||
|
|
||||||
// Location of a variable on its stack frame. Returns a value above
|
// Location of a variable on its stack frame. Returns a value above
|
||||||
// the stack (once the function returns to the caller).
|
// the stack (once the function returns to the caller).
|
||||||
char* top_of_stack() {
|
char* top_of_stack() {
|
||||||
|
@ -78,9 +119,9 @@ char* top_of_stack() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count the number of test bytes at the specified location.
|
// Count the number of test bytes at the specified location.
|
||||||
inline int32_t count_test_bytes(const char * const ptr) {
|
inline int32_t count_test_bytes(const char * const start_free_memory) {
|
||||||
for (uint32_t i = 0; i < 32000; i++)
|
for (uint32_t i = 0; i < 32000; i++)
|
||||||
if (char(ptr[i]) != TEST_BYTE)
|
if (char(start_free_memory[i]) != TEST_BYTE)
|
||||||
return i - 1;
|
return i - 1;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -93,35 +134,35 @@ inline int32_t count_test_bytes(const char * const ptr) {
|
||||||
#if ENABLED(M100_FREE_MEMORY_DUMPER)
|
#if ENABLED(M100_FREE_MEMORY_DUMPER)
|
||||||
/**
|
/**
|
||||||
* M100 D
|
* M100 D
|
||||||
* Dump the free memory block from __brkval to the stack pointer.
|
* Dump the free memory block from brkval to the stack pointer.
|
||||||
* malloc() eats memory from the start of the block and the stack grows
|
* malloc() eats memory from the start of the block and the stack grows
|
||||||
* up from the bottom of the block. Solid test bytes indicate nothing has
|
* up from the bottom of the block. Solid test bytes indicate nothing has
|
||||||
* used that memory yet. There should not be anything but test bytes within
|
* used that memory yet. There should not be anything but test bytes within
|
||||||
* the block. If so, it may indicate memory corruption due to a bad pointer.
|
* the block. If so, it may indicate memory corruption due to a bad pointer.
|
||||||
* Unexpected bytes are flagged in the right column.
|
* Unexpected bytes are flagged in the right column.
|
||||||
*/
|
*/
|
||||||
inline void dump_free_memory(const char *ptr, const char *sp) {
|
inline void dump_free_memory(const char *start_free_memory, const char *end_free_memory) {
|
||||||
//
|
//
|
||||||
// Start and end the dump on a nice 16 byte boundary
|
// Start and end the dump on a nice 16 byte boundary
|
||||||
// (even though the values are not 16-byte aligned).
|
// (even though the values are not 16-byte aligned).
|
||||||
//
|
//
|
||||||
ptr = (char*)((ptr_int_t)((uint32_t)ptr & 0xFFFFFFF0)); // Align to 16-byte boundary
|
start_free_memory = (char*)((ptr_int_t)((uint32_t)start_free_memory & 0xFFFFFFF0)); // Align to 16-byte boundary
|
||||||
sp = (char*)((ptr_int_t)((uint32_t)sp | 0x0000000F)); // Align sp to the 15th byte (at or above sp)
|
end_free_memory = (char*)((ptr_int_t)((uint32_t)end_free_memory | 0x0000000F)); // Align end_free_memory to the 15th byte (at or above end_free_memory)
|
||||||
|
|
||||||
// Dump command main loop
|
// Dump command main loop
|
||||||
while (ptr < sp) {
|
while (start_free_memory < end_free_memory) {
|
||||||
print_hex_address(ptr); // Print the address
|
print_hex_address(start_free_memory); // Print the address
|
||||||
SERIAL_CHAR(':');
|
SERIAL_CHAR(':');
|
||||||
for (uint8_t i = 0; i < 16; i++) { // and 16 data bytes
|
for (uint8_t i = 0; i < 16; i++) { // and 16 data bytes
|
||||||
if (i == 8) SERIAL_CHAR('-');
|
if (i == 8) SERIAL_CHAR('-');
|
||||||
print_hex_byte(ptr[i]);
|
print_hex_byte(start_free_memory[i]);
|
||||||
SERIAL_CHAR(' ');
|
SERIAL_CHAR(' ');
|
||||||
}
|
}
|
||||||
serial_delay(25);
|
serial_delay(25);
|
||||||
SERIAL_CHAR('|'); // Point out non test bytes
|
SERIAL_CHAR('|'); // Point out non test bytes
|
||||||
for (uint8_t i = 0; i < 16; i++) {
|
for (uint8_t i = 0; i < 16; i++) {
|
||||||
char ccc = (char)ptr[i]; // cast to char before automatically casting to char on assignment, in case the compiler is broken
|
char ccc = (char)start_free_memory[i]; // cast to char before automatically casting to char on assignment, in case the compiler is broken
|
||||||
if (&ptr[i] >= (const char*)command_queue && &ptr[i] < (const char*)(command_queue + sizeof(command_queue))) { // Print out ASCII in the command buffer area
|
if (&start_free_memory[i] >= (const char*)command_queue && &start_free_memory[i] < (const char*)(command_queue + sizeof(command_queue))) { // Print out ASCII in the command buffer area
|
||||||
if (!WITHIN(ccc, ' ', 0x7E)) ccc = ' ';
|
if (!WITHIN(ccc, ' ', 0x7E)) ccc = ' ';
|
||||||
}
|
}
|
||||||
else { // If not in the command buffer area, flag bytes that don't match the test byte
|
else { // If not in the command buffer area, flag bytes that don't match the test byte
|
||||||
|
@ -130,7 +171,7 @@ inline int32_t count_test_bytes(const char * const ptr) {
|
||||||
SERIAL_CHAR(ccc);
|
SERIAL_CHAR(ccc);
|
||||||
}
|
}
|
||||||
SERIAL_EOL();
|
SERIAL_EOL();
|
||||||
ptr += 16;
|
start_free_memory += 16;
|
||||||
serial_delay(25);
|
serial_delay(25);
|
||||||
idle();
|
idle();
|
||||||
}
|
}
|
||||||
|
@ -143,7 +184,7 @@ inline int32_t count_test_bytes(const char * const ptr) {
|
||||||
// Round the start and end locations to produce full lines of output
|
// Round the start and end locations to produce full lines of output
|
||||||
//
|
//
|
||||||
start = (char*)((ptr_int_t)((uint32_t)start & 0xFFFFFFF0)); // Align to 16-byte boundary
|
start = (char*)((ptr_int_t)((uint32_t)start & 0xFFFFFFF0)); // Align to 16-byte boundary
|
||||||
end = (char*)((ptr_int_t)((uint32_t)end | 0x0000000F)); // Align sp to the 15th byte (at or above sp)
|
end = (char*)((ptr_int_t)((uint32_t)end | 0x0000000F)); // Align end_free_memory to the 15th byte (at or above end_free_memory)
|
||||||
dump_free_memory(start, end);
|
dump_free_memory(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,17 +193,15 @@ inline int32_t count_test_bytes(const char * const ptr) {
|
||||||
inline int check_for_free_memory_corruption(PGM_P const title) {
|
inline int check_for_free_memory_corruption(PGM_P const title) {
|
||||||
serialprintPGM(title);
|
serialprintPGM(title);
|
||||||
|
|
||||||
char *ptr = END_OF_HEAP(), *sp = top_of_stack();
|
char *start_free_memory = free_memory_start, *end_free_memory = free_memory_end;
|
||||||
int n = sp - ptr;
|
int n = end_free_memory - start_free_memory;
|
||||||
|
|
||||||
SERIAL_ECHOPAIR("\nfmc() n=", n);
|
SERIAL_ECHOPAIR("\nfmc() n=", n);
|
||||||
SERIAL_ECHOPAIR("\n&__brkval: ", hex_address(&__brkval));
|
SERIAL_ECHOPAIR("\nfree_memory_start=", hex_address(free_memory_start));
|
||||||
SERIAL_ECHOPAIR("=", hex_address(__brkval));
|
SERIAL_ECHOLNPAIR(" end_free_memory=", hex_address(end_free_memory));
|
||||||
SERIAL_ECHOPAIR("\n__bss_end: ", hex_address(&__bss_end));
|
|
||||||
SERIAL_ECHOPAIR(" sp=", hex_address(sp));
|
|
||||||
|
|
||||||
if (sp < ptr) {
|
if (end_free_memory < start_free_memory) {
|
||||||
SERIAL_ECHOPGM(" sp < Heap ");
|
SERIAL_ECHOPGM(" end_free_memory < Heap ");
|
||||||
// SET_INPUT_PULLUP(63); // if the developer has a switch wired up to their controller board
|
// SET_INPUT_PULLUP(63); // if the developer has a switch wired up to their controller board
|
||||||
// safe_delay(5); // this code can be enabled to pause the display as soon as the
|
// safe_delay(5); // this code can be enabled to pause the display as soon as the
|
||||||
// while ( READ(63)) // malfunction is detected. It is currently defaulting to a switch
|
// while ( READ(63)) // malfunction is detected. It is currently defaulting to a switch
|
||||||
|
@ -172,29 +211,29 @@ inline int check_for_free_memory_corruption(PGM_P const title) {
|
||||||
// idle();
|
// idle();
|
||||||
serial_delay(20);
|
serial_delay(20);
|
||||||
#if ENABLED(M100_FREE_MEMORY_DUMPER)
|
#if ENABLED(M100_FREE_MEMORY_DUMPER)
|
||||||
M100_dump_routine(PSTR(" Memory corruption detected with sp<Heap\n"), (char*)0x1B80, (char*)0x21FF);
|
M100_dump_routine(PSTR(" Memory corruption detected with end_free_memory<Heap\n"), (char*)0x1B80, (char*)0x21FF);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan through the range looking for the biggest block of 0xE5's we can find
|
// Scan through the range looking for the biggest block of 0xE5's we can find
|
||||||
int block_cnt = 0;
|
int block_cnt = 0;
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
if (ptr[i] == TEST_BYTE) {
|
if (start_free_memory[i] == TEST_BYTE) {
|
||||||
int32_t j = count_test_bytes(ptr + i);
|
int32_t j = count_test_bytes(start_free_memory + i);
|
||||||
if (j > 8) {
|
if (j > 8) {
|
||||||
// SERIAL_ECHOPAIR("Found ", j);
|
// SERIAL_ECHOPAIR("Found ", j);
|
||||||
// SERIAL_ECHOLNPAIR(" bytes free at ", hex_address(ptr + i));
|
// SERIAL_ECHOLNPAIR(" bytes free at ", hex_address(start_free_memory + i));
|
||||||
i += j;
|
i += j;
|
||||||
block_cnt++;
|
block_cnt++;
|
||||||
SERIAL_ECHOPAIR(" (", block_cnt);
|
SERIAL_ECHOPAIR(" (", block_cnt);
|
||||||
SERIAL_ECHOPAIR(") found=", j);
|
SERIAL_ECHOPAIR(") found=", j);
|
||||||
SERIAL_ECHOPGM(" ");
|
SERIAL_ECHOLNPGM(" ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SERIAL_ECHOPAIR(" block_found=", block_cnt);
|
SERIAL_ECHOPAIR(" block_found=", block_cnt);
|
||||||
|
|
||||||
if (block_cnt != 1 || __brkval != nullptr)
|
if (block_cnt != 1)
|
||||||
SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
|
SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
|
||||||
|
|
||||||
if (block_cnt == 0) // Make sure the special case of no free blocks shows up as an
|
if (block_cnt == 0) // Make sure the special case of no free blocks shows up as an
|
||||||
|
@ -215,12 +254,12 @@ inline int check_for_free_memory_corruption(PGM_P const title) {
|
||||||
* Return the number of free bytes in the memory pool,
|
* Return the number of free bytes in the memory pool,
|
||||||
* with other vital statistics defining the pool.
|
* with other vital statistics defining the pool.
|
||||||
*/
|
*/
|
||||||
inline void free_memory_pool_report(char * const ptr, const int32_t size) {
|
inline void free_memory_pool_report(char * const start_free_memory, const int32_t size) {
|
||||||
int32_t max_cnt = -1, block_cnt = 0;
|
int32_t max_cnt = -1, block_cnt = 0;
|
||||||
char *max_addr = nullptr;
|
char *max_addr = nullptr;
|
||||||
// Find the longest block of test bytes in the buffer
|
// Find the longest block of test bytes in the buffer
|
||||||
for (int32_t i = 0; i < size; i++) {
|
for (int32_t i = 0; i < size; i++) {
|
||||||
char *addr = ptr + i;
|
char *addr = start_free_memory + i;
|
||||||
if (*addr == TEST_BYTE) {
|
if (*addr == TEST_BYTE) {
|
||||||
const int32_t j = count_test_bytes(addr);
|
const int32_t j = count_test_bytes(addr);
|
||||||
if (j > 8) {
|
if (j > 8) {
|
||||||
|
@ -249,14 +288,14 @@ inline void free_memory_pool_report(char * const ptr, const int32_t size) {
|
||||||
* Corrupt <num> locations in the free memory pool and report the corrupt addresses.
|
* Corrupt <num> locations in the free memory pool and report the corrupt addresses.
|
||||||
* This is useful to check the correctness of the M100 D and the M100 F commands.
|
* This is useful to check the correctness of the M100 D and the M100 F commands.
|
||||||
*/
|
*/
|
||||||
inline void corrupt_free_memory(char *ptr, const uint32_t size) {
|
inline void corrupt_free_memory(char *start_free_memory, const uint32_t size) {
|
||||||
ptr += 8;
|
start_free_memory += 8;
|
||||||
const uint32_t near_top = top_of_stack() - ptr - 250, // -250 to avoid interrupt activity that's altered the stack.
|
const uint32_t near_top = top_of_stack() - start_free_memory - 250, // -250 to avoid interrupt activity that's altered the stack.
|
||||||
j = near_top / (size + 1);
|
j = near_top / (size + 1);
|
||||||
|
|
||||||
SERIAL_ECHOLNPGM("Corrupting free memory block.\n");
|
SERIAL_ECHOLNPGM("Corrupting free memory block.\n");
|
||||||
for (uint32_t i = 1; i <= size; i++) {
|
for (uint32_t i = 1; i <= size; i++) {
|
||||||
char * const addr = ptr + i * j;
|
char * const addr = start_free_memory + i * j;
|
||||||
*addr = i;
|
*addr = i;
|
||||||
SERIAL_ECHOPAIR("\nCorrupting address: ", hex_address(addr));
|
SERIAL_ECHOPAIR("\nCorrupting address: ", hex_address(addr));
|
||||||
}
|
}
|
||||||
|
@ -268,7 +307,7 @@ inline void free_memory_pool_report(char * const ptr, const int32_t size) {
|
||||||
* M100 I
|
* M100 I
|
||||||
* Init memory for the M100 tests. (Automatically applied on the first M100.)
|
* Init memory for the M100 tests. (Automatically applied on the first M100.)
|
||||||
*/
|
*/
|
||||||
inline void init_free_memory(char *ptr, int32_t size) {
|
inline void init_free_memory(char *start_free_memory, int32_t size) {
|
||||||
SERIAL_ECHOLNPGM("Initializing free memory block.\n\n");
|
SERIAL_ECHOLNPGM("Initializing free memory block.\n\n");
|
||||||
|
|
||||||
size -= 250; // -250 to avoid interrupt activity that's altered the stack.
|
size -= 250; // -250 to avoid interrupt activity that's altered the stack.
|
||||||
|
@ -277,17 +316,17 @@ inline void init_free_memory(char *ptr, int32_t size) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr += 8; // move a few bytes away from the heap just because we don't want
|
start_free_memory += 8; // move a few bytes away from the heap just because we don't want
|
||||||
// to be altering memory that close to it.
|
// to be altering memory that close to it.
|
||||||
memset(ptr, TEST_BYTE, size);
|
memset(start_free_memory, TEST_BYTE, size);
|
||||||
|
|
||||||
SERIAL_ECHO(size);
|
SERIAL_ECHO(size);
|
||||||
SERIAL_ECHOLNPGM(" bytes of memory initialized.\n");
|
SERIAL_ECHOLNPGM(" bytes of memory initialized.\n");
|
||||||
|
|
||||||
for (int32_t i = 0; i < size; i++) {
|
for (int32_t i = 0; i < size; i++) {
|
||||||
if (ptr[i] != TEST_BYTE) {
|
if (start_free_memory[i] != TEST_BYTE) {
|
||||||
SERIAL_ECHOPAIR("? address : ", hex_address(ptr + i));
|
SERIAL_ECHOPAIR("? address : ", hex_address(start_free_memory + i));
|
||||||
SERIAL_ECHOLNPAIR("=", hex_byte(ptr[i]));
|
SERIAL_ECHOLNPAIR("=", hex_byte(start_free_memory[i]));
|
||||||
SERIAL_EOL();
|
SERIAL_EOL();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,33 +336,36 @@ inline void init_free_memory(char *ptr, int32_t size) {
|
||||||
* M100: Free Memory Check
|
* M100: Free Memory Check
|
||||||
*/
|
*/
|
||||||
void GcodeSuite::M100() {
|
void GcodeSuite::M100() {
|
||||||
SERIAL_ECHOPAIR("\n__brkval : ", hex_address(__brkval));
|
|
||||||
SERIAL_ECHOPAIR("\n__bss_end : ", hex_address(&__bss_end));
|
|
||||||
|
|
||||||
char *ptr = END_OF_HEAP(), *sp = top_of_stack();
|
char *sp = top_of_stack();
|
||||||
|
if (!free_memory_end) free_memory_end = sp - MEMORY_END_CORRECTION;
|
||||||
SERIAL_ECHOPAIR("\nstart of free space : ", hex_address(ptr));
|
SERIAL_ECHOPAIR("\nbss_end : ", hex_address(end_bss));
|
||||||
SERIAL_ECHOLNPAIR("\nStack Pointer : ", hex_address(sp));
|
if (heaplimit) SERIAL_ECHOPAIR("\n__heaplimit : ", hex_address(heaplimit ));
|
||||||
|
SERIAL_ECHOPAIR("\nfree_memory_start : ", hex_address(free_memory_start));
|
||||||
|
if (stacklimit) SERIAL_ECHOPAIR("\n__stacklimit : ", hex_address(stacklimit));
|
||||||
|
SERIAL_ECHOPAIR("\nfree_memory_end : ", hex_address(free_memory_end ));
|
||||||
|
if (MEMORY_END_CORRECTION) SERIAL_ECHOPAIR("\nMEMORY_END_CORRECTION: ", MEMORY_END_CORRECTION );
|
||||||
|
SERIAL_ECHOLNPAIR("\nStack Pointer : ", hex_address(sp));
|
||||||
|
|
||||||
// Always init on the first invocation of M100
|
// Always init on the first invocation of M100
|
||||||
static bool m100_not_initialized = true;
|
static bool m100_not_initialized = true;
|
||||||
if (m100_not_initialized || parser.seen('I')) {
|
if (m100_not_initialized || parser.seen('I')) {
|
||||||
m100_not_initialized = false;
|
m100_not_initialized = false;
|
||||||
init_free_memory(ptr, sp - ptr);
|
init_free_memory(free_memory_start, free_memory_end - free_memory_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLED(M100_FREE_MEMORY_DUMPER)
|
#if ENABLED(M100_FREE_MEMORY_DUMPER)
|
||||||
if (parser.seen('D'))
|
if (parser.seen('D'))
|
||||||
return dump_free_memory(ptr, sp);
|
return dump_free_memory(free_memory_start, free_memory_end);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (parser.seen('F'))
|
if (parser.seen('F'))
|
||||||
return free_memory_pool_report(ptr, sp - ptr);
|
return free_memory_pool_report(free_memory_start, free_memory_end - free_memory_start);
|
||||||
|
|
||||||
#if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
|
#if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
|
||||||
|
|
||||||
if (parser.seen('C'))
|
if (parser.seen('C'))
|
||||||
return corrupt_free_memory(ptr, parser.value_int());
|
return corrupt_free_memory(free_memory_start, parser.value_int());
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue