@@ -372,9 +372,123 @@ mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
372372}
373373MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (pyb_rtc_datetime_obj , 1 , 2 , pyb_rtc_datetime );
374374
375+ // wakeup(None)
376+ // wakeup(ms, callback=None)
377+ // wakeup(wucksel, wut, callback)
378+ mp_obj_t pyb_rtc_wakeup (mp_uint_t n_args , const mp_obj_t * args ) {
379+ // wut is wakeup counter start value, wucksel is clock source
380+ // counter is decremented at wucksel rate, and wakes the MCU when it gets to 0
381+ // wucksel=0b000 is RTC/16 (RTC runs at 32768Hz)
382+ // wucksel=0b001 is RTC/8
383+ // wucksel=0b010 is RTC/4
384+ // wucksel=0b011 is RTC/2
385+ // wucksel=0b100 is 1Hz clock
386+ // wucksel=0b110 is 1Hz clock with 0x10000 added to wut
387+ // so a 1 second wakeup could be wut=2047, wucksel=0b000, or wut=4095, wucksel=0b001, etc
388+
389+ // disable wakeup IRQ while we configure it
390+ HAL_NVIC_DisableIRQ (RTC_WKUP_IRQn );
391+
392+ bool enable = false;
393+ mp_int_t wucksel ;
394+ mp_int_t wut ;
395+ mp_obj_t callback = mp_const_none ;
396+ if (n_args <= 3 ) {
397+ if (args [1 ] == mp_const_none ) {
398+ // disable wakeup
399+ } else {
400+ // time given in ms
401+ mp_int_t ms = mp_obj_get_int (args [1 ]);
402+ mp_int_t div = 2 ;
403+ wucksel = 3 ;
404+ while (div <= 16 && ms > 2000 * div ) {
405+ div *= 2 ;
406+ wucksel -= 1 ;
407+ }
408+ if (div <= 16 ) {
409+ wut = 32768 / div * ms / 1000 ;
410+ } else {
411+ wucksel = 4 ;
412+ wut = ms / 1000 ;
413+ if (ms > 0x10000 ) {
414+ wucksel = 5 ;
415+ ms -= 0x10000 ;
416+ if (ms > 0x10000 ) {
417+ nlr_raise (mp_obj_new_exception_msg (& mp_type_ValueError , "wakeup value too large" ));
418+ }
419+ }
420+ }
421+ wut -= 1 ;
422+ enable = true;
423+ }
424+ if (n_args == 3 ) {
425+ callback = args [2 ];
426+ }
427+ } else {
428+ // config values given directly
429+ wucksel = mp_obj_get_int (args [1 ]);
430+ wut = mp_obj_get_int (args [2 ]);
431+ callback = args [3 ];
432+ enable = true;
433+ }
434+
435+ // set the callback
436+ MP_STATE_PORT (pyb_extint_callback )[22 ] = callback ;
437+
438+ // disable register write protection
439+ RTC -> WPR = 0xca ;
440+ RTC -> WPR = 0x53 ;
441+
442+ // clear WUTE
443+ RTC -> CR &= ~(1 << 10 );
444+
445+ // wait until WUTWF is set
446+ while (!(RTC -> ISR & (1 << 2 ))) {
447+ }
448+
449+ if (enable ) {
450+ // program WUT
451+ RTC -> WUTR = wut ;
452+
453+ // set WUTIE to enable wakeup interrupts
454+ // set WUTE to enable wakeup
455+ // program WUCKSEL
456+ RTC -> CR |= (1 << 14 ) | (1 << 10 ) | (wucksel & 7 );
457+
458+ // enable register write protection
459+ RTC -> WPR = 0xff ;
460+
461+ // enable external interrupts on line 22
462+ EXTI -> IMR |= 1 << 22 ;
463+ EXTI -> RTSR |= 1 << 22 ;
464+
465+ // clear interrupt flags
466+ RTC -> ISR &= ~(1 << 10 );
467+ EXTI -> PR = 1 << 22 ;
468+
469+ HAL_NVIC_SetPriority (RTC_WKUP_IRQn , 0x0f , 0x0f );
470+ HAL_NVIC_EnableIRQ (RTC_WKUP_IRQn );
471+
472+ //printf("wut=%d wucksel=%d\n", wut, wucksel);
473+ } else {
474+ // clear WUTIE to disable interrupts
475+ RTC -> CR &= ~(1 << 14 );
476+
477+ // enable register write protection
478+ RTC -> WPR = 0xff ;
479+
480+ // disable external interrupts on line 22
481+ EXTI -> IMR &= ~(1 << 22 );
482+ }
483+
484+ return mp_const_none ;
485+ }
486+ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (pyb_rtc_wakeup_obj , 2 , 4 , pyb_rtc_wakeup );
487+
375488STATIC const mp_map_elem_t pyb_rtc_locals_dict_table [] = {
376489 { MP_OBJ_NEW_QSTR (MP_QSTR_info ), (mp_obj_t )& pyb_rtc_info_obj },
377490 { MP_OBJ_NEW_QSTR (MP_QSTR_datetime ), (mp_obj_t )& pyb_rtc_datetime_obj },
491+ { MP_OBJ_NEW_QSTR (MP_QSTR_wakeup ), (mp_obj_t )& pyb_rtc_wakeup_obj },
378492};
379493STATIC MP_DEFINE_CONST_DICT (pyb_rtc_locals_dict , pyb_rtc_locals_dict_table );
380494
0 commit comments