Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpu/saml21: add interaction with pm_layered for peripheral drivers #18821

Merged
merged 10 commits into from
Nov 7, 2022

Conversation

jue89
Copy link
Contributor

@jue89 jue89 commented Oct 29, 2022

Contribution description

Currently, RIOT just runs with by-default blocked power modes. This PR changes this for the saml21 family: All peripheral drivers now block and unblock pm modes depending on whether they are used or nor. In combination with #17607 this will get us near to seamless power management

Current state of this PR:

  • periph_timer
  • periph_uart
  • periph_gpio
  • periph_usbdev
  • periph_rtc
  • periph_rtt
  • periph_spi (DMA transfers ...)

Affected boards (using saml21):

  • bastwan
  • saml21-xpro
  • samr30-xpro
  • samr34-xpro
  • yarm

Testing procedure

periph_timer

Flash test/periph_timer on a saml21 board:

make -C tests/periph_timer BOARD=samr30-xpro flash term
2022-10-31 22:43:18,356 # Help: Press s to start test, r to print it is ready
s
2022-10-31 22:43:20,390 # START
2022-10-31 22:43:20,397 # main(): This is RIOT! (Version: 2023.01-devel-225-gd564e-feature/saml21_pheriph_pm)
2022-10-31 22:43:20,397 # 
2022-10-31 22:43:20,399 # Test for peripheral TIMERs
2022-10-31 22:43:20,399 # 
2022-10-31 22:43:20,401 # Available timers: 1
2022-10-31 22:43:20,401 # 
2022-10-31 22:43:20,403 # Testing TIMER_0:
2022-10-31 22:43:20,405 # [pm_layered] pm_block(1)
(STANDBY has been blocked by timer_init)
2022-10-31 22:43:20,408 # TIMER_0: initialization successful
2022-10-31 22:43:20,411 # [pm_layered] pm_unblock(1)
(STANDBY has been unblocked by timer_stop)
2022-10-31 22:43:20,412 # TIMER_0: stopped
2022-10-31 22:43:20,415 # TIMER_0: set channel 0 to 5000
2022-10-31 22:43:20,418 # TIMER_0: set channel 1 to 10000
2022-10-31 22:43:20,420 # TIMER_0: starting
2022-10-31 22:43:20,422 # [pm_layered] pm_block(1)
(STANDBY has been unblocked by timer_start)
2022-10-31 22:43:20,438 # TIMER_0: channel 0 fired at SW count    24003 - init:    24003
2022-10-31 22:43:20,443 # TIMER_0: channel 1 fired at SW count    47984 - diff:    23981
2022-10-31 22:43:20,443 # 
2022-10-31 22:43:20,445 # TEST SUCCEEDED
2022-10-31 22:43:20,451 # { "threads": [{ "name": "main", "stack_size": 1536, "stack_used": 492 }]}

periph_gpio

Flash test/periph_gpio on a saml21 board:

2022-10-31 22:34:54,582 # main(): This is RIOT! (Version: 2023.01-devel-225-gd564e-feature/saml21_pheriph_pm)
2022-10-31 22:34:54,584 # GPIO peripheral driver test
2022-10-31 22:34:54,584 # 
2022-10-31 22:34:54,590 # In this test, pins are specified by integer port and pin numbers.
2022-10-31 22:34:54,596 # So if your platform has a pin PA01, it will be port=0 and pin=1,
2022-10-31 22:34:54,599 # PC14 would be port=2 and pin=14 etc.
2022-10-31 22:34:54,599 # 
2022-10-31 22:34:54,604 # NOTE: make sure the values you use exist on your platform! The
2022-10-31 22:34:54,610 #       behavior for not existing ports/pins is not defined!
> pm show
2022-10-31 22:35:06,747 # pm show
2022-10-31 22:35:06,749 # mode 0 blockers: 0 
2022-10-31 22:35:06,751 # mode 1 blockers: 2     (one blocker from periph_timer used by ztimer and periph_uart used by stdio)
2022-10-31 22:35:06,753 # mode 2 blockers: 0 
2022-10-31 22:35:06,755 # Lowest allowed mode: 2
> init_int 0 28 0 1
2022-10-31 22:37:34,359 # init_int 0 28 0 1
2022-10-31 22:37:34,364 # GPIO_PIN(0, 28) successfully initialized as ext int
> pm show
2022-10-31 22:37:38,150 # pm show
2022-10-31 22:37:38,152 # mode 0 blockers: 1     (init_int added one blocker)   
2022-10-31 22:37:38,154 # mode 1 blockers: 2
2022-10-31 22:37:38,156 # mode 2 blockers: 0 
2022-10-31 22:37:38,158 # Lowest allowed mode: 2
> init_int 0 28 0 1
2022-10-31 22:37:57,024 # init_int 0 28 0 1
2022-10-31 22:37:57,027 # INT: external interrupt from pin 28
2022-10-31 22:37:57,032 # GPIO_PIN(0, 28) successfully initialized as ext int
> pm show
2022-10-31 22:38:00,304 # pm show
2022-10-31 22:38:00,305 # mode 0 blockers: 1     (second init didn't added a second blocker!)   
2022-10-31 22:38:00,307 # mode 1 blockers: 2 
2022-10-31 22:38:00,309 # mode 2 blockers: 0 
2022-10-31 22:38:00,311 # Lowest allowed mode: 2
> enable_int 0 28 0
2022-10-31 22:39:49,058 # enable_int 0 28 0
2022-10-31 22:39:49,061 # disabling GPIO interrupt
> pm show
2022-10-31 22:39:53,106 # pm show
2022-10-31 22:39:53,108 # mode 0 blockers: 0     (blocker removed)  
2022-10-31 22:39:53,110 # mode 1 blockers: 2 
2022-10-31 22:39:53,111 # mode 2 blockers: 0 
2022-10-31 22:39:53,113 # Lowest allowed mode: 2
> enable_int 0 28 0
2022-10-31 22:40:21,355 # enable_int 0 28 0
2022-10-31 22:40:21,357 # disabling GPIO interrupt
> pm show
2022-10-31 22:40:24,890 # pm show
2022-10-31 22:40:24,892 # mode 0 blockers: 0     (second call hasn't changed anything)  
2022-10-31 22:40:24,894 # mode 1 blockers: 2 
2022-10-31 22:40:24,896 # mode 2 blockers: 0 
2022-10-31 22:40:24,898 # Lowest allowed mode: 2
> enable_int 0 28 1
2022-10-31 22:40:51,460 # enable_int 0 28 1
2022-10-31 22:40:51,463 # enabling GPIO interrupt
> pm show
2022-10-31 22:40:56,635 # pm show
2022-10-31 22:40:56,637 # mode 0 blockers: 1     (re-enabling ints added one blocker)
2022-10-31 22:40:56,638 # mode 1 blockers: 2 
2022-10-31 22:40:56,640 # mode 2 blockers: 0 
2022-10-31 22:40:56,642 # Lowest allowed mode: 2
> enable_int 0 28 1
2022-10-31 22:41:30,373 # enable_int 0 28 1
2022-10-31 22:41:30,375 # enabling GPIO interrupt
> pm show
2022-10-31 22:41:32,411 # pm show
2022-10-31 22:41:32,413 # mode 0 blockers: 1     (no further blockers are added)
2022-10-31 22:41:32,415 # mode 1 blockers: 2 
2022-10-31 22:41:32,417 # mode 2 blockers: 0 
2022-10-31 22:41:32,419 # Lowest allowed mode: 2

periph_usbdev

Flash tests/usbus_cdc_ecm on a saml21 board:

make -C tests/usbus_cdc_ecm BOARD=samr30-xpro flash term
2022-10-31 22:47:04,378 # [pm_layered] pm_block(1)
(timer_init called by ztimer)
2022-10-31 22:47:04,381 # [pm_layered] pm_block(0)
2022-10-31 22:47:04,384 # [pm_layered] pm_block(1)
(blocked by _usbdev_init)
2022-10-31 22:47:04,386 # [pm_layered] pm_unblock(1)
(unblocked because no USB cable is connceted)
2022-10-31 22:47:04,395 # main(): This is RIOT! (Version: 2023.01-devel-225-gd564e-feature/saml21_pheriph_pm)
2022-10-31 22:47:04,399 # Test application for the USBUS CDC ECM interface
2022-10-31 22:47:04,399 # 
2022-10-31 22:47:04,405 # This test pulls in parts of the GNRC network stack, use the
2022-10-31 22:47:04,410 # provided shell commands (i.e. ifconfig, ping) to interact with
2022-10-31 22:47:04,413 # the CDC ECM based network interface.
2022-10-31 22:47:04,413 # 
2022-10-31 22:47:04,416 # Starting the shell now...
> pm show
2022-10-31 22:47:15,339 # pm show
2022-10-31 22:47:15,341 # mode 0 blockers: 1 
2022-10-31 22:47:15,343 # mode 1 blockers: 2 
2022-10-31 22:47:15,344 # mode 2 blockers: 0 
2022-10-31 22:47:15,346 # Lowest allowed mode: 2
(connect USB cable)
2022-10-31 22:49:20,413 # [pm_layered] pm_block(1)
2022-10-31 22:49:20,417 # [pm_layered] pm_unblock(1)
2022-10-31 22:49:20,558 # [pm_layered] pm_block(1)
(Ethernet devices shows up on USB host)
> pm show
2022-10-31 22:50:17,422 # pm show
2022-10-31 22:50:17,424 # mode 0 blockers: 1 
2022-10-31 22:50:17,426 # mode 1 blockers: 3 
2022-10-31 22:50:17,428 # mode 2 blockers: 0 
2022-10-31 22:50:17,430 # Lowest allowed mode: 2
(disconnect USB cable)
2022-10-31 22:50:36,785 # [pm_layered] pm_unblock(1)

periph_uart

Flash tests/periph_uart on the samr30-xpro board:

Changes to the periph_conf.h:

diff --git a/boards/samr30-xpro/include/periph_conf.h b/boards/samr30-xpro/include/periph_conf.h
index dfa9f624dd..47ef6f3018 100644
--- a/boards/samr30-xpro/include/periph_conf.h
+++ b/boards/samr30-xpro/include/periph_conf.h
@@ -70,11 +70,22 @@ static const uart_conf_t uart_config[] = {
         .tx_pad   = UART_PAD_TX_0,
         .flags    = UART_FLAG_NONE,
         .gclk_src = SAM0_GCLK_MAIN,
+    },
+    {    /* EXT1 & EXT3 Pin Header */
+        .dev      = &(SERCOM5->USART),
+        .rx_pin   = GPIO_PIN(PB, 3),
+        .tx_pin   = GPIO_PIN(PB, 22),
+        .mux      = GPIO_MUX_D,
+        .rx_pad   = UART_PAD_RX_1,
+        .tx_pad   = UART_PAD_TX_2,
+        .flags    = UART_FLAG_NONE,
+        .gclk_src = SAM0_GCLK_MAIN,
     }
 };
 
 /* interrupt function name mapping */
 #define UART_0_ISR          isr_sercom0
+#define UART_1_ISR          isr_sercom5
 
 #define UART_NUMOF          ARRAY_SIZE(uart_config)
 /** @} */
@@ -100,23 +111,6 @@ static const spi_conf_t spi_config[] = {
         .rx_trigger = SERCOM4_DMAC_ID_RX,
 #endif
     },
-    {    /* EXT1 & EXT3 Pin Header */
-        .dev      = &(SERCOM5->SPI),
-        .miso_pin = GPIO_PIN(PB, 2),
-        .mosi_pin = GPIO_PIN(PB, 22),
-        .clk_pin  = GPIO_PIN(PB, 23),
-        .miso_mux = GPIO_MUX_D,
-        .mosi_mux = GPIO_MUX_D,
-        .clk_mux  = GPIO_MUX_D,
-        .miso_pad = SPI_PAD_MISO_0,
-        .mosi_pad = SPI_PAD_MOSI_2_SCK_3,
-        .gclk_src = SAM0_GCLK_MAIN,
-#ifdef MODULE_PERIPH_DMA
-        /* The SAML21 doesn't support DMA triggers on SERCOM5 */
-        .tx_trigger = DMA_TRIGGER_DISABLED,
-        .rx_trigger = DMA_TRIGGER_DISABLED,
-#endif
-    }
 };
 
 #define SPI_NUMOF           ARRAY_SIZE(spi_config)

Bridge PB03 + PB22.

make -C tests/periph_uart BOARD=samr30-xpro flash term
> init 1 115200
2022-11-01 23:45:41,625 # init 1 115200
2022-11-01 23:45:41,627 # [pm_layered] pm_block(1)
2022-11-01 23:45:41,632 # Success: Initialized UART_DEV(1) at BAUD 115200
2022-11-01 23:45:41,639 # UARD_DEV(1): test uart_poweron() and uart_poweroff()  ->  [pm_layered] pm_unblock(1)
2022-11-01 23:45:41,892 # [pm_layered] pm_block(1)
2022-11-01 23:45:41,892 # [OK]
> init 1 115200
2022-11-01 23:45:43,721 # init 1 115200
2022-11-01 23:45:43,724 # [pm_layered] pm_unblock(1)
2022-11-01 23:45:43,726 # [pm_layered] pm_block(1)
2022-11-01 23:45:43,730 # Success: Initialized UART_DEV(1) at BAUD 115200
2022-11-01 23:45:43,738 # UARD_DEV(1): test uart_poweron() and uart_poweroff()  ->  [pm_layered] pm_unblock(1)
2022-11-01 23:45:43,990 # [pm_layered] pm_block(1)
2022-11-01 23:45:43,991 # [OK]
(Second init unblock STANDBY mode ...)
> test 1
2022-11-01 23:46:20,138 # test 1
2022-11-01 23:46:20,139 # [START]
2022-11-01 23:46:20,141 # [pm_layered] pm_unblock(1)
2022-11-01 23:46:20,143 # [pm_layered] pm_block(1)
2022-11-01 23:46:20,183 # [pm_layered] pm_unblock(1)
2022-11-01 23:46:20,186 # [pm_layered] pm_block(1)
2022-11-01 23:46:20,207 # [pm_layered] pm_unblock(1)
2022-11-01 23:46:20,209 # [pm_layered] pm_block(1)
2022-11-01 23:46:20,224 # [pm_layered] pm_unblock(1)
2022-11-01 23:46:20,226 # [pm_layered] pm_block(1)
2022-11-01 23:46:20,238 # [pm_layered] pm_unblock(1)
2022-11-01 23:46:20,241 # [pm_layered] pm_block(1)
2022-11-01 23:46:20,251 # [pm_layered] pm_unblock(1)
2022-11-01 23:46:20,253 # [pm_layered] pm_block(1)
2022-11-01 23:46:20,262 # [pm_layered] pm_unblock(1)
2022-11-01 23:46:20,264 # [pm_layered] pm_block(1)
2022-11-01 23:46:20,272 # [pm_layered] pm_unblock(1)
2022-11-01 23:46:20,274 # [pm_layered] pm_block(1)
2022-11-01 23:46:20,281 # [pm_layered] pm_unblock(1)
2022-11-01 23:46:20,283 # [pm_layered] pm_block(1)
2022-11-01 23:46:20,290 # [pm_layered] pm_unblock(1)
2022-11-01 23:46:20,292 # [pm_layered] pm_block(1)
2022-11-01 23:46:20,299 # [pm_layered] pm_unblock(1)
2022-11-01 23:46:20,301 # [pm_layered] pm_block(1)
2022-11-01 23:46:20,307 # [pm_layered] pm_unblock(1)
2022-11-01 23:46:20,309 # [pm_layered] pm_block(1)
2022-11-01 23:46:20,313 # [SUCCESS]
(Switching baud rates caused 12 pm_unblock/pm_block pairs)

periph_spi

Flash tests/periph_spi with DMA support on the samr30-xpro board:

USEMODULE=periph_dma make -C tests/periph_spi BOARD=samr30-xpro flash term
2022-11-02 00:00:27,823 # [pm_layered] pm_block(0)
2022-11-02 00:00:27,825 # [pm_layered] pm_block(1)
2022-11-02 00:00:27,833 # main(): This is RIOT! (Version: 2023.01-devel-241-ge2c7b-feature/saml21_pheriph_pm)
2022-11-02 00:00:27,838 # Manual SPI peripheral driver test (see README.md)
2022-11-02 00:00:27,842 # There are 2 SPI devices configured for your platform.
> init 0 0 2 2 0
2022-11-02 00:00:35,171 # init 0 0 2 2 0
2022-11-02 00:00:35,178 # Trying to initialize SPI_DEV(0): mode: 0, clk: 2, cs_port: 2, cs_pin: 0
2022-11-02 00:00:35,183 # Note: Failed assertion (crash) means configuration not supported
> send HELLOWORLDHELLOWORLD
2022-11-02 00:00:40,525 # send HELLOWORLDHELLOWORLD
2022-11-02 00:00:40,527 # [pm_layered] pm_block(1)
2022-11-02 00:00:40,530 # [pm_layered] pm_unblock(1)
2022-11-02 00:00:40,531 # Sent bytes
2022-11-02 00:00:40,541 #    0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   19 
2022-11-02 00:00:40,550 #   0x48 0x45 0x4c 0x4c 0x4f 0x57 0x4f 0x52 0x4c 0x44 0x48 0x45 0x4c 0x4c 0x4f 0x57 0x4f 0x52 0x4c 0x44
2022-11-02 00:00:40,560 #     H    E    L    L    O    W    O    R    L    D    H    E    L    L    O    W    O    R    L    D 
2022-11-02 00:00:40,560 # 
2022-11-02 00:00:40,561 # Received bytes
2022-11-02 00:00:40,571 #    0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   19 
2022-11-02 00:00:40,581 #   0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
2022-11-02 00:00:40,590 #    ??   ??   ??   ??   ??   ??   ??   ??   ??   ??   ??   ??   ??   ??   ??   ??   ??   ??   ??   ?? 
2022-11-02 00:00:40,590 # 
> pm show
2022-11-02 00:02:09,843 # pm show
2022-11-02 00:02:09,845 # mode 0 blockers: 1 (periph_rtt (used by ztimer_sec))
2022-11-02 00:02:09,846 # mode 1 blockers: 2 (periph_uart + periph_timer (used by ztimer_uec))
2022-11-02 00:02:09,848 # mode 2 blockers: 0 
2022-11-02 00:02:09,850 # Lowest allowed mode: 2

Issues/PRs references

My talk from the last RIOT summit: https://www.youtube.com/watch?v=N2etFVR5mfg

Waiting for #18825

@jue89 jue89 added Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet Area: pm Area: (Low) power management Area: cpu Area: CPU/MCU ports labels Oct 29, 2022
@github-actions github-actions bot added Area: sys Area: System Platform: ARM Platform: This PR/issue effects ARM-based platforms labels Oct 29, 2022
@jue89
Copy link
Contributor Author

jue89 commented Oct 29, 2022

@benpicco I touched your periph_usbdev interaction with pm_layered ... maybe you can test if i broke the samd21 cpu?

@jue89 jue89 added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Oct 29, 2022
@riot-ci
Copy link

riot-ci commented Oct 29, 2022

Murdock results

✔️ PASSED

73e6886 cpu/saml21: define required power modes

Success Failures Total Runtime
2000 0 2000 06m:21s

Artifacts

This only reflects a subset of all builds from https://ci-prod.riot-os.org. Please refer to https://ci.riot-os.org for a complete build for now.

@benpicco
Copy link
Contributor

Will test!

btw, I don't think DMA transfers are a problem as the API is still blocking.
When spi_transfer_bytes() returns you can be sure that no SPI/DMA operation is ongoing anymore.

@jue89
Copy link
Contributor Author

jue89 commented Oct 29, 2022

btw, I don't think DMA transfers are a problem as the API is still blocking.
When spi_transfer_bytes() returns you can be sure that no SPI/DMA operation is ongoing anymore.

The thread calling spi_transfer_bytes() is blocked by a mutex, which is unlocked once DMA finishes. I'd say, we need to block pm modes here, as well. It's already interacting with pm_layered for the samd21.

@jue89
Copy link
Contributor Author

jue89 commented Oct 29, 2022

SPI in DMA mode is done, as well.

Maybe it's a good idea to split off the pm-related stuff in a separate PR? (I.e. defining saml21 power modes and fixing blocking the IDLE mode.)

@jue89 jue89 added State: waiting for other PR State: The PR requires another PR to be merged first and removed State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet labels Oct 31, 2022
@jue89 jue89 marked this pull request as ready for review October 31, 2022 21:56
@benpicco benpicco removed the State: waiting for other PR State: The PR requires another PR to be merged first label Oct 31, 2022
@github-actions github-actions bot removed the Area: sys Area: System label Nov 1, 2022
@jue89
Copy link
Contributor Author

jue89 commented Nov 1, 2022

I'd say this one ready to be reviewed. #18825 is merged and I rebased this one on master.

One question: When to block IRQs? I'm not sure. Most periph driver don't block any IRQs and trust they are used by just one thread. But I don't know if this assumption is correct. Especially the gpio driver might be used by several threads.

cpu/sam0_common/periph/gpio.c Outdated Show resolved Hide resolved
cpu/sam0_common/periph/rtc_rtt.c Outdated Show resolved Hide resolved
cpu/saml21/include/periph_cpu.h Show resolved Hide resolved
cpu/sam0_common/periph/uart.c Outdated Show resolved Hide resolved
cpu/sam0_common/periph/rtc_rtt.c Outdated Show resolved Hide resolved
@jue89 jue89 removed the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Nov 1, 2022
@jue89
Copy link
Contributor Author

jue89 commented Nov 1, 2022

Shall we block this PR until the discussion @kfessel brought up in #17607 is resolved?

If this gets merged, ztimer is forced to start/stop timers to gain power savings ... stalling them silently isn't possible anymore, which is currently abused by ztimer.

Just to recap:

  • The ztimer_ondemand feature will make ztimer turning timers on and off regularly if no ztimer_t are runnning or the user indicated that clocks shouldn't be turned off.
  • timer_start()/timer_stop() on the saml21 cpu take ~1us each without this PR. With this PR its ~2us each.
  • timer_start()/timer_stop() on the efr32xg23 cpu take ~2.5us and implements the same pattern like this PR.

@jue89 jue89 added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Nov 1, 2022
* @{
*/
#define SAM0_GPIO_PM_BLOCK SAML21_PM_MODE_BACKUP /**< GPIO IRQs require STANDBY mode */
#define SAM0_RTCRTT_PM_BLOCK SAML21_PM_MODE_BACKUP /**< RTC/TRR require STANDBY mode */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure the RTT/RTC is always on as it can be used to wake from BACKUP sleep

The Backup Power Domain (PDBACKUP) is always on, except in the off sleep mode. It contains the 32KHz oscillator sources, the Supply Controller, the Reset Controller, the Real Time Counter, and the Power Manager itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, right. But we're loosing context. Callback functions are never called, then ;-)

Maybe we can work with two cases:

  1. A callback function has been specified (i.e. nun-NULL) with the rtt_set_overflow_cb(), rtt_set_arlarm(), rtc_set_alarm(). -> Block BACKUP
  2. No callback function he been specified -> Don't block a power state at all.

Would that fit your use case?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes of course.
But doesn't that mean BACKUP mode should never be entered automatically by pm_layered as we always lose all state there - it can only be entered explicitly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If everything is setup correctly, BACKUP will be blocked by some peripherals. We don't need the default-blocked here ... I would say this is already the case?!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if BACKUP must always be blocked, why add code to the drivers to block it and not just block it by default?

Copy link
Contributor

@benpicco benpicco Nov 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tell the GPIO driver to stop listening for IRQs. And the RTC driver is also turned off.

But then how are you going to wake up from Deep Sleep?
Maybe we need an additional API function for that. For the GPIO driver we could have gpio_init_wake(pin, …) and for the RTC/RTT driver we could have rtx_set_wakeup(offset)?

The former would certainly be cleaner than the current approach where if gpio_init_int() is called on a pin that is capable of waking the system from Deep Sleep, it will just configure it to do so. (The advantage of this approach was that it required no driver change, if you connect your accelerometer to a wake pin and set the threshold even, it would just wake you up from Deep Sleep without the need to configure anything).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see ... yeah, we need the RTC ;-)

The correct way to do it (code size optimization out of the way) is to block and unblock in the rtx_set_alarm() / rtx_clear_alarm() resp. rtt_set_overflow_cb() / rtt_clear_overflow_cb() method and have a dedicated rtx_set_wakeup() method, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

39bf4a2 tries to demonstrate that. The RTC/RTT driver is kinda crowded ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ROM size for tests/periph_rtc on the samr30-xpro:

# Driver from current master copied in place
   text	   data	    bss	    dec	    hex	filename
  13836	    160	   2316	  16312	   3fb8	/home/jue/Projects/ssv/RIOT/tests/periph_rtc/bin/samr30-xpro/tests_periph_rtc.elf

# With SAM0_RTCRTT_PM_BLOCK undefined (i.e. no pm in this driver)
   text	   data	    bss	    dec	    hex	filename
  13836	    160	   2316	  16312	   3fb8	/home/jue/Projects/ssv/RIOT/tests/periph_rtc/bin/samr30-xpro/tests_periph_rtc.elf

# With SAM0_RTCRTT_PM_BLOCK defined
   text	   data	    bss	    dec	    hex	filename
  13928	    160	   2316	  16404	   4014	/home/jue/Projects/ssv/RIOT/tests/periph_rtc/bin/samr30-xpro/tests_periph_rtc.elf

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding gpio_init_int vs. wake-up. I'd prefer to have a special gpio_wake_enable() / gpio_wake_disable() interface. It's a special feature that boards/cpus may provide. This separation would give users the option to opt-out. On top we can do proper power management ;-)

What do you think?

@jue89
Copy link
Contributor Author

jue89 commented Nov 3, 2022

May I squash? All those fixup commits become hard to handle ;-)

@benpicco
Copy link
Contributor

benpicco commented Nov 3, 2022

Sure, go ahead with squashing

Otherwise we get stuck in an endless loop ...
periph_cpu.h should define the required pm modes.
Additionally, some CPUs require a certain pm mode in USB IDLE mode.
Due to the RIOT_EPOCH of 2020 this overflow will happen in year 2084. It would be scary if IoT devices are still around then.

We can save RAM and ROM. Furthermore, this overflow handling should block BACKUP power mode in order to keep track of the reference year.
In DMA mode SPI transfers are carried out by HW. We need to block certain pm modes during transfer.
We can get rid initially blocked pm modes \o/
@benpicco
Copy link
Contributor

benpicco commented Nov 3, 2022

I can confirm that USB still works on samr21-xpro.

Copy link
Contributor

@benpicco benpicco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.
I don't quite sure about the ramifications this will have, but efm32 seems to be a good canary.

I'll give this a try on our saml21 based sensor/app just to see if things crash & burn horribly (but since we use ztimer_no_periph_rtt probably nothing will change).

@jue89
Copy link
Contributor Author

jue89 commented Nov 4, 2022

Thank you a lot for your effort looking into this and all the valuable input! It improved the implementation significantly, especially the RTC/RTT part.

Do you want to try this out on your sensors before we merge? Or shall we merge and fix problems later - if they occur?

@kfessel
Copy link
Contributor

kfessel commented Nov 4, 2022

Shall we block this PR until the discussion @kfessel brought up in #17607 is resolved?

No (this one is right from my pov)

I think timer_start and stop doing pm_block / unblock is good (this PR) (this does not block irq for 2us but 2x1us)

But i don't think ztimer should stop the timer (the other PR) if it does not care if the timer is running in background-> just do pm in ztimer

@jue89
Copy link
Contributor Author

jue89 commented Nov 4, 2022

Last test on our sensor with samr30 cpu:

make -C examples/gnrc_networking -j8 BOARD=samr30-xpro flash term
2022-11-04 14:01:24,948 # main(): This is RIOT! (Version: 2023.01-devel-231-g73e68-feature/saml21_pheriph_pm)
2022-11-04 14:01:24,952 # RIOT network stack example application
2022-11-04 14:01:24,954 # All up, running the shell now
> pm show
2022-11-04 14:01:27,791 # pm show
2022-11-04 14:01:27,793 # mode 0 blockers: 2    (periph_gpio IRQ + periph_rtt)
2022-11-04 14:01:27,853 # mode 1 blockers: 2    (periph_uart + periph_timer)
2022-11-04 14:01:27,854 # mode 2 blockers: 0 
2022-11-04 14:01:27,854 # Lowest allowed mode: 2
> ping6 ff02::1
2022-11-04 14:01:44,512 # ping6 ff02::1
2022-11-04 14:01:44,543 # 12 bytes from fe80::3c3a:eecf:ab31:cc80%6: icmp_seq=0 ttl=64 rssi=-74 dBm time=21.914 ms
2022-11-04 14:01:45,539 # 12 bytes from fe80::3c3a:eecf:ab31:cc80%6: icmp_seq=1 ttl=64 rssi=-71 dBm time=17.987 ms
2022-11-04 14:01:46,536 # 12 bytes from fe80::3c3a:eecf:ab31:cc80%6: icmp_seq=2 ttl=64 rssi=-74 dBm time=13.882 ms
2022-11-04 14:01:46,536 # 
2022-11-04 14:01:46,539 # --- ff02::1 PING statistics ---
2022-11-04 14:01:46,544 # 3 packets transmitted, 3 packets received, 0% packet loss
2022-11-04 14:01:46,549 # round-trip min/avg/max = 13.882/17.927/21.914 ms

Works for me! ;-)

@benpicco benpicco merged commit 8559472 into RIOT-OS:master Nov 7, 2022
@jue89
Copy link
Contributor Author

jue89 commented Nov 10, 2022

Thank you again :)

@jue89 jue89 deleted the feature/saml21_pheriph_pm branch November 10, 2022 09:22
@kaspar030 kaspar030 added this to the Release 2023.01 milestone Jan 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: cpu Area: CPU/MCU ports Area: pm Area: (Low) power management CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Platform: ARM Platform: This PR/issue effects ARM-based platforms Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants