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

[stm32L031] Jak najmniejszy pobór prądu i zliczanie impulsów

korteksik 06 Sty 2018 21:13 1398 34
  • #1 06 Sty 2018 21:13
    korteksik
    Poziom 8  

    Witajcie,

    Z nowym rokiem nowe wyzwania :)
    Zwracam się do Was z pytaniem, czy moja koncepcja jest słuszna...
    Otóż, potrzebuję zbudować urządzenie, które będzie zasilane bateryjnie (docelowo 2xAA), które ma tylko zliczać impulsy zewnętrzne w ciągu każdej godziny działania urządzenia. Po odliczeniu godziny ma te informacje przesłać po rs485 dalej.Tych impulsów może być od kilku na godzinę do nawet 10tyś/godzinę. Czas trwania impulsu to ok. 10ms.
    Do zrealizowania zadania wybrałem procesor stm32l031 ze względu na dobry stosunek cena/możliwości/energooszczędność.
    Po zapoznaniu z DS wymyśliłem, że procesor będzie pracował w trybie "Stop mode with RTC" ponieważ:
    - pobiera 0,4uA
    - LSE/LSI działają
    -procesor można obudzić z trybu zatrzymania za pomocą dowolnej linii EXTI
    - układ wyposażony jest w LowPowerTimer, który to działa w tym trybie i może być taktowany z LSE


    Do taktowania LSE użyję kwarca zewnętrznego 32,768kHz i podam go na LPTIM. Reszta peryferiów będzie pracowała z MSI RC na np. 1.049MHz. Układ po inicjalizacji przejdzie w tryb STOP mode, jednocześnie LPTIM będzie odliczał 1s (docelowo do 3600). W czasie odliczania pełnej godziny będę zliczał przychodzące przerwania zewnętrzne.

    CubeMX teoretycznie pozwala na taką kombinację:

    [stm32L031] Jak najmniejszy pobór prądu i zliczanie impulsów

    Czy taka koncepcja ma szansę zadziałać prawidłowo?
    Pytam, bo już zaczynam mieć wątpliwości, czy LPTIM to dobry wybór. W CubeMX jest bardzo uboga lista ustawień tego timera:

    [stm32L031] Jak najmniejszy pobór prądu i zliczanie impulsów

    Nie ma tu choćby ustawienia wartości do przeładowania ARR jak w innych timerach:

    [stm32L031] Jak najmniejszy pobór prądu i zliczanie impulsów

    0 29
  • #2 06 Sty 2018 21:20
    Freddie Chopin
    Specjalista - Mikrokontrolery

    LPTIM ma przecież:

    Cytat:
    External clock source over LPTIM input (working with no LP oscillator running,
    used by Pulse Counter application)


    Wydaje się to dużo lepszą opcją niż budzenie co przerwanie. Impulsy taktują timer, cały układ jest wyłączony, co godzinę budzisz układ przez RTC, odczytujesz licznik timera, odejmujesz od poprzednio odczytanej wartości, zapisujesz sobie odczytaną wartość na następny raz, wysyłasz wynik przez RS-485.

    0
  • #3 06 Sty 2018 21:46
    Marek_Skalski
    Moderator Projektowanie

    Popieram ten pomysł. Nawet jeżeli pojawi się 10000 impulsów na godzinę, to nie będzie przepełnienia licznika, więc pomiar będzie prawidłowy, a układ będzie pobierał minimalną ilość energii.
    Bardziej istotne może być podłączenie portu RS-485, aby nie było strat prądu (przecieków).
    Zamiast alarmu z RTC, możesz też wykorzystać WakeUp Timer taktowany co sekundę, który przeładowujesz stałą wartością, w odróżnieniu od alarmu, który musisz aktualizować co godzinę.

    0
  • #4 06 Sty 2018 21:51
    korteksik
    Poziom 8  

    Freddie Chopin napisał:
    LPTIM ma przecież:

    Cytat:
    External clock source over LPTIM input (working with no LP oscillator running,
    used by Pulse Counter application)


    Wydaje się to dużo lepszą opcją niż budzenie co przerwanie. Impulsy taktują timer, cały układ jest wyłączony, co godzinę budzisz układ przez RTC, odczytujesz licznik timera, odejmujesz od poprzednio odczytanej wartości, zapisujesz sobie odczytaną wartość na następny raz, wysyłasz wynik przez RS-485.


    Freddie - w sumie to takie oczywiste, że brak mi słów dlaczego ja na to nie wpadłem...
    Dzięki za naprowadzenie. Zabieram się za pisanie kodu...


    Marek_Skalski napisał:

    Zamiast alarmu z RTC, możesz też wykorzystać WakeUp Timer taktowany co sekundę, który przeładowujesz stałą wartością, w odróżnieniu od alarmu, który musisz aktualizować co godzinę.


    Dziękuję za kolejną wskazówkę. Muszę zapoznać się ze wszystkimi funkcjami RTC :)

    0
  • #5 06 Sty 2018 21:55
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Marek_Skalski napisał:
    Nawet jeżeli pojawi się 10000 impulsów na godzinę, to nie będzie przepełnienia licznika, więc pomiar będzie prawidłowy, a układ będzie pobierał minimalną ilość energii.

    Przepełnienie licznika to nie problem - przerwanie od przepełnienia załatwi tą sprawę.

    0
  • #6 06 Sty 2018 23:37
    BlueDraco
    Specjalista - Mikrokontrolery

    Obawiam się, że RS485 będzie pobierał ze 100 razy więcej prądu niż mikrokontroler.

    0
  • #7 07 Sty 2018 11:29
    korteksik
    Poziom 8  

    BlueDraco napisał:
    Obawiam się, że RS485 będzie pobierał ze 100 razy więcej prądu niż mikrokontroler.


    Planuję sterować zasilaniem rs'a i włączać go tylko na czas wysłania danych.

    0
  • #8 07 Sty 2018 13:22
    JacekCz
    Poziom 36  

    Jeden z wątków, któremu radośnie się kibicuje, rozwija się, przepływają i kumulują się informacje.

    Mam pytanie, jest STM32L031 w formie płytki? Pobieżnie szukając nie znalazłem.
    Ja z tych nie lutujących VLSI.

    0
  • #10 07 Sty 2018 13:44
    Freddie Chopin
    Specjalista - Mikrokontrolery

    JacekCz napisał:
    Mam pytanie, jest STM32L031 w formie płytki? Pobieżnie szukając nie znalazłem.

    Zależnie od tego jaki dokładnie model wybierzesz, są też wersje w przyjaznych obudowach - LQFP 48 (STM32L031C), TSSOP 20 (STM32L031F), LQFP 32 (STM32L031K - niektóre), czy UFQFPN 28 lub 32 (STM32L031G i niektóre STM32L031K). Jakby ktoś chciał napisać, że UFQFPN to jakaś masakra bez nóżek, to chciałbym naprawdę zachęcić do spróbowania - obudowę tą lutuje się łatwiej niż QFP czy cokolwiek innego z gęsto umieszczonymi nóżkami! Jedyny ból jest taki, że jeśli obudowa ma thermalpada to albo trzeba go olać, albo trzeba mieć hot-aira i pastę, albo może ktoś jest w stanie coś wycudować żeby go przylutować grotem i zwykłą cyną <:

    Da się kupić malutką płytkę Nucleo-32 z tym układem - http://www.st.com/content/st_com/en/products/...val-tools/stm32-mcu-nucleo/nucleo-l031k6.html

    0
  • #11 07 Sty 2018 13:58
    Marek_Skalski
    Moderator Projektowanie

    Freddie Chopin napisał:
    albo może ktoś jest w stanie coś wycudować żeby go przylutować grotem i zwykłą cyną

    Dzisiaj używam do tego pasty i gorącego powietrza. Dawniej robiłem serię otworów (3x3 albo 4x4) w obszarze thermal pad, podgrzewałem jedną stronę (grotem) i podawałem spoiwo, które przepływało do środka, a następnie wypełniało przestrzeń między płytką a układem i wypełniało (lub wypływało przez) pozostałe otwory. Płytka była zawsze lekko pod kątem i wcześniej potraktowana topnikiem. Łatwo nie jest, ale możliwe do wykonania :)

    0
  • #12 10 Lut 2018 15:06
    korteksik
    Poziom 8  

    Wracam do tematu :)

    Na chwilę obecną mam uruchomiony LPTIMER i RTC. Wszystko pięknie mi działa - w trybie STOP timer zlicza impulsy zewnętrzne, RTC wybudza rdzeń po zadanym czasie.
    Po wybudzeniu odczytuję z rejestru CNT timera liczbę zliczonych impulsów - i tutaj pojawia się mój problem. Chciałbym po odczycie, wyzerować rejestr CNT.
    Rejestr CNT jest tylko do odczytu, jak można go wyzerować? Przeglądnąłem RM i nie znalazłem bezpośrednio informacji nt. ustawienie którego parametru LPTIMERA zeruje rejestr CNT.
    Naprowadzicie gdzie znaleźć taką informację?

    0
  • Pomocny post
    #13 10 Lut 2018 15:34
    Marek_Skalski
    Moderator Projektowanie

    Masz 2 możliwości.
    - Zresetować licznik jako peryferium i ponownie go skonfigurować. Wtedy CNT przyjmuje wartość 0x0000, ale może zgubić przychodzący impuls.
    - Nic nie resetować, tylko wyznaczyć różnicę miedzy wskazaniami - wykonać odejmowanie stanu aktualnego od stanu poprzedniego i ewentualnie skorygować wartość o limit przepełnienia.

    0
  • #14 10 Lut 2018 16:02
    korteksik
    Poziom 8  

    Marek_Skalski napisał:
    Masz 2 możliwości.
    - Zresetować licznik jako peryferium i ponownie go skonfigurować. Wtedy CNT przyjmuje wartość 0x0000, ale może zgubić przychodzący impuls.
    - Nic nie resetować, tylko wyznaczyć różnicę miedzy wskazaniami - wykonać odejmowanie stanu aktualnego od stanu poprzedniego i ewentualnie skorygować wartość o limit przepełnienia.


    Dzięki za szybką odpowiedź. Niestety, ale tak podejrzewałem, że tylko ponowna inicjalizacja zresetuje mi CNT...
    Nie chcę przeliczać poprzez odejmowanie wartości poprzedniej, bo to mocno skomplikuje program. Musiałbym uwzględniać przepełnienia itp.
    Spróbuję resetować licznik.

    0
  • #15 10 Lut 2018 17:22
    BlueDraco
    Specjalista - Mikrokontrolery

    No fakt, 3 linijki więcej to poważna komplikacja...

    0
  • #16 10 Lut 2018 17:47
    Freddie Chopin
    Specjalista - Mikrokontrolery

    korteksik napisał:
    Nie chcę przeliczać poprzez odejmowanie wartości poprzedniej, bo to mocno skomplikuje program. Musiałbym uwzględniać przepełnienia itp.

    No (;

    difference = (new < previous ? 0xffff + 1 : 0) + new - previous; // 0xffff - max wartość timera, dla niektórych liczników może to być 0xffffffff

    Komplikacja nie z tej ziemi <:

    0
  • #17 10 Lut 2018 18:28
    korteksik
    Poziom 8  

    Wszystko fajnie, ale jeśli założymy, że układ ma pracować non-stop, to do jakich wartości zmiennych dojdziemy uwzględniając przepełnienia licznika po przekroczeniu zakresu?

    Problem rozwiązałem resetując licznik i ponownie go inicjalizując - działa w 100% :)
    Ale dziękuję za sugestie :)

    Mam jeszcze chyba inny problem, ale muszę się upewnić że jest powtarzalny - jeśli nie znajdę rozwiązania, to jeszcze w tym wątku go opiszę.

    Tymczasem dziękuję za pomoc!

    0
  • #18 10 Lut 2018 19:03
    Freddie Chopin
    Specjalista - Mikrokontrolery

    korteksik napisał:
    Wszystko fajnie, ale jeśli założymy, że układ ma pracować non-stop, to do jakich wartości zmiennych dojdziemy uwzględniając przepełnienia licznika po przekroczeniu zakresu?

    No ale Ty masz zapisywać poprzednią wartość rejestru licznika - nie dojdzie więc nigdy do wartości większej niż 0xffff / 0xffffffff. Naprawdę nie ma tu problemu o którym myślisz.

    0
  • #19 10 Lut 2018 20:38
    korteksik
    Poziom 8  

    Chyba nie rozumiem...
    Załóżmy, że co godzinę lptim zaliczać będzie 20 tyś impulsów. W czwartej godzinie nastąpi przepełnienie, bo smarycznie przekroczę zakres 0xffff. Oczywiście mogę sobie zliczać przepełnienia i liczyć wszystko wg podanego wzoru. Tylko mi nie pasuje jakim cudem nie przekroczę zakresu nie resetujac cnt licznika.

    0
  • #20 10 Lut 2018 20:51
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Ale jaka wielkość Cię interesuje? Różnica między dwoma odczytami?Naprawdę nie wiem gdzie masz problem - chyba po prostu się zafixowałeś na problemie który nie istnieje.

    Załóżmy że licznik sobie odczytujesz co 10000 cykli. W momencie odczytu masz więc wartości 0, 10000, 20000, 30000, 40000, 50000, 60000, [PRZEPEŁNIENIE], 4464, 14464, 24464, ... Po każdym odczycie i po obliczeniach zapisujesz sobie wartość którą właśnie odczytałeś w zmiennej `previous`. Przy każdym odczycie masz więc zarówno wartość aktualną, jak i `previous` - czyli to co było w CNT poprzednio.

    Tak więc gdy odczytujesz licznik i ma on wartość 40000, to w `previous` jest 30000, gdy w CNT jest 60000, to w `previous` jest 50000, a gdy odczytałeś 4464, to w `previous jest 60000.

    Magiczny wzór na różnicę (poprzednio się pomyliłem o jeden):

    difference = (new < previous ? 0x10000 : 0) + new - previous;

    Dla 3 przypadków które wymieniłem powyżej będziesz miał więc:
    difference = (new < previous ? 0x10000 : 0) + new - previous = (40000 < 30000 ? 0x10000 : 0) + 40000 - 30000 = (false ? 0x10000 : 0) + 10000 = 0 + 10000 = 10000
    difference = (new < previous ? 0x10000 : 0) + new - previous = (60000 < 50000 ? 0x10000 : 0) + 60000 - 50000 = (false ? 0x10000 : 0) + 10000 = 0 + 10000 = 10000
    difference = (new < previous ? 0x10000 : 0) + new - previous = (4464 < 60000 ? 0x10000 : 0) + 4464 - 60000 = (true ? 0x10000 : 0) + (-55536) = 0x10000 + (-55536) = 10000

    Może więc Ty wytłumacz gdzie tu widzisz problem, bo jak dla mnie to działa w nieskończoność jeśli tylko miedzy dwoma odczytami jest max jedno przepełnienie (Twój kod z resetami ma zresztą podobne ograniczenie, bo nie może być żadnych przepełnień).

    0
  • #21 10 Lut 2018 22:30
    2675900
    Użytkownik usunął konto  
  • #22 10 Lut 2018 22:37
    korteksik
    Poziom 8  

    Freddie Chopin napisał:


    Może więc Ty wytłumacz gdzie tu widzisz problem, bo jak dla mnie to działa w nieskończoność jeśli tylko miedzy dwoma odczytami jest max jedno przepełnienie (Twój kod z resetami ma zresztą podobne ograniczenie, bo nie może być żadnych przepełnień).


    Ok, przekonałeś mnie, że to zadziała. Ale tak jak napisałeś - pod warunkiem, że będzie tylko jedno przepełnienie.

    Nie zgodzę się jednak, że rozwiązanie z resetem timera i inicjalizacją ponowną jest gorsze (dla mnie przynajmniej prostsze). Czemu? - Bo zliczam na wszelki wypadek przepełnienia w przerwaniu, dodaję zawartość odczytaną z CNT i mam wynik. Po odczycie mam wyzerowany CNT , zeruję zmienną przepełnień - i tak w kółko.

    Na chwilę obecną tak działa i jest OK. Pobór prądu w czasie uśpienia mam na poziomie 1,19uA z włączonym LPTIMERem i RTC - czyli osiągnąłem to co chciałem.

    Ale oczywiście jestem wdzięczny za pomoc i naprowadzenie na prawidłowe myślenie :)

    0
  • Pomocny post
    #23 10 Lut 2018 22:48
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Piotrus_999 napisał:
    Chyba trochę uprościłeś.

    No dobra - warunek jest taki, że pomiędzy kolejnymi odczytami nie może upłynąć więcej niż max jeden pełny okres timera, może być max jedno przepełnienie (;

    Z testowaniem flagi przepełnienia można by niby wykombinować więcej, ale tu pojawiają się bardzo nieprzyjemne sytuacje brzegowe:
    - jeśli odczytujesz najpierw CNT a potem flagę - jeśli odczytałeś 0xffff i flagę przepełnienia, to nie wiesz czy przepełnienie nastąpiło przed czy po odczycie z CNT;
    - jeśli odczytujesz najpierw flagę a potem CNT - jeśli odczytałeś że nie było przepełnienia i 0, to nie wiesz czy na pewno nie było przepełnienia pomiędzy tymi dwoma odczytami;

    Oczywiście i to da się wyeliminować (lub ewentualnie zignorować, tracąc minimalnie dokładność), ale tutaj zaczyna się to robić nadmiernie problematyczne już faktycznie, zwłaszcza jeśli jest założenie że odczyty będą "wystarczająco często".

    korteksik napisał:
    Nie zgodzę się jednak, że rozwiązanie z resetem timera i inicjalizacją ponowną jest gorsze (dla mnie przynajmniej prostsze). Czemu? - Bo zliczam na wszelki wypadek przepełnienia w przerwaniu, dodaję zawartość odczytaną z CNT i mam wynik. Po odczycie mam wyzerowany CNT , zeruję zmienną przepełnień - i tak w kółko.

    Możemy się tak spierać, niemniej jednak:
    1. rozwiązanie z resetem timera ma potencjał zgubienia impulsu/impulsów i nic z tym nie zrobisz;
    2. rozwiązanie z resetem timera zajmuje więcej kodu źródłowego i trwa dłużej;
    3. rozwiązanie z resetem timera jest bardziej skomplikowane niż ekstremalnie prosty warunek i dodatkowa zmienna;
    4. rozwiązanie opisane przez Ciebie wymaga przerwania;

    0
  • Pomocny post
    #24 10 Lut 2018 23:00
    2675900
    Użytkownik usunął konto  
  • #25 10 Lut 2018 23:02
    korteksik
    Poziom 8  

    Freddie Chopin napisał:

    Możemy się tak spierać, niemniej jednak:
    1. rozwiązanie z resetem timera ma potencjał zgubienia impulsu/impulsów i nic z tym nie zrobisz;
    2. rozwiązanie z resetem timera zajmuje więcej kodu źródłowego i trwa dłużej;
    3. rozwiązanie z resetem timera jest bardziej skomplikowane niż ekstremalnie prosty warunek i dodatkowa zmienna;
    4. rozwiązanie opisane przez Ciebie wymaga przerwania;


    Zgadzam się w pełni :)

    Generalnie cieszę się, że dzięki Waszym wskazówkom udało mi się uruchomić układ tak jak chciałem.
    Zmierzę tylko jaki czas potrzebny na przeinicjalizowanie timera - ale jak na razie nie zgubił żadnego impulsu - a podaję mu 25 tyś imp/h.

    0
  • #26 10 Lut 2018 23:11
    Freddie Chopin
    Specjalista - Mikrokontrolery

    korteksik napisał:
    Zmierzę tylko jaki czas potrzebny na przeinicjalizowanie timera - ale jak na razie nie zgubił żadnego impulsu - a podaję mu 25 tyś imp/h.

    Nie zmierzysz tego i nic z tego nie wywnioskujesz. Jeśli z impulsem trafisz dokładnie w ten moment w którym timer jest chwilowo zresetowany lub wyłączony, to nie zostanie on zarejestrowany. Możesz sobie co najwyżej wyliczyć prawdopodobieństwo że tak będzie, które oczywiście jest niezerowe (;

    0
  • #27 10 Lut 2018 23:19
    korteksik
    Poziom 8  

    Cytat:
    Nie zmierzysz tego i nic z tego nie wywnioskujesz. (;


    Wydaje mi się, że jeśli po resecie timera ustawię sobie jakiś pin a po zakończonej inicjalizacji go zresetuję to analizatorem zmierzę ten czas - przynajmniej tak mi się wydaje. Chyba, że znowu czegoś nie wiem? :)

    0
  • #28 10 Lut 2018 23:28
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Źle się wyraziłem. Ten czas jest niezerowy ale to że jest o kilka rzędów wielkości mniejszy niż czas pomiędzy Twoimi impulsami jest bez znaczenia i wcale nie oznacza że nigdy nic nie zgubisz - tak jak pisałem, tutaj chodzi o prawdopodobieństwo że impuls przyjdzie akurat wtedy gdy Twój timer nie działa (bo go resetujesz lub ponownie inicjalizujesz). Prawdopodobieństwo to oczywiście jest dosyć małe, ale generalnie jeśli wyjdzie Ci jakiś ułamek, to spokojnie możesz sobie założyć że dokładnie taki ułamek impulsów zostanie zgubiony przez Twój algorytm. Jeśli nie jest to dla Ciebie problemem to oczywiście spoko, niemniej jednak akurat to jest problem który sam sobie stworzyłeś (;

    0
  • #29 11 Lut 2018 00:02
    Marek_Skalski
    Moderator Projektowanie

    Timer typu LPTIM taktowany ze źródła asynchronicznego względem CPU wymaga trochę więcej troski. W manualu znajdziesz informację:
    "When the LPTIM is running with an asynchronous clock, reading the LPTIM_CNT register may return unreliable values. So in this case it is necessary to perform two consecutive read accesses and verify that the two returned values are identical.
    It should be noted that for a reliable LPTIM_CNT register read access, two consecutive read accesses must be performed and compared. A read access can be considered reliable when the values of the two consecutive read accesses are equal."
    Oznacza to, że pojedynczy odczyt jest obarczony ryzykiem.
    Przyrostowe wyznaczanie czasu jest bezpieczniejsze dla pomiarów i zużywa mniej energii. Jeżeli ARR ma wartość 0xFFFF, to zadanie jest wręcz banalne i ogranicza się do 2 odczytów rejestru CNT i trzymania w pamięci poprzedniego wyniku. Włączanie i wyłączanie LPTIM trwa określony czas, a rachunek prawdopodobieństwa jest nieubłagany ;) Prędzej lub później zgubisz impuls. Nie wiedząc jakie to niesie konsekwencje, nie potrafię powiedzieć czy to jest akceptowalne, ale stosując metodę przyrostową, masz gwarancję poprawności zliczania przez cały cas życia urządzenia. Z uwagi na wielkość rejestru CNT, wynik będzie 16-bitowy i nie masz się czym przejmować.
    Założenie początkowe było do 10000 impulsów na godzinę i ten warunek jest spełniony z dużym zapasem. Ja bym zliczał zastosował metodę przyrostową.

    0
  • #30 14 Lut 2018 19:49
    korteksik
    Poziom 8  

    Przyznaję rację, że liczenie i zastosowanie metody Freddiego działa rewelacyjnie!
    Dzięki :)
    W zasadzie wszystko działa tak jak zostało założone, ale...

    Chciałbym Was zapytać o jeden mały problem - z którym sobie poradziłem - ale może można łatwiej...

    Otóż, przy każdym przepełnieniu (to akurat rozumiem) oraz przy pierwszym zliczonym impulsie LPTIM wskakuje w obsługę swojego przerwania LPTIM1_IRQHandler. Problem w tym, że wybudza to procesor i wysyła mi po uarcie zliczone impulsy. Problem rozwiązałem ustawiając flagę w przerwaniu RTC i w mainie sprawdzam, czy wybudzenie jest od RTC czy LPTIM.
    Czy jest jakieś lepsze rozwiązanie?

    0
  Szukaj w 5mln produktów