Загрузка данных
#include "fsl_debug_console.h"
#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "fsl_cache.h"
/* Диапазон DDR для проведения измерений (весь этот регион будет циклически перезаписываться) */
#define DDR_TEST_START_ADDR 0x80000000U /* Начинаем с самого начала DDR */
#define DDR_TEST_SIZE_BYTES (64 * 1024 * 1024) /* Размер тестового окна: 64 МБ (можно увеличить) */
#define DDR_TEST_SIZE_WORDS (DDR_TEST_SIZE_BYTES / sizeof(uint32_t))
void run_intense_memtest_loop(uint32_t start_addr, uint32_t words_count);
void print_menu(void);
int main(void)
{
char input_ch;
/* Инициализация стандартной периферии и Debug UART */
BOARD_InitBootPins();
BOARD_InitBootClocks();
BOARD_InitDebugConsole();
PRINTF("\r\n==================================================\r\n");
PRINTF(" i.MX95 M7: DTCM-Executed DDR Load Generator (BCU)\r\n");
PRINTF("==================================================\r\n");
PRINTF("[INFO] Код и стек M7 работают из внутренней памяти DTCM.\r\n");
PRINTF("[INFO] Целевой регион теста DDR: 0x%08X - 0x%08X (%d МБ)\r\n",
DDR_TEST_START_ADDR,
DDR_TEST_START_ADDR + DDR_TEST_SIZE_BYTES,
DDR_TEST_SIZE_BYTES / (1024 * 1024));
print_menu();
while (1)
{
/* Ожидаем команду из консоли */
input_ch = GETCHAR();
PUTCHAR(input_ch); /* Эхо-вывод */
if (input_ch == '1')
{
PRINTF("\r\n[START] Запуск непрерывного Memtest. Нажмите 'ANY KEY' для остановки...\r\n");
PRINTF("--> Фиксируйте пиковое потребление шины DDR в утилите BCU.\r\n");
/* Запуск генератора нагрузки */
run_intense_memtest_loop(DDR_TEST_START_ADDR, DDR_TEST_SIZE_WORDS);
print_menu();
}
else if (input_ch == '2')
{
PRINTF("\r\n[IDLE] Тест остановлен. Шина DDR находится в режиме ожидания.\r\n");
PRINTF("--> Фиксируйте фоновое (холостое) потребление DDR в утилите BCU.\r\n");
print_menu();
}
}
}
void print_menu(void)
{
PRINTF("\r\nДоступные команды:\r\n");
PRINTF(" - Включить максимальную нагрузку на DDR (Бесконечный Memtest)\r\n");
PRINTF(" - Перейти в режим ожидания (DDR Idle)\r\n");
PRINTF("Выберите действие: ");
}
/**
* @brief Функция генерации плотного трафика в шину DDR.
* Код работает из DTCM, поэтому циклы `for` не создают трафика на системной шине,
* а все обращения к `start_addr` идут напрямую в контроллер DRAM.
*/
void run_intense_memtest_loop(uint32_t start_addr, uint32_t words_count)
{
volatile uint32_t *ddr_ptr = (volatile uint32_t *)start_addr;
uint32_t pattern_a = 0x55555555;
uint32_t pattern_b = 0xAAAAAAAA;
uint32_t read_val;
char stop_ch;
uint32_t iteration = 0;
while (1)
{
iteration++;
/* Шаг 1: Агрессивная запись чередующихся инверсных паттернов */
for (uint32_t i = 0; i < words_count; i++)
{
ddr_ptr[i] = (i % 2 == 0) ? pattern_a : pattern_b;
}
/* Шаг 2: Принудительный сброс D-Cache.
Даже когда код выполняется из DTCM, обращения к DDR кэшируются.
Вызов этой функции выталкивает измененные строки кэша (Write-Back) в физическую DDR,
создавая плотный поток транзакций. */
L1CACHE_CleanInvalidateDCacheByRange(start_addr, words_count * sizeof(uint32_t));
/* Шаг 3: Чтение данных и верификация (проверка целостности) */
for (uint32_t i = 0; i < words_count; i++)
{
read_val = ddr_ptr[i];
uint32_t expected = (i % 2 == 0) ? pattern_a : pattern_b;
if (read_val != expected)
{
PRINTF("\r\n[MEMTEST ERROR] Итерация %d: Ошибка данных по адресу 0x%08X! Прочитано: 0x%08X\r\n",
iteration, (uint32_t)&ddr_ptr[i], read_val);
return; /* Выход из теста при аппаратной ошибке памяти */
}
}
/* Шаг 4: Проверка нажатия клавиши для прерывания теста (без блокировки выполнения) */
if (DbgConsole_TryGetChar(&stop_ch) == kStatus_Success)
{
PRINTF("\r\n[STOP] Цикл Memtest успешно завершен. Пройдено итераций: %d\r\n", iteration);
break;
}
}
}