Zhzhzh & Nubus
Nubus Nubus
Привет, Жора, я тут покопался в новой прошивке для микроконтроллера ARM Cortex-M — не помешаю, если расскажу, что интересного нарыл?
Zhzhzh Zhzhzh
Давай, выкладывай — рассказывай, что там за фишки, я слушаю, как заворожённый.
Nubus Nubus
Слушай, вот что я выяснил. Во-первых, иногда вектор сброса указывает на неразмещенную страницу памяти, если таблица векторов загрузчика не перенесена правильно – вылетает жёсткий сбой при старте. Во-вторых, регистр предделителя сторожевого таймера возвращает ноль, даже если ты пишешь 0xFF, потому что ядро захватывает значение на следующем такте – нужно добавить фиктивное чтение перед записью. В-третьих, регистр перезагрузки SysTick принимает только 24-битные значения; если переполнишь его, таймер тихо переполнится, и твои функции задержки начнут сбиваться. И последнее: регистр управления тактированием периферии имеет один неприятный нюанс – включение бита тактирования может сбрасывать внутреннее состояние периферии, поэтому нужно переинициализировать эти устройства после повторного включения тактирования. Вот с этими обычно все затыкиваются.
Zhzhzh Zhzhzh
Вау, это глубоко, конечно. Сброс вектора, странность таймера сторожевого режима, переполнение SysTick на 24 бита, и сброс периферии через управление тактированием. Есть какие-нибудь быстрые исправления или фрагменты кода, которые помогут смягчить самые болезненные моменты? Нужно, чтобы форматирование было идеальным. Используй запятые вместо тире. Только финальный вариант. Отличный список – сброс вектора, захват сторожевого режима, переполнение SysTick, сброс периферии через управление тактированием. Есть какие-нибудь быстрые патчи или примеры кода, которые ты используешь, чтобы обойти самые сложные проблемы?
Nubus Nubus
Конечно, вот минимальные патчи, которые я обычно добавляю в проект перед сборкой: Перемещение таблицы векторов ```c // После включения, перемести таблицу векторов в оперативную память, если используешь загрузчик из ПЗУ SCB->VTOR = (uint32_t)(&__vector_table_start__); // Убедись, что адрес выровнен по границе 128 байт ``` Глюк предделителя сторожевого таймера ```c // Фиктивное чтение перед записью предделителя uint32_t tmp = WWDG->SR; // чтение регистра статуса (void)tmp; // подавление предупреждения о неиспользуемой переменной WWDG->KR = 0xAAAA; // ключ перезагрузки WWDG->KR = 0x5555; // установка нового предделителя WWDG->KR = 0xAAAA; // повторный "пинок" для фиксации ``` Ограничение SysTick до 24 бит ```c // Ограничение значения перезагрузки максимальным 24-битным uint32_t reload = (desired_ticks < 0xFFFFFF) ? desired_ticks : 0xFFFFFF; SysTick->LOAD = reload; SysTick->VAL = 0; SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; ``` Проблема сброса управления тактовой частотой ```c // После включения тактовой частоты периферии, переинициализируй периферию RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // пример: включение TIM2 HAL_TIM_Base_Init(&htim2); // или любая другая рутина инициализации ``` Это должно решить большинство неприятных сюрпризов. Если столкнешься с чем-то еще, дай знать, покопаемся поглубже.