diff --git a/stm-firmware/boot/startup-tests.c b/stm-firmware/boot/startup-tests.c new file mode 100644 index 0000000..587cfcb --- /dev/null +++ b/stm-firmware/boot/startup-tests.c @@ -0,0 +1,126 @@ +#include "startup-tests.h" + +uint32_t startup_test_perform_ccm_ram_check(void) +{ + const void *ccmram_base = (void *)0x10000000UL; + const uint32_t ccmram_size = 64U * 1024UL; + volatile uint32_t *word_ptr; + uint32_t target_val; + uint32_t idx; + uint32_t ret = 0UL; + + + /* Perform inversion test with 0x55 and 0xAA, Part 1 */ + for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) { + word_ptr[idx] = idx & 1 ? 0x55AA55AAUL : 0xAA55AA55UL; + } + for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) { + target_val = idx & 1 ? 0x55AA55AAUL : 0xAA55AA55UL; + if (target_val != word_ptr[idx]) { + ret = (uint32_t)&word_ptr[idx]; + goto exit_ret_address; + } + } + + /* Perform inversion test with 0x55 and 0xAA, Part 2 */ + for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) { + word_ptr[idx] = idx & 1 ? 0xAA55AA55UL : 0x55AA55AAUL; + } + for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) { + target_val = idx & 1 ? 0xAA55AA55UL : 0x55AA55AAUL; + if (target_val != word_ptr[idx]) { + ret = (uint32_t)&word_ptr[idx]; + goto exit_ret_address; + } + } + + /* Perform static test with 0xFF */ + for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) { + word_ptr[idx] = 0xFFFFFFFFUL; + } + for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) { + target_val = 0xFFFFFFFFUL; + if (target_val != word_ptr[idx]) { + ret = (uint32_t)&word_ptr[idx]; + goto exit_ret_address; + } + } + + /* Perform static test with 0x00 */ + for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) { + word_ptr[idx] = 0x0UL; + } + for (idx = 0, word_ptr = (volatile uint32_t *)ccmram_base; idx < ccmram_size / 4U; idx++) { + target_val = 0x0UL; + if (target_val != word_ptr[idx]) { + ret = (uint32_t)&word_ptr[idx]; + goto exit_ret_address; + } + } + + +exit_ret_address: + return ret; +} + +uint32_t startup_test_perform_system_ram_check() +{ + const void *ram_base = (void *)0x20000000UL; + const uint32_t ram_size = 128U * 1024UL; + volatile uint32_t *word_ptr; + uint32_t target_val; + uint32_t idx; + uint32_t ret = 0UL; + + + /* Perform inversion test with 0x55 and 0xAA, Part 1 */ + for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) { + word_ptr[idx] = idx & 1 ? 0x55AA55AAUL : 0xAA55AA55UL; + } + for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) { + target_val = idx & 1 ? 0x55AA55AAUL : 0xAA55AA55UL; + if (target_val != word_ptr[idx]) { + ret = (uint32_t)&word_ptr[idx]; + goto exit_ret_address; + } + } + + /* Perform inversion test with 0x55 and 0xAA, Part 2 */ + for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) { + word_ptr[idx] = idx & 1 ? 0xAA55AA55UL : 0x55AA55AAUL; + } + for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) { + target_val = idx & 1 ? 0xAA55AA55UL : 0x55AA55AAUL; + if (target_val != word_ptr[idx]) { + ret = (uint32_t)&word_ptr[idx]; + goto exit_ret_address; + } + } + + /* Perform static test with 0xFF */ + for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) { + word_ptr[idx] = 0xFFFFFFFFUL; + } + for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) { + target_val = 0xFFFFFFFFUL; + if (target_val != word_ptr[idx]) { + ret = (uint32_t)&word_ptr[idx]; + goto exit_ret_address; + } + } + + /* Perform static test with 0x00 */ + for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) { + word_ptr[idx] = 0x0UL; + } + for (idx = 0, word_ptr = (volatile uint32_t *)ram_base; idx < ram_size / 4U; idx++) { + target_val = 0x0UL; + if (target_val != word_ptr[idx]) { + ret = (uint32_t)&word_ptr[idx]; + goto exit_ret_address; + } + } + +exit_ret_address: + return ret; +} diff --git a/stm-firmware/boot/startup-tests.h b/stm-firmware/boot/startup-tests.h new file mode 100644 index 0000000..cfeb64f --- /dev/null +++ b/stm-firmware/boot/startup-tests.h @@ -0,0 +1,25 @@ +#ifndef _STARTUP_TESTS_H_ +#define _STARTUP_TESTS_H_ + +#include + +/** + * @brief Do a RAM check of the CCM RAM. + * + * Loop over the whole CCM memory area and check it. + * + * @return 0 if successful. Else the defect address is returned. + * @warning This will completely corrupt this memory! + * You have to ensure to set it to sane values afterwards! + */ +uint32_t startup_test_perform_ccm_ram_check(void); + +/** + * @brief Do a RAM check of the stnadard SRAM regions + * @return 0 if successful. If an error is found, the faulty address is returned + * @warning This completely destroys all content in the memory! + * @warning Ensure that the stack pointer is moved to a different memory reagion (CCM RAM)! + */ +uint32_t startup_test_perform_system_ram_check(void); + +#endif /* _STARTUP_TESTS_H_ */ diff --git a/stm-firmware/boot/startup_stm32f407vx.c b/stm-firmware/boot/startup_stm32f407vx.c index c6fb891..544daf2 100644 --- a/stm-firmware/boot/startup_stm32f407vx.c +++ b/stm-firmware/boot/startup_stm32f407vx.c @@ -19,6 +19,7 @@ */ #include +#include "startup-tests.h" /* C++ library init */ # if defined(__cplusplus) @@ -288,7 +289,7 @@ extern unsigned int __ld_eheap; #define CPACR (*((volatile uint32_t *)0xE000ED88)) -void Reset_Handler(void) { +void __attribute__((noreturn)) Reset_Handler(void) { /* Stack is already initialized by hardware */ /* The first thing we do here, is to initialize the FPU @@ -297,6 +298,9 @@ void Reset_Handler(void) { */ CPACR |= (0xF << 20); + /** + * Prepare RAM etc for the System Init function. This ensures, the RAM tests execute at max speed. + */ /* Copy .data section */ __init_section(&__ld_load_data, &__ld_sdata, &__ld_edata); @@ -311,6 +315,41 @@ void Reset_Handler(void) { /* Set clocks, waitstates, ART operation etc. */ SystemInit(); + + if (startup_test_perform_ccm_ram_check()) { + /* Hang forever in case of an error. We cannot handle this (yet?) */ + while (1); + } + + /* Move the Stack pointer to CCMRAM + * This allows us to perform a RAM test on the main RAM. + * Note: sp is not required to be inside the clobber list! + */ + __asm__ __volatile__ ("mov sp, %0\n\t" :: "r"(0x10000000UL + (64U * 1024UL)) :); + + if (startup_test_perform_system_ram_check()) { + while (1); + } + + /* Move the stack pointer back. Note: This only works if this function does not use the stack for variables. + * Otherwise everything will be broken. + */ + __asm__ __volatile__ ("mov sp, %0\n\t" :: "r"(&__ld_top_of_stack) :); + + /** + * RAM tests destroyed our values. So we have to copy them again... + */ + + /* Copy .data section */ + __init_section(&__ld_load_data, &__ld_sdata, &__ld_edata); + /* Fill bss with zero */ + __fill_zero(&__ld_sbss, &__ld_ebss); + /* Fill Heap with zero */ + __fill_zero(&__ld_sheap, &__ld_eheap); + /* Fill static CCM memory with zeroes */ + __fill_zero(&__ld_sbss_ccm, &__ld_ebss_ccm); + /* Init CCM RAM data section */ + __init_section(&__ld_load_ccm_data, &__ld_sdata_ccm, &__ld_edata_ccm); /* C++ init function */ #if defined(__cplusplus)