Skip to content

drivers: spi: stm32 spi driver supporting DMA in asynchronous mode #55302

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 33 additions & 16 deletions drivers/spi/spi_ll_stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ static void dma_callback(const struct device *dev, void *arg,
k_sem_give(&data->status_sem);
}

#if !defined(CONFIG_SPI_STM32_INTERRUPT) && !defined(CONFIG_SPI_ASYNC)
static int spi_stm32_dma_tx_load(const struct device *dev, const uint8_t *buf,
size_t len)
{
Expand Down Expand Up @@ -220,6 +221,7 @@ static int spi_dma_move_buffers(const struct device *dev, size_t len)

return ret;
}
#endif /* !defined(CONFIG_SPI_STM32_INTERRUPT) && !defined(CONFIG_SPI_ASYNC) */

#endif /* CONFIG_SPI_STM32_DMA */

Expand Down Expand Up @@ -386,7 +388,7 @@ static void spi_stm32_complete(const struct device *dev, int status)
{
const struct spi_stm32_config *cfg = dev->config;
SPI_TypeDef *spi = cfg->spi;
#ifdef CONFIG_SPI_STM32_INTERRUPT
#if defined(CONFIG_SPI_STM32_INTERRUPT) || defined(CONFIG_SPI_ASYNC)
struct spi_stm32_data *data = dev->data;

ll_func_disable_int_tx_empty(spi);
Expand Down Expand Up @@ -415,12 +417,12 @@ static void spi_stm32_complete(const struct device *dev, int status)

ll_func_disable_spi(spi);

#ifdef CONFIG_SPI_STM32_INTERRUPT
#if defined(CONFIG_SPI_STM32_INTERRUPT) || defined(CONFIG_SPI_ASYNC)
spi_context_complete(&data->ctx, dev, status);
#endif
}

#ifdef CONFIG_SPI_STM32_INTERRUPT
#if defined(CONFIG_SPI_STM32_INTERRUPT) || defined(CONFIG_SPI_ASYNC)
static void spi_stm32_isr(const struct device *dev)
{
const struct spi_stm32_config *cfg = dev->config;
Expand Down Expand Up @@ -616,12 +618,6 @@ static int transceive(const struct device *dev,
return 0;
}

#ifndef CONFIG_SPI_STM32_INTERRUPT
if (asynchronous) {
return -ENOTSUP;
}
#endif

spi_context_lock(&data->ctx, asynchronous, cb, userdata, config);

ret = spi_stm32_configure(dev, config);
Expand Down Expand Up @@ -656,7 +652,7 @@ static int transceive(const struct device *dev,
/* This is turned off in spi_stm32_complete(). */
spi_stm32_cs_control(dev, true);

#ifdef CONFIG_SPI_STM32_INTERRUPT
#if defined(CONFIG_SPI_STM32_INTERRUPT) || defined(CONFIG_SPI_ASYNC)
ll_func_enable_int_errors(spi);

if (rx_bufs) {
Expand Down Expand Up @@ -689,6 +685,7 @@ static int transceive(const struct device *dev,

#ifdef CONFIG_SPI_STM32_DMA

#if !defined(CONFIG_SPI_STM32_INTERRUPT) && !defined(CONFIG_SPI_ASYNC)
static int wait_dma_rx_tx_done(const struct device *dev)
{
struct spi_stm32_data *data = dev->data;
Expand Down Expand Up @@ -722,6 +719,7 @@ static int wait_dma_rx_tx_done(const struct device *dev)

return res;
}
#endif

static int transceive_dma(const struct device *dev,
const struct spi_config *config,
Expand All @@ -740,10 +738,6 @@ static int transceive_dma(const struct device *dev,
return 0;
}

if (asynchronous) {
return -ENOTSUP;
}

spi_context_lock(&data->ctx, asynchronous, cb, userdata, config);

k_sem_reset(&data->status_sem);
Expand Down Expand Up @@ -776,6 +770,18 @@ static int transceive_dma(const struct device *dev,
/* This is turned off in spi_stm32_complete(). */
spi_stm32_cs_control(dev, true);

#if defined(CONFIG_SPI_STM32_INTERRUPT) || defined(CONFIG_SPI_ASYNC)
Copy link
Member

Choose a reason for hiding this comment

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

Do we want to change behavior in config Interrup + DMA (SPI_ASYNC = n) ?
Isn't it sufficient to do defined(CONFIG_SPI_ASYNC) here ?

Copy link
Member

Choose a reason for hiding this comment

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

Do you use DMA in this case? It looks like transceive function in async mode without DMA.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Do you use DMA in this case? It looks like transceive function in async mode without DMA.

yes, if CONFIG_SPI_STM32_DMA=y

ll_func_enable_int_errors(spi);

if (rx_bufs) {
ll_func_enable_int_rx_not_empty(spi);
}

ll_func_enable_int_tx_empty(spi);

ret = spi_context_wait_for_completion(&data->ctx);

#else
while (data->ctx.rx_len > 0 || data->ctx.tx_len > 0) {
size_t dma_len;

Expand Down Expand Up @@ -842,6 +848,8 @@ static int transceive_dma(const struct device *dev,
}
#endif /* CONFIG_SPI_SLAVE */

#endif

end:
spi_context_release(&data->ctx, ret);

Expand Down Expand Up @@ -874,6 +882,15 @@ static int spi_stm32_transceive_async(const struct device *dev,
spi_callback_t cb,
void *userdata)
{
#ifdef CONFIG_SPI_STM32_DMA
struct spi_stm32_data *data = dev->data;

if ((data->dma_tx.dma_dev != NULL)
&& (data->dma_rx.dma_dev != NULL)) {
return transceive_dma(dev, config, tx_bufs, rx_bufs,
Copy link
Member

Choose a reason for hiding this comment

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

The transceive_dma function calls wait_dma_rx_tx_done, so it waits for transfer to end, so it is not an asynchronous mode. It looks like, it is a synchronous mode with calling the callback at the end of transfer.

Copy link
Collaborator Author

@FRASTM FRASTM Mar 30, 2023

Choose a reason for hiding this comment

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

Ok, I am Changing the transceive_dma when the ASYNC mode is activated: behaves like the transceive() does.

true, cb, userdata);
}
#endif /* CONFIG_SPI_STM32_DMA */
return transceive(dev, config, tx_bufs, rx_bufs, true, cb, userdata);
}
#endif /* CONFIG_SPI_ASYNC */
Expand Down Expand Up @@ -935,7 +952,7 @@ static int spi_stm32_init(const struct device *dev)
}
}

#ifdef CONFIG_SPI_STM32_INTERRUPT
#if defined(CONFIG_SPI_STM32_INTERRUPT) || defined(CONFIG_SPI_ASYNC)
cfg->irq_config(dev);
#endif

Expand Down Expand Up @@ -966,7 +983,7 @@ static int spi_stm32_init(const struct device *dev)
return 0;
}

#ifdef CONFIG_SPI_STM32_INTERRUPT
#if defined(CONFIG_SPI_STM32_INTERRUPT) || defined(CONFIG_SPI_ASYNC)
#define STM32_SPI_IRQ_HANDLER_DECL(id) \
static void spi_stm32_irq_config_func_##id(const struct device *dev)
#define STM32_SPI_IRQ_HANDLER_FUNC(id) \
Expand Down
2 changes: 1 addition & 1 deletion drivers/spi/spi_ll_stm32.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ typedef void (*irq_config_func_t)(const struct device *port);
struct spi_stm32_config {
SPI_TypeDef *spi;
const struct pinctrl_dev_config *pcfg;
#ifdef CONFIG_SPI_STM32_INTERRUPT
#if defined(CONFIG_SPI_STM32_INTERRUPT) || defined(CONFIG_SPI_ASYNC)
irq_config_func_t irq_config;
#endif
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_subghz)
Expand Down
21 changes: 21 additions & 0 deletions tests/drivers/spi/spi_loopback/boards/disco_l475_iot1.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2023 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/

&spi1 {
dmas = <&dma1 1 3 STM32_DMA_PERIPH_TX
&dma1 1 2 STM32_DMA_PERIPH_RX>;
dma-names = "tx", "rx";
slow@0 {
compatible = "test-spi-loopback-slow";
reg = <0>;
spi-max-frequency = <500000>;
};
fast@0 {
compatible = "test-spi-loopback-fast";
reg = <0>;
spi-max-frequency = <16000000>;
};
};
21 changes: 20 additions & 1 deletion tests/drivers/spi/spi_loopback/testcase.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,28 @@ tests:
integration_platforms:
- sam_e70_xplained
drivers.spi.stm32_spi_dma.loopback:
extra_args: OVERLAY_CONFIG="overlay-stm32-spi-dma.conf"
extra_configs:
- CONFIG_SPI_STM32_DMA=y
- CONFIG_SPI_ASYNC=n
filter: CONFIG_SOC_FAMILY_STM32
platform_allow:
- disco_l475_iot1
- nucleo_g474re
- nucleo_f207zg
- nucleo_f429zi
- nucleo_f746zg
- nucleo_wb55rg
- nucleo_l152re
- nucleo_wl55jc
- nucleo_h743zi
integration_platforms:
- nucleo_g474re
drivers.spi.stm32_spi_async_dma.loopback:
extra_configs:
- CONFIG_SPI_STM32_DMA=y
filter: CONFIG_SOC_FAMILY_STM32
platform_allow:
- disco_l475_iot1
- nucleo_g474re
- nucleo_f207zg
- nucleo_f429zi
Expand Down