logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[STM32] Jak uruchomić przerwanie RTC w STM32? Konfiguracja i debugowanie.

dziechu 24 Maj 2012 10:29 5133 30
Najlepsze odpowiedzi

Jak w STM32F103 włączyć i uruchomić przerwanie od RTC?

Trzeba nie tylko ustawić bit zezwolenia w RTC, ale też włączyć samo przerwanie w NVIC, np. wywołując `NVIC_EnableIRQ(RTC_IRQn)`. Przerwania SysTick są przerwaniami rdzenia i działają inaczej, natomiast RTC jest przerwaniem mikrokontrolera, więc bez konfiguracji NVIC nie zostanie wywołane [#10929257] Dokumentację NVIC trzeba szukać w materiałach ARM, bo w RM0008 od ST są głównie szczegóły implementacyjne, takie jak przyporządkowanie kanałów i liczba priorytetów [#10929402]
Podsumowanie wygenerowane przez AI na podstawie treści dyskusji.
REKLAMA
  • #1 10929103
    dziechu
    Poziom 27  
    Posty: 1609
    Pomógł: 27
    Ocena: 71
    Wczoraj uruchomiłem RTC, działa ładnie, choć nie wiem dlaczego na koniec wpisu do rejestru RTC_CNT muszę dwa razy wyzerować bit RTC_CRL_CNF:)
    W następnej kolejności chcę uruchomić przerwanie od RTC, no i oczywiscie nie działa, inaczej nie pisałbym tu. Jak rozumiem z dokumntacji (tej cześci którą przeczytałem) i opisu przykladów, najpierw powinny być ustawione wektory przerwań, czyli wskazane adresy pod którymi są wywoływane. Mam to w pliku startup. Z opisu w tym pliku wynika, że jeżeli umieszczę funkcję z przerwaniem np. w pliku stm32f10x_it.c dołączonym do projektu, jeżeli nazwa tej funkcji bedzie zgodna z nazwą w wektorze, jeżeli odblokuję dane przerwanie, to powinno ono być wywoływane. Czy jest coś jeszcze co muszę zrobić? W rozdziale o NVIC w R0008 nic ciekawego nie znalzlem, a przerwanie nie działa. Jest w nim dodany rozkaz zapalenia LEDa, żeby zobaczyć czy jest wywoływane - nie jest.
    To fragment z funkcją przerwania zawartą w pliku stm32f10x_it.c

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Tu jest funkcja inicjalizacji RTC z włączeniem przerwania RTC_SEC.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Procesor w dalszym ciągu STM32F103VCT6 taktowany 72MHz.
    Dodam, że np. SysTick przerwanie działa (po usunieciu '//'), ale ten SysTick zawsze działa:)
  • REKLAMA
  • Pomocny post
    #2 10929257
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    SysTick to przerwanie systemowe (rdzenia). RTC to przerwanie mikrokontrolera. Te pierwsze są zawsze włączone. Te drugie trzeba włączyć w kontrolerze NVIC.

    Jest do tego funkcja NVIC_EnableIRQ() czy jakoś tak, a do niej definicje z numerami przerwań.

    4\/3!!
  • #3 10929368
    dziechu
    Poziom 27  
    Posty: 1609
    Pomógł: 27
    Ocena: 71
    A jest to gdzieś opisane? Znalazłem NVIC_EnableIRQ( RTC_IRQn ); i chyba jest ok, ale w rozdziale o NVIC w RM0008 jakos nic o tym nie ma. LED swieci, więc chyba przerwanie jest wywoływane, teraz musze posprzątać i badać dalej:).
  • #4 10929402
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Dokumentacji NVIC należy szukać na stronie ARMa, w dokumentacji od ST masz tylko kilka detali typu przyporządkowanie kanałów i ilość priorytetów, czyli rzeczy zależne od implementacji.

    4\/3!!
  • #5 10929417
    dziechu
    Poziom 27  
    Posty: 1609
    Pomógł: 27
    Ocena: 71
    Ok. Na razie priorytetów nie ustawiam, puki innych przerwań nie będę potrzebował. Jest tego wszystkiego trochę, ale ogólnie praca z STM32 jest bardzo przyjemna, no i z C:) Robienie tego wszystkiego w asm od zera, to byłoby dość karkołomne.

    Dodano po 11 [minuty]:

    W sumie muszą być dwie funkcje inicjalizacji RTC, np. RTC_Init(); i RTC_Init_Full(); Pierwsza do inicjalizacji np. RTC_CRH_SECIE, bo nie jest 'na podtrzymaniu' i jest zerowany po każdym włączeniu zasilania. Druga full do jednokrotnego ustawienia RTC po np. wymianie baterii czy pierwszym uruchomieniu i ewentualnie zerowania licznika podczas ustawiania czasu. Z tym UNIXowym czasem to zupełnie jak na razie czarna magia, to jakieś biblioteki chyba w time.h. Zastanawiam sie czy nie łatwiej bedzie mi zrobić wszystko samemu.
  • REKLAMA
  • #6 10929602
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Z dokumentacji biblioteki libc:

    Cytat:
    8.6 localtime—convert time to local representation
    Synopsis
    #include <time.h>
    struct tm *localtime(time_t *clock);
    struct tm *localtime_r(time_t *clock, struct tm *res);
    Description
    localtime converts the time at clock into local time, then converts its representation from
    the arithmetic representation to the traditional representation defined by struct tm.
    localtime constructs the traditional time representation in static storage; each call to
    gmtime or localtime will overwrite the information generated by previous calls to either
    function.
    mktime is the inverse of localtime.
    Returns
    A pointer to the traditional time representation (struct tm).
    Portability
    ANSI C requires localtime.
    localtime requires no supporting OS subroutines.


    Są też funkcje tworzące ładny łańcuch znakowy.

    4\/3!!
  • REKLAMA
  • #7 10930422
    dziechu
    Poziom 27  
    Posty: 1609
    Pomógł: 27
    Ocena: 71
    Nie bardzo wiedziałbym jak tego użyć. Chyba że jakiś przykład miałby ktos, kto to już robił. Na razie staram sie jakos sam z tym uporać. Podczas ustawiania czasu/daty, zapisuję nieulotnie czas i datę oraz zeruję licznik RTC_CNT. Po każdym włączeniu zczytuję aktualny stan licznika RTC_CNT, przeliczam (to znaczy staram się:) na sekundy, minuty, godziny... i odpowiednio dodaję do zapisanej daty/godziny, ale jakos mi to nie chodzi jak trzeba. Jedynie sekundy dodają się prawidłowo. Wyglada to tak:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    timeup to uint32_t. najpierw liczę resztę z dzielenia przez 60 i dodaję do sekund. Potem tą resztę odejmuję od timeup żeby sie nie dodała do minut i liczę resztę z dzielenia przez 3600, którą dodaję do minut itd. Po dodawaniu sprawdzam czy nie przekroczyło np. min>59 itd... albo źle myślę, albo źle napisałem. Sekund nie sprawdzam na przepełnienie, bo przy ustawianiu zawsze zapisują się jako 0, wiec przepełnienia nie bedzie.

    Dodano po 1 [godziny] 21 [minuty]:

    No jasne że jest źle, same głupoty:)

    Dodano po 4 [minuty]:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    To już mniej wiecej działa, najgorsze będą miesiące.
  • #8 10930727
    Jado_one
    Poziom 22  
    Posty: 650
    Pomógł: 43
    Ocena: 12
    O ile pamięć mnie nie myli, to robiło się tak, że ustalało się jakąś datę startową (może być nawet dzisiejsza) - i to oznaczało stan zero licznika.
    Potem w trakcie użytkowania licznik liczył upływające sekundy.
    Aktualną datę/czas otrzymywało się dodając do daty startowej liczbę dni, godzin, minut, sekund obliczoną przez podzielenie liczby sekund jakie zliczył nasz licznik przez odpowiednie liczby.
    Jest to trochę upierdliwe w porównaniu z gotowym układem RTC, ale cóż - tak sobie wymyślił ST w tym modelu scalaka...
  • Pomocny post
    #9 10930750
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Twoje obliczenia dalej są dalekie od optymalnych...

    Można to zrobić o wiele prościej:
    sekundy = licznik % 60;
    licznik /= 60;
    minuty = licznik % 60;
    licznik /= 60;
    godziny = licznik % 24;
    licznik /= 24;
    Dopiero od tego momentu robi się nieprzyjemnie, bo trzeba myśleć o miesiącach, dniach, latach przestępnych itp. chyba że zadowala Cię znajdująca się w tym momencie w liczniku liczba dni od "chwili zero".

    4\/3!!
  • #10 10930813
    Konto nie istnieje
    Konto nie istnieje  
  • #12 10930864
    Jado_one
    Poziom 22  
    Posty: 650
    Pomógł: 43
    Ocena: 12
    albertb napisał:
    O rany, to ta przyjemna praca z STM32 ?

    To ja jednak wolę LPC17xx, lub 8 bitowe PIC. Tam to jest RTC!
    Bo toto co opisujecie to RTC tylko z nazwy, a de facto zwykły timer.

    Albert


    W 32F4 jest już normalny RTC, a w F1.....zwykły timer...brrr...
    Dlatego do F1 ja użyłem zalegającego akurat DS1307 i olałem cały ten "RTC" :-)
  • #13 10930867
    Konto nie istnieje
    Konto nie istnieje  
  • #14 10930874
    dziechu
    Poziom 27  
    Posty: 1609
    Pomógł: 27
    Ocena: 71
    To tez nie bedzie działać powyżej 1 miesiaca:(

    Dodano po 8 [minuty]:

    Fakt że jest to dość wredne, w tak rozbudowanych procesorach, które maja po kilka timerów, usartów, I2C, SPI i mnóstwo innych kawałków, dodać tych kilka rejestrów czasowych liczacych do 59, 23 itd... zamiast jednego, 32bit liczącego 15000000 sekund.... Dopiero F4. Te miesiace są niefajne, bo nie można liczyć jednego miesiąca w kółko, jak ja to zrobiłem, trzeba je kolejno odejmować, ale dzisiaj już mi sie nie chce. Poza tym ma to być urzadzenie sieciowe, czasami odłączane na krótki czas. Nawet zegarki za 5 zł. mają takie liczniki:)
  • Pomocny post
    #15 10931418
    m.ki
    Poziom 15  
    Posty: 117
    Pomógł: 13
    dziechu napisał:
    Nie bardzo wiedziałbym jak tego użyć. Chyba że jakiś przykład miałby ktos, kto to już robił.


    A może tak:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Do komunikacji z użytkownikiem używasz struktury *loctim, a w liczniku RTC masz liczbę sekund od 01.01.1970 00:00:00.
    Całą konwersję robi Ci biblioteka C. A jak dodasz zmienną środowiska "TZ=CET-1CEST,M3.5.0/2,M10.5.0/3" to Ci nawet uwzględni czas zimowy i letni.
    Było o tym w tym wątku: https://www.elektroda.pl/rtvforum/topic2107428.html

    Trzeba tylko pamiętać, że loctim->tm_mon liczy się od 0 do 11, a do loctim->tm_year trzeba dodać 1900, żeby była właściwa liczba.

    Pozdrowienia,
    MKi
  • #16 10932607
    dziechu
    Poziom 27  
    Posty: 1609
    Pomógł: 27
    Ocena: 71
    Pewnie do tego to służy:) Musiałbym gdzieś poczytać o tych strukturach. Zobaczę też wskazany wątek. Jak chyba rozumiem, mktime zawiera czas obecny, zapisywany do licznika, czyli ilość sek. jaka mineła od 00;00;00 01.01.1970, więc w jakiś ściśle określony sposób trzeba obecną datę wprowadzić do mktime. I odwrotnie - przy czytaniu wyłuskać z loctime rok, miesiąc itd... Fajnie, dzięki za pomoc:)
  • #17 10932646
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    dziechu napisał:
    Jak chyba rozumiem, mktime zawiera czas obecny, zapisywany do licznika, czyli ilość sek. jaka mineła od 00;00;00 01.01.1970, więc w jakiś ściśle określony sposób trzeba obecną datę wprowadzić do mktime.

    Nope. Do mktime() podajesz strukturę z "ludzką" zawartością, czyli z polami dla sekund, godzin, dni, miesięcy itd., a dostajesz w efekcie ilość sekund od "chwili zero".

    Opis tych funkcji i tych struktur jest - poza tym, że "w necie" - w dokumencie libc.pdf który znajdziesz gdzieś w katalogu share kompilatora. np:
    c:\Program Files\linaro\4.6 2012q1\share\doc\pdf\libc.pdf

    4\/3!!
  • #18 10932665
    dziechu
    Poziom 27  
    Posty: 1609
    Pomógł: 27
    Ocena: 71
    Tak wlasnie gdzies cos czytam, i tą ludzką datę chyba w postaci znaków ASCII
    np. takie cóś


    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    To będę musiał dla nich przedefiniować nazwy dni i miesięcy na PL.
  • #19 10932696
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Po pierwsze - łańcuch 3 znakowy zajmuje w pamięci CZTERY znaki (bo jest jeszcze '\0' na końcu).

    Po drugie - przejrzyj naprawdę ten dokument który wskazałem, znajdziesz w nim np coś takiego:
    8.1 asctime—format time as string
    8.3 ctime—convert time to local and format as string
    8.8 strftime—convert date and time to a formatted string

    To ostatnie nawet powinno zadziałać dla polskiego języka, ale trzeba pogrzebać w locale.

    Po trzecie - jak już zapewne zauważyłeś, funkcja sprintf() zajmuje ze 20kB, więc do prostszych zastosowań możesz pobrać z mojej strony nieco uproszczoną wersję, która obsługuje kilka popularniejszych specyfikatorów, ale akurat nie obsługuje pól szerokości ".3". Tak na przyszłość (;

    4\/3!!
  • #20 10932711
    dziechu
    Poziom 27  
    Posty: 1609
    Pomógł: 27
    Ocena: 71
    Jasne że przjrzę te wszystkie dokumenty chcę mieć tylko trochę wstępnej orientacji zanim zacznę to robić. Poszukam tez na Twojej stronie tej uproszczonej wersji, bo 20kB to niby nie tragedia, ale jak zbierze się kilka takich przypadków to juz może braknąc pamieci. Poza tym procesor obsługuje kolorowy TFT 3.2" z panelem dotykowym (rewelacja!) więc mam już 100 kB zajete, z czego kod jakieś 15kB, reszta ikonki itp. bajery:)
  • Pomocny post
    #22 10934809
    stanleysts
    Poziom 27  
    Posty: 838
    Pomógł: 115
    Ocena: 2
    oto kod który przekształci timestampa na datę, oczywiście można sobie te pola zrobić jako strukturę czy jak kto woli, ja tylko daje gotowy algorytm z którego korzystałem podczas obsługi tego śmiesznego RTC w stm32f1 :D

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    I nie trzeba korzystać z żadnych bibliotek typu time.h
  • #23 10934879
    Jado_one
    Poziom 22  
    Posty: 650
    Pomógł: 43
    Ocena: 12
    Na koniec wypadałoby jeszcze zmienić temat wątku na np.: Obsługa RTC w STM32F1 - dla potomnych ;-)
  • REKLAMA
  • #24 10935161
    dziechu
    Poziom 27  
    Posty: 1609
    Pomógł: 27
    Ocena: 71
    To prawda, wątek zmienił temat, ale jest krótki i zawiera bardzo ciekawe informacje.

    Dodano po 7 [minuty]:

    stanleyst wielkie dzięki za zwarty, krótki, elegancki kod:) Jak widzę, do kompletu brakuje części ustawiającej timestampa przy ustawianiu daty, czyli funkcji odwrotnej, przeliczajacej ilość sek. od 1970..... do teraz, mozesz wrzucić?
  • #25 10935622
    stanleysts
    Poziom 27  
    Posty: 838
    Pomógł: 115
    Ocena: 2
    to są moje własne funkcje, nie mam narazie tej odwrotnej, bo nie było mi to potrzebne, ale wieczorem będę miał czas to napiszę i wrzucę.

    Update:
    Oto mój kod, testowałem go tylko raz w porównaniu z jakąś stronką w necie i o dziwo działa, wiec pewnie jest ok.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Dodam, że funkcje są dopasowane pod konretny typ wpisywania daty:

    15:46:00x26/05/2012 ,gdzie x oznacza dowolny char za wyjątkiem cyferek.
  • #26 10938167
    dziechu
    Poziom 27  
    Posty: 1609
    Pomógł: 27
    Ocena: 71
    WIELKIE dzięki:) Format mozna sobie dostosować juz samemu, wykorzystać fragmenty, ciekawe pomysły szybkiego wyliczania (np. roku przystepnego). Wczoraj straciłem cały dzień na uruchomienie I2C. Nawet nie pisałem tu, zeby nie zawracać głowy. Robiłem to wiele razy w asm bez żadnych problemów, a wczoraj normalnie nic - nie idzie i już. Okazało się że nie można ufać dokumentacji. Oto jej fragment:

    "This pin can be connected to either VSS, VCC or left
    floating. Internal pull-down circuitry on this pin will keep
    the device in the unprotected state if left floating. If tied
    to VSS or left floating, normal memory operation is
    enabled (read/write the entire memory 0000-7FFF)."

    No to wisiał sobie ten pin. Dzisiaj rano, tak bez nadziei dopiąłem go do GND i ... wszystko poszło od razu bez problemu. EEPROM 24LC256.
    P.S. czy jest jakiś sposób kopiowania zawartości okna z kodem? Kiedy używam CTRL+C to kopiuje sieczkę bez formatowania.

    Ok, już mam, po prostu IE nie jest zbyt lubiany:) W Firefoxie da się.
  • #27 10938638
    stanleysts
    Poziom 27  
    Posty: 838
    Pomógł: 115
    Ocena: 2
    Powiem szczerze - bardzo pokrętne to tłumaczenie o tym pinie -> skąd to wziąłeś.

    Ps. Robi się tutaj multi-temat. ;D
  • #28 10938692
    dziechu
    Poziom 27  
    Posty: 1609
    Pomógł: 27
    Ocena: 71
    No jak skąd:) Z oficjalnego dokumentu .pdf Microchip 24AA256/24LC256/24FC256, strona 5:

    2.4 Write-Protect (WP)
    This pin can be connected to either VSS, VCC or left
    floating. Internal pull-down circuitry on this pin will keep
    the device in the unprotected state if left floating. If tied
    to VSS or left floating, normal memory operation is
    enabled (read/write the entire memory 0000-7FFF).
    If tied to VCC, write operations are inhibited. Read
    operations are not affected.

    To ciekawe, bo dokument jest z roku 2004.
    W innym z 2011 jest:

    2.4 Write-Protect (WP)
    This pin must be connected to either VSS or VCC. If tied
    to VSS, write operations are enabled. If tied to VCC,
    write operations are inhibited but read operations are
    not affected.

    a w jeszcze innym z 1998:

    6.3 Write Protection
    The WP pin allows the user to write-protect the entire
    array (0000-7FFF) when the pin is tied to VCC. If tied to
    VSS or left floating, the write protection is disabled. The
    WP pin is sampled at the STOP bit for every write command
    (Figure 1-1) Toggling the WP pin after the STOP
    bit will have no effect on the execution of the write cycle.

    Jak widać ten sam układ (ta sama nazwa) 24LC256 może się różnić dość zasadniczo w zależności od roku produkcji:)

    Dodano po 14 [minuty]:

    Widać najlepiej wszystkie piny dopinać, bo tylko wtedy te pamięci działają tak samo, "wiszące" piny lepiej nie zostawiać, bez względu na opis.
    Aaaa. nie będą działać tak samo, bo wersja ostatnia jest 'na opak':)
    Jakby ktoś szukał wersji którą się posługiwałem, to najlepiej szukać Microchip DS21203M
  • #29 10938785
    stanleysts
    Poziom 27  
    Posty: 838
    Pomógł: 115
    Ocena: 2
    NO to widzisz, czyli w tym z 2011r. napisali to, co faktycznie zadziałało jak tak zmieniłeś. Układ spokojnie może się trochę zmienić przez szczególnie przez 7 lat.
  • #30 10938838
    Jado_one
    Poziom 22  
    Posty: 650
    Pomógł: 43
    Ocena: 12
    Generalna zasada to nie polegać na jakiśtam wewnętrznych podciągach, tylko zawsze dawać do plusa lub masy - bezpośrednio lub przez rezystor - w zależności od sytuacji. Dotyczy to zarówno pinów konfiguracyjnych jak i transmisyjnych (np. I2C), a również np. pinów klawiatury, itd.... I odporność na zakłócenia rośnie, i w razie przypadkowej zmiany w programie, która np. wyłącza pull-up'y unikamy problemów.

Podsumowanie tematu

✨ W dyskusji poruszono problem uruchomienia przerwania RTC w mikrokontrolerach STM32. Użytkownik zauważył, że po zapisaniu do rejestru RTC_CNT musi dwukrotnie wyzerować bit RTC_CRL_CNF. W odpowiedziach podano, że przerwania RTC należy włączyć w kontrolerze NVIC za pomocą funkcji NVIC_EnableIRQ(RTC_IRQn). Użytkownicy dzielili się doświadczeniami związanymi z inicjalizacją RTC oraz konwersją czasu na format ludzki, sugerując użycie struktury tm oraz funkcji mktime() do obliczeń związanych z czasem. Wskazano również na różnice w implementacji RTC w różnych modelach STM32, gdzie w serii F4 RTC działa lepiej niż w F1, który jest bardziej ograniczony. Użytkownicy podzielili się kodem do konwersji timestampów oraz omówili problemy z dokumentacją i podłączeniem pinów w kontekście I2C.
Podsumowanie wygenerowane przez AI na podstawie treści dyskusji.
REKLAMA