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 <guillaume.gautier-ext@st.com>
This commit is contained in:
Guillaume Gautier 2024-02-05 11:46:36 +01:00 committed by Carles Cufí
parent b567a7db83
commit 97177ba01a
5 changed files with 146 additions and 12 deletions

View file

@ -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 <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:

View file

@ -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";
};

View file

@ -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]

View file

@ -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

View file

@ -13,7 +13,10 @@
#include <zephyr/pm/device_runtime.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/entropy.h>
#include <zephyr/drivers/spi.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#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");