Skocz do zawartości

Kurs STM32 F4 - #8 - Zaawansowane funkcje liczników


Komentator

Pomocna odpowiedź

Witam,

W jednym miejscu coś mi się nie zgadza, kiedy jest fragment artykułu, gdzie jest generowanie sygnału PWM z wykorzystaniem DMA użyta jest funkcja:

HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_3, &Duty, 1);

Gdzie zmienna Duty jest typu uint16_t, natomiast funkcja HAL_TIM_PWM_START_DMA wymaga wskaźnika na uint32_t :

HAL_StatusTypeDef HAL_TIM_PWM_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length);

Zatem czy jeśli chcemy żeby zmienna Duty pozostała uint16_t, nie powinno się zrobić następującego rzutowania :

HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_3,(uint16_t*) &Duty, 1);

?

Link do komentarza
Share on other sites

Jestem w tej chwili w pracy i nie mam dostępu do CubeMX - mogę więcej napisać wieczorem, teraz napiszę tak "z głowy", bez kodu i testowania.

W programie widzimy że Duty ma typ uint16_t, natomiast HAL_TIM_PWM_Start oczekuje wskaźnika do uint32_t. W rzeczywistości jest to błąd, albo chociaż niedoskonałość biblioteki HAL - w końcu za pomocą DMA można przesyłać różne typy danych, nie tylko uint32_t. Poprawnie zaprojektowane biblioteki (przykładowo zgodne z POSIX) używają w takim przypadku typu void*. Ale ktoś, kto projektował Cube HAL chciał być bardziej poprawny i użył uint32_t...

Typ wskaźników w rzeczywistości nie ma większego znaczenia - stąd w C częste użycie void* chociażby w funkcjach systemowych - read, write itd.

Nie testowałem, ale poprawnie program powinien wyglądać raczej tak:

HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_3, (uin32_t*) &Duty, 1);

W tej wersji po prostu informujemy kompilator że wiemy co robimy i specjalnie zmieniamy typ wskaźnika - co kompilator powinien uszanować i wyłączyć ostrzeżenie.

Natomiast jak napisałem na początku - obie wersje działają tak samo, a ze zmienną Duty nic złego się nie dzieje.

  • Lubię! 1
  • Pomogłeś! 1
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

@PiotrPierPeter super, że problem rozwiązany. Powodzenia w dalszych eksperymentach!

PS Pamiętaj, że pomocne posty można odpowiednio oceniać (ikona serca w prawym dolnym rogu wiadomości). Dzięki temu można podziękować bezpośrednio autorowi i (co czasami ważniejsze) wyróżnić daną odpowiedź, aby inni widzieli od razu, że jest ona rozwiązaniem opisywanego problemu. Zachęcam do korzystania z tej opcji 😉

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

@gekon83 witam na forum i dzięki za aktualizację z rozwiązaniem problemu 🙂 Niestety w tym kursie często pojawiają się jakieś drobne problemy wynikające z aktualizacji CubeMX, które bywają mniej lub bardziej "dopracowane". Na szczęście udaje nam się wspólnymi siłami odnajdywać rozwiązania tych zagadek 😉

Link do komentarza
Share on other sites

Witam forumowiczów 🙂

Próbowałem właśnie wykonać część pierwszą (tę najprostszą, bez DMA), jednakże po zaprogramowaniu kod nie wykazuje żadnego działania. Ustawiłem zegar na maksymalną częstotliwość, podłączyłem czerwoną diodę na kanał 3 timera 4 oraz wpisałem kod w odpowiednie miejsca, lecz mimo nic się nie dzieje. Korzystam z najnowszej wersji Eclipse oraz CubeMX. Czy ma ktoś może pomysł na rozwiązanie tego problemu ? Próbowałem stosować również  rozwiązania z komentarzy i nic nie pomogło.

Z góry dzięki 😉

Link do komentarza
Share on other sites

Witam, 

Oczywiście wybacz, dodaje zdjęcia z CubeMX zegarów, bo nie jestem ich pewien. Dodaję też kod maina. Wydaje mi się, że zrobiłem wszystko zgodnie z instrukcją. Tak jak mówiłem są tam zmiany, które jeden kolega opisał jakieś dwa komentarze wyżej. Płytka została zakupiona na waszej stronie i do niej był dodany ten kurs, więc sprzęt powinien być odpowiedni.

111.jpg

main.rar

Link do komentarza
Share on other sites

Dnia 15.10.2019 o 22:01, RFM napisał:

Praktycznie nigdy nie korzystam z  Callback jakiejkolwiek funkcji. Zawsze swój kod wstawiałem w


  /* USER CODE BEGIN SysTick_IRQn 0 */
 
  /* USER CODE END SysTick_IRQn 0 */

więc problemu nie mam. W Callback  trzeba sprawdzać źródło przerwania (np który uart wywołał przerwanie, który pin EXTI) a wstawiając swój kod w handler nie trzeba nic sprawdzać lub mniej niż w przypadku Callback.

Też mnie to zastanawia. Takie sprawdzanie źródła przerwania zajmuje niepotrzebnie czas. 

Czy mógłby ktoś ten temat rozwinąć. Jak stosować SysTick_IRQn?

Link do komentarza
Share on other sites

@jaceksz73 Wystarczy, że wstawisz swój kod w części "user code" w funkcji przerwania w pliku przerwań. Plik ten w drzewie projektu jest najczęściej obok pliku main.c (przynajmniej w środowisku SW4STM).

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

Jak uruchomić kilka kanałów timera w trybie DMA funkcją: HAL_TIM_PWM_Start_DMA(TIM_HandleTypeDef * htim, uint32_t Channel, uint32_t * pData, uint16_t Length) ?

Przykładowe wywołanie:

uint32_t PrawoPWM = 100;
uint32_t LewoPWM = 100;

HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_1 , &PrawoPWM, 1);
HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_2 , &LewoPWM, 1);

Uruchamia tylko kanał 1. 

Natomiast wywołanie:

//HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_1 , &PrawoPWM, 1);
HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_2 , &LewoPWM, 1);

Uruchamia kanał 2. 

To pytanie pojawiło się kilka razy, ale nie znalazłem odpowiedzi.

Generalnie pytanie jest o ostani parametr tej funkcji czyli "length". Co on tak naprawdę oznacza i jak się go wykorzystuje?

I dlaczego tylko pierwszy kanał, który startujemy uruchamia się?

Dokumentacja mówi: Length:  The length of data to be transferred from memory to TIM peripheral.

Niestety nie rozumiem tego.

Link do komentarza
Share on other sites


Tak samo jak w części #6, CKD  nie jest preskalerem licznika, w kursie jest błąd, który kosztował mnie trochę czasu do rozgryzienia - okazuje się, że wzór na częstotliwość licznika w kursie jest niepoprawny. Zamiast 
FREQ = TIM_CLK/(ARR+1)(PSC+1)(CKD+1)
Powinno być:
FREQ = TIM_CLK/(ARR+1)(PSC+1)(RCR+1)
Gdzie RCR to repetiton counter i dzięki niemu możemy przerwania otrzymywać nie co każde zliczenie licznika, lecz dopiero po kilku zliczeniach. Nie jest to jednak to samo, co preskaler - dla sygnału PWM ta sztuczka nie zadziała. 
Rejestr CKD jest preskalerem... do licznika dead time w trybach input capture.

Źródło:
https://www.st.com/resource/en/application_note/dm00042534-stm32-crossseries-timer-overview-stmicroelectronics.pdf (s. 11)

Edytowano przez Bobalke
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.