
Доброго времени суток!
В данной статье речь пойдет о системе самодиагностики микроконтроллера STM32, в частности — STM32F100RB, который входит в отладочный комплект STM32-Discovery. Но так как микроконтроллеры STM32 во многом схожи, и отличаются в основном своей периферией — написанное будет верно и для других контроллеров (возможно с небольшими изменениями). Статья расчитана на людей, уже немного знакомых с STM32, но постараюсь рассказывать по возможности подробнее.
Clock security system (CSS)
Итак, начнем.
А начнем мы с рассмотрения источников системной частоты, лезем в даташит:
Разберемся — что и куда — на периферию системная частота попадает с высокопроизводительной шины AHB. На саму шину, с делителя, позволяющего разделить системную частоту на 1..512. А собственно сама системная частота определяется мультиплексором, обозначенным на схеме как SW. На мультиплексор подаются частоты с трёх источников: HSI, PLL,HSE, кратенько пробежимся по каждому из них:
HSI(High Speed Internal oscillator)
Внутренняя 8MHz RC цепочка, которая может быть использована как источник системной частоты или, делённая на 2, как входной сигнал для PLL(ФАПЧ). Может использоваться в дешевых устройствах, где нет особых требований к точности и стабильности системной частоты, в дешевых — потому что можно обойтись без внешнего кварца. Частота генерации зависит от температуры, напряжения, погоды в Тайване и магнитных бурь на Солнце, в общем — плавает очень сильно, хотя производитель и калибрует их с точностью 1% при температуре 25C — при изменении температуры — частота поплывет, что недопустимо, если от нее зависит точность измерений или временные задержки. Кроме того может использоваться как резервный источник системной частоты в CSSHSE(High Speed External oscillator)
Внешний генератор тактовой частоты — может быть, как резонатор, так и внешний тактирующий сигнал. В случае с кварцем — отличается высокой температурной стабильностью, точностью частоты и долговечностью. Отсюда тактовые импульсы — либо сразу идут на мультиплексор, либо через делитель 1..16 на вход PLLPLL(High Speed External oscillator)
Или ФАПЧ позволяет умножить входной сигнал в 2..16 раз, при этом погрешность тоже умножается, поэтому, если входной сигнал плавал +-1MHz — умноженный в 16 раз он будет плавать +-16MHz, кроме того выходная частота не должна превышать максимально допустимую частоту AHBТак — с источниками частоты вроде разобрались — теперь перейдем к теме статьи. Чаще всего в системах высокой надежности в качестве источника системной частоты используется именно кварцевый резонатор, который может по каким то причинам отказать или сбойнуть. Для того, чтобы минимизировать плохие последствия такого сбоя в STM32 и существует CSS. Суть ее в следующем: при запуске HSE включается детектор частоты, который при ее сбое ( даже если HSE не является источником системной частоты) сразу же выключает HSE, включает HSI, устанавливает его источником системной частоты, посылает сигнал ошибки системной частоты расширенным таймерам и генерирует прерывание, извещая программу о сбое HSE
Пример кода в CoIDE:
код
#include "stm32f10x_rcc.h" #include "stm32f10x_gpio.h" #include "stm32f10x.h" #define LED_PORT GPIOC void LED_GPIO_Configuration(void); void Delay(__IO uint32_t nCount); void NMI_Handler(); int delay_time = 300; int main() { static unsigned long ticks; unsigned char Clock1s; //==================System Clock Init================== //Сбрасываем настройки RCC_DeInit(); //Включаем HSE RCC_HSEConfig(RCC_HSE_ON); //Ждем пока запустится кварц while(RCC_WaitForHSEStartUp() != SUCCESS); //Включаем Clock Security System RCC->CR |= RCC_CR_CSSON; //Переключаем системную частоту на HSE RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE); //Выключаем HSI для экономии энергии RCC_HSICmd(DISABLE); //======================GPIO Init====================== LED_GPIO_Configuration(); //Простенькая функция мигания светодиодиком while(1) { if (ticks++ >= 9999) { ticks = 0; Clock1s = 1; } if (Clock1s) { Clock1s = 0; Delay(delay_time); GPIO_WriteBit(LED_PORT, GPIO_Pin_9, Bit_SET); Delay(delay_time); GPIO_WriteBit(LED_PORT, GPIO_Pin_9, Bit_RESET); } } } //Инициализируем порт GPIOC void LED_GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; //Разрешаем тактирование RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //Настраиваем GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); } void NMI_Handler() { //Очищаем флаг прерывания CSS RCC->CIR |= RCC_CIR_CSSC; //Ждем некоторое время после сбоя, если он кратковременный //Возможно удастся перезапустить Delay(100); //Пытаемся запустить HSE RCC_HSEConfig(RCC_HSE_ON); //Задержка на запуск кварца Delay(1); if (RCC_WaitForHSEStartUp() == SUCCESS) { //Если запустился - устанавливаем HSE источником системной частоты RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE); //Выключаем HSI RCC_HSICmd(DISABLE); //Меняем период мигания зеленым светодиодом delay_time = 100; } else GPIO_SetBits(GPIOC,GPIO_Pin_8); //Если не удалось запустить кварц - остаемся на HSI //Зажигаем синий светодиод } //Нубская функция задержки void Delay(__IO uint32_t nCount) { uint32_t i = 0; for (; nCount != 0; i++) { if (i == 1000) { i = 0; nCount--; } } }
Видео работы:
На этом пока все — при подготовке статьи пользовался даташитом, примерами кода из CoIDE, а также статьями уважаемого DI Halta, обработчик прерывания дан лишь для примера и не претендует на супер надежное решение — просто демонстрация возможностей
