Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[LPC1769][FreeRTOS] Pomiar długości impulsu PWM ~1-2ms, 50Hz - jak?

lord-enigma 18 Apr 2012 14:53 2159 7
  • #1
    lord-enigma
    Level 2  
    Hej,

    Mam moduł pomiarowo-sterujący, pracujący na LPC1769 pod kontrolą FreeRTOS (5 tasków przy zegarze 100MHz, komunikacja na dwóch UARTach, wykorzystane trochę GPIO, 4xADC, PWM na 4 kanałach, jeden timer i SSP do komunikacji z kartą microSD).
    W projekcie pojawiło się zagadnienie pomiaru impulsu PWM o długości rzędu 1-2ms, powtarzającego się co ok. 20ms (jak interfejs serwa modelarskiego). Pomiar taki musi być wykonany na minimum czterech kanałach (a najlepiej 6-8), przy czym:



    - wejścia przerwań zewnętrznych są już zajęte (zresztą i tak jest ich za mało)
    - taktowanie FreeRTOS (pojedynczy "tick") to jedna milisekunda, a więc za mało, żeby spróbować zrobić jakiś polling w tasku
    - sporo pinów jest już zajętych i muszę oprzeć się o zwykłe GPIO (ew. coś z timerem)
    - dość złożona płytka jest już wykonana i bardzo chciałbym uniknąć dużych zmian w hardware (typu dodatkowy scalak czy coś) - chyba że w ostateczności

    Staram się coś wykombinować, dysponując samymi wejściami GPIO, ale nie wiem, jak uzyskać żadaną rozdzielczośc pomiaru przy jednoczesnym użyciu FreeRTOS (tak z 5-10 uS byłoby świetnie). Utknąłem w martwym punkcie, a ta funkcjonalność jest w tej chwili bardzo potrzebna.

    Czy ktoś może spotkał się z podobnym problemem lub ma jakieś pomysły?
    Będę wdzięczny za każdą sugestię.

    LE
  • #2
    gaskoin
    Level 38  
    lord-enigma wrote:

    - sporo pinów jest już zajętych i muszę oprzeć się o zwykłe GPIO (ew. coś z timerem)


    timer powinien mieć taki tryb jak input capture, poczytaj o nim w nocie i wszystko stanie się proste :)
  • #3
    valarian
    Level 22  
    Czy mi się wydaje, czy input capture działa tylko na jednym, specyficznym pinie (na timer), a autorowi chodziło o kilka kanałów jednocześnie? :)
  • #4
    stanleysts
    Level 27  
    no moze sobie zrobic jakis multiplekser co bedzie te kanaly przelaczal i badal po kolei na timerze w trybie input capture.
  • #5
    gaskoin
    Level 38  
    valarian wrote:
    Czy mi się wydaje, czy input capture działa tylko na jednym, specyficznym pinie (na timer), a autorowi chodziło o kilka kanałów jednocześnie? :)


    No właśnie wydaje Ci się, bo jeśli timer ma 4 kanały to na jednym kanale mamy 4 wejścia ICP. Jest też specjalny tryb PWM input ale wymaga zużyćia 2 kanałów na 1 sygnał.
  • Helpful post
    #6
    ahaczewski
    Level 10  
    LPC176x (czyli wersja 100-nóżkowa) posiada 4 timery, każdy z nich posiada po dwa wejścia: CAP0 i CAP1. Daje to max 8 wejść, czyli może się udać. Pokrótce wejścia CAP pozwalają zapisać aktualny stan timera (rejestr TC) w rejestrze CR0/CR1 w momencie zmiany stanu na takim wejściu. Pomiar szerokości impulsu PWM jest tym samym tak dokładny, jak często tyka timer i jest więcej niż wystarczająco dokładny do pomiaru czasów rzędu 2 ms. Osobiście generowałem (nie capturowałem) na tych timerach impulsy PWM dla serw z rozdzielczością 100 ns, czyli 10 tyś. punktów pomiędzy najwęższym impulsem a najszerszym (co i tak uważam za lekką przesadę, ale testowałem możliwości LPCka) i według oscyloskopu dokładność była powalająca (na oscyloskopie widziałem dokładnie to co było w kodzie wpisane, więc nawet nie jestem w stanie powiedzieć jaki był błąd). Nie było też żadnych wahań, co przy serwach ma znaczenie.

    Wielkim minusem rozwiązania opartego na timerach LPC17xx jest to, że pozbywasz się wszystkich timerów na rzecz czytania z 8 kanałów PWM. Pewną trudnością może być też synchronizacja pomiędzy tymi timerami.

    Alternatywą jest skorzystanie z przerwań GPIO:

    Po pierwsze: musisz pamiętać, że w LPC17xx tylko port 0 i port 2 obsługują przerwania GPIO.

    Po drugie: i tak musisz odpalić jakiś timer, bo SysTick się nie nadaje.

    Po trzecie: pamiętaj, że możesz obserwować najpierw narastające zbocze, a potem opadające; tj. możesz przełączyć obserwowane zbocze w obsłudze przerwania - ma to gigantyczne znaczenie, wiem z autopsji (jak na przykład dwa razy pod rząd było generowane przerwanie na opadającym zboczu, bez zbocza narastającego...).

    Po czwarte: w obsłudze przerwania musisz robić niezbędne minimum, czyli na początku sczytać TC timera, sczytać piny, które wygenerowały przerwanie oraz zbocza, na które czekałeś i wrzucić te dane do jakiejś kolejki / bufora kołowego, który dopiero poza przerwaniem będziesz przetwarzał sczytując szerokości impulsów.

    Po piąte: pamiętaj, że jak jedno ze zboczy opada, to inne w tym czasie mogło narastać, przez co w obsłudze przerwania możesz mieć przerwanie z dwóch pinów, dlatego warto zapisać cały rejestr IntStatR i IntStatF. Na ich podstawie też możesz odwracać obserwowane zbocze (patrz "Po trzecie").

    Na koniec ustaw priorytet przerwania na najwyższy i już - dokładne odczyty gwarantowane :-). Zrobiłem coś takiego na LPC13xx, więc podejrzewam, że na 17tce też się da.

    @gaskoin: to jest LPC, nie STM. Procek 2-3 razy tańszy. You get what you paid for.
  • #7
    lord-enigma
    Level 2  
    Dziękuję bardzo za odpowiedzi.
    Niestety nie mogę sobie pozwolić na zajęcie wszystkich timerów, dlatego spróbuję sposobu z przerwaniami z GPIO. Mam jeden wolny timer, którym będę mierzył czas i trochę wolnych portów 0 i 2.
    Jeśli uda mi się wszystko zrobić, podzielę się rezultatem :)
  • #8
    ahaczewski
    Level 10  
    lord-enigma wrote:
    Dziękuję bardzo za odpowiedzi.
    Niestety nie mogę sobie pozwolić na zajęcie wszystkich timerów, dlatego spróbuję sposobu z przerwaniami z GPIO. Mam jeden wolny timer, którym będę mierzył czas i trochę wolnych portów 0 i 2.
    Jeśli uda mi się wszystko zrobić, podzielę się rezultatem :)

    Najlepiej użyć tylko jednego portu dla wszystkich odczytów, inaczej będziesz musiał więcej rejestrów odczytać w obsłudze przerwania - IntStaty dla obu portów zamiast dla jednego.

    Jeszcze jedno: pamiętaj, że jak będziesz czyścił status przerwania (pisząc do IntClear), to czyść tylko te bity, które odczytałeś z IntStatów, wtedy jak pomiędzy odczytem z intstat, wyczyszczeniem przerwań i wrzuceniem danych do kolejki pojawi się jeszcze jedno przerwanie, to od razu po wyjściu z obsługi aktualnego przerwania wejdziesz ponownie do obsługi następnego i nie stracisz żadnego zbocza, ewentualnie będzie minimalny błąd w odczycie TC, który w praktyce można pominąć.