Определение текущей тактовой частоты при отладке

Тактовая частота это важнейший параметр, точное знание которого необходимо при расчете многих значений. Начиная от банальных выдержек, до генерации UART передачи.
 

И если даже на AVR, где тактовые режимы можно по пальцам одной руки пересчитать, и где все изначально предсказуемо работает по дефолту, прозрачно и явно, у многих новичков были проблемы с пониманием того, в каком режиме работает генератор.
 

То в STM32, где описание системы RCC занимает 35 страниц убористого текста, схема не влезает на экран, а куча библиотек, вроде CMSIS и SPL или визардов, наподобие того что есть в CoIDE, генерируют стартовый код, определить текущую тактовую частоту превращается в непростую задачу. Ее и будем решать.
 

Как же понять, что у нас получилось на SYSCLOCK после всех этих HSI, HSE, делителей, мультиплексоров и PLL умножителей?
 

Master Clock Output
Для STM32 у нас есть отличная штука, как MCO вывод. На который можно пнуть тактовую частоту и поглядеть осциллографом или частотомером. Правда если вы работаете на максимальной частоте в 72Мгц, то на MCO в лучшем случае вы можете выдать частоту поделеную всего лишь на два. А это 36Мгц, далеко не каждый осцил или частотомер в мультиметре такое схавает.
 

Но метод хорош, позволяет произвести непосредственный замер.

Вот тут, в нижней части схемы стоит мультиплексор MCO. На который можно вывести

  • PLLCLK/2 — на крайняк, когда точно знаем, что SYSCLOCK переведен на PLL можно смотреть ее
  • SYSCLOCK — собственно тактовая частота
  • HSI — внутренний RC генератор
  • HSE — внешний кварцевый генератор

 

Таким образом, через MCO можно поглядеть также на то, насколько плавает частота у HSI или поглядеть запустился ли HSE. А то и затактовать внешнюю периферию. В общем, вариантов применения много.
 

Итак, надо всего лишь правильно сконфигурировать вывод МСО. На STM32F103C8T6, который используется в модулях ARM STM для Pinboard это вывод А08

 

Если через SPL, то это выглядит вообще просто:

1
2
3
4
5
6
7
8
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	// Тактуем порт
 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);			// Конфигурируем вывод MCO
 
RCC_MCOConfig(RCC_MCO_PLLCLK_Div2);			// Подаем на MCO сигнал с PLL/2

 

Вручную чуть сложней, надо будет полазать в даташите и в определениях CMSIS:
 

1
2
3
4
5
6
7
8
9
10
11
RCC->APB2ENR 	|= RCC_APB2ENR_IOPAEN;		// Подаем тактирование на порт
 
GPIOA->CRH	&= ~GPIO_CRH_CNF8;		// Сбрасываем биты CNF для бита 8. Режим 00 - Push-Pull 
GPIOA->CRH	|= GPIO_CRH_CNF8_1;		// Ставим режим для 8 го бита режим CNF  = 10 (альтернативная функция, Push-Pull)
 
GPIOA->CRH	&=~GPIO_CRH_MODE8;				// Сбрасываем биты MODE для бита 8
GPIOA->CRH	|= GPIO_CRH_MODE8_1 | GPIO_CRH_MODE8_0;	// Выставляем бит MODE для пятого пина. Режим MODE11 = Max Speed 50MHz
 
RCC->CFGR	&=~(RCC_CFGR_MCO);		// Обнуляем MCO
RCC->CFGR	|=RCC_CFGR_MCO_PLL;		// Выставлем для MCO сигнал с PLL/2
//RCC->CFGR	|=RCC_CFGR_MCO_SYSCLK;		// Выставляем для МСО сигнал с SYSCLK

 
Но результат тот же — тактовый сигнал на входе MCO который можно измерить осциллографом и понять на какой частоте завелся контроллер.
 

Отладочные средства Keil
При работе в Keil, если запустить под отладчиком. например CoLinkEX (или просто CoLink, что установлен на Pinboard II), то можно открыть окно с настройками RCC и там посмотреть как происходит инициализация генератора. Какие режимы выставляются и так далее.
 

И, что самое приятное, там можно в режиме реального времени что угодно поменять на лету. Например, выдав сигнал на MCO (предварительно сконфигурировав вывод. Причем сделать это можно там же, в Keil, вызывав окно настроек GPIO и расставив галочки)
 


 

Эталонный код
На худой конец можно сунуть в память простейший эталонный код. Который выдает заведомо известную выдержку на заведомо известной частоте. И по расхождении частоты судить о реальной частоте контроллера.
 

Вот этот код, например, выдает по 1килогерцу на 1 мегагерц тактовой. Замеряя частотомером сигнал на выходе B05 можно узнать величину тактовой частоты контроллера в текущий момент:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
RCC->APB2ENR 	|= RCC_APB2ENR_IOPBEN;
					// Конфигурируем CRL регистры. 
GPIOB->CRL	&= ~GPIO_CRL_CNF5;	// Сбрасываем биты CNF для бита 5. Режим 00 - Push-Pull 
GPIOB->CRL 	|= GPIO_CRL_MODE5_0;	// Выставляем бит MODE0 для пятого пина. Режим MODE01 = Max Speed 10MHz
 
 
while(1)
	{
	GPIOB->BSRR = GPIO_BSRR_BR5;		// Сбросили бит.
	Delay(55560);
	GPIOB->BSRR = GPIO_BSRR_BS5;		// Установили бит.
	Delay(55560);
	}
}
 
 
/* Тупая задержка */
void Delay( uint32_t Val) 
{
for( ; Val != 0; Val--) 
  		{
		__nop();
  		}
}

В примере используется порт B05 т.к. мне удобно его бросить на светодиод на Pinboard. А так можно его перенастроить на любой другой. Разумеется изменив инициализацию.

Вот как это выглядит:

14 thoughts on “Определение текущей тактовой частоты при отладке”

  1. а куча библиотек, вроде CMSIS и SPL или визардов, наподобие того что есть в CoIDE, генерирующих стартовый код, определить текущую тактовую частоту

    Предложение несогласовано. Ты скорее всего какой-то кусок фразы забыл написать.

  2. В RM0090 для камня STM32F4Dsicovery пишут:
    «MCO2: Microcontroller clock output 2. Set and cleared by software. Clock source selection may generate glitches on MCO2. It is highly recommended to configure these bits only after reset before enabling the external oscillators and the PLLs.»
    Т.е. конфигурировать вывод надо в области инициализации тактирования. Не возникают те самые » glitches» при твоей конфигурации ?

    1. Ну начнем с того, что у меня совсем другое семейство. Другое ядро (кортекс м3) в котором все по другому. А во вторых, тут мсо полностью хардверное.

    2. Глитчи опасны только для периферии, которая с MCO клоком кормится (для чего он, собственно, и предназначен). Если ты просто хочешь померить тактовую частоту на нем — то глитчи пройдут задолго до того, как ты туда осциллом/частотомером доберешься.

  3. [i]Как же понять, что у нас получилось на SYSCLOCK после всех этих HSI, HSE, делителей, мультиплексоров и PLL умножителей?[/i]

    Арифметикой, не?
    Я просто распечатываю эту картинку из RM, во время написания кода инициализации клок-генератора проставляю на рисунке полученные частоты. Сначала опорная частота , потом после pll и т.д.
    Одно создает неприятности (по крайней мере для меня) — ограничение тактовой частоты на шинах APB1,APB2,AHB. про которые постоянно забываю.

    1. А ты их тоже на распечатке обозначь, можно еще до печати — тогда проставляя ручкой реальные частоты убедишься, чтобы соответствовало.

    2. Это если ты точно уверен, что все выставил правильно, что все работает именно так, как ты думаешь. Это ооочень часто бывает не так. Особенно когда только осваиваешь новое железо.

      1. Ну, так обычно и делаю. Распечатываю и пишу.
        Вот именно, когда новое железо. А после того, как фукнции отлажены (или спизжены из STD Periph Framework) уже нет необходимости следить за тактовой частотой (если не считать возможнй фейл кварца и переброс на RC).
        Или еще бывают варианты сбоя тактовой частоты?
        Поправьте, если ошибся.

    3. А зачем? Есть же утилитка в виде экселевского файла у них. Все наглядно+сама формирует стартовый код.

  4. Привет всем! Новая статья про стм32 радует. Вопрос DI HALT’у. Какую версию кейла ты используешь (если можно ссылку на скачивание), поддерживает ли она (версия) камень STM32F107VCT6, и если да, то позволяет ли отладчик симулить периферию его? Что то я не встречал пока возможность симуляции этого камня, если честно. Что уж говорить о STM32F4xx серии!

  5. Доброго времени суток.
    1. В статье, к последнему примеру, указано про «1МГц = 1КГц на выходе». Фактически, если замерить, то выходит что «1МГц = 1Гц», все перепроверил, настроено все верно. Выходит, в статье опечатка?
    2. В видео говорится, что в отладчике PLL перенастроить нельзя, фактически — можно, если сперва переключить SW на источник, отличный от PLL, затем отключить PLLON, а после уже возможно изменять параметры PLL.
    3. И последний вопрос — как понять точное время выполнения инструкции? Откуда вот взялось число 55560 для Delay()?
    Спасибо!

  6. В статье:

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	// Тактуем порт

    Необходимо ещё включить тактирование AFIO (MCO относится к AF, судя по RM).

Добавить комментарий

Ваш e-mail не будет опубликован.

Перед отправкой формы:
Human test by Not Captcha