Elektroda.pl
Elektroda.pl
X
CControls
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Jak uśpić ARMa instrukcją __WFI ?

Zlotorowicz 08 Kwi 2018 11:27 825 23
  • #1 08 Kwi 2018 11:27
    Zlotorowicz
    Poziom 4  

    Witam,

    Mam program, w którym procesor nic nie robi, tylko czeka na przerwanie od Timera.
    W tle pracuje DMA na kilku kanałach.
    Chciałem zmniejszyć pobór prądu i w chwili wyczekiwania na przerwanie Timera dałem polecenie uśpienia __WFI.
    Ale nie ma reakcji, pobór prądu jest identyczny.
    Co więcej, jesli zablokuje Timer a także Systick to procek, jakby nie reagował na to polecenie.
    Czy trzeba jeszcze coś zrobić, aby ten tryb uśpienia uzyskać?

    Próbowałem jeszcze dodać wcześniej : NVIC_SystemLPConfig(NVIC_LP_SLEEPONEXIT,ENABLE); ale to blokuje całkowicie procesor.


    pozdrawiam

    0 23
  • CControls
  • #2 08 Kwi 2018 11:43
    BlueDraco
    Specjalista - Mikrokontrolery

    Albo __WFI() w pętli for (;;), albo włączyć SleepOnExit i potem pojedyncze WFI (ładniej). Jeśli nie zauważasz spadku natężenia prądu, to być może masz stale aktywne przerwanie, bo np. nie kasujesz znacznika jego zgłoszenia. Dopóki nie pokażesz minimalnego kodu - możemy tylko pogdybać.

    0
  • CControls
  • #3 08 Kwi 2018 11:59
    Zlotorowicz
    Poziom 4  

    No więc mam w Mainie coś takiego:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Timer na 100% dziala, przerwanie wygląda tak:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    A jednak efekt jest taki, że procesor zatrzymuje się na tym __WFI jesli jest wcześniej NVIC_SystemLPConfig(NVIC_LP_SLEEPONEXIT,ENABLE);.

    Chyba że źle rozumiem ten __WFI, bo wydaje mi się, że powinno być tak, że procek na tej instrukcji sie zatrzymuje i czeka na dowolne przerwanie.
    Gdy je uzyska, to idzie dalej.
    Czy tak to działa?

    0
  • #5 08 Kwi 2018 12:06
    Zlotorowicz
    Poziom 4  

    Dzieki.
    Spróbuje zmienić wszystkie piny i sprawdzę jaki to ma wpływ na pobór prądu.
    A mam jeszcze pytanie, czy użycie tego __WFI wymaga jeszcze czegoś wcześniej?
    Czy włączenie jakiegoś zegara jest potrzebne?
    Zastanawia mnie to, bo bez przerwania procek przechodzi przez to __WFI.

    Wstawienie NVIC_SystemLPConfig(NVIC_LP_SLEEPONEXIT,ENABLE); blokuje mi działanie programu nawet gdy zadziała przerwanie.

    Wydaje mi się, że jeśli będzie tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    To procek powinien sie zatrzymać.

    A jeśli tak:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    to powienien po otrzymania przerwania pójść dalej.
    Czy dobrze rozumuje?

    0
  • Pomocny post
    #6 08 Kwi 2018 12:19
    BlueDraco
    Specjalista - Mikrokontrolery

    Fakt, nieużywane linie trzeba ustawić inaczej niż jako wiszące wejścia - w tryb analogowy, jako wyjście, lub wejście podciągnięte.
    Problem może też leżeć w użyciu "wygodnych" funkcji i stałych. Zwłaszcza niebezpieczna jest stała SET.
    __WFI tak właśnie działa. Jeśli ustawisz SleepOnExit, to już nie "idzie dalej" nawet po przerwaniu.

    0
  • #7 08 Kwi 2018 12:39
    Zlotorowicz
    Poziom 4  

    BlueDraco napisał:
    __WFI tak właśnie działa. Jeśli ustawisz SleepOnExit, to już nie "idzie dalej" nawet po przerwaniu.


    to jak zrobić, aby procesor poszedł dalej , ale dopiero po przerwaniu?

    0
  • #8 08 Kwi 2018 15:24
    BlueDraco
    Specjalista - Mikrokontrolery

    Proste: nie ustawiaj SleepOnExit i wrzuć WFI w pętlę. Tylko zupełnie nie wiem, po co ma "chodzić dalej". Kod, który pokazujesz, jest dziwny, WFI jest zwykle ostatnią instrukcją prohgramu inicjującego - dalsza aktywność dzieje się wyłącznie w przerwaniach.

    0
  • #9 08 Kwi 2018 20:28
    Zlotorowicz
    Poziom 4  

    Może coś źle rozumiem.
    WFI to znaczy Wait For Interrupt.
    Czyli procesor w tym momencie sie zatrzymuje i czeka na jakiekolwiek przerwanie.
    Jeśli przerwanie się pojawia, to procesor sie budzi i przechodzi do nastepnej instrukcji po __WFI.
    Ale tak nie jest, bo u mnie bez przerwań , procesor nie zwraca uwagę na to WFI i leci dalej.

    Moja konstrukcja programu polegała na tym, aby w pętli głównej wykonywać tylko komendy po ustawieniu się flagi w przerwaniu.
    Pozwoliłem sobie uprościć program następująco:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Powyższy program według mojej logiki powinien działać w taki sposób, że dioda LED nie mruga gdy nie ma przerwan.
    Ale jeśli przerwanie się pojawi, to dioda powinna mrugnac.
    Dobrze myśle?
    Bo u mnie jest dokładnie tak jak wyżej, przerwania wyłaczyłem a dioda LED mruga.

    0
  • #10 08 Kwi 2018 21:17
    BlueDraco
    Specjalista - Mikrokontrolery

    źle myślisz.
    Po co Ci ta "pętla główna"? Do sztucznego podziału akcji podejmowanych w wyniku przerwania na dwa kawałki kodu bez potrzeby? (Ew. po co przerwanie i drugi znacznik programowy, skoro sam timer sprzętowo ustawia znacznik zdarzenia?)
    Jeżeli odblokowane w NVIC przerwanie jest zgłoszone, a priorytet procesora nie zezwala na jego obsługę,WFI się wykona i zakończy, a wykonanie programu będzie kontynuowane.

    0
  • #11 08 Kwi 2018 22:05
    Zlotorowicz
    Poziom 4  

    Faktycznie nie ogarniam tego.
    Wygladająca banalnie funkcja, a jednak nie do końca.
    Proste pytanie:
    Czy jeśli program zostanie ograniczony do czegos takiego:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Czy dioda będzie świecić, czy nie?

    0
  • #12 08 Kwi 2018 22:51
    BlueDraco
    Specjalista - Mikrokontrolery

    Nie zaświeci, bo:
    - nie zainicjowałeś portu dla LED, więc jest wejściem ;)
    - żadne przerwanie nie zostało włączone w NVIC ani w SYS. WFI zawiśnie na zawsze.

    0
  • #13 08 Kwi 2018 23:09
    Zlotorowicz
    Poziom 4  

    Faktycznie nie dodałem inicjacji portu od LEda.
    Raczej był to tylko przykład.

    Ale tak czy inaczej, jesli __WFI jest pierwszą instrukcją w programie i nie ma mozliwosci aby jakiekolwiek przerwanie było uruchomione to procesor przechodzi przez tą komendę bez problemu.

    Nie wiem o co chodzi.

    0
  • Pomocny post
    #14 09 Kwi 2018 12:37
    BlueDraco
    Specjalista - Mikrokontrolery

    Nie przechodzi. Zatrzymuje się i czeka na przerwanie z NVIC lub rdzenia. Przerwanie to nie musi być odblokowane w NVIC i nie musi być obsługiwane, ważne, żeby wystąpiło.

    0
  • #15 09 Kwi 2018 19:26
    Zlotorowicz
    Poziom 4  

    Tylko ze, jesli umieszczam instrukcje WFI jako pierwsza w Main, to czemu procesor przechodzi przez nia ? Nie zatrzymuje sie, na nic nie czeka tylko jakby to byl NOP idzie dalej. To jest dla mnie niezrozumiale.

    0
  • #16 13 Kwi 2018 08:42
    Zlotorowicz
    Poziom 4  

    Czy taka koncepcja jest prawidłowa:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Cały program dałem do procedury obsługi przerwania.
    Czy teraz jest dobrze?

    0
  • Pomocny post
    #17 13 Kwi 2018 09:25
    BlueDraco
    Specjalista - Mikrokontrolery

    źle, bo po wyjściu z WFI procesor będzie kręcił się w pętli i już nie uśnie. Umieść WFI w pętli lub (lepiej) włącz SleepOnExit przed WFI.

    0
  • #18 13 Kwi 2018 11:28
    Zlotorowicz
    Poziom 4  

    Dziękuję BlueDraco za cierpliowość i cenne rady.

    Czy tak będzie dobrze?

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Tylko, że mam inny problem.
    Otóż nie mogę wszystkiego przerzucić do przerwania.
    Czy może więc być tak, że w przerwaniu ustawiana jest tylko flaga, a w Mainie jest oczekiwanie na nią w uśpieniu.
    Myślę o czyms takim:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #19 13 Kwi 2018 14:57
    BlueDraco
    Specjalista - Mikrokontrolery

    A z jakiego to niby powodu nie możesz przerzucić wszystkiego do przerwania?

    Pomyśl, co się stanie, gdy przerwanie nastąpi po sprawdzeniu znacznika w warunku if(), a przed _WFI...

    Prościutki błąd początkujących.

    0
  • #20 13 Kwi 2018 17:00
    Zlotorowicz
    Poziom 4  

    Przerzuciłem cały program do przerwania, ale nie działał mi prawidłowo. Chodzi o to, że w programie też używam przerwań, więc powstają przerwania w przerwaniu. Wiem że to sie da jakoś ze sobą połączyć, ale nie jestem na tyle biegły aby to zrobić.
    Chciałem zrobić prosty delay , w czasie którego procesor będzie pobieral mniej prądu.
    Ale widzę że to nie jest proste.

    0
  • #21 13 Kwi 2018 18:00
    3149400
    Użytkownik usunął konto  
  • #22 13 Kwi 2018 18:26
    BlueDraco
    Specjalista - Mikrokontrolery

    Priorytetów przerwań nie ruszaj. Najpierw zastanów się, co właściwie chcesz osiągnąć i jakie przerwania są do tego potrzebne. Podajesz tak wyrywkowe informacje, że nie sposób zrozumieć, o co właściwie chodzi.

    0
  • #23 14 Kwi 2018 08:32
    Zlotorowicz
    Poziom 4  

    Ok, to wyjaśnie raz jeszcze.
    Mam program, który wykorzystuje DMA do pomiaru ADC, wysyłki i odbioru UARTA.
    Program używa też wtedy innych Timerów.
    Wszystko pieknie działa.
    Postanowiłem powalczyć trochę o ekologię i obniżyć pobór prądu.
    Działanie całego programu sprowadziłem do tego, że może on tylko zostawać wykonywany raz na 100ms.
    Program sie wykonuje i znów Delay(100) i tak w kółko.
    Użyłem do tego Timera, który co 100ms ustawia flagę i program sie uruchamia.
    I teraz postanowiłem, aby do czasu gdy Timer nie zgłosi przerwania panował stan uśpienia.
    Całość zatem działa następująco:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Wydaje mi się, że znalazłem rozwiązanie.
    Niby działa, ale nie wiem, czy jest to prawidłowe:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Nie jestem pewien, czy bezpieczniej użyć __WFI() w ifie. czy w głónej pętli.

    0
  • #24 14 Kwi 2018 08:43
    BlueDraco
    Specjalista - Mikrokontrolery

    Przemyśl i napisz jeszcze raz od początku. Co naprawdę masz do zrobienia co 100 ms? Nie wiemy. Powienieneś to robić w przerwaniu, ale w tym przerwaniu nie możesz na nic czekać - do akcji wymagających oczekiwania/rozciągnięcia w czasie użyj innych przerwań lub DMA. Póki co nic nie wskazuje na to, że musisz mieć jakąś "pętlę główną", a funkcjonalność programu trzymasz w tajemnicy.
    Odbiór z UART najłtwiej zrobić na przerwaniach, nadawanie być może łatwiej przez DMA. Odliczaj w przerwaniu timera do 100 ms i inicjuj odpowiednie akcje, które dalej będą wykonywać się "same".

    0