diff --git a/ports/stm32/main.c b/ports/stm32/main.c index d7afb9e4af..3ff7077ac2 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -404,7 +404,7 @@ void stm32_main(uint32_t reset_mode) { bool sdram_valid = true; UNUSED(sdram_valid); #if MICROPY_HW_SDRAM_STARTUP_TEST - sdram_valid = sdram_test(true); + sdram_valid = sdram_test(false); #endif #endif #if MICROPY_PY_THREAD diff --git a/ports/stm32/sdram.c b/ports/stm32/sdram.c index 514192519a..e0e3500836 100644 --- a/ports/stm32/sdram.c +++ b/ports/stm32/sdram.c @@ -283,52 +283,106 @@ void sdram_leave_low_power(void) { #pragma GCC diagnostic ignored "-Wstringop-overflow" #endif -bool sdram_test(bool fast) { +bool __attribute__((optimize("O0"))) sdram_test(bool exhaustive) { uint8_t const pattern = 0xaa; uint8_t const antipattern = 0x55; uint8_t *const mem_base = (uint8_t *)sdram_start(); - /* test data bus */ - for (uint8_t i = 1; i; i <<= 1) { - *mem_base = i; - if (*mem_base != i) { - printf("data bus lines test failed! data (%d)\n", i); + #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR + char error_buffer[1024]; + #endif + + #if (__DCACHE_PRESENT == 1) + bool i_cache_disabled = false; + bool d_cache_disabled = false; + + // Disable caches for testing. + if (SCB->CCR & (uint32_t)SCB_CCR_IC_Msk) { + SCB_DisableICache(); + i_cache_disabled = true; + } + + if (SCB->CCR & (uint32_t)SCB_CCR_DC_Msk) { + SCB_DisableDCache(); + d_cache_disabled = true; + } + #endif + + // Test data bus + for (uint32_t i = 0; i < MICROPY_HW_SDRAM_MEM_BUS_WIDTH; i++) { + *((uint32_t *)mem_base) = (1 << i); + if (*((uint32_t *)mem_base) != (1 << i)) { + #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR + snprintf(error_buffer, sizeof(error_buffer), + "Data bus test failed at 0x%p expected 0x%x found 0x%lx", + &mem_base[0], (1 << i), ((uint32_t *)mem_base)[0]); + __fatal_error(error_buffer); + #endif return false; } } - /* test address bus */ - /* Check individual address lines */ + // Test address bus for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) { mem_base[i] = pattern; if (mem_base[i] != pattern) { - printf("address bus lines test failed! address (%p)\n", &mem_base[i]); + #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR + snprintf(error_buffer, sizeof(error_buffer), + "Address bus test failed at 0x%p expected 0x%x found 0x%x", + &mem_base[i], pattern, mem_base[i]); + __fatal_error(error_buffer); + #endif return false; } } - /* Check for aliasing (overlaping addresses) */ + // Check for aliasing (overlaping addresses) mem_base[0] = antipattern; for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) { if (mem_base[i] != pattern) { - printf("address bus overlap %p\n", &mem_base[i]); + #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR + snprintf(error_buffer, sizeof(error_buffer), + "Address bus overlap at 0x%p expected 0x%x found 0x%x", + &mem_base[i], pattern, mem_base[i]); + __fatal_error(error_buffer); + #endif return false; } } - /* test all ram cells */ - if (!fast) { - for (uint32_t i = 0; i < MICROPY_HW_SDRAM_SIZE; ++i) { + // Test all RAM cells + if (exhaustive) { + // Write all memory first then compare, so even if the cache + // is enabled, it's not just writing and reading from cache. + // Note: This test should also detect refresh rate issues. + for (uint32_t i = 0; i < MICROPY_HW_SDRAM_SIZE; i++) { mem_base[i] = pattern; + } + + for (uint32_t i = 0; i < MICROPY_HW_SDRAM_SIZE; i++) { if (mem_base[i] != pattern) { - printf("address bus test failed! address (%p)\n", &mem_base[i]); + #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR + snprintf(error_buffer, sizeof(error_buffer), + "Address bus slow test failed at 0x%p expected 0x%x found 0x%x", + &mem_base[i], pattern, mem_base[i]); + __fatal_error(error_buffer); + #endif return false; } } - } else { - memset(mem_base, pattern, MICROPY_HW_SDRAM_SIZE); } + #if (__DCACHE_PRESENT == 1) + // Re-enable caches if they were enabled before the test started. + if (i_cache_disabled) { + SCB_EnableICache(); + } + + if (d_cache_disabled) { + SCB_EnableDCache(); + } + #endif + return true; } diff --git a/ports/stm32/sdram.h b/ports/stm32/sdram.h index 773a30802f..f7a124addd 100644 --- a/ports/stm32/sdram.h +++ b/ports/stm32/sdram.h @@ -13,5 +13,5 @@ void *sdram_start(void); void *sdram_end(void); void sdram_enter_low_power(void); void sdram_leave_low_power(void); -bool sdram_test(bool fast); +bool sdram_test(bool exhaustive); #endif // __SDRAM_H__