Тактирование STM32F405

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
funascan
Первый раз сказал Мяу!
Сообщения: 27
Зарегистрирован: Пт янв 04, 2019 19:14:29

Тактирование STM32F405

Сообщение funascan »

Всем привет. Только начал вникать в stm32. Думаю, что я что-то напортачил с тактированием. Systick приспособил для отсчета микросекундных задержек и он явно что то не то считает. Должна быть задержка примерно пол секунды, а получается где то 2. Помогите, пожалуйста, разобраться.

Код: Выделить всё

#include "stm32f4xx.h"
void delay_us(uint32_t us) ;

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

int ClockInit(char g)
{
  __IO int StartUpCounter;
  if (g == 'I')
  {
    RCC->CR |= (1<<RCC_CR_HSION_Pos);                                           //Enable internal generator
    for(StartUpCounter=0; ; StartUpCounter++)                                   //Waiting for internal generator on
    {
      if(RCC->CR & (1<<RCC_CR_HSIRDY_Pos))        
        break;
      if(StartUpCounter > 0x1000) 
      {
        return 1;                                                              
      }
    }
    
    RCC->PLLCFGR        |=      (0xA8<<RCC_PLLCFGR_PLLN_Pos)                    //PLL VCO multiplier x168  
                        |       (0x08<<RCC_PLLCFGR_PLLM_Pos);                   //Divide HSI by 8 for PLL
    RCC->PLLCFGR        &=     ~(0x01<<RCC_PLLCFGR_PLLSRC_Pos);                 //PLL connected to HSI
    RCC->PLLCFGR        &=     ~(0x3<<RCC_PLLCFGR_PLLP_Pos);                    //Divide by 2 for system clock  
    RCC->CR             |=      (1<<RCC_CR_PLLON_Pos);                          //Enable PLL
    
    for(StartUpCounter=0; ; StartUpCounter++)                                   //Waiting for PLL on
    {
      if(RCC->CR & (1<<RCC_CR_PLLRDY_Pos))
        break;
      if(StartUpCounter > 0x1000)                                             
      {
        RCC->CR         &=     ~(1<<RCC_CR_PLLON_Pos); 
        return 2;
      }
    }
    
    FLASH->ACR          |=      (0x05<<FLASH_ACR_LATENCY_Pos);                  //Set delay for flash memory
  
    RCC->CFGR           |=      (0x04<<RCC_CFGR_PPRE2_Pos)                      //Set APB1 and APB2 prescalers
                        |       (0x05<<RCC_CFGR_PPRE1_Pos);
  
    RCC->CFGR           |=      (0x02<<RCC_CFGR_SW_Pos);                        //Switch to PLL clocking
  
    while((RCC->CFGR & RCC_CFGR_SWS_Msk) != (0x02<<RCC_CFGR_SWS_Pos));          //Waiting for clocking from PLL           
    return 0;
  }   
  
  if (g == 'E')
  {
    RCC->CR |= (1<<RCC_CR_HSEON_Pos);                                           //Enable external generator
    for(StartUpCounter=0; ; StartUpCounter++)                                   //Waiting for internal generator on
    {
      if(RCC->CR & (1<<RCC_CR_HSERDY_Pos))        
        break;
      if(StartUpCounter > 0x1000) 
      {
        RCC->CR &= ~(1<<RCC_CR_HSEON_Pos);                              
        return 1;                                                               
      }
    }
    
    RCC->PLLCFGR        |=      (0x01<<RCC_PLLCFGR_PLLSRC_Pos);                  //PLL connected to HSE      
                        |       (0xA8<<RCC_PLLCFGR_PLLN_Pos)                    //PLL VCO multiplier x168  
                        |       (0x02<<RCC_PLLCFGR_PLLM_Pos)                   //Divide HSE by 2 for PLL

    RCC->PLLCFGR        &=     ~(0x3<<RCC_PLLCFGR_PLLP_Pos);                    //Divide by 2 for system clock  
    RCC->CR             |=      (1<<RCC_CR_PLLON_Pos);                          //Enable PLL
    
    for(StartUpCounter=0; ; StartUpCounter++)                                   //Waiting for PLL on
    {
      if(RCC->CR & (1<<RCC_CR_PLLRDY_Pos))
        break;
      if(StartUpCounter > 0x1000)                                           
      {
        RCC->CR         &=     ~(1<<RCC_CR_PLLON_Pos); 
        return 2;
      }
    }
    
    FLASH->ACR          |=      (0x05<<FLASH_ACR_LATENCY_Pos);                  //Set delay for flash memory
  
    RCC->CFGR           |=      (0x04<<RCC_CFGR_PPRE2_Pos)                      //Set AHB, APB1 and APB2 prescalers
                        |       (0x05<<RCC_CFGR_PPRE1_Pos);
  
    RCC->CFGR           |=      (0x02<<RCC_CFGR_SW_Pos);                        //Switch to PLL clocking
  
    while((RCC->CFGR & RCC_CFGR_SWS_Msk) != (0x02<<RCC_CFGR_SWS_Pos));          //Waiting for clocking from PLL           
    return 0;
  }
  return 3;
}

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

void PortInit(void)
{
  RCC->AHB1ENR          |=      (1<<RCC_AHB1ENR_GPIOAEN_Pos );                  //Enable GPIOA clocking
  RCC->AHB1ENR          |=      (1<<RCC_AHB1ENR_GPIOBEN_Pos );                  //Enable GPIOB clocking
}


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

void TIM_Init(void)                                                             //Timer initialization for microseconds delay
{
   SysTick->CTRL        &=     ~(1<<SysTick_CTRL_CLKSOURCE_Pos);                //Select AHB frequency/8 as clocksource 
   

}

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

void delay_us(uint32_t us)                                                      //Microseconds delay function
{
    SysTick->LOAD       |=      (21*us<<SysTick_LOAD_RELOAD_Pos);              
    SysTick->CTRL       |=      (1<<SysTick_CTRL_ENABLE_Pos);
    while(!(SysTick->CTRL & (1<<SysTick_CTRL_COUNTFLAG_Pos)));
    SysTick->CTRL       &=     ~(1<<SysTick_CTRL_ENABLE_Pos);
}

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

void main()
{
  ClockInit('E');
  PortInit();
  GPIOB->MODER          |=      (0x01<<GPIO_MODER_MODER14_Pos)                  
                        |       (0x01<<GPIO_MODER_MODER13_Pos)              
                        |       (0x01<<GPIO_MODER_MODER12_Pos)                  
                        |       (0x01<<GPIO_MODER_MODER11_Pos);
  GPIOB->OSPEEDR        |=      (0x03<<GPIO_OSPEEDR_OSPEED14_Pos)              
                        |       (0x03<<GPIO_OSPEEDR_OSPEED13_Pos)
                        |       (0x03<<GPIO_OSPEEDR_OSPEED12_Pos)
                        |       (0x03<<GPIO_OSPEEDR_OSPEED11_Pos);
  TIM_Init();
  while (1)
  {
    GPIOB->BSRR         |=      (1<<GPIO_BSRR_BS14_Pos);
   //delay_us(500000);
    delay_us(500000);
    GPIOB->BSRR         |=      (1<<GPIO_BSRR_BR14_Pos);
   //delay_us(500000);
    delay_us(500000);

  }
}
Реклама
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Тактирование STM32F405

Сообщение Reflector »

У тебя PLLP равна 8, хоть в комменте написано, что 2.
А не, сорри, это мне уже привиделось :)

На входе PLL должно быть 1-2MHz, не знаю на сколько там кварц, но очень сомневаюсь, что на 4MHz, т.к. входная частота делится на 2...
Последний раз редактировалось Reflector Вт апр 21, 2020 09:39:08, всего редактировалось 1 раз.
Реклама
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Тактирование STM32F405

Сообщение VladislavS »

Что же так сложно то...
Вот пример от 407-го. Не должно сильно отличаться. Главное - принцип. Ну можно условие незапуска кварца ещё обработать.

Код: Выделить всё

// Настройка FLASH
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS;
//Включаем HSE = 8 MHz
RCC->CR = _VAL2FLD(RCC_CR_HSITRIM,16) | RCC_CR_HSION | RCC_CR_HSEON;
while(!(RCC->CR & RCC_CR_HSERDY));
//Задаём источники тактирования и прескалеры SYSCLK = 168 МГц  USB = 48 МГц
RCC->PLLCFGR = RCC_PLLCFGR_PLLSRC_HSE 
             | _VAL2FLD(RCC_PLLCFGR_PLLQ,7) 
             | _VAL2FLD(RCC_PLLCFGR_PLLN,168) 
             | _VAL2FLD(RCC_PLLCFGR_PLLM,4) 
             | RCC_PLLCFGR_PLLP_div2;
//Включаем PLL
RCC->CR = _VAL2FLD(RCC_CR_HSITRIM,16) | RCC_CR_HSION | RCC_CR_HSEON | RCC_CR_PLLON;
while(!(RCC->CR & RCC_CR_PLLRDY));
//Установим делители шин и переключаемся на PLL
RCC->CFGR = RCC_CFGR_MCO2_HSE 
          | RCC_CFGR_MCO2PRE_div1 
          | RCC_CFGR_MCO1PRE_div1 
          | RCC_CFGR_I2SSRC_PLLI2S 
          | RCC_CFGR_MCO1_HSE 
          | _VAL2FLD(RCC_CFGR_RTCPRE,8) 
          | RCC_CFGR_PPRE2_DIV2 
          | RCC_CFGR_PPRE1_DIV4 
          | RCC_CFGR_HPRE_DIV1 
          | RCC_CFGR_SW_PLL;
//Выключаем HSI
RCC->CR = _VAL2FLD(RCC_CR_HSITRIM,16) | RCC_CR_HSEON | RCC_CR_PLLON;
И что-то я не пойму что ты с SysTick делаешь? До переполнения его гонишь? Параметр us то где используется?

Посмотри в моём примере как правильно с битами и полями в регистрах работать. Все определения и макросы из того же CMSIS. Это уменьшает писанину и кол-во ошибок.

Код: Выделить всё

__IO int StartUpCounter;
Вот тут __IO не надо. В цикле есть доступ к регистрам, они тоже __IO и компилятор не посмеет цикл выкинуть. Ну и лучше для переменных (где действительно надо) использовать volatile, а __IO оставить регистрам.
Последний раз редактировалось VladislavS Вт апр 21, 2020 09:55:42, всего редактировалось 1 раз.
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Тактирование STM32F405

Сообщение Reflector »

[uquote="VladislavS",url="/forum/viewtopic.php?p=3830889#p3830889"]И что-то я не пойму что ты с SysTick делаешь? До переполнения его гонишь? Параметр us то где используется?[/uquote]
Us множится на 21(168/8), там главное задержку делать не более ~0.8 сек...
Реклама
Эиком - электронные компоненты и радиодетали
funascan
Первый раз сказал Мяу!
Сообщения: 27
Зарегистрирован: Пт янв 04, 2019 19:14:29

Re: Тактирование STM32F405

Сообщение funascan »

[uquote="Reflector",url="/forum/viewtopic.php?p=3830898#p3830898"]Us множится на 21(168/8), там главное задержку делать не более ~0.8 сек...[/uquote]
Да, именно так. Там я по 0.5 секунды беру.
Короче попробовал просто от HSE запустить. Работает как надо. Надо значит настройки PLL ковырять
Реклама
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Тактирование STM32F405

Сообщение VladislavS »

[uquote="Reflector",url="/forum/viewtopic.php?p=3830898#p3830898"]Us множится на 21(168/8)[/uquote]Точно, не заметил. Всякая лабуда так широко написана, а основное - хрен рассмотришь. Это и есть "стиль".
Реклама
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Тактирование STM32F405

Сообщение Reflector »

Частота HSE то какая?
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Тактирование STM32F405

Сообщение VladislavS »

[uquote="funascan",url="/forum/viewtopic.php?p=3830902#p3830902"]Надо значит настройки PLL ковырять[/uquote]Запусти куб, там хороший калькулятор, можно все делители визуально расставить и в СВОЁМ коде выставить.
funascan
Первый раз сказал Мяу!
Сообщения: 27
Зарегистрирован: Пт янв 04, 2019 19:14:29

Re: Тактирование STM32F405

Сообщение funascan »

[uquote="VladislavS",url="/forum/viewtopic.php?p=3830889#p3830889"]Посмотри в моём примере как правильно с битами и полями в регистрах работать. Все определения и макросы из того же CMSIS. Это уменьшает писанину и кол-во ошибок.[/uquote]
Спасибо. Я так пишу, чтобы уровень абстракции немного снизить. Мне так более понятно куда какие значения загоняются. Но _VAL2FLD обязательно попробую.
[uquote="Reflector",url="/forum/viewtopic.php?p=3830906#p3830906"]Частота HSE то какая?[/uquote]
4мгц

Добавлено after 4 minutes 24 seconds:
[uquote="VladislavS",url="/forum/viewtopic.php?p=3830908#p3830908"]Запусти куб, там хороший калькулятор, можно все делители визуально расставить и в СВОЁМ коде выставить.[/uquote]
Пробовал в кубе выставлять. но что то он в коде столько комментариев генерирует, что аж в глазах рябит. Трудно оттуда то, что нужно выцепить.
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Тактирование STM32F405

Сообщение Reflector »

Код: Выделить всё

SysTick->LOAD       |=      (21*us<<SysTick_LOAD_RELOAD_Pos);
Тут должно быть "=", к моменту когда ты выключаешь таймер его значение уже может быть 0xFFFFFF...
funascan
Первый раз сказал Мяу!
Сообщения: 27
Зарегистрирован: Пт янв 04, 2019 19:14:29

Re: Тактирование STM32F405

Сообщение funascan »

[uquote="Reflector",url="/forum/viewtopic.php?p=3830926#p3830926"]

Код: Выделить всё

SysTick->LOAD       |=      (21*us<<SysTick_LOAD_RELOAD_Pos);
Тут должно быть "=", к моменту когда ты выключаешь таймер его значение уже может быть 0xFFFFFF...[/uquote]
Точно, спасибо. :beer:
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Тактирование STM32F405

Сообщение VladislavS »

[uquote="funascan",url="/forum/viewtopic.php?p=3830910#p3830910"]Пробовал в кубе выставлять. но что то он в коде столько комментариев генерирует, что аж в глазах рябит.[/uquote]Не надо генерировать. Его просто как визуальное средства расчёта всех делителей использовать. Он всё на корректность проверит. И в СВОЙ КОД оттуда ЗНАЧЕНИЯ переноси.
Аватара пользователя
dosikus
Друг Кота
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Re: Тактирование STM32F405

Сообщение dosikus »

А здесь как рассчитать без калокуба ... http://mcu.goodboard.ru/viewtopic.php?id=11
Ответить

Вернуться в «ARM»