Ve volném pokračování tutoriálu o low-power technikách na STM32F0 si vyzkoušíme periodické buzení ze STOP režimu pomocí RTC.

STOP režim s periodickým buzením


V tomto tutoriálu volně navážeme na předchozí díl o low-power technikách. V něm jsme otestovali všechny tři režimy spánku a čip jsme budili stiskem tlačítka (nebo nějakým vnějším signálem). Mnohem užitečnější by bylo kdyby se čip uměl nějak vzbudit sám. To je samozřejmě možné. Například z režimu SLEEP (mělký spánek) lze čip budit libovolným timerem. My ale míříme k tomu jak čip budit z hlubších spánků - z režimů STOP a STANDBY. Tady se možnosti štěpí podle toho jaký čip používáte. Příslušníci rodiny STM32L0 mají v tomto ohledu vcelku slušný výběr periferií. My se ale budeme držet STM32F0. I tam jsou rozdíly značné. Například dobře vybavený STM32F051 lze budit pomocí RTC (kalendáře), I2C, UARTem, komparátorem, nebo rozhraním CEC. O poznání chudší STM32F030 s nímž pracujeme si musí vystačit pouze s RTC. A přesně to si vyzkoušíme. Naše ukázka bude mít jednoduchý úkol. Probudit se ze spánku každou sekundu (úplně na konci si ukážeme i probouzení s vyšší frekvencí). Aby to nebyla úplná nuda, tak si po probuzení přečteme stav RTC a pošleme ho UARTem do světa. Při odesílání zkusíme využít SLEEP režim a uděláme tak jakousi optimalizaci na spotřebu. Kdo bude chtít, může si odesílaný řetězec sbírat nějakým USB->UART převodníkem.


Motivační fotografie. Spotřeba i s běžícím RTC je okolo 7.2uA


LSI

Jak už jsme řekli, chceme náš čip budit v pravidelných intervalech a k tomu potřebujeme nějaký zdroj časování. Tedy nějaký oscilátor. Chceme také udržet spotřebu v rámci jednotek až desítek uA. Nabízí se tedy dva adepti. Vnitřní 40kHz LSI RC oscilátor a LSE (oscilátor s externím hodinovým krystalem). Druhá varianta je určitě tou lepší neboť tolerance frekvence LSI je značně široká (datasheet uvádí 30-50kHz). Nominální frekvence je 40kHz, a můj konkrétní kus měl při pokojové teplotě 41.5kHz. Záměrně uvádím že při pokojové teplotě, neboť teplotní závislost jeho frekvence je značná. Tak značná, že se datasheet ani neobtěžuje ji uvádět, neboť jeho autoři zcela oprávněně nepočítají s tím, že by to vůbec někdo mohl potřebovat. Zato s externím krystalem bychom hravě dosáhli přesnosti o několik řádů vyšší... pokud bychom ho měli na našem miniaturním STM32F030F4 kam připojit Hrátky s LSE a s ním uzce spjatým RTC si tedy ponecháme jako téma jiného dílu a smíříme se s nenáročným LSI.

RTC

RTC (Real Time Clock) je bohatá periferie a příklady použití by vystačily na několik samostatných článků. Proto si uděláme jen zběžnou prohlídku a povíme si jen to nezbytně nutné k našemu příkladu. Jistě jste se už dovtípili, že do RTC lze připojit clock z LSI. Clock prochází dvojicí děliček, jejichž smyslem je snížit frekvenci na 1Hz. Od níž se pak odvíjí činnost plnohodnotného kalendáře, který udržuje informaci o sekundách, minutách, hodinách, dnech v týdnu a v měsíci, měsíci a roku. Aktuální datum a čas se neustále porovnává s obsahem alarmu jehož položky lze různě maskovat (vyřadit z porovnávání). Díky tomu lze vyvolávat alarm za různých podmínek (například každý den ve stejnou hodinu). Stejný způsobem lze porovnávat i obsah druhé děličky a realizovat tak časy nebo alarmy s intervalem nebo rozlišením kratším jak sekunda. Této funkci se budeme ještě věnovat. Další (velmi zajímavé) funkce jen letmo naznačím. Patří mezi ně například "time stamp" (zaznamená čas a datum příchodu vnější události), jemná kalibrace frekvence (1ppm), přímé ovládání výstupu nebo automatická kalibrace proti referenčnímu signálu.

Příklad

Pojďme tedy rovnou na věc. Zde je základní kostra našeho programu:


int main(void){
 clock_8();
 pull_unused_gpio(); // pulldown pro nepoužité piny
 gpio_init(); // PA4 (TEST výtup)
 init_uart(); // nastavíme UART na 115200 s clockem přímo z HSI
 init_rtc(); // nastaví RTC (nezkoumám zda už běží)

 while (1){
  RTC_ClearFlag(RTC_FLAG_ALRAF); // před usnutím smažeme vlajku Alarmu RTC
  PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFE); // uspíme čip
  TEST_H; // pro informaci jak dlouho je čip vzhůru si nastavíme pomocný výstup
  clock_8(); // taktujeme čip na požadovanou frekvenci (není nutné - po probuzení je 8MHz HSI automaticky)
  print_time(); // uděláme nějakou zajímavou / užitečnou činnost
  TEST_L; // ... informuje o konci bdělého stavu
 }
}
 


Inicializace je typická. Nejprve si nastavíme clock (každý jak potřebuje, já na 8MHz). Ošetříme nepoužité piny (buď jako analog function, nebo jako vstupy s pull-up nebo pull-down). Poté inicializujeme USART, ale nezapneme ho. UART budeme zapínat až před samotným vysíláním. Pak přijde jádro věci. Konfigurace RTC. Nejprve si spustíme LSI oscilátor a počkáme až se rozběhne. Pak pustíme clock do PWR (Power Control). Protože celé RTC je v "backup doméně" a do té je přístup běžně "uzamčen", musíme si ho odemčít funkcí PWR_BackupAccessCmd() (kvůli ní jsme potřebovali rozběhnout PWR). Od této chvíle můžeme přistupovat k registrům RTC a nastavit ho. Nejprve zvolíme zdroj clocku (LSI) a pak clock do RTC pustíme. Následně se dáme do konfigurace děliček. Tady nás čeká myšlenková práce. První (asynchronní) děličce lze nastavit dělicí poměr až 128, druhé (synchronní) až 8192. Nastavení pro hodinový krystal je triviální 32768/(128*256)=1Hz (Asynchronní dělička 128, synchronní dělička 256). Stejně jednoduchá práce by to byla kdyby náš vnitřní oscilátor měl nominálních 40kHz. Jenže jak už víme, on nemá. Takže kdo chce sekundu alespoň s 1% přesností bude si muset dosadit individuální hodnoty. Fajn, ale jak zjistit frekvenci LSI ? Jasně vyvedeme si ji na MCO ! Ten se nachází na pinu PA8... no a ten na našem miniaturním "F030F" není Takže smůla. Měřit budeme nepřímo. Jedna za variant je předpokládat, že LSI=40kHz, nastavit děličky na (100*400) a změřit si frekvenci s jakou se naše aplikace probouzí (viz oscilogram na konci). Z ní pak lze snadno dopočítat frekvenci LSI pouhým násobením 40k. Já se dopočítal k 41.525kHz a proto jsem děličku nastavil na (11*3775). Nezapomeňte, že nastavení děliček se počítá "od nuly", takže do nich zapisujete hodnotu o jedno nižší. Inicializaci clocku provedeme funkcí RTC_Init(). Všimněte si, že inicializační funkce u RTC vrací "ErrorStatus". RTC jde totiž konfigurovat pouze v "init módu" a tudíž se může stát, že se konfigurace nepovede. Funkce z SPL, mají tuhle komplikaci ošetřenou, takže to můžete pustit z hlavy.


void init_rtc(void){
 RTC_InitTypeDef rtc;
 RTC_AlarmTypeDef alarm;
 EXTI_InitTypeDef EXTI_InitStructure;
 ErrorStatus err;

 // PWR ovládá přístup do backup domény
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
 // spustit LSI oscilátor (~40kHz)
 RCC_LSICmd(ENABLE);
 // počkat na rozběh LSI
 while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) != SET);
 // povolit přístup do backu domény
 PWR_BackupAccessCmd(ENABLE);
 // LSI jako clock pro RTC
 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
 // Povolit clock do RTC
 RCC_RTCCLKCmd(ENABLE);

 // nastavit dělení clocku pro RTC (jen z legrace zkusíme velmi nepřesné LSI trochu umravnit)
 // moje LSI mělo při pokojové teplotě (důležitá informace) 41525Hz, takže nejlepší způsob jak udělat 1s je:
 // 41525/11/3775 = 1Hz
 // pokud bychom chtěli periodické buzení s kratším intervalem než 1s, museli bychom SynchPrediv volit chytře !
 rtc.RTC_AsynchPrediv = 10; // 11-1
 rtc.RTC_SynchPrediv = 3774; // 3775-1
 rtc.RTC_HourFormat = RTC_HourFormat_24;
 err=RTC_Init(&rtc);

 // nastavit datum (pro pouhé periodické buzení není třeba)
 date.RTC_Date = 5;
 date.RTC_Month = RTC_Month_May;
 date.RTC_WeekDay = RTC_Weekday_Sunday;
 date.RTC_Year = 19;
 err=RTC_SetDate(RTC_Format_BIN,&date);

 // nastavit čas (pro pouhé periodické buzení není třeba)
 time.RTC_H12 = RTC_H12_AM;
 time.RTC_Hours = 9;
 time.RTC_Minutes = 48;
 time.RTC_Seconds = 0;
 RTC_SetTime(RTC_Format_BIN,&time);

 // nastavujeme alarm na buzení každou sekundu
 // předplníme si nastavení sekund,minut,hodin... protože nehrají roli
 RTC_AlarmStructInit(&alarm);
 // klasické položky (rok, měsíc, den, hodina, minuta, sekunda) alarmu maskujeme
 alarm.RTC_AlarmMask = RTC_AlarmMask_All;
 // alarm lze přepisovat jen když je vypnutý (takže ho pro jistotu vypneme !)
 err=RTC_AlarmCmd(RTC_Alarm_A, DISABLE);
 // Aplkikujeme naše nastavení Alarmu
 RTC_SetAlarm(RTC_Format_BIN,RTC_Alarm_A,&alarm);
 // nastavíme sub-second alarm na periodické buzení každou sekundu
 RTC_AlarmSubSecondConfig(RTC_Alarm_A,0,RTC_AlarmSubSecondMask_None);
 // povolíme Alarm
 err=RTC_AlarmCmd(RTC_Alarm_A, ENABLE);
 // povolíme přerušení od Alarmu
 RTC_ITConfig(RTC_IT_ALRA,ENABLE);

 // Přerušení od RTC vedou do EXTI (pustíme EXTI clock)
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
 // povolíme Event od RTC (ten nás bude budit)
 EXTI_InitStructure.EXTI_Line = EXTI_Line17; // To je IRQ od Alarmu
 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;  // Event (!)
 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
 EXTI_InitStructure.EXTI_LineCmd = ENABLE;
 EXTI_Init(&EXTI_InitStructure);
}
 


Nastavení času a data je pro naši aplikaci spíš zbytečné a slouží jen k tomu abychom měli něco zajímavého k posílání na uart. Všimněte si, že čas i datum lze nastavovat (a jak uvidíte i číst) buď v binárním formátu nebo jako BCD. V registrech RTC se čas skladuje jako BCD. BCD formát zjednodušuje výpis času a data na "displej" a my toho později také využijeme. Další zamyšlení nás čeká u alarmu. Ten není koncipován pro periodické buzení s intervalem menším jak minuta. Obsah RTC se porovnává s obsahem Alarmu a když nastane shoda, alarm se aktivuje. Z porovnání můžeme pomocí maskování vyřadit jednotlivé položky data a času (dny, měsíce, hodiny, minuty atd.). Vyřadíme-li všechno krom sekund, bude se porovnávat jen obsah sekund a ten se zopakuje vždy jednou za minutu. To je ale pro nás příliš dlouhá doba. My tedy vymaskujeme všechny položky alarmu (pomocí RTC_AlarmMask_All). Díky tomu nám příliš nezáleží na tom jaké konkrétní hodnoty jsou v alarmu nastavené (proto jsem si dovolil využít RTC_AlarmStructInit() k "předvyplnění"). Jenže jak přesvědčit alarm aby nás budil každou sekundu ?

Řešení se nachází v "sub second" registrech. Synchronní dělička (o níž už byla řeč) je jen pouhý čítače (s nastavitelným stropem) a jeho obsah je přístupný. A hlavně účastní se též porovnávání s alarmem. Alarm tedy lze vyvolávat s jemnějším rozlišením než 1s. Rozlišení a časy jichž lze dosahovat, ale závisí na konfiguraci synchronní děličky. Jestliže dělíme 400, můžeme čas specifikovat až na 1/400s. Stejně jako alarm, lze jednotlivé bity tohoto "sub second" čítače maskovat a vyřadit je tak z porovnávání. Ti optimističtější z vás se teď zaradují, že alarmem půjdou dělat i desetiny a setiny sekundy a že čip půjde budit třeba 5x za sekundu. Ti realističtější z vás tuší, že v tom bude nějaký háček když o tom píšu. A taky že je. Uvedu to na příkladu. Do synchronní děličky přichází 400Hz. Náš čítač/dělička tedy čítá od 0 do 399 (celkem 400 kroků) než uplyne jedna sekunda. Maskování jednotlivých bitů mi umožní generovat alarm každý druhý, čtvrtý, osmý, šestnáctý... tik. Oněch 400 tedy můžu dělit 1,2,4,8,16,32,64,128,256. Můžu vytvořit 1/200s, 1/100s, 1/50s a 1/25s. Ale 1/12.5s už je blbost ... a hlavně nelze získat 1/10 ani 1/5 a ani 1/4s a žádný další hezký zlomek sekundy. A to jsme měli ještě štěstí, že jsme zvolili 400Hz, protože je slušně dělitelné dvěma. Zkusme teď zvolit realističtější hodnotu 3775 jako v mém příkladě. To číslo vůbec dělitelné dvěma není ! Takže z něj nepůjde udělat žádné buzení v pravidelných intervalech ! Práce by byla výrazně jednodušší kdyby synchronní dělička udržovala dělící poměr jako mocninu dvou (což je splněno například u 32.768kHz clocku). Vraťme se ale k původnímu plánu - budit aplikaci každou sekundu.

Zavoláním funkce RTC_AlarmSubSecondConfig(RTC_Alarm_A,0,RTC_AlarmSubSecondMask_All) vymaskujeme všechny bity i v "sub second" části alarmu (a máme tak vymaskované naprosto všechny položky Alarmu) a díky tomu se alarm zavolá každou sekundu. Stejného efektu bychom dosáhli i voláním RTC_AlarmSubSecondConfig(RTC_Alarm_A,0,RTC_AlarmSubSecondMask_None). V tomto případě by se obsah "sub second" registru porovnával s nulovou hodnotou a shoda (kdy je v čítači/děličce přesně 0) by nastala opět každou sekundu (dělička/čítač by přetekl). Tím máme tu nejobtížnější práci za sebou. Zapomněl jsem poznamenat, že alarm lze konfigurovat jen když je vypnutý, takže je dobré si ho předem vypnout. Po nastavení je potřeba alarm povolit, pak povolit přerušení od alarmu (RTC umí obecně volat vícero přerušení). Přerušení od Alarmu vede do EXTI na linku 17, takže ji musíme také nastavit. Nastavíme ji jako event a čip budeme uspávat pomocí WFE (viz předchozí díl). Od teď už můžeme čip uspávat a měl by se probudit. Přirozeně před uspáním musíme vymazat vlajku Alarmu, jinak se čip neuspí.

Teď ještě pár poznámek k výpisu na UART. Čas a datum vyčteme z RTC v BCD formátu, nemusíme pak složitě konvertovat binární hodnotu na text (např pomocí sprintf a pod.). O sestavení zprávy se stará funkce print_time(). Odeslání UARTem provedeme trochu netradičně. Protože chceme čip hned po odeslání uspat, musíme si počkat než se zpráva celá odešle ! Jak jistě víte v UARTu je buffer, do kterého nacpeme data a ze kterého si je UART sám přebírá a posílá. Je tedy na nás abychom si hlídali kolik dat jsme do UARTu nacpali a kolik z nich se kompletně odeslalo. To nám umožní vlajka TC (Transfer Complete). Takže vysílání provedeme netradičně kontrolou této vlajky namísto běžného postupu s TXE (Transmit buffer empty). Během odesílání nemá čip nic na práci a jen čeká na nastavení vlajky. To je situace jako stvořená pro využití SLEEP režimu. Takže prostoje během odesílání jednotlivých znaků prospíme. Povolíme si v UARTu přerušení od TC a využijeme informace z předchozího dílu o buzení libovolným přerušením (SEVONPEND).


void print_time(void){
 // vyčteme čas a datum z RTC
 RTC_GetTime(RTC_Format_BCD, &time);
 RTC_GetDate(RTC_Format_BCD, &date);
 // využijeme BCD formátu a vyhneme se použití sprintf ...
 // ... a připravíme si řetězec
 txt[0]=(time.RTC_Hours >> 4) + '0'; // desítky hodin
 txt[1]=(time.RTC_Hours & 0x0f)  + '0'; // jednotky hodin
 txt[2]=':';
 txt[3]=(time.RTC_Minutes >> 4) + '0'; // desítky minut
 txt[4]=(time.RTC_Minutes & 0x0f) + '0'; // jednotky minut
 txt[5]=':';
 txt[6]=(time.RTC_Seconds >> 4) + '0'; // desítky sekund
 txt[7]=(time.RTC_Seconds & 0x0f) + '0'; // jednotky sekund
 txt[8] = ' ';
 // vypíšeme den v týdnu
 if(date.RTC_WeekDay == RTC_Weekday_Monday){txt[9]='P';txt[10]='o';}
 if(date.RTC_WeekDay == RTC_Weekday_Tuesday){txt[9]='U';txt[10]='t';}
 if(date.RTC_WeekDay == RTC_Weekday_Wednesday){txt[9]='S';txt[10]='t';}
 if(date.RTC_WeekDay == RTC_Weekday_Thursday){txt[9]='C';txt[10]='t';}
 if(date.RTC_WeekDay == RTC_Weekday_Friday){txt[9]='P';txt[10]='a';}
 if(date.RTC_WeekDay == RTC_Weekday_Saturday){txt[9]='S';txt[10]='o';}
 if(date.RTC_WeekDay == RTC_Weekday_Sunday){txt[9]='N';txt[10]='e';}
 // vypíšeme datum
 txt[11] = ' ';
 txt[12]=(date.RTC_Date >> 4) + '0'; // den (desítky)
 txt[13]=(date.RTC_Date & 0x0f)  + '0'; // den (jednotky)
 txt[14]='.';
 txt[15]=(date.RTC_Month >> 4) + '0'; // měsíc (desítky)
 txt[16]=(date.RTC_Month & 0x0f)  + '0'; // měsíc (jednotky)
 txt[17]=' ';
 // a rok (2019)
 txt[18]='2';
 txt[19]='0';
 txt[20]=(date.RTC_Year >> 4) + '0';
 txt[21]=(date.RTC_Year & 0x0f)  + '0';
 txt[22]=0; // ukončení řetězce
 // vše pošleme na trochu optimalizovaný UART
 USART_puts(txt); // vypíšeme připravený řetězec
}
 



// funkce k odeslání řetězce, využívající režim spánku
void USART_puts(volatile char *s){
 // chceme během vysílání spát (jádro nemá co na práci)
 // povolíme buzení libovolným přerušením
 NVIC_SystemLPConfig(NVIC_LP_SEVONPEND, ENABLE);
 USART_Cmd(USART1,ENABLE); // zapneme UART
 // vyčistíme vlajku "Transfer Complete" (dokončené vysílání)
 USART_ClearFlag(USART1,USART_FLAG_TC);
 // povolíme přerušení od "Transfer Complete"
 USART_ITConfig(USART1,USART_IT_TC,ENABLE);
 while(*s){ // dokud je co vysílat
  USART_SendData(USART1, *s); // naložíme znak k odeslání
  s++; // posuneme se na další znak
  // než se vysílání dokončí tak si zdřímneme
  PWR_EnterSleepMode(PWR_SLEEPEntry_WFE); // mělkým spánkem (SLEEP)
  // vysílání dokončeno
  // tady by asi bylo na místě si pro jistotu zkontrolovat zda nás nevzbudilo něco jiného
  USART_ClearFlag(USART1,USART_FLAG_TC); // vyčistíme vlajku (jinak znovu neusneme)
  NVIC_ClearPendingIRQ(USART1_IRQn); // vyčistíme "vlajku" i v NVIC (jinak znovu neusneme)
 }
 // po odeslání celé zprávy vypneme přerušení od USARTu
 USART_ITConfig(USART1,USART_IT_TC,DISABLE);
 USART_Cmd(USART1,DISABLE); // vypneme UART
 // a deaktivujeme buzení libovolným přerušením
 NVIC_SystemLPConfig(NVIC_LP_SEVONPEND, DISABLE);
}
 


Nadešel čas, podívat se jak náš příklad pracuje. Dobře to ilustrují následující dva oscilogramy.



Na prvním oscilogramu ověřujeme 1Hz frekvenci. Je patrné, že i přes precizní ruční ladění jeho přesnost pro plnohodnotné RTC stačit nebude.


V druhém oscilogramu si prohlédneme detail na aktivity našeho programu v bdělé fázi (červená stopa). Modrá stopa je signál z Tx pinu a můžeme si na něm přečíst zprávu. Žlutá stopa je orientační měření spotřeby na 10Ohm rezistoru zapojeném v serii s napájením čipu. Další informace v textu. Náš program probdí přibližně 2.2ms z každé sekundy.


Opět jsem si dovolil neprezentovat celý zdrojový kód, ale jen jeho klíčové fragmenty, takže si ho stáhněte. Z prvního oscilogramu si můžete všimnout, že odchylku frekvence jsme zkrotili někde k 200ppm. Ale on je to spíš takový optický klam, protože teplotní závislost je v řádu desítek až stovek ppm na stupeň Celsia. Takže stačí na čip položit prst a frekvence se začne viditelně hýbat. Tedy LSI je použitelné jen tam kde přesné časování nevyžadujeme. Z druhého oscilogramu je vidět, že naše aplikace pracuje podle očekávání. Po probuzení nastaví svůj testovací výstup do log.1 (červená stopa) a my díky tomu můžeme vidět, že v bdělém stavu stráví přibližně 2.2ms. Žlutá stopa představuje odběr. Hned po probuzení aplikace zahájí "výpočty" (sestavuje zprávu pro UART). Během této fáze je čip taktován 8MHz, jeho odběr je vyšší a na žluté stopě se to projeví jako pík. Až začne odesílání dat tak se odběr díky uspávání trochu sníží. Podle osciloskopu je plocha pod grafem rovna 2.83uA*s. To by znamenalo, že při našem 1Hz buzení se zvedne průměrný odběr právě o těchto 2.8uA. Jak asi tušíte tohle se těžko ověřuje (viz metoda jak měřit odběr z tutoriálu o AVR). Spotřeba během spánku je přibližně 7.2uA, což jsem prozradil už na titulní fotografii. S vypnutím VDDA monitoru v option bytes pak klesne na 6.1uA.

Úprava

Kdo potřebuje pravidelné buzení v kratších intervalech, může si změnit hodnoty děliček. Nastavíme-li synchronní děličku na 512 a asynchronní děličku na 81, pokazíme si sice frekvenci (f=1.001Hz), ale otevře se nám možnost realizovat různé zlomky sekundy. A to 1/2, 1/4, 1/8, 1/16 (a další zlomky mocnin dvou). Což nejspíš bude užitečná funkce, takže si dovolím uvést jednoduchý postup úpravy kódu. Přirozeně ale existují i jiné postupy, třeba alarm při každém probuzení rekonfigurovat. Pak si můžete dělat intervaly libovolně dlouhé podle aktuální potřeby. Já tuto variantu vyřadil, protože jsem se pokoušel sestavit nějakou šablonu, kterou budu kopírovat do svých low-power aplikacích jako kostru programu.


// LSI = 41525, F1Hz = 41525/81/512 = 1.00128Hz
rtc.RTC_AsynchPrediv = 80; // 81-1
rtc.RTC_SynchPrediv = 511; // 512-1
// ...
RTC_AlarmSubSecondConfig(RTC_Alarm_A,0,RTC_AlarmSubSecondMask_SS14_8); // maskovat bity 14 až 8 a budit čip každou 1/2s
RTC_AlarmSubSecondConfig(RTC_Alarm_A,0,RTC_AlarmSubSecondMask_SS14_7); // maskovat bity 14 až 7 a budit čip každou 1/4s
RTC_AlarmSubSecondConfig(RTC_Alarm_A,0,RTC_AlarmSubSecondMask_SS14_6); // maskovat bity 14 až 6 a budit čip každou 1/8s
// ... atd...
 


Závěr

Závěrem bych chtěl říct, že jsem to čekal o něco snazší. Ale tak to chodí. Ti z vás, kteří chtějí si mohou upravit příklad s využitím režimu STANDBY. Já jsem se do toho nepouštěl, protože většina aplikací co dělám, potřebuje udržet obsah RAM a STANDBY režim tedy neplánuji využívat. Doufám že příklad poslouží i vám a budu rád když se na mě obrátíte s náměty jak ho vyladit.

Odkazy


Reference manual STM32F030
Datasheet STM32F030
STM32F Low-power RTC appnote<
STM32F RTC appnote
Vybrané Low-Power postupy pro STM32F0
Low Power techniky 2 (AVR)

Zdrojový kód ke stažení: zdrojaky.zip

Rozcestník na další díly seriálu naleznete na www.elektromys.eu/stm32.php V1.00 8.5.2019
By Michal Dudka (m.dudka@seznam.cz)