From 97177ba01a829511826c5e5cdb55f611c08b172f Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Mon, 5 Feb 2024 11:46:36 +0100 Subject: [PATCH] samples: boards: stm32: pm: s2ram: add spi Add SPI transfer in the suspend to ram samples to test SPI PM. Signed-off-by: Guillaume Gautier --- .../power_mgmt/suspend_to_ram/README.rst | 2 + .../boards/nucleo_wba55cg.overlay | 27 +++++ .../dts/bindings/test-spi-loopback.yaml | 13 ++ .../stm32/power_mgmt/suspend_to_ram/prj.conf | 5 +- .../power_mgmt/suspend_to_ram/src/main.c | 111 ++++++++++++++++-- 5 files changed, 146 insertions(+), 12 deletions(-) create mode 100644 samples/boards/stm32/power_mgmt/suspend_to_ram/dts/bindings/test-spi-loopback.yaml diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst b/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst index 246ac96ea10..29590134f19 100644 --- a/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst @@ -9,6 +9,8 @@ Overview This sample is a minimum application to demonstrate basic power management behavior in a basic blinking LED set up using the :ref:`GPIO API ` in low power context + ADC measurements and entropy. +SPI loopback is also available but not yet implemented for Suspend To RAM PM +mode. .. _stm32-pm-suspend-to-ram-sample-requirements: diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/boards/nucleo_wba55cg.overlay b/samples/boards/stm32/power_mgmt/suspend_to_ram/boards/nucleo_wba55cg.overlay index a3d46e95fb7..bf8f1747cff 100644 --- a/samples/boards/stm32/power_mgmt/suspend_to_ram/boards/nucleo_wba55cg.overlay +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/boards/nucleo_wba55cg.overlay @@ -31,6 +31,18 @@ /* adjust channel number according to pinmux in board.dts */ io-channels = <&adc4 8>; }; + + leds: leds { + compatible = "gpio-leds"; + red_led_3: led_3 { + gpios = <&gpiob 8 GPIO_ACTIVE_LOW>; + label = "User LD2"; + }; + }; + + aliases { + led2 = &red_led_3; + }; }; &lptim1 { @@ -50,3 +62,18 @@ zephyr,resolution = <12>; }; }; + +&spi1 { + dmas = <&gpdma1 0 2 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH) + &gpdma1 1 1 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>; + dma-names = "tx", "rx"; + fast@0 { + compatible = "test-spi-loopback"; + reg = <0>; + spi-max-frequency = <500000>; + }; +}; + +&gpdma1 { + status = "okay"; +}; diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/dts/bindings/test-spi-loopback.yaml b/samples/boards/stm32/power_mgmt/suspend_to_ram/dts/bindings/test-spi-loopback.yaml new file mode 100644 index 00000000000..48043c088b7 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/dts/bindings/test-spi-loopback.yaml @@ -0,0 +1,13 @@ +# +# Copyright (c) 2024 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: | + This binding provides resources required to build and run an SPI + loopback test under power management conditions + +compatible: "test-spi-loopback" + +include: [spi-device.yaml] diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf b/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf index acef64bb9a8..78963168c5a 100644 --- a/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf @@ -5,4 +5,7 @@ CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n CONFIG_PM_S2RAM=y CONFIG_ADC=y CONFIG_ENTROPY_GENERATOR=y -#CONFIG_DEBUG=y +CONFIG_SPI=y +CONFIG_SPI_STM32_DMA=y +CONFIG_SPI_STM32_INTERRUPT=n +CONFIG_SPI_ASYNC=n diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c b/samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c index bb1ca9dbb55..0f77e7d85d9 100644 --- a/samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c @@ -13,7 +13,10 @@ #include #include #include +#include #include +#include +#include #define SLEEP_TIME_STOP0_MS 800 #define SLEEP_TIME_STOP1_MS 1500 @@ -21,7 +24,7 @@ #define SLEEP_TIME_BUSY_MS 2000 static const struct gpio_dt_spec led = - GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios); + GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios); #if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \ !DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels) @@ -43,6 +46,86 @@ const struct device *rng_dev; static uint8_t entropy_buffer[BUFFER_LENGTH] = {0}; +#define SPI_TEST_DEV DT_COMPAT_GET_ANY_STATUS_OKAY(test_spi_loopback) + +#define FRAME_SIZE (8) + +#define SPI_OP(frame_size) SPI_OP_MODE_MASTER | SPI_MODE_CPOL | \ + SPI_MODE_CPHA | SPI_WORD_SET(frame_size) | SPI_LINES_SINGLE + +static struct spi_dt_spec spi_test_dev = SPI_DT_SPEC_GET(SPI_TEST_DEV, SPI_OP(FRAME_SIZE), 0); + +#define SPI_BUF_SIZE 18 + +static const char spi_tx_data[SPI_BUF_SIZE] = "0123456789abcdef-\0"; +static __aligned(32) char spi_buffer_tx[SPI_BUF_SIZE] __used; +static __aligned(32) char spi_buffer_rx[SPI_BUF_SIZE] __used; + +static uint8_t spi_buffer_print_tx[SPI_BUF_SIZE * 5 + 1]; +static uint8_t spi_buffer_print_rx[SPI_BUF_SIZE * 5 + 1]; + +static void to_display_format(const uint8_t *src, size_t size, char *dst) +{ + size_t i; + + for (i = 0; i < size; i++) { + sprintf(dst + 5 * i, "0x%02x,", src[i]); + } +} + +static int spi_test(void) +{ + const struct spi_buf tx_bufs[] = { + { + .buf = spi_buffer_tx, + .len = SPI_BUF_SIZE, + }, + }; + const struct spi_buf rx_bufs[] = { + { + .buf = spi_buffer_rx, + .len = SPI_BUF_SIZE, + }, + }; + const struct spi_buf_set tx = { + .buffers = tx_bufs, + .count = ARRAY_SIZE(tx_bufs) + }; + const struct spi_buf_set rx = { + .buffers = rx_bufs, + .count = ARRAY_SIZE(rx_bufs) + }; + + int ret; + + ret = spi_transceive_dt(&spi_test_dev, &tx, &rx); + if (ret) { + printk("SPI transceive failed: %d\n", ret); + return ret; + } + + if (memcmp(spi_buffer_tx, spi_buffer_rx, SPI_BUF_SIZE)) { + to_display_format(spi_buffer_tx, SPI_BUF_SIZE, spi_buffer_print_tx); + to_display_format(spi_buffer_rx, SPI_BUF_SIZE, spi_buffer_print_rx); + printk("Buffer contents are different\n"); + printk("tx: %s\n", spi_buffer_print_tx); + printk("rx: %s\n", spi_buffer_print_rx); + return -1; + } + + return 0; +} + +static void spi_setup(void) +{ + memset(spi_buffer_tx, 0, sizeof(spi_buffer_tx)); + memcpy(spi_buffer_tx, spi_tx_data, sizeof(spi_tx_data)); + + if (!spi_is_ready_dt(&spi_test_dev)) { + printk("Fast spi lookback device is not ready\n"); + } +} + static int adc_test(void) { int err; @@ -122,6 +205,17 @@ void print_buf(uint8_t *buffer) printk("\n"); } +static void loop(void) +{ + gpio_pin_set_dt(&led, 1); + adc_test(); + if (!IS_ENABLED(CONFIG_PM_S2RAM)) { + spi_test(); + } + k_busy_wait(SLEEP_TIME_BUSY_MS*1000); + gpio_pin_set_dt(&led, 0); +} + int main(void) { __ASSERT_NO_MSG(gpio_is_ready_dt(&led)); @@ -131,20 +225,17 @@ int main(void) printk("error: random device not ready"); } + spi_setup(); + printk("Device ready\n"); while (true) { gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); - adc_test(); - k_busy_wait(SLEEP_TIME_BUSY_MS*1000); - gpio_pin_set_dt(&led, 0); + loop(); k_msleep(SLEEP_TIME_STOP0_MS); printk("Exit Stop0\n"); - gpio_pin_set_dt(&led, 1); - adc_test(); - k_busy_wait(SLEEP_TIME_BUSY_MS*1000); - gpio_pin_set_dt(&led, 0); + loop(); k_msleep(SLEEP_TIME_STOP1_MS); printk("Exit Stop1\n"); @@ -153,9 +244,7 @@ int main(void) printk("Sync entropy: "); print_buf(entropy_buffer); - gpio_pin_set_dt(&led, 1); - adc_test(); - k_busy_wait(SLEEP_TIME_BUSY_MS*1000); + loop(); gpio_pin_configure_dt(&led, GPIO_DISCONNECTED); k_msleep(SLEEP_TIME_STANDBY_MS); printk("Exit Standby\n");