MyTetra Share
Делитесь знаниями!
Пример быстрого ногодрыганья на BluePill STM32F103C8T6 через CMSIS (период 60 наносекунд)
Время создания: 07.04.2022 21:27
Текстовые метки: stm32, STM32F103C8T6, CMSIS, переключение, ногодрыгание, ножка, пин, максимально, быстро
Раздел: Компьютер - Аппаратное обеспечение - Микроконтроллеры ARM
Запись: xintrea/mytetra_syncro/master/base/1649356037s300hvspev/text.html на raw.github.com

Здесь дается пример исходного кода для максимально быстрого переключения ноги микроконтроллера с 0 до 1 в бесконечном цикле. Используется пин PB12. Все делается с помощью библиотеки CMSIS.


В этом примере происходит инициализация на максимальную частоту Blue Pill в 72MHz.


В итоге получается время переключения (один период) равный 60нс (нано-секунд). Скорость переключения замерялась осциллографом Rigol DS1054Z.


Для компиляции данного кода необходим флаг -std=c99, так как используются языковые возможности стандарта C99.


Непосредственно, сам код:



#include <stdbool.h>


#include "stm32f1xx.h"


#define LED1 (12)


// Настройка тактирование системы от внешнего кварца

// через PLL на максимально возможных частотах.

// Внешний кварц должен быть на 8МГц

// Возвращает:

// 0 - завершено успешно

// 1 - не запустился кварцевый генератор

// 2 - не запустился PLL

// Итоговая настройка делается на 72МГц

int ClockInit(void)

{

__IO int StartUpCounter;

////////////////////////////////////////////////////////////

//Запускаем кварцевый генератор

////////////////////////////////////////////////////////////

RCC->CR |= (1<<RCC_CR_HSEON_Pos); //Запускаем генератор HSE

//Ждем успешного запуска или окончания тайм-аута

for(StartUpCounter=0; ; StartUpCounter++)

{

//Если успешно запустилось, то

//выходим из цикла

if(RCC->CR & (1<<RCC_CR_HSERDY_Pos))

break;

//Если не запустилось, то

//отключаем все, что включили

//и возвращаем ошибку

if(StartUpCounter > 0x1000)

{

RCC->CR &= ~(1<<RCC_CR_HSEON_Pos); //Останавливаем HSE

return 1;

}

}

////////////////////////////////////////////////////////////

//Настраиваем и запускаем PLL

////////////////////////////////////////////////////////////

//Настраиваем PLL

RCC->CFGR |= (0x07<<RCC_CFGR_PLLMULL_Pos) //PLL множитель равен 9

| (0x01<<RCC_CFGR_PLLSRC_Pos); //Тактирование PLL от HSE

RCC->CR |= (1<<RCC_CR_PLLON_Pos); //Запускаем PLL

//Ждем успешного запуска или окончания тайм-аута

for(StartUpCounter=0; ; StartUpCounter++)

{

//Если успешно запустилось, то

//выходим из цикла

if(RCC->CR & (1<<RCC_CR_PLLRDY_Pos))

break;

//Если по каким-то причинам не запустился PLL, то

//отключаем все, что включили

//и возвращаем ошибку

if(StartUpCounter > 0x1000)

{

RCC->CR &= ~(1<<RCC_CR_HSEON_Pos); //Останавливаем HSE

RCC->CR &= ~(1<<RCC_CR_PLLON_Pos); //Останавливаем PLL

return 2;

}

}

////////////////////////////////////////////////////////////

//Настраиваем FLASH и делители

////////////////////////////////////////////////////////////

//Устанавливаем 2 цикла ожидания для Flash

//так как частота ядра у нас будет 48 MHz < SYSCLK <= 72 MHz

FLASH->ACR |= (0x02<<FLASH_ACR_LATENCY_Pos);

//Делители

RCC->CFGR |= (0x00<<RCC_CFGR_PPRE2_Pos) //Делитель шины APB2 отключен

| (0x04<<RCC_CFGR_PPRE1_Pos) //Делитель нишы APB1 равен 2

| (0x00<<RCC_CFGR_HPRE_Pos); //Делитель AHB отключен

RCC->CFGR |= (0x02<<RCC_CFGR_SW_Pos); //Переключаемся на работу от PLL

//Ждем, пока переключимся

while((RCC->CFGR & RCC_CFGR_SWS_Msk) != (0x02<<RCC_CFGR_SWS_Pos))

{

}

//После того, как переключились на

//внешний источник такирования

//отключаем внутренний RC-генератор

//для экономии энергии

RCC->CR &= ~(1<<RCC_CR_HSION_Pos);

//Настройка и переклбючение сисемы

//на внешний кварцевый генератор

//и PLL запершилось успехом.

//Выходим

return 0;

}


void msDelay(int ms)

{

while (ms-- > 0) {

volatile int x=500;

while (x-- > 0)

__asm("nop");

}

}



//Alternates blue and green LEDs quickly

int main(void)

{

ClockInit();


//Включаем тактирование порта GPIOB

RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;


// Для начала сброс конфигурации порта B12 в ноль

GPIOB->CRH &= ~(GPIO_CRH_MODE12 | GPIO_CRH_CNF12);


// Конфигурация пина PB12

// MODE: выход с максимальной частотой 50 МГц

// CNF: режим push-pull

GPIOB->CRH |= (0b11 << GPIO_CRH_MODE12_Pos) | (0x00 << GPIO_CRH_CNF12_Pos);


while (true) {

// msDelay(500);


// Медленное переключение

// 1мкс+1мкс = 2мкс - один период - на обычной частоте (неизвестно какой, которая стандартная)

// GPIOB->ODR ^= (1<<LED1);


// Более быстрое переключение

// 250нс+250нс = 500нс - один период - на обычной частоте (неизвестно какой, которая стандартная)

// 30нс+30нс = 60нс - один период - на частоте 72МГц

GPIOB->BSRR = (1<<LED1); // Hi

GPIOB->BRR = (1<<LED1); // Low

}


return 0;

}


Так же в этом разделе:
 
MyTetra Share v.0.59
Яндекс индекс цитирования