Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

STM32F4 Inicijalizacija - frekvencija

[es] :: Elektronika :: Mikrokontroleri :: STM32F4 Inicijalizacija - frekvencija

[ Pregleda: 1649 | Odgovora: 6 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.31.24.217.adsl2.beograd.com.

Sajt: mysql.rs


+2377 Profil

icon STM32F4 Inicijalizacija - frekvencija05.03.2012. u 20:05 - pre 147 meseci
Elem, kada se STM32 mcu pokrene on radi na HSI kloku. HSI je "High Speed Internal", dakle njegov interni oscilator, ne preterano precizan ali dovoljno dobar za startap. Ceo STM32 moze da radi na internom oscilatoru, ali u tom slucaju zaboravite na vece brzine UART-a i potpuno zaboravite na USB.

Vi u vasem kodu mozete da nasetujete frekvenciju koja vas zanima. Obratite da kompajler ne zna koja je max frekvencija, i koje su dozvoljene kombinacije tako da ako vam se ne podigne mcu ... dalje, takodje mcu ce da dozvoli da ga overklokujes koliko god hoces ali onda nece da radi stabilno, dakle uvek proveri max vrednosti u datasheet-u.

Kod atollic-a, atollic sam u projekat doda startap kod koji poziva SystemInit(); koji se nalazi u system_stm32f4xx.c gde se podesava neka "safe" vrednost oscilatora. Ako hocete da vas projekat radi na nekoj frekvenciji najlakse je promeniti define-ove tamo direkt i to je to.

Ono sto stoji default u system_stm32f4xx.c je
Code:

#define PLL_M      25
#define PLL_N      336
#define PLL_P      2


Sto daje sistemski klok od 53.76 MHz


Ako hocemo max brzinu, sve sto treba je da to zamenimo sa:

Code:

#define PLL_M      8
#define PLL_N      336
#define PLL_P      2


i dobicemo 168 MHz

E sad, posto je skroz ok da vi bilo gde u kodu promenite brzinu evo ga jedan primer gde imamo funkciju koja bilo gde u kodu menja brzinu na "max".

Code (c):

#include "stm32f4xx.h"

volatile int i,j;

// Offset za pocetak "vector table" (tabele sa interaptima)
// mora da bude n*512
#define VECT_TAB_OFFSET  0x00

// Parametri za PLL
// formule (HSE je frekvencija externog kristalnog rezonatora):
// PLL_VCO = (HSE / PLL_M) * PLL_N
// Sistem klok:
// SYSCLK = PLL_VCO / PLL_P
// Klok za usb on the go i ekipu (PLL_Q izlaz)
// USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ

// ovim dobijamo 168MHz za sysclock sto je max za
// mcu na stm32f4discovery plocki
// 8MHz externi kristal (HSE) podelimo sa PLL_M od 8 i na ulazu
// u glavni PLL imamo 1MHz
// njega pomnozimo sa 336 (PLL_N) i iskoristimo prescaler od 2 na
// izlazu (PLL_P) i dobijemo 168MHz :)

#define PLL_M      8
#define PLL_N      336
#define PLL_P      2
#define PLL_Q      7

int max_brzina(void) {
     volatile uint32_t StartUpCounter = 0;
     volatile uint32_t HSEStatus = 0;

     // ako imamo FPU ( a imamo )
     // onda moramo da setujemo CP10 i CP11
     // kako bi koristili isti
     SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));

     // Reset RCC modula
     RCC->CR |= (uint32_t)0x00000001;
     RCC->CFGR = 0x00000000;
     RCC->CR &= (uint32_t)0xFEF6FFFF;
     RCC->PLLCFGR = 0x24003010;
     RCC->CR &= (uint32_t)0xFFFBFFFF;
     RCC->CIR = 0x00000000; // gasimo interapte

     // u ovom trenutku nam mcu radi na "interni" clock generator
     // i svi RCC registri su setovani na "reset" state
     // tj sto se RCC-a tice, kao da smo sad dobili struju


     // konfiguracija klok generatora
     // hocemo da nam sistemski klok bude
     // generisan od strane externog rezonatora
     // kontrolisan internim PLL-om

     RCC->CR |= ((uint32_t)RCC_CR_HSEON);
     do {
         HSEStatus = RCC->CR & RCC_CR_HSERDY; // da li je HSE oscilator spreman za rad
         StartUpCounter++;
     } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
     // HSE oscilator se pravilno zaoscilovao i mozemo da nastavimo dalje
     // ova do-while petlja je mnogo bitna posto razliciti kristalni / keramicki
     // rezonatori traze razlicito vreme da lepo zaosciluju tako da umesto da cekamo
     // neko "najduze vreme" da bi bili sigurni da je oscilator proradio kako treba
     // ARM jezgro nam nudi nacin da proverimo da li je externi oscilator spreman za
     // rad. Tu "spremnost" citamo tako sto citamo bit RCC_CR_HSERDY iz CR registra RSS
     // modula. Da ne bi cekali oscilator "beskonacno" (ako je mozda ne ispravan)
     // cekamo ga max HSE_STARTUP_TIMEOUT (500) puta.

     // sada proverimo jos jednom status HSERDY bita da bi znali da li smo iz
     // malopredjasnje "cekajuce" petlje izasli zato sto je HSE najzad spreman
     // ili zato sto nije bio spreman ni posle 500 puta
     // i to zapisemo u nasu HSEStatus varijablu
     if ((RCC->CR & RCC_CR_HSERDY) != 0){
          HSEStatus = (uint32_t)0x01; //SPREMAN
     } else {
          HSEStatus = (uint32_t)0x00; //NIJE SPREMAN
     }

     // Ako je HSE ok
     if (HSEStatus == (uint32_t)0x01){
          RCC->APB1ENR |= RCC_APB1ENR_PWREN; //Upali voltage regulator
          PWR->CR |= PWR_CR_VOS;

          // setuje preskalere za razlicite periferije
         RCC->CFGR |= RCC_CFGR_HPRE_DIV1;  //  HCLK = SYSCLK
         RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; //  PCLK = HCLK / 2
         RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; // PCLK1 = HCLK / 4

         // Glavni PLL
         RCC->PLLCFGR = PLL_M |
               (PLL_N << 6) |
               (((PLL_P >> 1) -1) << 16) |
               (RCC_PLLCFGR_PLLSRC_HSE) |
               (PLL_Q << 24);

         RCC->CR |= RCC_CR_PLLON; // Ukljuci glavni PLL

         // sacekaj da se glavni pll "smiri"
         while((RCC->CR & RCC_CR_PLLRDY) == 0);

         // za razlicite frekvencije moramo posebno da setujemo
         // vrednosti keseva i wait-state-ova
         // fora je u tome sto iako jezgro moze da trci na 168MHz
         // to ne znaci da periferija moze da trci na istom taktu
         // tako da ovde upalimo kesh, dodamo wait states...
         // Flash prefetch
         // Instruction cache
         // Data cache
         // wait state

         FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;



         // posto je sve namesteno, sada prebacijuemo
         // sistemski klok na izlaz od PLL-a
         RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
         RCC->CFGR |= RCC_CFGR_SW_PLL;

         // sacekamo da se izvrsi prebacivanje sistemskog
         // takta na PLL
         while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);

         // VOILA - sada trcimo na 168MHz


         // postavimo vrednost za SystemCoreClock
         SystemCoreClock = (8000000UL / PLL_M) * PLL_N / PLL_P;

         // postavimo offset za tabelu interapta
          SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
          return 0;
       } else{
           // IZ NEGKO RAZLOGA NISMO USPELI DA INICIJALIZUJEMO EXTERNI OSCILATOR
            return -1; // greska
       }

}

int main(void)
{
     //inicijalizuj gpio
     GPIO_InitTypeDef  GPIO;
     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
     GPIO.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
     GPIO.GPIO_Mode = GPIO_Mode_OUT;
     GPIO.GPIO_OType = GPIO_OType_PP;
     GPIO.GPIO_PuPd = GPIO_PuPd_NOPULL;
     GPIO.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_Init(GPIOD, &GPIO);

     // 10 puta trepni na "original brzini"
     for(j=0;j<10;j++){
          GPIOD->BSRRL = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 ;
          for (i=0;i<1000000;i++);
          GPIOD->BSRRH = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 ;
          for (i=0;i<1000000;i++);
     }

     //prebaci se na externi oscilator na max brzinu
     max_brzina();

     // nastavi da trepces max
     while(1){
          GPIOD->BSRRL = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 ;
          for (i=0;i<1000000;i++);
          GPIOD->BSRRH = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 ;
          for (i=0;i<1000000;i++);
     }

}
 

 
Odgovor na temu

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.31.24.217.adsl2.beograd.com.

Sajt: mysql.rs


+2377 Profil

icon Re: STM32F4 Inicijalizacija - frekvencija05.03.2012. u 21:45 - pre 147 meseci
evo malo novije verzije :D

Code (c):

#include "stm32f4xx.h"

volatile int i,j;

// Offset za pocetak "vector table" (tabele sa interaptima)
// mora da bude n*512
#define VECT_TAB_OFFSET  0x00

// Parametri za PLL
// formule (HSE je frekvencija externog kristalnog rezonatora):
// PLL_VCO = (HSE / PLL_M) * PLL_N
// Sistem klok:
// SYSCLK = PLL_VCO / PLL_P
// Klok za usb on the go i ekipu (PLL_Q izlaz)
// USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ

// ovim dobijamo 168MHz za sysclock sto je max za
// mcu na stm32f4discovery plocki
// 8MHz externi kristal (HSE) podelimo sa PLL_M od 8 i na ulazu
// u glavni PLL imamo 1MHz
// njega pomnozimo sa 336 (PLL_N) i iskoristimo prescaler od 2 na
// izlazu (PLL_P) i dobijemo 168MHz :)

#define PLL_M      8
#define PLL_N      336
#define PLL_P      2
#define PLL_Q      7

int sporo(void){
     // ako imamo FPU ( a imamo )
     // onda moramo da setujemo CP10 i CP11
     // kako bi koristili isti
     SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));

     // Reset RCC modula
     RCC->CR |= (uint32_t)0x00000001;
     RCC->CFGR = 0x00000000;
     RCC->CR &= (uint32_t)0xFEF6FFFF;
     RCC->PLLCFGR = 0x24003010;
     RCC->CR &= (uint32_t)0xFFFBFFFF;
     RCC->CIR = 0x00000000; // gasimo interapte
}

int max_brzina(void) {
     volatile uint32_t StartUpCounter = 0;
     volatile uint32_t HSEStatus = 0;

     // ako imamo FPU ( a imamo )
     // onda moramo da setujemo CP10 i CP11
     // kako bi koristili isti
     SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));

     // Reset RCC modula
     RCC->CR |= (uint32_t)0x00000001;
     RCC->CFGR = 0x00000000;
     RCC->CR &= (uint32_t)0xFEF6FFFF;
     RCC->PLLCFGR = 0x24003010;
     RCC->CR &= (uint32_t)0xFFFBFFFF;
     RCC->CIR = 0x00000000; // gasimo interapte

     // u ovom trenutku nam mcu radi na "interni" clock generator
     // i svi RCC registri su setovani na "reset" state
     // tj sto se RCC-a tice, kao da smo sad dobili struju


     // konfiguracija klok generatora
     // hocemo da nam sistemski klok bude
     // generisan od strane externog rezonatora
     // kontrolisan internim PLL-om

     RCC->CR |= ((uint32_t)RCC_CR_HSEON);
     do {
         HSEStatus = RCC->CR & RCC_CR_HSERDY; // da li je HSE oscilator spreman za rad
         StartUpCounter++;
     } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
     // HSE oscilator se pravilno zaoscilovao i mozemo da nastavimo dalje
     // ova do-while petlja je mnogo bitna posto razliciti kristalni / keramicki
     // rezonatori traze razlicito vreme da lepo zaosciluju tako da umesto da cekamo
     // neko "najduze vreme" da bi bili sigurni da je oscilator proradio kako treba
     // ARM jezgro nam nudi nacin da proverimo da li je externi oscilator spreman za
     // rad. Tu "spremnost" citamo tako sto citamo bit RCC_CR_HSERDY iz CR registra RSS
     // modula. Da ne bi cekali oscilator "beskonacno" (ako je mozda ne ispravan)
     // cekamo ga max HSE_STARTUP_TIMEOUT (500) puta.

     // sada proverimo jos jednom status HSERDY bita da bi znali da li smo iz
     // malopredjasnje "cekajuce" petlje izasli zato sto je HSE najzad spreman
     // ili zato sto nije bio spreman ni posle 500 puta
     // i to zapisemo u nasu HSEStatus varijablu
     if ((RCC->CR & RCC_CR_HSERDY) != 0){
          HSEStatus = (uint32_t)0x01; //SPREMAN
     } else {
          HSEStatus = (uint32_t)0x00; //NIJE SPREMAN
     }

     // Ako je HSE ok
     if (HSEStatus == (uint32_t)0x01){
          RCC->APB1ENR |= RCC_APB1ENR_PWREN; //Upali voltage regulator
          PWR->CR |= PWR_CR_VOS;

          // setuje preskalere za razlicite periferije
         RCC->CFGR |= RCC_CFGR_HPRE_DIV1;  //  HCLK = SYSCLK
         RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; //  PCLK = HCLK / 2
         RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; // PCLK1 = HCLK / 4

         // Glavni PLL
         RCC->PLLCFGR = PLL_M |
               (PLL_N << 6) |
               (((PLL_P >> 1) -1) << 16) |
               (RCC_PLLCFGR_PLLSRC_HSE) |
               (PLL_Q << 24);

         RCC->CR |= RCC_CR_PLLON; // Ukljuci glavni PLL

         // sacekaj da se glavni pll "smiri"
         while((RCC->CR & RCC_CR_PLLRDY) == 0);

         // za razlicite frekvencije moramo posebno da setujemo
         // vrednosti keseva i wait-state-ova
         // fora je u tome sto iako jezgro moze da trci na 168MHz
         // to ne znaci da periferija moze da trci na istom taktu
         // tako da ovde upalimo kesh, dodamo wait states...
         // Flash prefetch
         // Instruction cache
         // Data cache
         // wait state

         FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;



         // posto je sve namesteno, sada prebacijuemo
         // sistemski klok na izlaz od PLL-a
         RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
         RCC->CFGR |= RCC_CFGR_SW_PLL;

         // sacekamo da se izvrsi prebacivanje sistemskog
         // takta na PLL
         while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);

         // VOILA - sada trcimo na 168MHz


         // postavimo vrednost za SystemCoreClock
         SystemCoreClock = (8000000UL / PLL_M) * PLL_N / PLL_P;

         // postavimo offset za tabelu interapta
          SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
          return 0;
       } else{
           // IZ NEGKO RAZLOGA NISMO USPELI DA INICIJALIZUJEMO EXTERNI OSCILATOR
            return -1; // greska
       }

}

int main(void)
{
     //inicijalizuj gpio
     GPIO_InitTypeDef  GPIO;
     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
     GPIO.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
     GPIO.GPIO_Mode = GPIO_Mode_OUT;
     GPIO.GPIO_OType = GPIO_OType_PP;
     GPIO.GPIO_PuPd = GPIO_PuPd_NOPULL;
     GPIO.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_Init(GPIOD, &GPIO);

     // 10 puta trepni na "original brzini"
     for(j=0;j<10;j++){
          GPIOD->BSRRL = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 ;
          for (i=0;i<1000000;i++);
          GPIOD->BSRRH = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 ;
          for (i=0;i<1000000;i++);
     }

     while(1){
          sporo();
          // 5 puta trepni na "sporoj brzini"
          for(j=0;j<5;j++){
               GPIOD->BSRRL = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 ;
               for (i=0;i<1000000;i++);
               GPIOD->BSRRH = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 ;
               for (i=0;i<1000000;i++);
          }

          //prebaci se na externi oscilator na max brzinu
          max_brzina();
          // 10 puta trepni na "max brzini"
          for(j=0;j<10;j++){
               GPIOD->BSRRL = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 ;
               for (i=0;i<1000000;i++);
               GPIOD->BSRRH = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15 ;
               for (i=0;i<1000000;i++);
          }
     }

}

 

 
Odgovor na temu

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.31.24.217.adsl2.beograd.com.

Sajt: mysql.rs


+2377 Profil

icon Re: STM32F4 Inicijalizacija - frekvencija06.03.2012. u 23:02 - pre 147 meseci
zanimljivo, ladno svima sve jasno :), niko nema pitanja
 
Odgovor na temu

HeYoo

Član broj: 72595
Poruke: 491



+1017 Profil

icon Re: STM32F4 Inicijalizacija - frekvencija07.03.2012. u 00:22 - pre 147 meseci
To je zato sto si dobro komentarisao.
Ne brini, ne pises za dzaba :)

Zasto HSI ne moze da pogoni periferije koje traze brzinu kad i on moze da ide na PLL?
 
Odgovor na temu

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.31.24.217.adsl2.beograd.com.

Sajt: mysql.rs


+2377 Profil

icon Re: STM32F4 Inicijalizacija - frekvencija07.03.2012. u 10:08 - pre 147 meseci
Citat:
HeYoo: Zasto HSI ne moze da pogoni periferije koje traze brzinu kad i on moze da ide na PLL?


Sa HSI bez problema mozes da poteras istih ovih 168MHz. Problem sa HSI je sto je to RC oscilator a RC oscilator je sam po sebi prilicno netacan i ima ogroman drift kroz temperaturu tako da, ne mozes da ispostujes tacne tajminge potrebne za neke protokole (poput uart ili usb-a), za druge protokole (poput spi, usart ... na primer) koji su sinhronizovani posebnim pinom umesto vremenskom bazom nemas problem


 
Odgovor na temu

the_tosic

Član broj: 37314
Poruke: 381
*.ptt.rs.



+128 Profil

icon Re: STM32F4 Inicijalizacija - frekvencija08.03.2012. u 19:19 - pre 147 meseci
Citat:
bogdan.kecman: zanimljivo, ladno svima sve jasno :), niko nema pitanja


Da ne bude da su svi iskulirali :), ja sam odma pokrenuo probao iscitao :p, al nikako da nadjem vremena da (se udubim) pogledam u datasheet-u sta je koje polje u registrima! (razumem sta je hsi hse pll)
Inace to mi je kao pocet\niku najveci problem, sta kojim redom treba raditi i kako da znam sta sve treba da odradim.

Hvala za koristan post.
 
Odgovor na temu

bogdan.kecman
Bogdan Kecman
"specialist"
Oracle
srbistan

Član broj: 201406
Poruke: 15887
*.31.24.217.adsl2.beograd.com.

Sajt: mysql.rs


+2377 Profil

icon Re: STM32F4 Inicijalizacija - frekvencija08.03.2012. u 19:53 - pre 147 meseci
tome i sluzi ova serija postova oko inicijalizacija ... ono "sta sve treba usiljiti" da bi nesto radilo
 
Odgovor na temu

[es] :: Elektronika :: Mikrokontroleri :: STM32F4 Inicijalizacija - frekvencija

[ Pregleda: 1649 | Odgovora: 6 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.