main.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. /*
  2. Clock for the STM32L031
  3. EXTI line
  4. 17 RTC alarm
  5. 19 RTC tamper & timestamp & CSS_LSE
  6. 20 RTC wakeup timer
  7. PA0 TAMP2 Button
  8. PA2 TAMP3 Button
  9. __enable_irq();
  10. __disable_irq();
  11. */
  12. #include <stdint.h>
  13. #include <stddef.h>
  14. #include "stm32l031xx.h"
  15. #include "delay.h"
  16. #include "u8g2.h"
  17. //#include "rtc.h"
  18. #include "key.h"
  19. #include "gui.h"
  20. /*=======================================================================*/
  21. /* Configuration */
  22. /* Note: 50ms systick */
  23. /* delay until other another button press is accepted */
  24. /* time is in systicks (50ms) */
  25. #define TAMPER_SYSTICK_DELAY 22
  26. /* delay until the menu goes back time display and standby mode */
  27. /* delay in systicks (50ms) */
  28. /* 50ms*20 = 1 second */
  29. /* 50ms*20*10 = 10 second */
  30. /* 50ms*20*18 = 18 second */
  31. #define MENU_IDLE_SYSTICK_TIMEOUT (20*18)
  32. /* max alarm duration */
  33. /* time in systicks (50ms) */
  34. /* 50ms*20 = 1 second */
  35. /* 50ms*20*10 = 10 second */
  36. /* 50ms*20*18 = 18 second */
  37. /* 50ms*20*120 = 120 seconds */
  38. #define ALARM_MAX_SYSTICK_TIME (20*30)
  39. /* wakeup period: The uC will wake up after the specified number of seconds */
  40. /* the value is one less the intended number of seconds: */
  41. /* 0: wakeup every 1 second */
  42. /* 14: wakeup every 15 seconds */
  43. /* 29: wakeup every 30 seconds */
  44. /* After wakeup the uC will refresh the display and check for the alarms. This means the wakeup time should not be */
  45. /* more than 1 minute. There might be also a delay of up to WAKEUP_PERIOD+1 seconds until the alarm is detected. */
  46. /* Large values reduce power consumtion, but displayed time and alarm might be later than the actual RTC time. */
  47. #define WAKEUP_PERIOD 14
  48. /* DST (daylight savings time) rules */
  49. /* 0: DST not applied */
  50. /* 1: EU */
  51. /* 2: US */
  52. #define DST_RULE 1
  53. /* Contrast value for the display in normal mode (u8g2_SetContrast). */
  54. /* 208: default value for the SSD1306 */
  55. #define DISPLAY_CONTRAST_NORMAL 210
  56. /* Contrast value for the display in standby mode, if the display mode DISPLAY_STANDBY_MODE_REDUCED is aktive. */
  57. /* 208: default value for the SSD1306, value 0 still shows something on the display */
  58. #define DISPLAY_CONTRAST_REDUCED 5
  59. /* the following variable defines the behavior of the display during standby of the uC */
  60. #define DISPLAY_STANDYB_MODE_ALWAYS_ON 0
  61. #define DISPLAY_STANDBY_MODE_REDUCED 1
  62. #define DISPLAY_STANDBY_MODE_OFF 2
  63. volatile unsigned long DisplayStandbyMode = DISPLAY_STANDBY_MODE_OFF;
  64. /*=======================================================================*/
  65. /* external functions */
  66. uint8_t u8x8_gpio_and_delay_stm32l0(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
  67. int is_dst_by_date(uint8_t region);
  68. void adjustDST(uint8_t region);
  69. /*=======================================================================*/
  70. /* global variables */
  71. #define RESET_REASON_POR 0
  72. #define RESET_REASON_NVIC_RESET 1
  73. #define RESET_REASON_TAMP2 2
  74. #define RESET_REASON_TAMP3 3
  75. #define RESET_REASON_WUF 4
  76. volatile unsigned long SysTickCount = 0;
  77. volatile unsigned long RTCWUCount = 0;
  78. volatile unsigned long RTCIRQCount = 0;
  79. volatile unsigned long isIgnoreNextKey = 0;
  80. volatile unsigned long Tamper2Count = 0;
  81. volatile unsigned long Tamper3Count = 0;
  82. volatile unsigned long MenuIdleTimer = 0;
  83. volatile unsigned long PWR_CSR_Backup;
  84. volatile unsigned long ResetReason = RESET_REASON_POR;
  85. volatile unsigned long AlarmSeqPos = 0;
  86. volatile unsigned long AlarmSeqDly = 0;
  87. const uint8_t *AlarmSeqPtr = NULL;
  88. const uint8_t *AlarmSeqStart = NULL;
  89. volatile unsigned long AlarmSeqTime = 0;
  90. volatile unsigned long RTCUpdateCount = 0; // decremented in SysTick IRQ if not 0
  91. volatile unsigned long NextDSTAdjustment = 0;
  92. //rtc_t rtc;
  93. u8g2_t u8g2;
  94. /*=======================================================================*/
  95. #define AOff(dly) (0<<5)|((dly)&0x01f)
  96. #define ABeep(dly) (1<<5)|((dly)&0x01f)
  97. #define ARepeat() (0xfe)
  98. #define AEnd() (0xff)
  99. /*=======================================================================*/
  100. const uint8_t ASeqTrippleBeep[] =
  101. { ABeep(1),AOff(2), ABeep(1),AOff(2),ABeep(1),AOff(22), ARepeat() };
  102. /*=======================================================================*/
  103. void set_alarm_sequence(const uint8_t *alarm_sequence)
  104. {
  105. GPIOA->BSRR = GPIO_BSRR_BR_6; /* atomic clr PA6 */
  106. AlarmSeqDly = 0;
  107. AlarmSeqPtr = alarm_sequence;
  108. AlarmSeqStart = alarm_sequence;
  109. AlarmSeqTime = 0;
  110. }
  111. void ExecuteAlarmSequenceStep(void)
  112. {
  113. if ( AlarmSeqPtr == NULL )
  114. return;
  115. //AlarmSeqTime++;
  116. //if ( AlarmSeqTime > ALARM_MAX_SYSTICK_TIME )
  117. //{
  118. // set_alarm_sequence(NULL);
  119. // gui_data.is_alarm = 0; // disable alarm
  120. // return;
  121. //}
  122. if ( AlarmSeqDly > 0 )
  123. {
  124. AlarmSeqDly--;
  125. return ;
  126. }
  127. switch( (*AlarmSeqPtr)>>5 )
  128. {
  129. case 0:
  130. GPIOA->BSRR = GPIO_BSRR_BR_6; /* atomic clr PA6 */
  131. AlarmSeqDly = ((*AlarmSeqPtr) & 0x01f);
  132. break;
  133. case 1:
  134. GPIOA->BSRR = GPIO_BSRR_BS_6; /* atomic set PA13 */
  135. AlarmSeqDly = ((*AlarmSeqPtr) & 0x01f);
  136. break;
  137. default:
  138. if ( *AlarmSeqPtr == 0x0fe )
  139. AlarmSeqPtr = AlarmSeqStart;
  140. return;
  141. }
  142. AlarmSeqPtr++;
  143. }
  144. void SetAlarmSequence(const uint8_t *alarm_sequence)
  145. {
  146. __disable_irq();
  147. set_alarm_sequence(alarm_sequence);
  148. __enable_irq();
  149. }
  150. /*=======================================================================*/
  151. void __attribute__ ((interrupt, used)) SysTick_Handler(void)
  152. {
  153. int is_t2 = 0;
  154. int is_t3 = 0;
  155. SysTickCount++;
  156. /* read the tamper/button state */
  157. /* this is more complicated, because there are no external pull ups for the buttons */
  158. /* pull ups can be activated via GPIO, but are disabled if the pin is configured as tamper input */
  159. /* As a consequence, we have to disable tamper (so that the internal pullups are active), then */
  160. /* after some delay, get the GPIO value of the tamper input and restore tamper status */
  161. if ( Tamper2Count > 0 || Tamper3Count > 0 )
  162. {
  163. RTC->WPR = 0x0ca; /* disable RTC write protection */
  164. RTC->WPR = 0x053;
  165. RTC->TAMPCR &= ~RTC_TAMPCR_TAMP2E; /* disable tamper so that we can do normal GPIO access */
  166. RTC->TAMPCR &= ~RTC_TAMPCR_TAMP3E; /* disable tamper so that we can do normal GPIO access */
  167. __NOP(); /* add delay after disable tamper so that GPIO can read the value */
  168. __NOP();
  169. is_t2 = (GPIOA->IDR & GPIO_IDR_ID0) != 0 ? 1 : 0;
  170. is_t3 = (GPIOA->IDR & GPIO_IDR_ID2) != 0 ? 1 : 0;
  171. RTC->TAMPCR |= RTC_TAMPCR_TAMP2E; /* enable tamper */
  172. RTC->TAMPCR |= RTC_TAMPCR_TAMP3E; /* enable tamper */
  173. RTC->WPR = 0; /* enable RTC write protection */
  174. RTC->WPR = 0;
  175. }
  176. if ( Tamper3Count > 0 )
  177. {
  178. Tamper3Count--;
  179. /* check for timeout or whether the user has released the button */
  180. if ( Tamper3Count == 0 || is_t3 )
  181. {
  182. Tamper3Count = 0;
  183. RTC->ISR &= ~RTC_ISR_TAMP3F; /* clear tamper flag, allow new tamper event */
  184. }
  185. }
  186. else
  187. {
  188. RTC->ISR &= ~RTC_ISR_TAMP3F; /* clear tamper flag, allow new tamper event */
  189. }
  190. if ( Tamper2Count > 0 )
  191. {
  192. Tamper2Count--;
  193. /* check for timeout or whether the user has released the button */
  194. if ( Tamper2Count == 0 || is_t2)
  195. {
  196. Tamper2Count = 0;
  197. RTC->ISR &= ~RTC_ISR_TAMP2F; /* clear tamper flag, allow new tamper event */
  198. }
  199. }
  200. else
  201. {
  202. RTC->ISR &= ~RTC_ISR_TAMP2F; /* clear tamper flag, allow new tamper event */
  203. }
  204. ExecuteAlarmSequenceStep();
  205. MenuIdleTimer++;
  206. if ( RTCUpdateCount > 0 )
  207. RTCUpdateCount--;
  208. }
  209. void __attribute__ ((interrupt, used)) RTC_IRQHandler(void)
  210. {
  211. //enableRCCRTCWrite();
  212. if ( (EXTI->PR & EXTI_PR_PIF20) != 0 ) /* interrupt caused by wake up */
  213. {
  214. EXTI->PR = EXTI_PR_PIF20; /* wake up is connected to line 20, clear this IRQ */
  215. RTCWUCount++;
  216. }
  217. /* the wake up time flag must be cleared, otherwise no further IRQ will happen */
  218. /* in principle, this should happen only when a IRQ line 20 IRQ happens, but */
  219. /* it will be more safe to clear this flag for any interrupt */
  220. RTC->ISR &= ~RTC_ISR_WUTF; /* clear the wake up flag */
  221. if ( (EXTI->PR & EXTI_PR_PIF19) != 0 ) /* interrupt caused by tamper event */
  222. {
  223. EXTI->PR = EXTI_PR_PIF19; /* clear tamper IRQ */
  224. /* The TAMPxF flag has to be cleared, but this is done in the systick handler after some delay */
  225. //RTC->ISR &= ~RTC_ISR_TAMP3F;
  226. //RTC->ISR &= ~RTC_ISR_TAMP2F;
  227. if ( RTC->ISR & RTC_ISR_TAMP3F )
  228. {
  229. if ( isIgnoreNextKey == 0 )
  230. {
  231. key_add(KEY_NEXT);
  232. }
  233. isIgnoreNextKey = 0;
  234. MenuIdleTimer = 0;
  235. Tamper3Count = TAMPER_SYSTICK_DELAY;
  236. }
  237. if ( RTC->ISR & RTC_ISR_TAMP2F )
  238. {
  239. if ( isIgnoreNextKey == 0 )
  240. {
  241. key_add(KEY_SELECT);
  242. }
  243. isIgnoreNextKey = 0;
  244. MenuIdleTimer = 0;
  245. Tamper2Count = TAMPER_SYSTICK_DELAY;
  246. }
  247. }
  248. //disableRCCRTCWrite();
  249. RTCIRQCount++;
  250. }
  251. /*=======================================================================*/
  252. /*
  253. Enable several power regions: PWR, GPIOA
  254. Enable write access to RTC
  255. This must be executed after each reset.
  256. */
  257. void startUp(void)
  258. {
  259. RCC->IOPENR |= RCC_IOPENR_IOPAEN; /* Enable clock for GPIO Port A */
  260. RCC->APB1ENR |= RCC_APB1ENR_PWREN; /* enable power interface */
  261. PWR->CR |= PWR_CR_DBP; /* activate write access to RCC->CSR and RTC */
  262. PWR_CSR_Backup = PWR->CSR; /* create a backup of the original PWR_CSR register for later analysis */
  263. PWR->CR |= PWR_CR_CSBF; /* clear the standby flag in the PWR_CSR register, but luckily we have a copy */
  264. PWR->CR |= PWR_CR_CWUF; /* also clear the WUF flag in PWR_CSR */
  265. /* PA0, TAMP2, button input */
  266. GPIOA->MODER &= ~GPIO_MODER_MODE0; /* clear mode for PA0 */
  267. GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD0; /* no pullup/pulldown for PA0 */
  268. GPIOA->PUPDR |= GPIO_PUPDR_PUPD0_0; /* pullup for PA0 */
  269. /* PA2, TAMP3, button input */
  270. GPIOA->MODER &= ~GPIO_MODER_MODE2; /* clear mode for PA2 */
  271. GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD2; /* no pullup/pulldown for PA2 */
  272. GPIOA->PUPDR |= GPIO_PUPDR_PUPD2_0; /* pullup for PA2 */
  273. /* buzzer output */
  274. GPIOA->MODER &= ~GPIO_MODER_MODE6; /* clear mode for PA6 */
  275. GPIOA->MODER |= GPIO_MODER_MODE6_0; /* Output mode for PA6 */
  276. GPIOA->OTYPER &= ~GPIO_OTYPER_OT_6; /* Push/Pull for PA6 */
  277. GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED6; /* low speed for PA6 */
  278. GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD6; /* no pullup/pulldown for PA6 */
  279. GPIOA->BSRR = GPIO_BSRR_BR_6; /* atomic clr PA6 */
  280. }
  281. /*=======================================================================*/
  282. /*
  283. Set internal high speed clock as clock for the system
  284. Also call SystemCoreClockUpdate()
  285. This must be executed after each reset.
  286. */
  287. void startHSIClock()
  288. {
  289. /* test if the current clock source is something else than HSI */
  290. if ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
  291. {
  292. /* enable HSI */
  293. RCC->CR |= RCC_CR_HSION;
  294. /* wait until HSI becomes ready */
  295. while ( (RCC->CR & RCC_CR_HSIRDY) == 0 )
  296. ;
  297. /* enable the HSI "divide by 4" bit */
  298. RCC->CR |= (uint32_t)(RCC_CR_HSIDIVEN);
  299. /* wait until the "divide by 4" flag is enabled */
  300. while((RCC->CR & RCC_CR_HSIDIVF) == 0)
  301. ;
  302. /* then use the HSI clock */
  303. RCC->CFGR = (RCC->CFGR & (uint32_t) (~RCC_CFGR_SW)) | RCC_CFGR_SW_HSI;
  304. /* wait until HSI clock is used */
  305. while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
  306. ;
  307. }
  308. /* disable PLL */
  309. RCC->CR &= (uint32_t)(~RCC_CR_PLLON);
  310. /* wait until PLL is inactive */
  311. while((RCC->CR & RCC_CR_PLLRDY) != 0)
  312. ;
  313. /* set latency to 1 wait state */
  314. FLASH->ACR |= FLASH_ACR_LATENCY;
  315. /* At this point the HSI runs with 4 MHz */
  316. /* Multiply by 16 device by 2 --> 32 MHz */
  317. RCC->CFGR = (RCC->CFGR & (~(RCC_CFGR_PLLMUL| RCC_CFGR_PLLDIV ))) | (RCC_CFGR_PLLMUL16 | RCC_CFGR_PLLDIV2);
  318. /* enable PLL */
  319. RCC->CR |= RCC_CR_PLLON;
  320. /* wait until the PLL is ready */
  321. while ((RCC->CR & RCC_CR_PLLRDY) == 0)
  322. ;
  323. /* use the PLL has clock source */
  324. RCC->CFGR |= (uint32_t) (RCC_CFGR_SW_PLL);
  325. /* wait until the PLL source is active */
  326. while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
  327. ;
  328. }
  329. /*=======================================================================*/
  330. /*
  331. Setup systick interrupt.
  332. A call to SystemCoreClockUpdate() is required before calling this function.
  333. This must be executed after each reset.
  334. */
  335. void startSysTick(void)
  336. {
  337. SysTick->LOAD = (SystemCoreClock/1000)*50 - 1; /* 50ms task */
  338. SysTick->VAL = 0;
  339. SysTick->CTRL = 7; /* enable, generate interrupt (SysTick_Handler), do not divide by 2 */
  340. }
  341. /*=======================================================================*/
  342. /*
  343. Setup u8g2
  344. This must be executed after every reset
  345. */
  346. void initDisplay(uint8_t is_por)
  347. {
  348. /* setup display */
  349. u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_sw_i2c, u8x8_gpio_and_delay_stm32l0);
  350. gui_Init(&u8g2, is_por);
  351. u8g2_SetFlipMode(&u8g2, 1);
  352. }
  353. /*=======================================================================*/
  354. /*
  355. configure and start RTC
  356. This must be executed only after POR reset.
  357. write access must be activated before calling this function: PWR->CR |= PWR_CR_DBP;
  358. return values:
  359. 0: no clock avilable
  360. 1: external clock
  361. 2: external oszillator
  362. */
  363. unsigned int initRTC(void)
  364. {
  365. unsigned int r = 0;
  366. /* real time clock enable */
  367. //enableRCCRTCWrite();
  368. __disable_irq();
  369. RTC->WPR = 0x0ca; /* disable RTC write protection */
  370. RTC->WPR = 0x053;
  371. /* try externel 32K clock source */
  372. RCC->CSR |= RCC_CSR_LSEBYP; /* bypass oscillator */
  373. RCC->CSR |= RCC_CSR_LSEON; /* enable low speed external clock */
  374. delay_micro_seconds(100000*5); /* LSE requires between 100ms to 200ms */
  375. if ( RCC->CSR & RCC_CSR_LSERDY )
  376. {
  377. r = 1;
  378. }
  379. else
  380. {
  381. RCC->CSR &= ~RCC_CSR_LSEON; /* disable external clock */
  382. /* try externel 32K oscillator */
  383. RCC->CSR &= ~RCC_CSR_LSEBYP; /* no bypass oscillator */
  384. RCC->CSR &= ~RCC_CSR_LSEDRV_Msk; /* lowest drive */
  385. RCC->CSR |= RCC_CSR_LSEDRV_0; /* medium low drive */
  386. RCC->CSR |= RCC_CSR_LSEON; /* enable low speed external clock */
  387. delay_micro_seconds(100000*6); /* LSE requires between 200ms and 400ms */
  388. if ( RCC->CSR & RCC_CSR_LSERDY )
  389. {
  390. r = 2;
  391. }
  392. }
  393. if ( r > 0 )
  394. {
  395. RCC->CSR &= ~RCC_CSR_RTCSEL_Msk; /* no clock selection for RTC */
  396. RCC->CSR |= RCC_CSR_RTCSEL_LSE; /* select LSE */
  397. RCC->CSR |= RCC_CSR_RTCEN; /* enable RTC */
  398. RTC->ISR = RTC_ISR_INIT; /* request RTC stop */
  399. while((RTC->ISR & RTC_ISR_INITF)!=RTC_ISR_INITF) /* wait for stop */
  400. ;
  401. RTC->PRER = 0x07f00ff; /* 1 Hz clock */
  402. RTC->TR = 0;
  403. RTC->ISR =~ RTC_ISR_INIT; /* start RTC */
  404. }
  405. RTC->WPR = 0; /* enable RTC write protection */
  406. RTC->WPR = 0;
  407. __enable_irq();
  408. return r;
  409. }
  410. /*=======================================================================*/
  411. /*
  412. enable RTC wakeup and interrupt
  413. This must be executed after any reset.
  414. */
  415. void startRTCWakeUp(void)
  416. {
  417. /* wake up time setup & start */
  418. __disable_irq();
  419. RTC->WPR = 0x0ca; /* disable RTC write protection */
  420. RTC->WPR = 0x053;
  421. RTC->CR &=~ RTC_CR_WUTE; /* disable wakeup timer for reprogramming */
  422. while((RTC->ISR & RTC_ISR_WUTWF) != RTC_ISR_WUTWF)
  423. ;
  424. RTC->WUTR = WAKEUP_PERIOD; /* wakeup time */
  425. //RTC->WUTR = 0; /* reload is 1: 1Hz with the 1Hz clock */
  426. RTC->CR &= ~RTC_CR_WUCKSEL; /* clear selection register */
  427. RTC->CR |= RTC_CR_WUCKSEL_2; /* select the 1Hz clock */
  428. RTC->CR |= RTC_CR_WUTE | RTC_CR_WUTIE ;
  429. /* clear all the detection flags, not 100% sure whether this is required */
  430. RTC->ISR &= ~RTC_ISR_WUTF;
  431. RTC->ISR &= ~RTC_ISR_TAMP2F;
  432. RTC->ISR &= ~RTC_ISR_TAMP3F;
  433. /* tamper (button) detection */
  434. /* low level, filtered, pullup enabled, IRQ enabled, Sample Freq is 128Hz */
  435. RTC->TAMPCR =
  436. RTC_TAMPCR_TAMP3NOERASE | RTC_TAMPCR_TAMP3IE | RTC_TAMPCR_TAMP3E |
  437. RTC_TAMPCR_TAMP2NOERASE | RTC_TAMPCR_TAMP2IE | RTC_TAMPCR_TAMP2E |
  438. RTC_TAMPCR_TAMPPRCH_0 | RTC_TAMPCR_TAMPFLT_1 | RTC_TAMPCR_TAMPFREQ;
  439. // RTC_TAMPCR_TAMPPUDIS
  440. /* wake up IRQ is connected to line 20 */
  441. EXTI->RTSR |= EXTI_RTSR_RT20; /* rising edge for wake up line */
  442. EXTI->IMR |= EXTI_IMR_IM20; /* interrupt enable */
  443. /* tamper IRQ is connected to line 19 */
  444. EXTI->RTSR |= EXTI_RTSR_RT19; /* rising edge for tamper*/
  445. EXTI->IMR |= EXTI_IMR_IM19; /* interrupt enable */
  446. RTC->WPR = 0; /* disable RTC write protection */
  447. RTC->WPR = 0;
  448. __enable_irq();
  449. }
  450. /* read values from RTC and store the values into the gui_data struct */
  451. void readRTC(void)
  452. {
  453. uint32_t r;
  454. int i;
  455. uint8_t bcd[12];
  456. r = RTC->TR;
  457. i = 0;
  458. do
  459. {
  460. bcd[i] = r & 15;
  461. r >>= 4;
  462. i++;
  463. } while( i < 6 );
  464. bcd[1] &= 7; /* seconds */
  465. bcd[3] &= 7; /* minutes */
  466. bcd[5] &= 3; /* hours */
  467. gui_data.h = bcd[4] + bcd[5]*10;;
  468. gui_data.mt = bcd[3];
  469. gui_data.mo = bcd[2];
  470. gui_data.st = bcd[1];
  471. gui_data.so = bcd[0];
  472. r = RTC->DR;
  473. i = 0;
  474. do
  475. {
  476. bcd[i] = r & 15;
  477. r >>= 4;
  478. i++;
  479. } while( i < 6 );
  480. bcd[1] &= 3; /* days */
  481. bcd[3] &= 1; /* months */
  482. gui_data.day = bcd[0] + bcd[1]*10;
  483. gui_data.month = bcd[2] + bcd[3]*10;
  484. gui_data.year_o = bcd[4];
  485. gui_data.year_t = bcd[5];
  486. gui_date_adjust(); /* calculate weekday */
  487. //gui_Recalculate(); /* this will also store the values back in the backup registers */
  488. }
  489. void enterStandByMode(void)
  490. {
  491. MenuIdleTimer = 0;
  492. if ( DisplayStandbyMode == DISPLAY_STANDBY_MODE_REDUCED )
  493. u8g2_SetContrast(&u8g2, DISPLAY_CONTRAST_REDUCED);
  494. if ( DisplayStandbyMode == DISPLAY_STANDBY_MODE_OFF )
  495. u8g2_SetPowerSave(&u8g2, 1);
  496. SetAlarmSequence(NULL);
  497. GPIOA->MODER &= ~GPIO_MODER_MODE6; /* clear mode for PA6 --> input */
  498. PWR->CR |= PWR_CR_PDDS; /* Power Down Deepsleep */
  499. SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; /* set the cortex M0+ deep sleep flag */
  500. __DSB(); /* finish memory access */
  501. __WFI(); /* enter deep sleep */
  502. __NOP();
  503. }
  504. /*
  505. ch 0..15: GPIO
  506. ch 16: ???
  507. ch 17: vref (bandgap)
  508. ch18: temperature sensor
  509. returns 12 bit result, right aligned
  510. */
  511. uint16_t readADC(uint8_t ch)
  512. {
  513. uint32_t data;
  514. uint32_t i;
  515. __disable_irq();
  516. /* ADC RESET */
  517. RCC->APB2ENR |= RCC_APB2ENR_ADCEN; /* enable ADC clock */
  518. __NOP(); /* let us wait for some time */
  519. __NOP(); /* let us wait for some time */
  520. RCC->APB2RSTR |= RCC_APB2RSTR_ADCRST;
  521. __NOP(); /* let us wait for some time */
  522. __NOP(); /* let us wait for some time */
  523. RCC->APB2RSTR &= ~RCC_APB2RSTR_ADCRST;
  524. __NOP(); /* let us wait for some time */
  525. __NOP(); /* let us wait for some time */
  526. /* Enable some basic parts */
  527. ADC1->IER = 0; /* do not allow any interrupts */
  528. ADC1->CFGR2 &= ~ADC_CFGR2_CKMODE; /* select HSI16 clock */
  529. ADC1->CR |= ADC_CR_ADVREGEN; /* enable ADC voltage regulator, probably not required, because this is automatically activated */
  530. ADC->CCR |= ADC_CCR_VREFEN; /* Wake-up the VREFINT */
  531. ADC->CCR |= ADC_CCR_TSEN; /* Wake-up the temperature sensor */
  532. __NOP(); /* let us wait for some time */
  533. __NOP(); /* let us wait for some time */
  534. /* CALIBRATION */
  535. if ((ADC1->CR & ADC_CR_ADEN) != 0) /* clear ADEN flag if required */
  536. {
  537. ADC1->CR &= (uint32_t)(~ADC_CR_ADEN);
  538. }
  539. ADC1->CR |= ADC_CR_ADCAL; /* start calibration */
  540. while ((ADC1->ISR & ADC_ISR_EOCAL) == 0) /* wait for clibration finished */
  541. {
  542. }
  543. ADC1->ISR |= ADC_ISR_EOCAL; /* clear the status flag, by writing 1 to it */
  544. __NOP(); /* not sure why, but some nop's are required here, at least 4 of them */
  545. __NOP();
  546. __NOP();
  547. __NOP();
  548. __NOP();
  549. __NOP();
  550. /* ENABLE ADC */
  551. ADC1->ISR |= ADC_ISR_ADRDY; /* clear ready flag */
  552. ADC1->CR |= ADC_CR_ADEN; /* enable ADC */
  553. while ((ADC1->ISR & ADC_ISR_ADRDY) == 0) /* wait for ADC */
  554. {
  555. }
  556. //printBits(5, ADC1->ISR );
  557. //printBits(6, ADC1->CR );
  558. /* CONFIGURE ADC */
  559. ADC1->CFGR1 &= ~ADC_CFGR1_EXTEN; /* software enabled conversion start */
  560. ADC1->CFGR1 &= ~ADC_CFGR1_ALIGN; /* right alignment */
  561. ADC1->CFGR1 &= ~ADC_CFGR1_RES; /* 12 bit resolution */
  562. ADC1->CHSELR = 1<<ch; /* Select channel */
  563. ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2; /* Select a sampling mode of 111 (very slow)*/
  564. /* DO CONVERSION */
  565. data = 0;
  566. for( i = 0; i < 8; i++ )
  567. {
  568. ADC1->CR |= ADC_CR_ADSTART; /* start the ADC conversion */
  569. while ((ADC1->ISR & ADC_ISR_EOC) == 0) /* wait end of conversion */
  570. {
  571. }
  572. data += ADC1->DR; /* get ADC result and clear the ISR_EOC flag */
  573. }
  574. data >>= 3;
  575. /* DISABLE ADC */
  576. /* at this point the end of sampling and end of sequence bits are also set in ISR registr */
  577. if ( (ADC1->CR & ADC_CR_ADEN) != 0 )
  578. {
  579. ADC1->CR |= ADC_CR_ADDIS; /* disable ADC... maybe better execute a reset */
  580. while ((ADC1->CR & ADC_CR_ADEN) != 0) /* wait for ADC disable, ADEN is also cleared */
  581. {
  582. }
  583. }
  584. /* DISABLE OTHER PARTS, INCLUDING CLOCK */
  585. ADC->CCR &= ~ADC_CCR_VREFEN; /* disable VREFINT */
  586. ADC->CCR &= ~ADC_CCR_TSEN; /* disable temperature sensor */
  587. ADC1->CR &= ~ADC_CR_ADVREGEN; /* disable ADC voltage regulator */
  588. RCC->APB2ENR &= ~RCC_APB2ENR_ADCEN; /* disable ADC clock */
  589. __enable_irq();
  590. return data;
  591. }
  592. uint16_t getTemperature(void)
  593. {
  594. int16_t y1, y2,x1, x2, t;
  595. int16_t y;
  596. y1 = 30;
  597. x1 = *(uint16_t *)(0x1FF8007A); // 30 degree with 3.0V
  598. x1 *=30;
  599. x1 /=33;
  600. y2 = 110; // AN3964: 110 degree, Datasheet: 130 degree
  601. x2 = *(uint16_t *)(0x1FF8007E); // 130 degree with 3.0V
  602. x2 *=30;
  603. x2 /=33;
  604. t = readADC(18);
  605. y = ( (y2 - y1) * ( t - x1) ) / (x2 - x1) + y1;
  606. return y;
  607. }
  608. uint8_t getBatteryLevels(uint16_t adc, uint16_t cnt)
  609. {
  610. uint16_t levels;
  611. if ( adc < 1233 )
  612. return 0;
  613. adc -= 1233;
  614. levels = (adc*cnt)/(4096-1223);
  615. return levels;
  616. }
  617. void drawBatSymbol(uint16_t adc)
  618. {
  619. u8g2_uint_t w, levels;
  620. w = u8g2_GetDisplayWidth(&u8g2);
  621. u8g2_DrawHLine(&u8g2, w-5, 0, 2);
  622. u8g2_DrawFrame(&u8g2, w-7, 1, 6, 9);
  623. levels = getBatteryLevels(adc, 8);
  624. while( levels > 0 )
  625. {
  626. u8g2_DrawHLine(&u8g2, w-6, 9-levels, 4);
  627. levels--;
  628. }
  629. }
  630. /*=======================================================================*/
  631. int main()
  632. {
  633. int i;
  634. uint16_t adc;
  635. startHSIClock(); /* Increase system clock, must be executed after each reset */
  636. SystemCoreClockUpdate(); /* Update variable SystemCoreClock, must be executed after each reset */
  637. startUp(); /* basic system setup + make a backup of PWR_CSR (PWR_CSR_Backup), must be executed after each reset */
  638. startSysTick(); /* start the sys tick interrupt, must be executed after each reset */
  639. adjustDST(DST_RULE); /* adjust DST... ok,this is only done after reset, hopefully this is often enough. This must be called before readRTC() */
  640. /* LED output line */
  641. GPIOA->MODER &= ~GPIO_MODER_MODE13; /* clear mode for PA13 */
  642. GPIOA->MODER |= GPIO_MODER_MODE13_0; /* Output mode for PA13 */
  643. GPIOA->OTYPER &= ~GPIO_OTYPER_OT_13; /* Push/Pull for PA13 */
  644. GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED13; /* low speed for PA13 */
  645. GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD13; /* no pullup/pulldown for PA13 */
  646. GPIOA->BSRR = GPIO_BSRR_BR_13; /* atomic clr PA13 */
  647. GPIOA->BSRR = GPIO_BSRR_BS_13; /* atomic set PA13 */
  648. /* the lowest two bits of the PWR_CSR reg indicate wake up from standby (bit 1) and WUF als source (bit 0) */
  649. /* both bits are 0 for POR and button reset, both bits are 1 for a wakeup reset */
  650. /* bits | root cause */
  651. /* 00 | POR or NVIC --> perform full setup */
  652. /* 11 | Standby + WUF --> continue with main screen */
  653. /* 01 | NVIC-Reset --> perform full setup */
  654. /* we check bit 1 only */
  655. switch(PWR_CSR_Backup & 3)
  656. {
  657. case 0: /* Power on reset */
  658. ResetReason = RESET_REASON_POR;
  659. break;
  660. case 1: /* reset by NVIC_SystemReset() */
  661. ResetReason = RESET_REASON_NVIC_RESET;
  662. break;
  663. default: /* probably a reset caused by RTC */
  664. /* analyse RTC_ISR register */
  665. if ( RTC->ISR & RTC_ISR_TAMP2F )
  666. ResetReason = RESET_REASON_TAMP2;
  667. else if ( RTC->ISR & RTC_ISR_TAMP3F )
  668. ResetReason = RESET_REASON_TAMP3;
  669. else
  670. ResetReason = RESET_REASON_WUF;
  671. break;
  672. }
  673. if ( ResetReason == RESET_REASON_POR || ResetReason == RESET_REASON_NVIC_RESET )
  674. {
  675. unsigned int r;
  676. /* Power on reset */
  677. r = initRTC();
  678. readRTC();
  679. initDisplay(1); /* init display assumes proper values in gui_data */
  680. if ( r == 0 )
  681. {
  682. u8g2_ClearBuffer(&u8g2);
  683. u8g2_SetFont(&u8g2, MENU_NORMAL_FONT);
  684. u8g2_DrawStr(&u8g2, 0, 15, "No RTC Clock");
  685. u8g2_SendBuffer(&u8g2);
  686. delay_micro_seconds(3000000);
  687. do_reset();
  688. }
  689. /*set a alarm time for testing */
  690. //gui_alarm_list[0].enable = 1;
  691. //gui_alarm_list[0].m = 1;
  692. //gui_alarm_list[0].wd[5] = 1;
  693. gui_Recalculate();
  694. }
  695. else
  696. {
  697. /* Reset caused by wakeup */
  698. /* we probably have to clear the RTC detection flags for WUF and TAMPER */
  699. /* this is done later in startRTCWakeUp() */
  700. readRTC();
  701. /* do a warm start of the display, this means that the display reset is skipped and the init sequence is not sent */
  702. initDisplay(0); /* init display assumes proper values in gui_data, additionally the alarm flag might be set here */
  703. }
  704. if ( DisplayStandbyMode != DISPLAY_STANDYB_MODE_ALWAYS_ON )
  705. {
  706. /* before the RTC is enabled via startRTCWakeUp(), avoid key detection if we are in any other mode than ALWAYS_ON */
  707. if ( ResetReason == RESET_REASON_TAMP2 || ResetReason == RESET_REASON_TAMP3 )
  708. isIgnoreNextKey = 1;
  709. }
  710. startRTCWakeUp(); /* setup wakeup and temper, enable RTC IRQ, probably required after each reset */
  711. NVIC_SetPriority(RTC_IRQn, 0);
  712. NVIC_EnableIRQ(RTC_IRQn);
  713. if ( ResetReason == RESET_REASON_WUF && gui_data.is_alarm == 0 )
  714. {
  715. /* update current time */
  716. u8g2_ClearBuffer(&u8g2);
  717. GPIOA->BSRR = GPIO_BSRR_BR_13; /* atomic set PA13 */
  718. gui_Draw();
  719. GPIOA->BSRR = GPIO_BSRR_BS_13; /* atomic clr PA13 */
  720. u8g2_SendBuffer(&u8g2);
  721. /* go back to sleep mode */
  722. enterStandByMode();
  723. }
  724. /* turn on display now */
  725. u8g2_SetPowerSave(&u8g2, 0); /* not required for the ALWAYS_ON mode, but does not matter in the other modes */
  726. //u8g2_SetContrast(&u8g2, DISPLAY_CONTRAST_NORMAL);
  727. set_contrast();
  728. /* get current voltage level of the battery */
  729. adc = readADC(5);
  730. /* start user loop */
  731. for(;;)
  732. {
  733. if ( RTCUpdateCount == 0 )
  734. {
  735. if ( gui_menu.me_list == melist_display_time )
  736. {
  737. readRTC();
  738. gui_SignalTimeChange();
  739. }
  740. else
  741. {
  742. //readRTC();
  743. //gui_Recalculate();
  744. }
  745. RTCUpdateCount = 10; // update every 10 systicks (half second)
  746. }
  747. for(;;)
  748. {
  749. i = key_get();
  750. if ( i == KEY_NONE )
  751. break;
  752. if ( i == KEY_SELECT )
  753. gui_Select();
  754. if ( i == KEY_NEXT )
  755. gui_Next();
  756. }
  757. u8g2_ClearBuffer(&u8g2);
  758. GPIOA->BSRR = GPIO_BSRR_BR_13; /* atomic set PA13 */
  759. gui_Draw();
  760. if ( gui_menu.me_list == melist_display_time )
  761. {
  762. u8g2_SetFont(&u8g2, MENU_NORMAL_FONT);
  763. if ( gui_data.display_voltage )
  764. u8g2_DrawStr(&u8g2, 0, 8, u8x8_u16toa((adc*330UL)>>12, 3));
  765. drawBatSymbol(adc);
  766. }
  767. GPIOA->BSRR = GPIO_BSRR_BS_13; /* atomic clr PA13 */
  768. u8g2_SendBuffer(&u8g2);
  769. if ( MenuIdleTimer > MENU_IDLE_SYSTICK_TIMEOUT )
  770. {
  771. if ( gui_data.is_equal == 0 ) // idea is, that the alarm does not go off during the alarm to avoid another alarm in the same minute
  772. {
  773. if ( gui_menu.me_list != melist_display_time )
  774. {
  775. /* jump back to the display menu and redraw the time. not sure if this is required */
  776. menu_SetMEList(&gui_menu, melist_display_time, 0);
  777. readRTC();
  778. gui_SignalTimeChange();
  779. u8g2_ClearBuffer(&u8g2);
  780. gui_Draw();
  781. u8g2_SetFont(&u8g2, MENU_NORMAL_FONT);
  782. u8g2_DrawStr(&u8g2, 0, 8, u8x8_u16toa((adc*330UL)>>12, 3));
  783. drawBatSymbol(adc);
  784. u8g2_SendBuffer(&u8g2);
  785. }
  786. /* stop everything except RTC */
  787. enterStandByMode();
  788. }
  789. else
  790. {
  791. /* read and recalculate so that the gui_data.is_equal is updated */
  792. readRTC();
  793. gui_Recalculate();
  794. }
  795. }
  796. __DSB(); /* finish memory access */
  797. __WFI(); /* enter sleep */
  798. __NOP();
  799. }
  800. }