Skocz do zawartości

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


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);

?

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

@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
  • 2 miesiące później...

@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 😉

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 😉

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

  • 4 tygodnie później...
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?

(edytowany)

@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
  • 1 miesiąc później...

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.

  • 6 miesiące później...
(edytowany)


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

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