stm32/sdram: Make SDRAM test cache aware, and optional failure with msg.

* Make SDRAM test cache-aware for newer MCUs.
* Use the defined data bus width (instead of the fixed 8-bits).
* Allow optional failure on error with verbose error messages.
* Test speed is now inverted (test accepts exhaustive instead fast).
This commit is contained in:
iabdalkader 2021-07-09 15:49:25 +02:00 committed by Damien George
parent 6214fa3f9e
commit 7649f5fbd2
3 changed files with 73 additions and 19 deletions

View File

@ -404,7 +404,7 @@ void stm32_main(uint32_t reset_mode) {
bool sdram_valid = true; bool sdram_valid = true;
UNUSED(sdram_valid); UNUSED(sdram_valid);
#if MICROPY_HW_SDRAM_STARTUP_TEST #if MICROPY_HW_SDRAM_STARTUP_TEST
sdram_valid = sdram_test(true); sdram_valid = sdram_test(false);
#endif #endif
#endif #endif
#if MICROPY_PY_THREAD #if MICROPY_PY_THREAD

View File

@ -283,52 +283,106 @@ void sdram_leave_low_power(void) {
#pragma GCC diagnostic ignored "-Wstringop-overflow" #pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif #endif
bool sdram_test(bool fast) { bool __attribute__((optimize("O0"))) sdram_test(bool exhaustive) {
uint8_t const pattern = 0xaa; uint8_t const pattern = 0xaa;
uint8_t const antipattern = 0x55; uint8_t const antipattern = 0x55;
uint8_t *const mem_base = (uint8_t *)sdram_start(); uint8_t *const mem_base = (uint8_t *)sdram_start();
/* test data bus */ #if MICROPY_HW_SDRAM_TEST_FAIL_ON_ERROR
for (uint8_t i = 1; i; i <<= 1) { char error_buffer[1024];
*mem_base = i; #endif
if (*mem_base != i) {
printf("data bus lines test failed! data (%d)\n", i); #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; return false;
} }
} }
/* test address bus */ // Test address bus
/* Check individual address lines */
for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) { for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) {
mem_base[i] = pattern; mem_base[i] = pattern;
if (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; return false;
} }
} }
/* Check for aliasing (overlaping addresses) */ // Check for aliasing (overlaping addresses)
mem_base[0] = antipattern; mem_base[0] = antipattern;
for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) { for (uint32_t i = 1; i < MICROPY_HW_SDRAM_SIZE; i <<= 1) {
if (mem_base[i] != pattern) { 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; return false;
} }
} }
/* test all ram cells */ // Test all RAM cells
if (!fast) { if (exhaustive) {
for (uint32_t i = 0; i < MICROPY_HW_SDRAM_SIZE; ++i) { // 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; mem_base[i] = pattern;
}
for (uint32_t i = 0; i < MICROPY_HW_SDRAM_SIZE; i++) {
if (mem_base[i] != pattern) { 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; 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; return true;
} }

View File

@ -13,5 +13,5 @@ void *sdram_start(void);
void *sdram_end(void); void *sdram_end(void);
void sdram_enter_low_power(void); void sdram_enter_low_power(void);
void sdram_leave_low_power(void); void sdram_leave_low_power(void);
bool sdram_test(bool fast); bool sdram_test(bool exhaustive);
#endif // __SDRAM_H__ #endif // __SDRAM_H__