Skocz do zawartości

[Kurs] Kurs programowania STM32 część 2 - pierwszy projekt


lukpep

Pomocna odpowiedź

Nareszcie:) Naprawdę zapowiada się ciekawie. Na początek mam kilka pytań:

1. Mógłbyś coś więcej napisać o bibliotekach CMSIS i StdPerph. Z tego co wiem jest sporo różnic i jedynie te drugie są znienawidzone;)

2. Co należy rozumieć przez 'prędkość' wyjścia? Chodzi tylko o max częstotliwość zmiany stanu wyjścia?

Kolejne pytania pojawią się pewnie w czasie walki z stm'em.

Myślę, że fajnie by było jak byś dodał alternatywą wersję, pisząc nie używając bibliotek;)

Dzięki za dobry kurs! Oby tak dalej!

Link do komentarza
Share on other sites

kling,

2. Owszem - zmieniajac predkosc zmieniamy czasy narastania i opadania zboczy sygnalu - ma to duzy wplyw na powstajace zaklocenia elektromagnetyczne oraz dopuszczalne pojemnosci obciazenia.

50 MHz - 30 pF

10 Mhz - 50 pF

2 MHz - 50 pF

Co do praktyki to nie za bardzo da rade osiagnac takie wartosci. Korzystajac z biblioteki czy tez nawet operacji o dostepie atomowym i ASM nie osiagniemy 50 MHz na wyjsciu... (kazda instrukcja to 1 a czasem wiecej taktow rdzenia). Predkosci te to raczej dla sprzetowych peryferii. Tu odpowiedni watek - http://www.elektroda.pl/rtvforum/topic2037447.html

Co do pytania 1 to odpowiem pozniej - po pracy 😉

Link do komentarza
Share on other sites

lukpep, Witam,
na początek chciałbym pogratulować kursu.

Ale mam parę pytań jako, że pomimo tego iż przedzieram się przez literaturę podobną, to kolega jest dużo bardziej zaawansowany.

Korzystam (i to zupełnym przypadkiem) z tej samej płytki, tego samego środowiska i tego samego programatora, a przedzieram się przez książkę w której autor korzysta z płytką ZL27ARM z prockiem STM32F103VBT6 zamiast tego jaki jest na ZL29ARM (STM32F107VCT6) i są pewne rozbieżności w funkcjach bibliotecznych, choćby w ustawieniu taktowania rdzenia, ale to już przebrnąłem.

Problem mój polega na tym że na tym że na ZL29ARM mamy kwarca 10MHz a nie 8MHz, a maksymalna częstotliwość rdzenia w dalszym ciągu jest 72MHz, dlatego RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9) teoretycznie nie powinno zadziałać bo daje to 90MHz, ale ku mojemu zdziwieniu działa. Nie wiem tylko czy jest to poprawne i rzeczywiście daje 90MHz, próbowałem ustawiać też RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_7) co teoretycznie powinno dać 70MHz ale ponieważ ugrzązłem w mnogości ustawień jakie daje system_stm32f10x.c to nie wiem czy częstotliwość żądana 70MHz jest rzeczywiście ustawiona i co gorsza nie wiem jak to sprawdzić.

Problem ten dla mnie jest o tyle poważny że muszę stworzyć aplikację która równo co 500ms będzie pobierać dane z przetwornika i zapisywać pomiary z znacznikiem czasowym, a jeżeli nie wiem jaką mam częstotliwość to nie ma możliwości poprawnie ustawić timerów i wszystko się rozjeżdża.

Mam nadzieję że kolega pomoże mi rozwiązać problem.

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

Nie wiem dokładnie jak to jest z wyższymi częstotliwościami, lecz jeśli potrzebujesz dokładnie 500 ms, to Ci aż tak wielkich częstotliwości nie potrzeba. Może pomoże Ci mój kod:

http://wklej.to/bVwTe

Przerwanie od Timera co 2 us i na tej podstawie mam funkcje opóźniające. Mam również diodkę zmieniającą stan co 1s podpiętą do pinu 1 portu B. Może akurat Ci się to przyda.

Pozdrawiam!

Daniel 🙂

Link do komentarza
Share on other sites

Arty,

Troszke zakrecilem z sygnalami zegarowymi - juz spiesze z wyjasnieniem:

zgodnie z tym rysunkiem:

IMG_4e2c471b37df15325.png

zegar taktujacy rdzen to HCLK i moze to byc max 72 MHz.

HLCK otrzymujemy wpuszczajac takt SYSCLK na dzielnik AHB.

SYSCLK mozemy otrzymac na 3 sposoby:

1. HSI - high speed internal - wew. oscylator RC 8 MHz

2. HSE - high speed external - zew. oscylator kwarcowy 3-25 MHz

3. Sygnal PLLCLK z wyjscia petli powielacza PLL1

Wybieramy opcje numer 3 😉

Sygnal na wejsciu petli PLL1 moze pochodzic z 2 zrodel:

1. HSI podzielone przez 2

2. Wyjscie dzielnika PREDIV1

Wybieramy bramke numer 2

Sygnal na wejscie dzielnika PREDIV1 moze pochodzic z 2 zrodel:

1. HSE

2. Sygnal PLL2CLK z wyjscia petli powielacza PLL2.

Ponownie bramka numer 2 nas interesuje.

Na wejscie petli PLL2 idzie zawsze sygnal HSE podzielony przez dzielnik PREDIV2.

Wiec jak to wszystko konfigurujemy?

HSE mamy 10 MHz.

PREDIV2 ustawiamy na 2 wiec na petle PLL2 wchodzi 5 MHz.

Mnoznik PLL2MUL petli PLL2 ustawiamy na 8 wiec z petli PLL2 wychodzi 40 MHz.

Sygnal z PLL2 (40 MHz) wchodzi na dzielnik PREDIV1 ktory ustawiamy na 5 wiec za dzielnikiem mamy 8 MHz.

Sygnalem z PREDIV1 wchodzimy na petle PLL1 z ustawionym mnoznikiem PLLMUL na 9 otrzymujac sygnal SYSCLK 72 MHz.

Dzielkik AHB ustawiamy na 1 wiec HLCK = SYSCLK = 72 MHz

Dzielnik APB1 ustawiamy na 2 co daje nam taktowanie 36 MHz PCLK1 dla peryferii na magistrali APB1

Dzielnik APB2 ustawiamy na 1 czyli na magistrali APB2 mamy sygnal PCLK2 = 72 MHz

I juz 😉

Troszke zakrecilem poniewaz rozkrecanie zegarow w moim projekcie pochodzi z bardziej rozbudowanej wersji korzystajacej z ethernetu - (stad tez 40 MHz na wyjsciu PLL2 ktore podaje sobie na MCU i taktuje tym PHY ethernetowe).

Teraz mam nadzieje juz wszystko jasne - kod, ktory wkleilem w zrodle jest niepelny ale mimo to dziala. Prawde mowiac nie wiem jak w takim przypadku zachowuje sie zegar - sygnal biore z PREDIV1, ktory ma na wejsciu albo sygnal z petli PLL2 albo HSE. Sygnal z PLL2 raczej odpada bo petla nie jest w ogole w tym kodzie konfigurowana i odpalana - pozostaje wiec HSE. I teraz pytanie - czy na SYSCLK idzie 90 MHz? W co watpie... czy tez zaraz po inicjacji PREDIV ma jakas wartosc rozna od 1 - np. 2 co by dawalo 36 MHz zegar - w co wierze 😉

Doczytam w dokumentacji jak to wyglada i dam znac.

W kazdym razie poprawny i kompletny kod rozkrecania zegarow wyglada tak:

int konf_zegary(void)
{
 RCC_DeInit();
 RCC_HSEConfig(RCC_HSE_ON);
 if (RCC_WaitForHSEStartUp() == ERROR)
   return -1;

 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
 FLASH_SetLatency(FLASH_Latency_2);

 /* preskaler AHB, HCLK = SYSCLK = 72 MHz */
 RCC_HCLKConfig(RCC_SYSCLK_Div1);

 /* preskaler APB1, PCLK1 = HCLK / 2 = 36 MHz */
 RCC_PCLK1Config(RCC_HCLK_Div2);

 /* preskaler APB2, PCLK2 = HCLK = 72 MHz */
 RCC_PCLK2Config(RCC_HCLK_Div1);

 /* PLL2: PLL2CLK = HSE / 2 * 8 = 40 MHz */
 RCC_PREDIV2Config(RCC_PREDIV2_Div2);
 RCC_PLL2Config(RCC_PLL2Mul_8);
 RCC_PLL2Cmd(ENABLE);
 while(!RCC_GetFlagStatus(RCC_FLAG_PLL2RDY));

 /* PLL1: PLLCLK = (PLL2 / 5) * 9 = 72 MHz */
 RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div5);
 RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);
 RCC_PLLCmd(ENABLE);
 while(!RCC_GetFlagStatus(RCC_FLAG_PLLRDY));

 /* Ustaw SYSCLK = PLLCLK i czekaj az PLL zostanie ustawiony jako
    zegar systemowy. */
 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
 while(RCC_GetSYSCLKSource() != 0x08);

 return 0;
}

[ Dodano: 02-08-2011, 11:31 ]

nie udalo mi sie znalezc jak to jest z PREDIV1 w stanie po resecie - bez konfiguracji.

W kazdym razie jak chcesz wyciagnac predkosci poszczegolnych zegarow to:

void RCC_GetClocksFreq ( RCC_ClocksTypeDef * RCC_Clocks )

Returns the frequencies of different on chip clocks.

Parameters:

RCC_Clocks,: pointer to a RCC_ClocksTypeDef structure which will hold the clocks frequencies.

Return values:

None

Definition at line 901 of file stm32f10x_rcc.c.

  • Lubię! 2
Link do komentarza
Share on other sites

danioto,

Wielkie dzięki na pewno się przyda.

lukpep,

Dzięki za rozwiązanie problemu, trochę mi się wyjaśniło.

Będę musiał albo ustawić wszystkie mnożniki, dzielniki i preskalery albo wybadać z jakimi mnożnikami się uruchamia. Swoją drogą byłem przekonany że z 10MHz kwarca to nie wykręcę 72MHz nawet nie wpadłem na to by dzielić i mnożyć na przemian.

Muszę przyznać że trochę to zakręcone ale działa.

Link do komentarza
Share on other sites

A ja trochę z innej beczki. Mianowicie mam problem z układem RTC w STM32F105, a dokładnie to z podtrzymywaniem czasu i daty. Czy jest jakieś rozwiązanie by nie trzeba było ciągle ustawiać daty i godziny w mikrokontrolerze ? Wszystko jest ok, gdy mikrokontroler jest włączony (mam zaimplementowana cały algorytm obsługi kalendarza). Ale oczywiście, gdy wyłączymy mikr. na pare dni to po ponownym włączeniu godzina będzie miała wartość kilkudziesięciu godzin, a data będzie kilka dni do tyłu (bo bateria podtrzymuje tylko licznik czasu, którego i tak nie zmieni bo jest wył. ;/ ?). Jakieś pomysły ?

Link do komentarza
Share on other sites

Owszem sa rejestry specjalnego przeznaczenia o podtrzymywanym przez baterie stanie. Backup registers sie zwa chyba - doczytaj. Jak nie znajdziesz to daj znac - napisze jak sie tego uzywa 🙂

EDIT:

Co do zegarow to uzylem fukcji RCC_GetClocksFreq przed poprawna konfiguracja i zwracalo zegary SYSCLK i HCLK po 90 MHz - ale on to liczy na podstawie konfiguracj iw rejestrach a nie faktycznych przebiegow.

Po zastosowaniu konfigu poprawnego z PREDIVami co wrzucilem pare postow wyzej pokazuje juz poprawne po 72 MHz.

  • Lubię! 1
Link do komentarza
Share on other sites

W nawiązaniu do kawałka dokumentacji:

In the case of a device in low-power mode or whose external supply is off when the counter reaches 86399, the counter cannot be reset and so the date is not updated. This is why, just after power reset, it is necessary to check the counter value and update the date as many times as the number of days during which the device remained in low-power mode or had its external main supply switched off.

Stworzyłem kawałek kodu:

// Aktualizacja daty i czasu
//load_date();			// z rejestru backup
while(RTC_GetFlagStatus(RTC_FLAG_RTOFF) == RESET);
czas = RTC_GetCounter();
liczba_dni = czas/86400;
for(l=liczba_dni ; l == 0 ; l--)			//86400 sekund - 1 doba
{
	update_date();
}
//save_date();			// do rejestru backup
czas -= 86400 * liczba_dni;
//while(RTC_GetFlagStatus(RTC_FLAG_RTOFF) == RESET);
//RTC_SetCounter(czas);
//while(RTC_GetFlagStatus(RTC_FLAG_RTOFF) == RESET);

Czyli tak:

- pobieram wartość licznika RTC

- sprawdzam ile dni urządzenie nie miało zasilania poprzez obliczenie liczby_dni

- tyle razy aktualizuje date ile jest tych dni

- uaktualniam czas

Teraz 3 rzeczy, które nie działaja !? ;/

- po pierwsze nie mogę zaktualizować wartości licznika RTC (RTC_SetCounter(czas)), gdy jest dołączona bateria - sick !?? (gdy wyjmę baterię, licznik aktualizuje się bez problemu przy tym kodzie)

- po drugie zastosowany algorytm nie działa (nie aktualizuje mi daty - czyli tak jakby liczba_dni była zawsze zero !?) dodam, ze gdy sprawdzam godzinę na wyświetlaczu to mam wynik ponad 300godzin:xxmin:xxsekund co by się zgadzało bo ostatni raz czas ustawiałem (oczywiście bez baterii) 25 lipca

- po trzecie jak zapisywać aktualna date do tych backup_registers ? bo należałoby zapisywać rok, miesiąc i dzień po aktualizacji i wczytywać je po każdym uruchomieniu urządzenia

Link do komentarza
Share on other sites

Ja do oczekiwania czy została zakończona operacja na RTC używam funkcji

RTC_WaitForLastTask();

Do zapisu danych w rejestrach backup używam funkcji:

	BKP_WriteBackupRegister(0x04,dzien);
BKP_WriteBackupRegister(0x08,miesiac);
BKP_WriteBackupRegister(0x0C,rok);

a do odczytu:

	dzien = BKP_ReadBackupRegister(0x04);
miesiac = BKP_ReadBackupRegister(0x08);
rok = BKP_ReadBackupRegister(0x0C);

Wszystkie te funkcje są w standardowych bibliotekach, w pliku stm32f10x_rtc.c.

Zmianę wartości licznika przeprowadzam tak:

		if(RTC_GetCounter() > 86398)
	{
		RTC_SetCounter(RTC_GetCounter() - (86400 - 1));
		//reszta kodu
Link do komentarza
Share on other sites

no wiec trochę się wyjaśniło ... ale w dalszym ciągu mam problem z wgraniem nowego czasu do licznika 🙁 ... jak wyjmę baterię to mogę ustawić godzinę bez problemu (całkowity bezsens ) ... i jeszcze mam pytanie jak inicjalizujesz rejestry chronione ?

[ Dodano: 07-08-2011, 22:16 ]

juz poszlo ... nie wiem dlaczego ale pomoglo dodanie linijki kodu: PWR_BackupAccesCmd(Enable); tuż przed wpisaniem nowej wartości do licznika

Link do komentarza
Share on other sites

Rejestrów backup nie inicjalizuje. Po prostu zapisuje aktualną wartością dnia,miesiąca itp.

Ja linijkę PWR_BackupAccesCmd(Enable); mam użytą raz, na samym początku procedurki konfiguracji RTC.

  • Lubię! 1
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • 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.