Skocz do zawartości

[C] [STM32] Przerwanie od RTC co sekundę nie działa


quatium

Pomocna odpowiedź

Cześć.

Chciałbym zrobić tak, żeby przerwanie generowane z RTC było co sekundę.

O ile samo RTC działa (licznik cały czas się zwiększa), to o tyle ani procedura obsługi przerwania nie jest wywoływana, ani flaga SECF w rejestrze RTC_CRL nie jest ustawiana.

Na testy w miejsca, które powinny być przetwarzane co sekundę, wstawiłem negację stanu diody na PA5.

Do testów używam Nucleo-F103RB (STM32F103RBT6).

Kod:


#include "stm32f10x.h"

   uint32_t rtc_count = 0;
   uint8_t sec, min, hour;
   uint8_t day, month;
   uint16_t year;

   void RTC_IRQHandler(void) __attribute__ ((interrupt));
   void RTC_IRQHandler(void)
   {
       GPIOA->ODR ^= GPIO_ODR_ODR5;
   	if(RTC->CRL & RTC_CRL_SECF)
   	{
   		rtc_count = (RTC->CNTL | (RTC->CNTH << 16)); //zapisujemy wartosc licznika rtc
   		calendar_update:
   		if(rtc_count > 86399) //jesli minelo 86399 sekund, to uplynal juz conajmniej dzien (urzadzenie moglo lezec wylaczone dlugo)
   		{
   			if((month == 1) || (month == 3) || (month == 5) || (month == 7) || (month == 8) || (month == 10) || (month == 12)) //jesli miesiac ma 31 dni
   			{
   				if(day < 31) day++; //jesli minelo mniej niz 31 dni, to doliczamy dzien
   				else if(month == 12) //a jesli to byl 31 dzien i grudzien
   				{
   					month = 1; //NOWY ROK!
   					day = 1;
   					year++;
   				} else  //a jesli to nie grudzien, ale minal 31 dzien
   				{
   					month++; //nastpeny miesiac
   					day++;
   				}
   			}
   			else if(month == 2) //a jesli to luty
   			{
   				if(day < 28) day++; //i jesli jest przed 28 lutego to dzien nastepny
   				else if(day == 28) //a jesli jest 28
   				{
   					if((year % 400 == 0) || ((year % 100 != 0) && (year % 4 == 0))) day++; //jesli to rok przestepny to dzien zwiekszamy
   					else
   					{
   						month++; //a jak nie to nastepny miesiac
   						day = 1;
   					}
   				} else //a jesli to 29 lutego (rok przestepny)
   				{
   					month++; //to nastepny miesiac
   					day = 1;
   				}
   			} else //a jak miesiac ma 30 dni
   			{
   				if(day < 31) //i jesli minal 30 dzien
   				{
   					month++; //nastepny miesiac
   					day = 1;
   				}
   				else day++; //a jak nie minal 30 dzien
   			}
   		}
   		rtc_count -= 86400; //odejmujemy ten dzien z licznika
   		if(rtc_count > 86399) goto calendar_update; //i jesli mimo to w liczniku mamy jeszcze jeden dzien (urzadzenie lezalo dlugo bez uruchomienia), to przetwarzamy i jego

   		hour = rtc_count / 3600; //zapisujemy godzine
   		min = (rtc_count % 3600) / 60; //i minute
   		sec = (rtc_count % 3600) % 60; //i sekunde


   		RTC->CRL |= RTC_CRL_RTOFF; //wlaczamy mozliwosc zapisu do rejestrow RTC

   		RTC->CRL &= ~RTC_CRL_RSF;
   		RTC->CNTL = (rtc_count & 0xFFFF); //zapisujemy pozostale rtc_count
   		while ((RTC->CRL & RTC_CRL_RSF) == 0);;

   		RTC->CRL &= ~RTC_CRL_RSF;
   		RTC->CNTH = (rtc_count & 0xFFFF0000);
   		while ((RTC->CRL & RTC_CRL_RSF) == 0);;

   		RTC->CRL &= ~RTC_CRL_RTOFF; //wylaczamy mozliwosc zapisu do rejestrow RTC

   		PWR->CR |= PWR_CR_DBP; //wlaczamy mozliwosc zapisu do rejestrow BKP

   		BKP->DR1 = day; //zapisujemy dzien, rok i miesiac
   		BKP->DR2 = month;
   		BKP->DR3 = year;

   		PWR->CR &= ~PWR_CR_DBP; //wlaczamy mozliwosc zapisu do rejestrow BKP

   		RTC->CRL &= ~RTC_CRL_SECF;
   	}
   }



   int main(void)
   {

           RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //zegrad dla GPIOA
           RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; //zegrad dla GPIOA
           RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; //zegar dla GPIOC
           RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; //zegar dla AFIO
           //RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; //zegar dla timera2
           //RCC->APB1ENR |= RCC_APB1ENR_USART2EN; //zegar dla usarta2
           //RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; //zegar dla adc1
           //RCC->AHBENR |= RCC_AHBENR_DMA1EN; //zegar dla dma
           RCC->APB1ENR |= RCC_APB1ENR_PWREN; //zegar dla PWR
           RCC->APB1ENR |= RCC_APB1ENR_BKPEN; //zegar dla BKP
           //RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; //wlaczamy I2C1


           GPIOA->CRL |= GPIO_CRL_MODE5_1; //ustawienie pinu PA5 jako wyjscia push pull 2mhz
           GPIOA->CRL &= ~GPIO_CRL_MODE5_0;
           GPIOA->CRL &= ~GPIO_CRL_CNF5;
           GPIOC->CRL |= GPIO_CRH_CNF13_1; //ustawienie pinu PC13 jako wejscia z podciagnieciem do zasilania
           GPIOA->CRL |= GPIO_CRL_MODE2_1; //usart2 wyjsce jako push pull
           GPIOA->CRL &= ~GPIO_CRL_CNF2_0; //usart2 wyjscie jako alternatywna funkcja
           GPIOA->CRL |= GPIO_CRL_CNF2_1;
           GPIOA->CRL |= GPIO_CRL_CNF3_0; //usart2 wejsce jako floating
           GPIOA->CRL &= ~GPIO_CRL_CNF3_1;

   		PWR->CR |= PWR_CR_DBP; //wlaczamy mozliwosc zapisu do rejestrow BKP

   		day = BKP->DR1; //odczytujemy ostanie dane kalendarza
   		month = BKP->DR2;
   		year = BKP->DR3;

   		PWR->CR &= ~PWR_CR_DBP; //wylaczamy mozliwosc zapisu do rejestrow BKP

           if((day == 0) || (month == 0) || (year == 0)) //jesli ktoras z wartosci w kalendarzu jest zerowa to ustawiamy domyslna
           {
           	day = 1;
           	month = 1;
           	year = 1970;
           }


           PWR->CR |= PWR_CR_DBP; //wlaczamy mozliwosc zapisu do rejestrow BKP
           RTC->CRL |= RTC_CRL_CNF; //wchodzimy w tryb konfiguracji RTC


           RTC->CRL &= ~RTC_CRL_RSF;

           RCC->BDCR = 0;
           RCC->BDCR |= RCC_BDCR_LSEON; //i wlaczamy kwarc 32768khz

           while((RCC->BDCR & RCC_BDCR_LSERDY) == 0);; //czekamy na zainicjowanie LSE 32768khz

           RCC->BDCR |= RCC_BDCR_RTCSEL_0; //ustwiamy zegar RTC z LSE
           RCC->BDCR &= ~RCC_BDCR_RTCSEL_1;

           RCC->BDCR |= RCC_BDCR_RTCEN; //wlaczamy RTC

           PWR->CR &= ~PWR_CR_DBP; //wylaczamy mozliwosc zapisu do rejestrow BKP

           while ((RTC->CRL & RTC_CRL_RSF) == 0);;
           while ((RTC->CRL & RTC_CRL_RTOFF) == 0);; //czekamy, az ostatnia operacja zapisu do RTC zostanie ukonczona

           RTC->PRLL = 32767; //ustawiamy preskaler zegara RTC
           while ((RTC->CRL & RTC_CRL_RTOFF) == 0);; //i czekamy, az ostatnia operacja zapisu do RTC zostanie ukonczona

           RTC->CRH |= RTC_CRH_SECIE; //wlaczamy przerwanie sekundowe
           while ((RTC->CRL & RTC_CRL_RTOFF) == 0);; //i czekamy, az ostatnia operacja zapisu do RTC zostanie ukonczona



           RTC->CRL &= ~RTC_CRL_CNF; //wychodzimy z trybu konfiguracji RTC


           NVIC_EnableIRQ(RTC_IRQn);

           while(1)
           {
           	if(RTC->CRL & RTC_CRL_SECF) //tylko na testy, czy pojawia sie chociazby flaga, no i sie nie pojawia
           	    	{

           		GPIOA->ODR ^= GPIO_ODR_ODR5;
           		RTC->CRL &= ~RTC_CRL_SECF;
           	    	}
           }
   }

Z góry dzięki za pomoc.

Link do komentarza
Share on other sites

Cześć.

Tak, poradziłem sobie z tym w końcu.

Problem jest prozaiczny - okazało się, że do edycji rejestrów RTC trzeba też włączyć edycję rejestrów BKP.

Linię

PWR->CR |= PWR_CR_DBP; //wlaczamy mozliwosc zapisu do rejestrow BKP 

należy przenieść nad linię

RTC->CRL |= RTC_CRL_RTOFF; //wlaczamy mozliwosc zapisu do rejestrow RTC 

i zaczyna działać.

Funkcja ma wyglądać tak:

    void RTC_IRQHandler(void) __attribute__ ((interrupt));
   void RTC_IRQHandler(void)
   {
       GPIOA->ODR ^= GPIO_ODR_ODR5;
       if(RTC->CRL & RTC_CRL_SECF)
       {
           rtc_count = (RTC->CNTL | (RTC->CNTH << 16)); //zapisujemy wartosc licznika rtc
           calendar_update:
           if(rtc_count > 86399) //jesli minelo 86399 sekund, to uplynal juz conajmniej dzien (urzadzenie moglo lezec wylaczone dlugo)
           {
               if((month == 1) || (month == 3) || (month == 5) || (month == 7) || (month == 8) || (month == 10) || (month == 12)) //jesli miesiac ma 31 dni
               {
                   if(day < 31) day++; //jesli minelo mniej niz 31 dni, to doliczamy dzien
                   else if(month == 12) //a jesli to byl 31 dzien i grudzien
                   {
                       month = 1; //NOWY ROK!
                       day = 1;
                       year++;
                   } else  //a jesli to nie grudzien, ale minal 31 dzien
                   {
                       month++; //nastpeny miesiac
                       day++;
                   }
               }
               else if(month == 2) //a jesli to luty
               {
                   if(day < 28) day++; //i jesli jest przed 28 lutego to dzien nastepny
                   else if(day == 28) //a jesli jest 28
                   {
                       if((year % 400 == 0) || ((year % 100 != 0) && (year % 4 == 0))) day++; //jesli to rok przestepny to dzien zwiekszamy
                       else
                       {
                           month++; //a jak nie to nastepny miesiac
                           day = 1;
                       }
                   } else //a jesli to 29 lutego (rok przestepny)
                   {
                       month++; //to nastepny miesiac
                       day = 1;
                   }
               } else //a jak miesiac ma 30 dni
               {
                   if(day < 31) //i jesli minal 30 dzien
                   {
                       month++; //nastepny miesiac
                       day = 1;
                   }
                   else day++; //a jak nie minal 30 dzien
               }
           }
           rtc_count -= 86400; //odejmujemy ten dzien z licznika
           if(rtc_count > 86399) goto calendar_update; //i jesli mimo to w liczniku mamy jeszcze jeden dzien (urzadzenie lezalo dlugo bez uruchomienia), to przetwarzamy i jego

           hour = rtc_count / 3600; //zapisujemy godzine
           min = (rtc_count % 3600) / 60; //i minute
           sec = (rtc_count % 3600) % 60; //i sekunde

           PWR->CR |= PWR_CR_DBP; //wlaczamy mozliwosc zapisu do rejestrow BKP
           RTC->CRL |= RTC_CRL_RTOFF; //wlaczamy mozliwosc zapisu do rejestrow RTC

           RTC->CRL &= ~RTC_CRL_RSF;
           RTC->CNTL = (rtc_count & 0xFFFF); //zapisujemy pozostale rtc_count
           while ((RTC->CRL & RTC_CRL_RSF) == 0);;

           RTC->CRL &= ~RTC_CRL_RSF;
           RTC->CNTH = (rtc_count & 0xFFFF0000);
           while ((RTC->CRL & RTC_CRL_RSF) == 0);;

           RTC->CRL &= ~RTC_CRL_RTOFF; //wylaczamy mozliwosc zapisu do rejestrow RTC



           BKP->DR1 = day; //zapisujemy dzien, rok i miesiac
           BKP->DR2 = month;
           BKP->DR3 = year;

           PWR->CR &= ~PWR_CR_DBP; //wlaczamy mozliwosc zapisu do rejestrow BKP

           RTC->CRL &= ~RTC_CRL_SECF;
       }
   }
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.