Skocz do zawartości

[C] STM32F4 discovery, konfiguracja SysTic od podstaw w coocox.


qwee

Pomocna odpowiedź

Panowie. Szukam odpowiedzi na wiele pytań, ale myślę, że takich jak ja jest ogrom.

Mianowicie, zachciało mi się przesiąść z avr na jakieś arm. Wybór padł na STM32f4 na płytce discovery. Poczytałem to i tamto, troche artykułów, troche literatury i doszedłem do wniosku, że nie potrzebnie kupiłem płytkę z cortexem M4, raczej mogłem zacząć od M3. No ale skoro już mam, to niech zostanie, spróbuje z tym ruszyć.

Jest mnustwo tutoriali na temat organizacji środowiska, lecz większość jest dla M3, choć postępując analogicznie napotkałem troche trudności, lecz w końcu się udało. To znaczy korzystam, a raczej próbuje korzystać, z CooCox, gdyż poszedł mi z kopyta bez najmniejszych problemów. Spodobało mi się to, że mogłem sobie wybrać jakie biblioteki chcę dorzucić, bez kombinowania z przenoszeniem wszelakich plików etc.

Kożystając z tego poradnika:

http://mikrokontroler.pl/content/coocox-coide-i-stm32f4discovery-%E2%80%93-jak-zacz%C4%85%C4%87

nauczyłem się mniej więcej działać na portach GPIO korzystając z API. Teraz czas na Timery i inne pierdoły.

Jak na razie mam wyobrażenie tylko o modelu jaki jest w avr - tj. ustawiamy rejestry timera w main(), a na dole procedura obsługi przerwania. Teraz troche cieżko mi to przychodzi. Załóżmy, że chciałbym wykorzystać SysTick i przy przejściu przez 0 wykonać jakieś działanie (mignąć diodą czy cokolwiek).

Niech będzie, że mam kod taki jak w tym tutorialu:

#include <stm32f4xx_rcc.h>
#include <stm32f4xx_gpio.h>

void Delay(void)
{
volatile uint32_t i;
for (i = 0; i != 0xFFFFF; i++);
}

int main(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

// Wlaczenie sygnalu taktujacego port D
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD , ENABLE);

GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_12 | GPIO_Pin_14);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);

// Wyzerowanie wyjscia PD14
GPIO_ResetBits(GPIOD, GPIO_Pin_14);

// Ustawienie wyjscia PD12
GPIO_SetBits(GPIOD, GPIO_Pin_12);

while(1){
	// Zmiana stanu wyjsc na przeciwny
	GPIO_ToggleBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_14);

	// Czekaj
	Delay();
}
}

Pierwsza sprawa co z taktowaniem? Tam jest napisane, że w jednym z plików, należy zmienić watość 25 na 8, co uczyniłem. To wszystko? W poradnikach dla M3 często była funkcja RCC_config...A tutaj tylko dostosowanie do aktualnego kwarcu?

Docelowo chciałbym aby while(1) był pusty a diody niech migają dzięki SysTick.

Rozumiem, że trzeba go najpierw skonfigurować, a później umieścić procedure obsługi przerwania, tak? Czy wystarczy zaincludwana biblioteka "stm32f4xx_rcc"?

Okno coocoxa wygląda tak:

Czy może ktoś naprowadzić mnie na poprawne rozwiązanie mojego problemu? Jak opanuję to to przejdę do kolejnych peryferiów.

Link do komentarza
Share on other sites

Nie znam f4 ale na pierwszy rzut oka nie masz w drzewku projektu biblioteki gpio. Oraz powinieneś też dołączyć bibliotekę od timerów. Czyli musisz poprostu zaznaczyć odpowiednie checkboxy w Repository.

Link do komentarza
Share on other sites

Tak, nie tren screen, już poprawiłem.

Dalej zaczynają się schody. Biblioteka jaką widze w repository to stm32f4xx_tim.h, lecz tam nigdzie nie widzę odwołań do jakiejkolwiek konfiguracji SysTic. Nie upieram się aż tak bardzo na ten licznik czasu, ale jeśli zaczynać od podstaw to myślę, że to jest elementarna sprawa.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Systick_Config() jest w core_cm4.h

Co do zegara to musisz jeszcze odpowiednio ustawić rejestry PLL. W pliku system_stm32f4x.c mam ustawione następujące wartości (dla kwarcu 8MHz):

/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
#define PLL_M      8
#define PLL_N      336

/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P      2

/* USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ */
#define PLL_Q      7

Dodatkowo musisz ustawić HSE_VALUE odpowiednio do częstotliwości kwarcu, w pliku stm32f4xx.h:

#if !defined  (HSE_VALUE) 
 #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */

Sprawdź jeszcze czy HSE_VALUE nie jest ustawiane gdzieś w Makefile'u, bo też jest taka możliwość (wtedy nie trzeba zmieniać w stm32f4xx.h).

Podczas ustawiania zegara najlepiej dodać do kodu wywołanie funkcji "SystemCoreClockUpdate();", a później sprawdzić jaka wartość znajduje się w zmiennej SystemCoreClock.

Link do komentarza
Share on other sites

Hmm w STM32F103... do ustawienia Systick mam taką funkcję

void SYSTICK_Conf(void)
{
#define FCPU				72000000
#define	SYSTICK_Prescaler	8
if (SysTick_Config((FCPU/SYSTICK_Prescaler)/1000))
	while(1);
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
}

I wymaga ona biblioteki misc.h

Ale pewnie w f4 jest już inaczej

Link do komentarza
Share on other sites

Dobra, no to includuje sobie rzeczoną misc.h w pliku main. W misc.c widzę funkcje :

void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)  

Domniemam więc, ze jest to funkcja konfiguracji źródła taktowania dla systic.

No to idąc dalej ustawiam:

SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);

Teraz zdaje się ustawiłem źródło taktowania jako HCLK.

sumarycznie spłodziłem taki kod:

#include <stm32f4xx_rcc.h>
#include <stm32f4xx_gpio.h>
#include <misc.h>


volatile int b;

int main(void)
{
//SystemCoreClockUpdate();
unsigned int a = SystemCoreClock;

GPIO_InitTypeDef GPIO_InitStructure;

// Wlaczenie sygnalu taktujacego port D
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD , ENABLE);

GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_12 | GPIO_Pin_14);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);

// Wyzerowanie wyjscia PD14
GPIO_ResetBits(GPIOD, GPIO_Pin_14);

// Ustawienie wyjscia PD12
GPIO_SetBits(GPIOD, GPIO_Pin_12);

SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
 if (SysTick_Config(SystemCoreClock / 1000))
	   {
	      while (1){}; // error
	   }


while(1){


}
}

void SysTick_Handler()
{
//	volatile static int b;
b++;
if(b==500)
{
	b=0;
	GPIO_ToggleBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_14);

}
//
}

Zasadniczo powinno to zwiększyć zmienną b co 0.001 s a co 0,5 s powinna być wykonana akcja zapisana w procedurze przerwania. Jednakże diody migają znacznie rzadzie. Obserwując miganie i nasłuchując tykanie zegarka na ścianie okazało się, że jest to ponad 10 razy dłużej niż 0,5 s i w dodatku nie jest ten czas pełną wielokrotnością. Jednym słowem diody migają z bliżej nieznaną częstotliwością. Czego jescze mi brakuje? Dodam, że gdy zapiszę:

SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_[b]Div8[/b])

sytuacja nie zmienia się - częstotliwość migania jest niezmienna

Podczas ustawiania zegara najlepiej dodać do kodu wywołanie funkcji "SystemCoreClockUpdate();", a później sprawdzić jaka wartość znajduje się w zmiennej SystemCoreClock.

Tak zrobiłem i zauważyłem, że gdy umieszcze funkcje SystemCoreClockUpdate() to zmienna SYstemCoreClock przyjmuje wartość 16000000 zgodnie z:

#if !defined  (HSI_VALUE)   
 #define HSI_VALUE    ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */

Zaś bez tej funkcji SystemCoreClock = 168000000, czyli tyle ile ma byc. Wniosek taki, że ta funkcja nadpisuje to co wcześniej ustawiłem. Na razie nie chcę się w to zagłębiać, przymę to na wiarę, później będzie czas na grzebanie w źródle tych funkcji.

edit:

Dołożyłem SystemCoreClockUpdate i teraz jest ładnie tak jak trzeba ale.. SystemCoreClock przyjmuje wartość 16000000 a tego przecież nie chcę.

Link do komentarza
Share on other sites

Oznacza to, że mikrokontroler nie może poprawnie ustawić zegara na PLL z zewnętrznego kwarcu. W konsekwencji wraca do 16MHz z kwarcu wewnętrznego (prawdopodobnie). Funkcja SystemCoreClockUpdate() odczytuje aktualny zegar (na podstawie rejestrów) i zapisuje go do zmiennej SystemCoreClock. Prawdopodobnie masz jakiś błąd w kodzie, wartości PLL albo zegara się nie zgadzają. Ustawiłeś wartości PLL i wartość HSE_VALUE tak jak wcześniej napisałem?

EDIT: Najlepiej porównaj swoje pliki do plików z przykładami w bibliotece od ST (http://www.st.com/web/en/catalog/tools/PF257904).

Link do komentarza
Share on other sites

To by się zgadzało. SysTickowi podaję na siłe taktowanie 168 Mhz, zaś system przełącza się na 16Mhz, co daje 10,5 raza mniejsze taktowania, stąd ponad 10 razy wolniej miga dioda co pisałem wcześniej:)

Zaglądam do funkcji

void SystemCoreClockUpdate(void)

i tam ustawiłem na siłę tmp=0x08.

Z takim ustawieniem musiał przełączyć się na PPL co w rezulatacie dało SYstemCoreClock =96 Mhz podczas debugowania. Co mnie troche dziwi bo nie wiem kompletnie skąd ta wartość. Aczkolwiek mimo to i tak system przełącza się na HSI, a 96 MHz jest tylko wartością zwracaną przez funkcję, która pełni rolę informacyjną, tak myślę.

/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
#define PLL_M      8
#define PLL_N      336

/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P      2

/* USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ */
#define PLL_Q      7



z stm32f4xx.h:

#if !defined  (HSE_VALUE) 
 #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */

To są moje ustawienia. Czyli wniosek taki, że coś niedobrego jest z PPL lub kwarcem, gdyż nie chce się przełączyć na tą częstotliwość.

Link do komentarza
Share on other sites

void SystemInit(void)
{
 /* FPU settings ------------------------------------------------------------*/
 #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
   SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
 #endif

 /* Reset the RCC clock configuration to the default reset state ------------*/
 /* Set HSION bit */
 RCC->CR |= (uint32_t)0x00000001;

 /* Reset CFGR register */
 RCC->CFGR = 0x00000000;

 /* Reset HSEON, CSSON and PLLON bits */
 RCC->CR &= (uint32_t)0xFEF6FFFF;

 /* Reset PLLCFGR register */
 RCC->PLLCFGR = 0x24003010;

 /* Reset HSEBYP bit */
 RCC->CR &= (uint32_t)0xFFFBFFFF;

 /* Disable all interrupts */
 RCC->CIR = 0x00000000;

#ifdef DATA_IN_ExtSRAM
 SystemInit_ExtMemCtl(); 
#endif /* DATA_IN_ExtSRAM */

 /* Configure the System clock source, PLL Multiplier and Divider factors, 
    AHB/APBx prescalers and Flash settings ----------------------------------*/
 SetSysClock();

 /* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
 SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
 SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}
void SystemCoreClockUpdate(void)
{
 uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;

 /* Get SYSCLK source -------------------------------------------------------*/
 tmp = RCC->CFGR & RCC_CFGR_SWS;

 switch (tmp)
 {
   case 0x00:  /* HSI used as system clock source */
     SystemCoreClock = HSI_VALUE;
     break;
   case 0x04:  /* HSE used as system clock source */
     SystemCoreClock = HSE_VALUE;
     break;
   case 0x08:  /* PLL used as system clock source */

     /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
        SYSCLK = PLL_VCO / PLL_P
        */    
     pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
     pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;

     if (pllsource != 0)
     {
       /* HSE used as PLL clock source */
       pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
     }
     else
     {
       /* HSI used as PLL clock source */
       pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);      
     }

     pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
     SystemCoreClock = pllvco/pllp;
     break;
   default:
     SystemCoreClock = HSI_VALUE;
     break;
 }
 /* Compute HCLK frequency --------------------------------------------------*/
 /* Get HCLK prescaler */
 tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
 /* HCLK frequency */
 SystemCoreClock >>= tmp;
}
static void SetSysClock(void)
{
/******************************************************************************/
/*            PLL (clocked by HSE) used as System clock source                */
/******************************************************************************/
 __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

 /* Enable HSE */
 RCC->CR |= ((uint32_t)RCC_CR_HSEON);

 /* Wait till HSE is ready and if Time out is reached exit */
 do
 {
   HSEStatus = RCC->CR & RCC_CR_HSERDY;
   StartUpCounter++;
 } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

 if ((RCC->CR & RCC_CR_HSERDY) != RESET)
 {
   HSEStatus = (uint32_t)0x01;
 }
 else
 {
   HSEStatus = (uint32_t)0x00;
 }

 if (HSEStatus == (uint32_t)0x01)
 {
   /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */
   RCC->APB1ENR |= RCC_APB1ENR_PWREN;
   PWR->CR |= PWR_CR_VOS;

   /* HCLK = SYSCLK / 1*/
   RCC->CFGR |= RCC_CFGR_HPRE_DIV1;

   /* PCLK2 = HCLK / 2*/
   RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;

   /* PCLK1 = HCLK / 4*/
   RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;

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

   /* Enable the main PLL */
   RCC->CR |= RCC_CR_PLLON;

   /* Wait till the main PLL is ready */
   while((RCC->CR & RCC_CR_PLLRDY) == 0)
   {
   }

   /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
   FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;

   /* Select the main PLL as system clock source */
   RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
   RCC->CFGR |= RCC_CFGR_SW_PLL;

   /* Wait till the main PLL is used as system clock source */
   while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
   {
   }
 }
 else
 { /* If HSE fails to start-up, the application will have wrong clock
        configuration. User can add here some code to deal with this error */
 }

}

Na rejestrach jeszcze nie znam się praktycznie wcale, więc nie umiem nic z tego wywnioskować. W każdym razie zmienna tmp w SystemCoreClockUpdate nie zmienia wartości. Jest zawsze 0.

Zastanawia mnie jednak zapis

tmp = RCC->CFGR & RCC_CFGR_SWS

patrząc w delkaracje RCC_CFGR_SWS ona ma wartość przypisaną na sztywno 0, więc tmp będzie zawsze zero...

Podmieniłem nawet treść pliku system_stm32f4xx.c na plik pobrany z strony stm z przykładami i bazą dla discovery i wciąż ta sama historia.

Link do komentarza
Share on other sites

W pliku stm32f4xx.h mam:

#define  RCC_CFGR_SWS                        ((uint32_t)0x0000000C)        /*!< SWS[1:0] bits (System Clock Switch Status) */

Gdzie masz zadeklarowane RCC_CFGR_SWS jako 0?

Link do komentarza
Share on other sites

No racja, jest tak jak u ciebie. Już mi się to wszysko zlewa. Koniec końców nie potrafię już znaleźć sensownej przyczyny dlaczgo nie może uruchomić się nic innego poza HSI.

Link do komentarza
Share on other sites

Ta różnica w częstotliwości migania nie wynosi czasem dokładnie 8???

Kolego podałem Ci wcześniej funkcja do odpalenia SysTick, więc czemu jej nie użyłeś??

Żebyś nie szukał, to podaje jeszcze raz

void SYSTICK_Conf(void) 
{ 
   #define FCPU                72000000 
   #define    SYSTICK_Prescaler    8 
   if (SysTick_Config((FCPU/SYSTICK_Prescaler)/1000)) 
       while(1); 
   SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
}

Zastanawiasz się pewnie czym ona różni się od Twojej. Ano kolejnością.

U ciebie jest najpierw

SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 

a dopiero później funkcja if.

Zamień kolejność i zobacz.

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.