diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_spi.c b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_spi.c index 8e65b759c5a..f2adf39a282 100644 --- a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_spi.c +++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_spi.c @@ -10,8 +10,15 @@ * 2019-01-03 zylx modify DMA initialization and spixfer function * 2020-01-15 whj4674672 Porting for stm32h7xx * 2020-06-18 thread-liu Porting for stm32mp1xx - * 2020-10-14 Dozingfiretruck Porting for stm32wbxx + * 2020-10-14 PeakRacing Porting for stm32wbxx * 2025-09-22 wdfk_prog Refactor spixfer to fix DMA reception bug, correct timeout calculation. + * 2026-04-14 wdfk_prog Refine SPI DMA config hierarchy + * 2026-04-16 wdfk_prog Add SPI interrupt transfer mode scaffolding + */ + +/** + * @file drv_spi.c + * @brief STM32 SPI bus driver implementation. */ #include @@ -20,84 +27,146 @@ #ifdef BSP_USING_SPI -#if defined(BSP_USING_SPI1) || defined(BSP_USING_SPI2) || defined(BSP_USING_SPI3) || defined(BSP_USING_SPI4) || defined(BSP_USING_SPI5) || defined(BSP_USING_SPI6) - #include "drv_spi.h" #include "drv_config.h" #include +#ifdef BSP_HARDWARE_SPI +/** + * @brief SPI transfer route policy. + * + * @details + * + * For a universal and most conservative strategy across all STM32 series + * under full-duplex operation at the highest supported SPI clock rates, + * there is no generally safe transfer-length threshold for interrupt mode. + * The interrupt servicing latency depends on MCU performance, bus clock, + * HAL/LL implementation cost, system interrupt load, and runtime context, + * so a single INT threshold cannot be guaranteed to work reliably on all targets. + * + * Therefore, use the following unified rule: + * - transfer length < 32 bytes : use polling mode + * - transfer length >= 32 bytes : use DMA mode + * - interrupt mode : disabled by default + * + * This policy prioritizes robustness and portability over theoretical peak efficiency. + */ +#ifndef BSP_SPI_DMA_TRANS_MIN_LEN +/* Minimum transfer length that may use DMA mode. */ +#define BSP_SPI_DMA_TRANS_MIN_LEN 32U +#endif /* BSP_SPI_DMA_TRANS_MIN_LEN */ +#ifndef BSP_SPI_INT_TRANS_MIN_LEN +/* Minimum transfer length that may use interrupt mode. */ +#define BSP_SPI_INT_TRANS_MIN_LEN 32U +#endif /* BSP_SPI_INT_TRANS_MIN_LEN */ + /*#define DRV_DEBUG*/ #define LOG_TAG "drv.spi" #include +/** + * @brief Runtime array indexes for enabled STM32 SPI instances. + * + * @note The index order must match @ref spi_config and @ref spi_bus_obj. + */ enum { #ifdef BSP_USING_SPI1 - SPI1_INDEX, + SPI1_INDEX, /**< Runtime array index for SPI1. */ #endif #ifdef BSP_USING_SPI2 - SPI2_INDEX, + SPI2_INDEX, /**< Runtime array index for SPI2. */ #endif #ifdef BSP_USING_SPI3 - SPI3_INDEX, + SPI3_INDEX, /**< Runtime array index for SPI3. */ #endif #ifdef BSP_USING_SPI4 - SPI4_INDEX, + SPI4_INDEX, /**< Runtime array index for SPI4. */ #endif #ifdef BSP_USING_SPI5 - SPI5_INDEX, + SPI5_INDEX, /**< Runtime array index for SPI5. */ #endif #ifdef BSP_USING_SPI6 - SPI6_INDEX, + SPI6_INDEX, /**< Runtime array index for SPI6. */ #endif }; +/** + * @var spi_config + * @brief Static STM32 SPI bus configuration table. + * + * @details The table contains one conditional SPIx_BUS_CONFIG entry for + * each enabled BSP_USING_SPIx instance. The table order must match the + * SPIx_INDEX values and @ref spi_bus_obj. + */ static struct stm32_spi_config spi_config[] = { #ifdef BSP_USING_SPI1 - SPI1_BUS_CONFIG, -#endif + SPI1_BUS_CONFIG, /**< Static bus configuration entry for SPI1. */ +#endif /* BSP_USING_SPI1 */ #ifdef BSP_USING_SPI2 - SPI2_BUS_CONFIG, -#endif + SPI2_BUS_CONFIG, /**< Static bus configuration entry for SPI2. */ +#endif /* BSP_USING_SPI2 */ #ifdef BSP_USING_SPI3 - SPI3_BUS_CONFIG, -#endif + SPI3_BUS_CONFIG, /**< Static bus configuration entry for SPI3. */ +#endif /* BSP_USING_SPI3 */ #ifdef BSP_USING_SPI4 - SPI4_BUS_CONFIG, -#endif + SPI4_BUS_CONFIG, /**< Static bus configuration entry for SPI4. */ +#endif /* BSP_USING_SPI4 */ #ifdef BSP_USING_SPI5 - SPI5_BUS_CONFIG, -#endif + SPI5_BUS_CONFIG, /**< Static bus configuration entry for SPI5. */ +#endif /* BSP_USING_SPI5 */ #ifdef BSP_USING_SPI6 - SPI6_BUS_CONFIG, -#endif + SPI6_BUS_CONFIG, /**< Static bus configuration entry for SPI6. */ +#endif /* BSP_USING_SPI6 */ }; +/** + * @brief Runtime STM32 SPI bus object table paired with @ref spi_config. + */ static struct stm32_spi spi_bus_obj[sizeof(spi_config) / sizeof(spi_config[0])] = {0}; +#ifdef BSP_SPI_USING_DMA +/** + * @brief Roll back SPI DMA setup that was partially initialized. + * + * @param spi_drv STM32 SPI driver context. + * @param dma_flags RT_DEVICE_FLAG_DMA_* bits indicating DMA channels to release. + */ static void stm32_spi_dma_rollback(struct stm32_spi *spi_drv, rt_uint16_t dma_flags) { - if ((dma_flags & SPI_USING_RX_DMA_FLAG) && (spi_drv->config->dma_rx != RT_NULL)) +#if defined(BSP_SPI_RX_USING_DMA) + if ((dma_flags & RT_DEVICE_FLAG_DMA_RX) && (spi_drv->config->dma_rx != RT_NULL)) { (void)stm32_dma_deinit(&spi_drv->dma.handle_rx, spi_drv->config->dma_rx, RT_FALSE); spi_drv->dma.handle_rx.Parent = RT_NULL; spi_drv->handle.hdmarx = RT_NULL; } +#endif /* BSP_SPI_RX_USING_DMA */ - if ((dma_flags & SPI_USING_TX_DMA_FLAG) && (spi_drv->config->dma_tx != RT_NULL)) +#if defined(BSP_SPI_TX_USING_DMA) + if ((dma_flags & RT_DEVICE_FLAG_DMA_TX) && (spi_drv->config->dma_tx != RT_NULL)) { (void)stm32_dma_deinit(&spi_drv->dma.handle_tx, spi_drv->config->dma_tx, RT_FALSE); spi_drv->dma.handle_tx.Parent = RT_NULL; spi_drv->handle.hdmatx = RT_NULL; } +#endif /* BSP_SPI_TX_USING_DMA */ } +#endif /* BSP_SPI_USING_DMA */ +/** + * @brief Initialize an STM32 SPI instance according to an RT-Thread SPI configuration. + * + * @param spi_drv STM32 SPI driver context. + * @param cfg RT-Thread SPI bus configuration. + * @return RT_EOK on success, otherwise an RT-Thread error code. + */ static rt_err_t stm32_spi_init(struct stm32_spi *spi_drv, struct rt_spi_configuration *cfg) { RT_ASSERT(spi_drv != RT_NULL); @@ -244,7 +313,6 @@ static rt_err_t stm32_spi_init(struct stm32_spi *spi_drv, struct rt_spi_configur #if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32WB) spi_handle->Init.NSSPMode = SPI_NSS_PULSE_DISABLE; #elif defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32MP1) - spi_handle->Init.Mode = SPI_MODE_MASTER; spi_handle->Init.NSS = SPI_NSS_SOFT; spi_handle->Init.NSSPMode = SPI_NSS_PULSE_DISABLE; spi_handle->Init.NSSPolarity = SPI_NSS_POLARITY_LOW; @@ -269,45 +337,59 @@ static rt_err_t stm32_spi_init(struct stm32_spi *spi_drv, struct rt_spi_configur SET_BIT(spi_handle->Instance->CR2, SPI_RXFIFO_THRESHOLD_HF); #endif +#ifdef BSP_SPI_USING_DMA /* DMA configuration */ - if (spi_drv->spi_dma_flag & SPI_USING_RX_DMA_FLAG) +#if defined(BSP_SPI_RX_USING_DMA) + if (spi_drv->spi_xfer_flags & RT_DEVICE_FLAG_DMA_RX) { if (stm32_dma_setup(&spi_drv->dma.handle_rx, &spi_drv->handle, &spi_drv->handle.hdmarx, spi_drv->config->dma_rx) != RT_EOK) { - stm32_spi_dma_rollback(spi_drv, SPI_USING_RX_DMA_FLAG); + stm32_spi_dma_rollback(spi_drv, RT_DEVICE_FLAG_DMA_RX); return -RT_EIO; } } +#endif /* BSP_SPI_RX_USING_DMA */ - if (spi_drv->spi_dma_flag & SPI_USING_TX_DMA_FLAG) +#if defined(BSP_SPI_TX_USING_DMA) + if (spi_drv->spi_xfer_flags & RT_DEVICE_FLAG_DMA_TX) { if (stm32_dma_setup(&spi_drv->dma.handle_tx, &spi_drv->handle, &spi_drv->handle.hdmatx, spi_drv->config->dma_tx) != RT_EOK) { - stm32_spi_dma_rollback(spi_drv, SPI_USING_TX_DMA_FLAG | (spi_drv->spi_dma_flag & SPI_USING_RX_DMA_FLAG)); + stm32_spi_dma_rollback(spi_drv, RT_DEVICE_FLAG_DMA_TX | (spi_drv->spi_xfer_flags & RT_DEVICE_FLAG_DMA_RX)); return -RT_EIO; } } +#endif /* BSP_SPI_TX_USING_DMA */ +#endif /* BSP_SPI_USING_DMA */ - if(spi_drv->spi_dma_flag & SPI_USING_TX_DMA_FLAG || spi_drv->spi_dma_flag & SPI_USING_RX_DMA_FLAG) +#ifdef BSP_SPI_USING_IRQ + if ((spi_drv->spi_xfer_flags & RT_DEVICE_FLAG_DMA_TX) || (spi_drv->spi_xfer_flags & RT_DEVICE_FLAG_DMA_RX) + || (spi_drv->spi_xfer_flags & RT_DEVICE_FLAG_INT_TX) || (spi_drv->spi_xfer_flags & RT_DEVICE_FLAG_INT_RX)) { HAL_NVIC_SetPriority(spi_drv->config->irq_type, 2, 0); HAL_NVIC_EnableIRQ(spi_drv->config->irq_type); } +#endif /* BSP_SPI_USING_IRQ */ LOG_D("%s init done", spi_drv->config->bus_name); return RT_EOK; } +/** + * @brief Transfer one RT-Thread SPI message over an STM32 SPI bus. + * + * @param device RT-Thread SPI device. + * @param message SPI message containing TX/RX buffers and transfer length. + * @return Transferred byte count on success, otherwise a negative RT-Thread error code. + */ static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message) { -#define DMA_TRANS_MIN_LEN 10 /* only buffer length >= DMA_TRANS_MIN_LEN will use DMA mode */ - HAL_StatusTypeDef state = HAL_OK; rt_size_t message_length, already_send_length; rt_uint16_t send_length; @@ -321,6 +403,7 @@ static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *m struct stm32_spi *spi_drv = rt_container_of(device->bus, struct stm32_spi, spi_bus); SPI_HandleTypeDef *spi_handle = &spi_drv->handle; + rt_bool_t need_abort = RT_FALSE; rt_uint64_t total_byte_ms = (rt_uint64_t)message->length * 1000; rt_uint32_t speed_bytes_per_sec = spi_drv->cfg->usage_freq / 8; if (speed_bytes_per_sec == 0) @@ -329,7 +412,9 @@ static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *m } rt_uint32_t timeout_ms = total_byte_ms / speed_bytes_per_sec + 100; +#ifdef BSP_SPI_USING_IRQ rt_tick_t timeout_tick = rt_tick_from_millisecond(timeout_ms); +#endif /* BSP_SPI_USING_IRQ */ if (message->cs_take && !(device->config.mode & RT_SPI_NO_CS) && (device->cs_pin != PIN_NONE)) { @@ -377,16 +462,31 @@ static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *m { recv_buf = (rt_uint8_t *)message->recv_buf + already_send_length; } - + const rt_bool_t scheduler_available = rt_scheduler_is_available(); + const rt_bool_t irq_disabled = rt_hw_interrupt_is_disabled(); +#ifdef BSP_SPI_USING_DMA const rt_uint8_t *dma_send_buf = send_buf; rt_uint8_t *dma_recv_buf = recv_buf; rt_uint8_t *aligned_send_buf = RT_NULL; rt_uint8_t *aligned_recv_buf = RT_NULL; - const rt_bool_t dma_eligible = (send_length >= DMA_TRANS_MIN_LEN); - const rt_bool_t use_tx_dma = dma_eligible && (spi_drv->spi_dma_flag & SPI_USING_TX_DMA_FLAG); - const rt_bool_t use_rx_dma = dma_eligible && (spi_drv->spi_dma_flag & SPI_USING_RX_DMA_FLAG); + rt_bool_t dma_eligible = (send_length >= BSP_SPI_DMA_TRANS_MIN_LEN); +#if defined(BSP_SPI_TX_USING_DMA) + rt_bool_t use_tx_dma = dma_eligible && (spi_drv->spi_xfer_flags & RT_DEVICE_FLAG_DMA_TX); +#else + rt_bool_t use_tx_dma = RT_FALSE; +#endif /* BSP_SPI_TX_USING_DMA */ +#if defined(BSP_SPI_RX_USING_DMA) + rt_bool_t use_rx_dma = dma_eligible && (spi_drv->spi_xfer_flags & RT_DEVICE_FLAG_DMA_RX); +#else + rt_bool_t use_rx_dma = RT_FALSE; +#endif /* BSP_SPI_RX_USING_DMA */ + + if (!scheduler_available || irq_disabled) + { + use_rx_dma = use_tx_dma = dma_eligible = RT_FALSE; + } if (dma_eligible) { @@ -427,48 +527,108 @@ static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *m if (dma_recv_buf) rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, dma_recv_buf, send_length); #endif } +#endif /* BSP_SPI_USING_DMA */ +#ifdef BSP_SPI_USING_INT + rt_bool_t int_eligible = (send_length >= BSP_SPI_INT_TRANS_MIN_LEN); +#if defined(BSP_SPI_TX_USING_INT) + rt_bool_t use_tx_int = int_eligible && spi_drv->spi_xfer_flags & RT_DEVICE_FLAG_INT_TX; +#else + rt_bool_t use_tx_int = RT_FALSE; +#endif /* BSP_SPI_TX_USING_INT */ +#if defined(BSP_SPI_RX_USING_INT) + rt_bool_t use_rx_int = int_eligible && spi_drv->spi_xfer_flags & RT_DEVICE_FLAG_INT_RX; +#else + rt_bool_t use_rx_int = RT_FALSE; +#endif /* BSP_SPI_RX_USING_INT */ + if (!scheduler_available || irq_disabled) + { + use_rx_int = use_tx_int = int_eligible = RT_FALSE; + } +#endif /* BSP_SPI_USING_INT */ + + rt_bool_t async_started = RT_TRUE; +#ifdef BSP_SPI_USING_IRQ + /* Reinitialize the completion object for the current transfer. */ + rt_completion_init(&spi_drv->cpt); +#endif /* BSP_SPI_USING_IRQ */ /* Start data exchange in full-duplex DMA mode. */ if (message->send_buf && message->recv_buf) { +#ifdef BSP_SPI_USING_DMA if (use_tx_dma && use_rx_dma) { state = HAL_SPI_TransmitReceive_DMA(spi_handle, (uint8_t *)dma_send_buf, dma_recv_buf, send_length); } else +#endif /* BSP_SPI_USING_DMA */ +#ifdef BSP_SPI_USING_INT + if (use_tx_int && use_rx_int) + { + state = HAL_SPI_TransmitReceive_IT(spi_handle, (uint8_t *)send_buf, recv_buf, send_length); + } + else +#endif /* BSP_SPI_USING_INT */ { state = HAL_SPI_TransmitReceive(spi_handle, (uint8_t *)send_buf, recv_buf, send_length, timeout_ms); + async_started = RT_FALSE; } } else if (message->send_buf) { +#ifdef BSP_SPI_USING_DMA if (use_tx_dma) { state = HAL_SPI_Transmit_DMA(spi_handle, (uint8_t *)dma_send_buf, send_length); } else +#endif /* BSP_SPI_USING_DMA */ +#ifdef BSP_SPI_USING_INT + if (use_tx_int) { - state = HAL_SPI_Transmit(spi_handle, (uint8_t *)send_buf, send_length, timeout_ms); + state = HAL_SPI_Transmit_IT(spi_handle, (uint8_t *)send_buf, send_length); } - - if (message->cs_release && (device->config.mode & RT_SPI_3WIRE)) + else +#endif /* BSP_SPI_USING_INT */ { - /* release the CS by disable SPI when using 3 wires SPI */ - __HAL_SPI_DISABLE(spi_handle); + state = HAL_SPI_Transmit(spi_handle, (uint8_t *)send_buf, send_length, timeout_ms); + async_started = RT_FALSE; } } - else if(message->recv_buf) + else if (message->recv_buf) { - rt_memset(dma_recv_buf, 0xFF, send_length); + rt_uint8_t *rx_dummy_buf = recv_buf; + + /* clear the old error flag */ + __HAL_SPI_CLEAR_OVRFLAG(spi_handle); +#ifdef BSP_SPI_USING_DMA + if (use_rx_dma) + { + rx_dummy_buf = dma_recv_buf; + } +#endif /* BSP_SPI_USING_DMA */ + /* + * STM32 HAL uses the receive buffer as dummy TX data in master + * receive-only mode, so preload the actual HAL buffer with 0xFF. + */ + rt_memset(rx_dummy_buf, 0xFF, send_length); +#ifdef BSP_SPI_USING_DMA if (use_rx_dma) { state = HAL_SPI_Receive_DMA(spi_handle, dma_recv_buf, send_length); } else +#endif /* BSP_SPI_USING_DMA */ +#ifdef BSP_SPI_USING_INT + if (use_rx_int) + { + state = HAL_SPI_Receive_IT(spi_handle, recv_buf, send_length); + } + else +#endif /* BSP_SPI_USING_INT */ { - /* clear the old error flag */ - __HAL_SPI_CLEAR_OVRFLAG(spi_handle); state = HAL_SPI_Receive(spi_handle, recv_buf, send_length, timeout_ms); + async_started = RT_FALSE; } } else @@ -484,41 +644,70 @@ static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *m spi_handle->State = HAL_SPI_STATE_READY; goto transfer_cleanup; } - else - { - LOG_D("%s transfer done", spi_drv->config->bus_name); - } - if (use_tx_dma || use_rx_dma) +#ifdef BSP_SPI_USING_IRQ + if (async_started) { /* blocking the thread,and the other tasks can run */ if (rt_completion_wait(&spi_drv->cpt, timeout_tick) != RT_EOK) { - state = HAL_ERROR; - LOG_E("wait for DMA interrupt overtime!"); - HAL_SPI_DMAStop(spi_handle); + state = HAL_TIMEOUT; + need_abort = RT_TRUE; + LOG_E("wait for SPI async transfer overtime!"); goto transfer_cleanup; } - } - else - { - rt_uint32_t timeout = timeout_ms; - while (HAL_SPI_GetState(spi_handle) != HAL_SPI_STATE_READY) + + if (spi_handle->ErrorCode != HAL_SPI_ERROR_NONE) { - if (timeout-- > 0) + rt_uint32_t err = spi_handle->ErrorCode; + rt_bool_t tx_only = (message->send_buf != RT_NULL) && (message->recv_buf == RT_NULL); + rt_bool_t ovr_only = ((err & HAL_SPI_ERROR_OVR) != 0U) && ((err & ~(HAL_SPI_ERROR_OVR | HAL_SPI_ERROR_ABORT)) == 0U); + + /** + * Ignore the expected OVR from a completed Tx-only transfer. + * + * In 2-line SPI mode, Tx-only transfer still receives data from + * MISO. Since no RX buffer is provided, the received data is not + * read and HAL may latch OVR after async Tx completion. + */ + if (tx_only && ovr_only && (spi_handle->Init.Direction == SPI_DIRECTION_2LINES) && (spi_handle->TxXferCount == 0U)) { - rt_thread_mdelay(1); + __HAL_SPI_CLEAR_OVRFLAG(spi_handle); + spi_handle->ErrorCode = HAL_SPI_ERROR_NONE; } else { - LOG_E("timeout! SPI state did not become READY."); - state = HAL_TIMEOUT; - break; + state = HAL_ERROR; + need_abort = RT_TRUE; + LOG_E("SPI async transfer failed, error code: 0x%08x", spi_handle->ErrorCode); + goto transfer_cleanup; } } } +#endif /* BSP_SPI_USING_IRQ */ + if (state == HAL_OK) + { + /* send-only */ + if (message->send_buf != RT_NULL && message->recv_buf == RT_NULL + && message->cs_release && (device->config.mode & RT_SPI_3WIRE)) + { + /* release the CS by disable SPI when using 3 wires SPI */ + __HAL_SPI_DISABLE(spi_handle); + } + LOG_D("%s transfer done", spi_drv->config->bus_name); + } transfer_cleanup: + if (need_abort) + { + if (HAL_SPI_Abort(spi_handle) != HAL_OK) + { + LOG_W("abort SPI async transfer failed, state: %d, error: 0x%08x", + HAL_SPI_GetState(spi_handle), + spi_handle->ErrorCode); + } + } +#ifdef BSP_SPI_USING_DMA /* Post-transfer processing */ if (state == HAL_OK) { @@ -534,7 +723,7 @@ static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *m // Free any temporary buffers that were allocated if (aligned_send_buf) rt_free_align(aligned_send_buf); if (aligned_recv_buf) rt_free_align(aligned_recv_buf); - +#endif /* BSP_SPI_USING_DMA */ if (state != HAL_OK) { break; @@ -556,6 +745,13 @@ static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *m return message->length; } +/** + * @brief Configure an RT-Thread SPI device backed by an STM32 SPI bus. + * + * @param device RT-Thread SPI device. + * @param configuration SPI mode, data width and clock configuration. + * @return RT_EOK on success, otherwise an RT-Thread error code. + */ static rt_err_t spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration) { @@ -568,12 +764,20 @@ static rt_err_t spi_configure(struct rt_spi_device *device, return stm32_spi_init(spi_drv, configuration); } +/** + * @brief RT-Thread SPI operation callbacks implemented by the STM32 driver. + */ static const struct rt_spi_ops stm_spi_ops = { .configure = spi_configure, .xfer = spixfer, }; +/** + * @brief Register all enabled STM32 SPI buses with RT-Thread. + * + * @return RT_EOK on success, otherwise an RT-Thread error code. + */ static int rt_hw_spi_bus_init(void) { rt_err_t result; @@ -584,8 +788,10 @@ static int rt_hw_spi_bus_init(void) spi_bus_obj[i].spi_bus.parent.user_data = &spi_config[i]; spi_bus_obj[i].handle.Instance = spi_config[i].Instance; +#ifdef BSP_SPI_USING_IRQ /* initialize completion object */ rt_completion_init(&spi_bus_obj[i].cpt); +#endif /* BSP_SPI_USING_IRQ */ result = rt_spi_bus_register(&spi_bus_obj[i].spi_bus, spi_config[i].bus_name, &stm_spi_ops); RT_ASSERT(result == RT_EOK); @@ -597,8 +803,13 @@ static int rt_hw_spi_bus_init(void) } /** - * Attach the spi device to SPI bus, this function must be used after initialization. - */ + * @brief Attach an SPI device to a registered STM32 SPI bus. + * + * @param bus_name SPI bus name, such as "spi1". + * @param device_name SPI device name to register. + * @param cs_pin Chip-select pin used by the SPI device. + * @return RT_EOK on success, otherwise an RT-Thread error code. + */ rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin) { RT_ASSERT(bus_name != RT_NULL); @@ -625,10 +836,11 @@ rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, } /** - * Detach the spi device from SPI bus. - * - * @param device_name the name of the spi device to be detached. - */ + * @brief Detach a previously attached STM32 SPI device. + * + * @param device_name SPI device name to detach. + * @return RT_EOK on success, otherwise an RT-Thread error code. + */ rt_err_t rt_hw_spi_device_detach(const char *device_name) { RT_ASSERT(device_name != RT_NULL); @@ -665,7 +877,10 @@ rt_err_t rt_hw_spi_device_detach(const char *device_name) return RT_EOK; } -#if defined(BSP_SPI1_TX_USING_DMA) || defined(BSP_SPI1_RX_USING_DMA) +#if defined(BSP_USING_SPI1) && defined(BSP_SPI1_USING_IRQ) +/** + * @brief Handle the SPI1 peripheral interrupt. + */ void SPI1_IRQHandler(void) { /* enter interrupt */ @@ -676,14 +891,11 @@ void SPI1_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif -#if defined(BSP_USING_SPI1) && defined(BSP_SPI1_RX_USING_DMA) +#ifdef BSP_SPI1_RX_USING_DMA /** - * @brief This function handles DMA Rx interrupt request. - * @param None - * @retval None - */ + * @brief Handle the SPI1 RX DMA interrupt. + */ void SPI1_DMA_RX_IRQHandler(void) { /* enter interrupt */ @@ -694,14 +906,12 @@ void SPI1_DMA_RX_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif +#endif /* BSP_SPI1_RX_USING_DMA */ -#if defined(BSP_USING_SPI1) && defined(BSP_SPI1_TX_USING_DMA) +#ifdef BSP_SPI1_TX_USING_DMA /** - * @brief This function handles DMA Tx interrupt request. - * @param None - * @retval None - */ + * @brief Handle the SPI1 TX DMA interrupt. + */ void SPI1_DMA_TX_IRQHandler(void) { /* enter interrupt */ @@ -712,9 +922,13 @@ void SPI1_DMA_TX_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif /* defined(BSP_USING_SPI1) && defined(BSP_SPI_USING_DMA) */ +#endif /* BSP_SPI1_TX_USING_DMA */ +#endif /* defined(BSP_USING_SPI1) && defined(BSP_SPI1_USING_IRQ) */ -#if defined(BSP_SPI2_TX_USING_DMA) || defined(BSP_SPI2_RX_USING_DMA) +#if defined(BSP_USING_SPI2) && defined(BSP_SPI2_USING_IRQ) +/** + * @brief Handle the SPI2 peripheral interrupt. + */ void SPI2_IRQHandler(void) { /* enter interrupt */ @@ -725,14 +939,11 @@ void SPI2_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif -#if defined(BSP_USING_SPI2) && defined(BSP_SPI2_RX_USING_DMA) +#ifdef BSP_SPI2_RX_USING_DMA /** - * @brief This function handles DMA Rx interrupt request. - * @param None - * @retval None - */ + * @brief Handle the SPI2 RX DMA interrupt. + */ void SPI2_DMA_RX_IRQHandler(void) { /* enter interrupt */ @@ -743,14 +954,12 @@ void SPI2_DMA_RX_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif +#endif /* BSP_SPI2_RX_USING_DMA */ -#if defined(BSP_USING_SPI2) && defined(BSP_SPI2_TX_USING_DMA) +#ifdef BSP_SPI2_TX_USING_DMA /** - * @brief This function handles DMA Tx interrupt request. - * @param None - * @retval None - */ + * @brief Handle the SPI2 TX DMA interrupt. + */ void SPI2_DMA_TX_IRQHandler(void) { /* enter interrupt */ @@ -761,9 +970,13 @@ void SPI2_DMA_TX_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif /* defined(BSP_USING_SPI2) && defined(BSP_SPI_USING_DMA) */ +#endif /* BSP_SPI2_TX_USING_DMA */ +#endif /* defined(BSP_USING_SPI2) && defined(BSP_SPI2_USING_IRQ) */ -#if defined(BSP_SPI3_TX_USING_DMA) || defined(BSP_SPI3_RX_USING_DMA) +#if defined(BSP_USING_SPI3) && defined(BSP_SPI3_USING_IRQ) +/** + * @brief Handle the SPI3 peripheral interrupt. + */ void SPI3_IRQHandler(void) { /* enter interrupt */ @@ -774,14 +987,11 @@ void SPI3_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif -#if defined(BSP_USING_SPI3) && defined(BSP_SPI3_RX_USING_DMA) +#ifdef BSP_SPI3_RX_USING_DMA /** - * @brief This function handles DMA Rx interrupt request. - * @param None - * @retval None - */ + * @brief Handle the SPI3 RX DMA interrupt. + */ void SPI3_DMA_RX_IRQHandler(void) { /* enter interrupt */ @@ -792,14 +1002,12 @@ void SPI3_DMA_RX_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif +#endif /* BSP_SPI3_RX_USING_DMA */ -#if defined(BSP_USING_SPI3) && defined(BSP_SPI3_TX_USING_DMA) +#ifdef BSP_SPI3_TX_USING_DMA /** - * @brief This function handles DMA Tx interrupt request. - * @param None - * @retval None - */ + * @brief Handle the SPI3 TX DMA interrupt. + */ void SPI3_DMA_TX_IRQHandler(void) { /* enter interrupt */ @@ -810,9 +1018,13 @@ void SPI3_DMA_TX_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif /* defined(BSP_USING_SPI3) && defined(BSP_SPI_USING_DMA) */ +#endif /* BSP_SPI3_TX_USING_DMA */ +#endif /* defined(BSP_USING_SPI3) && defined(BSP_SPI3_USING_IRQ) */ -#if defined(BSP_SPI4_TX_USING_DMA) || defined(BSP_SPI4_RX_USING_DMA) +#if defined(BSP_USING_SPI4) && defined(BSP_SPI4_USING_IRQ) +/** + * @brief Handle the SPI4 peripheral interrupt. + */ void SPI4_IRQHandler(void) { /* enter interrupt */ @@ -823,14 +1035,11 @@ void SPI4_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif -#if defined(BSP_USING_SPI4) && defined(BSP_SPI4_RX_USING_DMA) +#ifdef BSP_SPI4_RX_USING_DMA /** - * @brief This function handles DMA Rx interrupt request. - * @param None - * @retval None - */ + * @brief Handle the SPI4 RX DMA interrupt. + */ void SPI4_DMA_RX_IRQHandler(void) { /* enter interrupt */ @@ -841,14 +1050,12 @@ void SPI4_DMA_RX_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif +#endif /* BSP_SPI4_RX_USING_DMA */ -#if defined(BSP_USING_SPI4) && defined(BSP_SPI4_TX_USING_DMA) +#ifdef BSP_SPI4_TX_USING_DMA /** - * @brief This function handles DMA Tx interrupt request. - * @param None - * @retval None - */ + * @brief Handle the SPI4 TX DMA interrupt. + */ void SPI4_DMA_TX_IRQHandler(void) { /* enter interrupt */ @@ -859,9 +1066,13 @@ void SPI4_DMA_TX_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif /* defined(BSP_USING_SPI4) && defined(BSP_SPI_USING_DMA) */ +#endif /* BSP_SPI4_TX_USING_DMA */ +#endif /* defined(BSP_USING_SPI4) && defined(BSP_SPI4_USING_IRQ) */ -#if defined(BSP_SPI5_TX_USING_DMA) || defined(BSP_SPI5_RX_USING_DMA) +#if defined(BSP_USING_SPI5) && defined(BSP_SPI5_USING_IRQ) +/** + * @brief Handle the SPI5 peripheral interrupt. + */ void SPI5_IRQHandler(void) { /* enter interrupt */ @@ -872,14 +1083,11 @@ void SPI5_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif -#if defined(BSP_USING_SPI5) && defined(BSP_SPI5_RX_USING_DMA) +#ifdef BSP_SPI5_RX_USING_DMA /** - * @brief This function handles DMA Rx interrupt request. - * @param None - * @retval None - */ + * @brief Handle the SPI5 RX DMA interrupt. + */ void SPI5_DMA_RX_IRQHandler(void) { /* enter interrupt */ @@ -890,14 +1098,12 @@ void SPI5_DMA_RX_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif +#endif /* BSP_SPI5_RX_USING_DMA */ -#if defined(BSP_USING_SPI5) && defined(BSP_SPI5_TX_USING_DMA) +#ifdef BSP_SPI5_TX_USING_DMA /** - * @brief This function handles DMA Tx interrupt request. - * @param None - * @retval None - */ + * @brief Handle the SPI5 TX DMA interrupt. + */ void SPI5_DMA_TX_IRQHandler(void) { /* enter interrupt */ @@ -908,14 +1114,28 @@ void SPI5_DMA_TX_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif /* defined(BSP_USING_SPI5) && defined(BSP_SPI_USING_DMA) */ +#endif /* BSP_SPI5_TX_USING_DMA */ +#endif /* defined(BSP_USING_SPI5) && defined(BSP_SPI5_USING_IRQ) */ + +#if defined(BSP_USING_SPI6) && defined(BSP_SPI6_USING_IRQ) +/** + * @brief Handle the SPI6 peripheral interrupt. + */ +void SPI6_IRQHandler(void) +{ + /* enter interrupt */ + rt_interrupt_enter(); + + HAL_SPI_IRQHandler(&spi_bus_obj[SPI6_INDEX].handle); + + /* leave interrupt */ + rt_interrupt_leave(); +} -#if defined(BSP_USING_SPI6) && defined(BSP_SPI6_RX_USING_DMA) +#ifdef BSP_SPI6_RX_USING_DMA /** - * @brief This function handles DMA Rx interrupt request. - * @param None - * @retval None - */ + * @brief Handle the SPI6 RX DMA interrupt. + */ void SPI6_DMA_RX_IRQHandler(void) { /* enter interrupt */ @@ -926,14 +1146,12 @@ void SPI6_DMA_RX_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif +#endif /* BSP_SPI6_RX_USING_DMA */ -#if defined(BSP_USING_SPI6) && defined(BSP_SPI6_TX_USING_DMA) +#ifdef BSP_SPI6_TX_USING_DMA /** - * @brief This function handles DMA Tx interrupt request. - * @param None - * @retval None - */ + * @brief Handle the SPI6 TX DMA interrupt. + */ void SPI6_DMA_TX_IRQHandler(void) { /* enter interrupt */ @@ -944,96 +1162,198 @@ void SPI6_DMA_TX_IRQHandler(void) /* leave interrupt */ rt_interrupt_leave(); } -#endif /* defined(BSP_USING_SPI6) && defined(BSP_SPI_USING_DMA) */ +#endif /* BSP_SPI6_TX_USING_DMA */ +#endif /* defined(BSP_USING_SPI6) && defined(BSP_SPI6_USING_IRQ) */ -static void stm32_get_dma_info(void) +#ifdef BSP_SPI_USING_IRQ +/** + * @brief Populate per-instance SPI transfer flags and DMA configuration pointers. + */ +static void stm32_get_xfer_info(void) { +#ifdef BSP_USING_SPI1 + spi_bus_obj[SPI1_INDEX].spi_xfer_flags = 0; +#ifdef BSP_SPI1_RX_USING_INT + spi_bus_obj[SPI1_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_INT_RX; +#endif +#ifdef BSP_SPI1_TX_USING_INT + spi_bus_obj[SPI1_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_INT_TX; +#endif #ifdef BSP_SPI1_RX_USING_DMA - spi_bus_obj[SPI1_INDEX].spi_dma_flag |= SPI_USING_RX_DMA_FLAG; + spi_bus_obj[SPI1_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_DMA_RX; + /** SPI1 RX DMA configuration descriptor. */ static const struct stm32_dma_config spi1_dma_rx = SPI1_RX_DMA_CONFIG; spi_config[SPI1_INDEX].dma_rx = &spi1_dma_rx; #endif #ifdef BSP_SPI1_TX_USING_DMA - spi_bus_obj[SPI1_INDEX].spi_dma_flag |= SPI_USING_TX_DMA_FLAG; + spi_bus_obj[SPI1_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_DMA_TX; + /** SPI1 TX DMA configuration descriptor. */ static const struct stm32_dma_config spi1_dma_tx = SPI1_TX_DMA_CONFIG; spi_config[SPI1_INDEX].dma_tx = &spi1_dma_tx; #endif +#endif /* BSP_USING_SPI1 */ +#ifdef BSP_USING_SPI2 + spi_bus_obj[SPI2_INDEX].spi_xfer_flags = 0; +#ifdef BSP_SPI2_RX_USING_INT + spi_bus_obj[SPI2_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_INT_RX; +#endif +#ifdef BSP_SPI2_TX_USING_INT + spi_bus_obj[SPI2_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_INT_TX; +#endif #ifdef BSP_SPI2_RX_USING_DMA - spi_bus_obj[SPI2_INDEX].spi_dma_flag |= SPI_USING_RX_DMA_FLAG; + spi_bus_obj[SPI2_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_DMA_RX; + /** SPI2 RX DMA configuration descriptor. */ static const struct stm32_dma_config spi2_dma_rx = SPI2_RX_DMA_CONFIG; spi_config[SPI2_INDEX].dma_rx = &spi2_dma_rx; #endif #ifdef BSP_SPI2_TX_USING_DMA - spi_bus_obj[SPI2_INDEX].spi_dma_flag |= SPI_USING_TX_DMA_FLAG; + spi_bus_obj[SPI2_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_DMA_TX; + /** SPI2 TX DMA configuration descriptor. */ static const struct stm32_dma_config spi2_dma_tx = SPI2_TX_DMA_CONFIG; spi_config[SPI2_INDEX].dma_tx = &spi2_dma_tx; #endif +#endif /* BSP_USING_SPI2 */ +#ifdef BSP_USING_SPI3 + spi_bus_obj[SPI3_INDEX].spi_xfer_flags = 0; +#ifdef BSP_SPI3_RX_USING_INT + spi_bus_obj[SPI3_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_INT_RX; +#endif +#ifdef BSP_SPI3_TX_USING_INT + spi_bus_obj[SPI3_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_INT_TX; +#endif #ifdef BSP_SPI3_RX_USING_DMA - spi_bus_obj[SPI3_INDEX].spi_dma_flag |= SPI_USING_RX_DMA_FLAG; + spi_bus_obj[SPI3_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_DMA_RX; + /** SPI3 RX DMA configuration descriptor. */ static const struct stm32_dma_config spi3_dma_rx = SPI3_RX_DMA_CONFIG; spi_config[SPI3_INDEX].dma_rx = &spi3_dma_rx; #endif #ifdef BSP_SPI3_TX_USING_DMA - spi_bus_obj[SPI3_INDEX].spi_dma_flag |= SPI_USING_TX_DMA_FLAG; + spi_bus_obj[SPI3_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_DMA_TX; + /** SPI3 TX DMA configuration descriptor. */ static const struct stm32_dma_config spi3_dma_tx = SPI3_TX_DMA_CONFIG; spi_config[SPI3_INDEX].dma_tx = &spi3_dma_tx; #endif +#endif /* BSP_USING_SPI3 */ +#ifdef BSP_USING_SPI4 + spi_bus_obj[SPI4_INDEX].spi_xfer_flags = 0; +#ifdef BSP_SPI4_RX_USING_INT + spi_bus_obj[SPI4_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_INT_RX; +#endif +#ifdef BSP_SPI4_TX_USING_INT + spi_bus_obj[SPI4_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_INT_TX; +#endif #ifdef BSP_SPI4_RX_USING_DMA - spi_bus_obj[SPI4_INDEX].spi_dma_flag |= SPI_USING_RX_DMA_FLAG; + spi_bus_obj[SPI4_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_DMA_RX; + /** SPI4 RX DMA configuration descriptor. */ static const struct stm32_dma_config spi4_dma_rx = SPI4_RX_DMA_CONFIG; spi_config[SPI4_INDEX].dma_rx = &spi4_dma_rx; #endif #ifdef BSP_SPI4_TX_USING_DMA - spi_bus_obj[SPI4_INDEX].spi_dma_flag |= SPI_USING_TX_DMA_FLAG; + spi_bus_obj[SPI4_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_DMA_TX; + /** SPI4 TX DMA configuration descriptor. */ static const struct stm32_dma_config spi4_dma_tx = SPI4_TX_DMA_CONFIG; spi_config[SPI4_INDEX].dma_tx = &spi4_dma_tx; #endif +#endif /* BSP_USING_SPI4 */ +#ifdef BSP_USING_SPI5 + spi_bus_obj[SPI5_INDEX].spi_xfer_flags = 0; +#ifdef BSP_SPI5_RX_USING_INT + spi_bus_obj[SPI5_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_INT_RX; +#endif +#ifdef BSP_SPI5_TX_USING_INT + spi_bus_obj[SPI5_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_INT_TX; +#endif #ifdef BSP_SPI5_RX_USING_DMA - spi_bus_obj[SPI5_INDEX].spi_dma_flag |= SPI_USING_RX_DMA_FLAG; + spi_bus_obj[SPI5_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_DMA_RX; + /** SPI5 RX DMA configuration descriptor. */ static const struct stm32_dma_config spi5_dma_rx = SPI5_RX_DMA_CONFIG; spi_config[SPI5_INDEX].dma_rx = &spi5_dma_rx; #endif #ifdef BSP_SPI5_TX_USING_DMA - spi_bus_obj[SPI5_INDEX].spi_dma_flag |= SPI_USING_TX_DMA_FLAG; + spi_bus_obj[SPI5_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_DMA_TX; + /** SPI5 TX DMA configuration descriptor. */ static const struct stm32_dma_config spi5_dma_tx = SPI5_TX_DMA_CONFIG; spi_config[SPI5_INDEX].dma_tx = &spi5_dma_tx; #endif +#endif /* BSP_USING_SPI5 */ +#ifdef BSP_USING_SPI6 + spi_bus_obj[SPI6_INDEX].spi_xfer_flags = 0; +#ifdef BSP_SPI6_RX_USING_INT + spi_bus_obj[SPI6_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_INT_RX; +#endif +#ifdef BSP_SPI6_TX_USING_INT + spi_bus_obj[SPI6_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_INT_TX; +#endif #ifdef BSP_SPI6_RX_USING_DMA - spi_bus_obj[SPI6_INDEX].spi_dma_flag |= SPI_USING_RX_DMA_FLAG; + spi_bus_obj[SPI6_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_DMA_RX; + /** SPI6 RX DMA configuration descriptor. */ static const struct stm32_dma_config spi6_dma_rx = SPI6_RX_DMA_CONFIG; spi_config[SPI6_INDEX].dma_rx = &spi6_dma_rx; #endif #ifdef BSP_SPI6_TX_USING_DMA - spi_bus_obj[SPI6_INDEX].spi_dma_flag |= SPI_USING_TX_DMA_FLAG; + spi_bus_obj[SPI6_INDEX].spi_xfer_flags |= RT_DEVICE_FLAG_DMA_TX; + /** SPI6 TX DMA configuration descriptor. */ static const struct stm32_dma_config spi6_dma_tx = SPI6_TX_DMA_CONFIG; spi_config[SPI6_INDEX].dma_tx = &spi6_dma_tx; #endif +#endif /* BSP_USING_SPI6 */ } +/** + * @brief Handle STM32 HAL full-duplex SPI transfer completion. + * + * @param hspi STM32 HAL SPI handle that completed the transfer. + */ void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) { struct stm32_spi *spi_drv = rt_container_of(hspi, struct stm32_spi, handle); rt_completion_done(&spi_drv->cpt); } +/** + * @brief Handle STM32 HAL SPI TX completion. + * + * @param hspi STM32 HAL SPI handle that completed the transfer. + */ void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) { struct stm32_spi *spi_drv = rt_container_of(hspi, struct stm32_spi, handle); rt_completion_done(&spi_drv->cpt); } +/** + * @brief Handle STM32 HAL SPI RX completion. + * + * @param hspi STM32 HAL SPI handle that completed the transfer. + */ void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) { struct stm32_spi *spi_drv = rt_container_of(hspi, struct stm32_spi, handle); rt_completion_done(&spi_drv->cpt); } +/** + * @brief Handle STM32 HAL SPI asynchronous transfer errors. + * + * @param hspi STM32 HAL SPI handle that reported the error. + */ +void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) +{ + struct stm32_spi *spi_drv = rt_container_of(hspi, struct stm32_spi, handle); + LOG_W("%s error code 0x%08x", spi_drv->config->bus_name, hspi->ErrorCode); + rt_completion_done(&spi_drv->cpt); +} +#endif /* BSP_SPI_USING_IRQ */ + #if defined(SOC_SERIES_STM32F0) +/** + * @brief Dispatch the combined SPI1 DMA RX/TX interrupt. + */ void SPI1_DMA_RX_TX_IRQHandler(void) { #if defined(BSP_USING_SPI1) && defined(BSP_SPI1_TX_USING_DMA) @@ -1045,6 +1365,9 @@ void SPI1_DMA_RX_TX_IRQHandler(void) #endif } +/** + * @brief Dispatch the combined SPI2 DMA RX/TX interrupt. + */ void SPI2_DMA_RX_TX_IRQHandler(void) { #if defined(BSP_USING_SPI2) && defined(BSP_SPI2_TX_USING_DMA) @@ -1056,38 +1379,47 @@ void SPI2_DMA_RX_TX_IRQHandler(void) #endif } #elif defined(SOC_SERIES_STM32G0) -#if defined(BSP_SPI1_TX_USING_DMA) || defined(BSP_SPI1_RX_USING_DMA) +#if defined(BSP_USING_SPI1) && defined(BSP_SPI1_USING_DMA) +/** + * @brief Dispatch the combined SPI1 DMA RX/TX interrupt. + */ void SPI1_DMA_RX_TX_IRQHandler(void) { -#if defined(BSP_SPI1_TX_USING_DMA) +#if defined(BSP_USING_SPI1) && defined(BSP_SPI1_TX_USING_DMA) SPI1_DMA_TX_IRQHandler(); #endif -#if defined(BSP_SPI1_RX_USING_DMA) +#if defined(BSP_USING_SPI1) && defined(BSP_SPI1_RX_USING_DMA) SPI1_DMA_RX_IRQHandler(); #endif } -#endif /* defined(BSP_SPI1_TX_USING_DMA) || defined(BSP_SPI1_RX_USING_DMA) */ -#if defined(BSP_SPI2_TX_USING_DMA) || defined(BSP_SPI2_RX_USING_DMA) +#endif /* defined(BSP_USING_SPI1) && defined(BSP_SPI1_USING_DMA) */ +#if defined(BSP_USING_SPI2) && defined(BSP_SPI2_USING_DMA) +/** + * @brief Dispatch the combined SPI2 DMA RX/TX interrupt. + */ void SPI2_DMA_RX_TX_IRQHandler(void) { -#if defined(BSP_SPI2_TX_USING_DMA) +#if defined(BSP_USING_SPI2) && defined(BSP_SPI2_TX_USING_DMA) SPI2_DMA_TX_IRQHandler(); #endif -#if defined(BSP_SPI2_RX_USING_DMA) +#if defined(BSP_USING_SPI2) && defined(BSP_SPI2_RX_USING_DMA) SPI2_DMA_RX_IRQHandler(); #endif } -#endif /* defined(BSP_SPI1_TX_USING_DMA) || defined(BSP_SPI1_RX_USING_DMA) */ +#endif /* defined(BSP_USING_SPI2) && defined(BSP_SPI2_USING_DMA) */ #if defined(STM32G0B0xx) || defined(STM32G0B1xx) || defined(STM32G0C1xx) #if defined(BSP_USING_SPI2) || defined(BSP_USING_SPI3) +/** + * @brief Dispatch the shared SPI2/SPI3 peripheral interrupt. + */ void SPI2_3_IRQHandler(void) { -#if defined(BSP_SPI2_TX_USING_DMA) || defined(BSP_SPI2_RX_USING_DMA) +#if defined(BSP_USING_SPI2) && defined(BSP_SPI2_USING_IRQ) SPI2_IRQHandler(); #endif -#if defined(BSP_SPI3_TX_USING_DMA) || defined(BSP_SPI3_RX_USING_DMA) +#if defined(BSP_USING_SPI3) && defined(BSP_SPI3_USING_IRQ) SPI3_IRQHandler(); #endif } @@ -1095,12 +1427,20 @@ void SPI2_3_IRQHandler(void) #endif /* defined(STM32G0B0xx) || defined(STM32G0B1xx) || defined(STM32G0C1xx) */ #endif /* defined(SOC_SERIES_STM32F0) */ +/** + * @brief Initialize the STM32 SPI driver during board startup. + * + * @return RT_EOK on success, otherwise an RT-Thread error code. + */ int rt_hw_spi_init(void) { - stm32_get_dma_info(); +#ifdef BSP_SPI_USING_IRQ + stm32_get_xfer_info(); +#endif /* BSP_SPI_USING_IRQ */ return rt_hw_spi_bus_init(); } INIT_BOARD_EXPORT(rt_hw_spi_init); -#endif /* BSP_USING_SPI1 || BSP_USING_SPI2 || BSP_USING_SPI3 || BSP_USING_SPI4 || BSP_USING_SPI5 */ +#endif /* BSP_HARDWARE_SPI */ #endif /* BSP_USING_SPI */ + diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_spi.h b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_spi.h index 62506ba7dcc..bcf14bfb637 100644 --- a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_spi.h +++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_spi.h @@ -6,6 +6,12 @@ * Change Logs: * Date Author Notes * 2018-11-5 SummerGift first version + * 2026-04-16 wdfk-prog Add SPI interrupt transfer mode scaffolding + */ + +/** + * @file drv_spi.h + * @brief STM32 SPI bus driver private definitions. */ #ifndef __DRV_SPI_H__ @@ -18,52 +24,227 @@ #include "drv_dma.h" #include +/* Enable STM32 hardware SPI driver code when any SPI instance is selected. */ +#if defined(BSP_USING_SPI1) || defined(BSP_USING_SPI2) || defined(BSP_USING_SPI3) || defined(BSP_USING_SPI4) || defined(BSP_USING_SPI5) || defined(BSP_USING_SPI6) +#define BSP_HARDWARE_SPI +#endif + +/* Aggregate polling transfer configuration from per-instance Kconfig macros. */ +#if defined(BSP_SPI1_TX_USING_POLL) || defined(BSP_SPI2_TX_USING_POLL) || defined(BSP_SPI3_TX_USING_POLL) || defined(BSP_SPI4_TX_USING_POLL) || defined(BSP_SPI5_TX_USING_POLL) || defined(BSP_SPI6_TX_USING_POLL) +#define BSP_SPI_TX_USING_POLL +#endif + +#if defined(BSP_SPI1_RX_USING_POLL) || defined(BSP_SPI2_RX_USING_POLL) || defined(BSP_SPI3_RX_USING_POLL) || defined(BSP_SPI4_RX_USING_POLL) || defined(BSP_SPI5_RX_USING_POLL) || defined(BSP_SPI6_RX_USING_POLL) +#define BSP_SPI_RX_USING_POLL +#endif + +#if defined(BSP_SPI1_TX_USING_POLL) || defined(BSP_SPI1_RX_USING_POLL) +#define BSP_SPI1_USING_POLL +#endif + +#if defined(BSP_SPI2_TX_USING_POLL) || defined(BSP_SPI2_RX_USING_POLL) +#define BSP_SPI2_USING_POLL +#endif + +#if defined(BSP_SPI3_TX_USING_POLL) || defined(BSP_SPI3_RX_USING_POLL) +#define BSP_SPI3_USING_POLL +#endif + +#if defined(BSP_SPI4_TX_USING_POLL) || defined(BSP_SPI4_RX_USING_POLL) +#define BSP_SPI4_USING_POLL +#endif + +#if defined(BSP_SPI5_TX_USING_POLL) || defined(BSP_SPI5_RX_USING_POLL) +#define BSP_SPI5_USING_POLL +#endif + +#if defined(BSP_SPI6_TX_USING_POLL) || defined(BSP_SPI6_RX_USING_POLL) +#define BSP_SPI6_USING_POLL +#endif + +#if defined(BSP_SPI_TX_USING_POLL) || defined(BSP_SPI_RX_USING_POLL) +#define BSP_SPI_USING_POLL +#endif + +/* Aggregate DMA transfer configuration from per-instance Kconfig macros. */ +#if defined(BSP_SPI1_TX_USING_DMA) || defined(BSP_SPI2_TX_USING_DMA) || defined(BSP_SPI3_TX_USING_DMA) || defined(BSP_SPI4_TX_USING_DMA) || defined(BSP_SPI5_TX_USING_DMA) || defined(BSP_SPI6_TX_USING_DMA) +#define BSP_SPI_TX_USING_DMA +#endif + +#if defined(BSP_SPI1_RX_USING_DMA) || defined(BSP_SPI2_RX_USING_DMA) || defined(BSP_SPI3_RX_USING_DMA) || defined(BSP_SPI4_RX_USING_DMA) || defined(BSP_SPI5_RX_USING_DMA) || defined(BSP_SPI6_RX_USING_DMA) +#define BSP_SPI_RX_USING_DMA +#endif + +#if defined(BSP_SPI1_TX_USING_DMA) || defined(BSP_SPI1_RX_USING_DMA) +#define BSP_SPI1_USING_DMA +#endif + +#if defined(BSP_SPI2_TX_USING_DMA) || defined(BSP_SPI2_RX_USING_DMA) +#define BSP_SPI2_USING_DMA +#endif + +#if defined(BSP_SPI3_TX_USING_DMA) || defined(BSP_SPI3_RX_USING_DMA) +#define BSP_SPI3_USING_DMA +#endif + +#if defined(BSP_SPI4_TX_USING_DMA) || defined(BSP_SPI4_RX_USING_DMA) +#define BSP_SPI4_USING_DMA +#endif + +#if defined(BSP_SPI5_TX_USING_DMA) || defined(BSP_SPI5_RX_USING_DMA) +#define BSP_SPI5_USING_DMA +#endif + +#if defined(BSP_SPI6_TX_USING_DMA) || defined(BSP_SPI6_RX_USING_DMA) +#define BSP_SPI6_USING_DMA +#endif + +#if defined(BSP_SPI_TX_USING_DMA) || defined(BSP_SPI_RX_USING_DMA) +#define BSP_SPI_USING_DMA +#endif + +/* Aggregate interrupt transfer configuration from per-instance Kconfig macros. */ +#if defined(BSP_SPI1_TX_USING_INT) || defined(BSP_SPI2_TX_USING_INT) || defined(BSP_SPI3_TX_USING_INT) || defined(BSP_SPI4_TX_USING_INT) || defined(BSP_SPI5_TX_USING_INT) || defined(BSP_SPI6_TX_USING_INT) +#define BSP_SPI_TX_USING_INT +#endif + +#if defined(BSP_SPI1_RX_USING_INT) || defined(BSP_SPI2_RX_USING_INT) || defined(BSP_SPI3_RX_USING_INT) || defined(BSP_SPI4_RX_USING_INT) || defined(BSP_SPI5_RX_USING_INT) || defined(BSP_SPI6_RX_USING_INT) +#define BSP_SPI_RX_USING_INT +#endif + +#if defined(BSP_SPI1_TX_USING_INT) || defined(BSP_SPI1_RX_USING_INT) +#define BSP_SPI1_USING_INT +#endif + +#if defined(BSP_SPI2_TX_USING_INT) || defined(BSP_SPI2_RX_USING_INT) +#define BSP_SPI2_USING_INT +#endif + +#if defined(BSP_SPI3_TX_USING_INT) || defined(BSP_SPI3_RX_USING_INT) +#define BSP_SPI3_USING_INT +#endif + +#if defined(BSP_SPI4_TX_USING_INT) || defined(BSP_SPI4_RX_USING_INT) +#define BSP_SPI4_USING_INT +#endif + +#if defined(BSP_SPI5_TX_USING_INT) || defined(BSP_SPI5_RX_USING_INT) +#define BSP_SPI5_USING_INT +#endif + +#if defined(BSP_SPI6_TX_USING_INT) || defined(BSP_SPI6_RX_USING_INT) +#define BSP_SPI6_USING_INT +#endif + +#if defined(BSP_SPI_TX_USING_INT) || defined(BSP_SPI_RX_USING_INT) +#define BSP_SPI_USING_INT +#endif + +/* Aggregate IRQ requirements from DMA and interrupt transfer modes. */ +#if defined(BSP_SPI1_USING_DMA) || defined(BSP_SPI1_USING_INT) +#define BSP_SPI1_USING_IRQ +#endif + +#if defined(BSP_SPI2_USING_DMA) || defined(BSP_SPI2_USING_INT) +#define BSP_SPI2_USING_IRQ +#endif + +#if defined(BSP_SPI3_USING_DMA) || defined(BSP_SPI3_USING_INT) +#define BSP_SPI3_USING_IRQ +#endif + +#if defined(BSP_SPI4_USING_DMA) || defined(BSP_SPI4_USING_INT) +#define BSP_SPI4_USING_IRQ +#endif + +#if defined(BSP_SPI5_USING_DMA) || defined(BSP_SPI5_USING_INT) +#define BSP_SPI5_USING_IRQ +#endif + +#if defined(BSP_SPI6_USING_DMA) || defined(BSP_SPI6_USING_INT) +#define BSP_SPI6_USING_IRQ +#endif + +#if defined(BSP_SPI_USING_DMA) || defined(BSP_SPI_USING_INT) +#define BSP_SPI_USING_IRQ +#endif + #ifdef __cplusplus extern "C" { #endif +/** + * @brief Attach an SPI device to a registered STM32 SPI bus. + * + * @param bus_name SPI bus name, such as "spi1". + * @param device_name SPI device name to register. + * @param cs_pin Chip-select pin used by the SPI device. + * @return RT_EOK on success, otherwise an RT-Thread error code. + */ rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin); + +/** + * @brief Detach a previously attached STM32 SPI device. + * + * @param device_name SPI device name to detach. + * @return RT_EOK on success, otherwise an RT-Thread error code. + */ rt_err_t rt_hw_spi_device_detach(const char *device_name); #ifdef __cplusplus } #endif +/** + * @brief Static configuration for one STM32 SPI bus instance. + */ struct stm32_spi_config { - SPI_TypeDef *Instance; - char *bus_name; - IRQn_Type irq_type; - const struct stm32_dma_config *dma_rx, *dma_tx; + SPI_TypeDef *Instance; /**< SPI peripheral register base. */ + char *bus_name; /**< RT-Thread SPI bus name. */ + IRQn_Type irq_type; /**< SPI peripheral IRQ number. */ +#ifdef BSP_SPI_RX_USING_DMA + const struct stm32_dma_config *dma_rx; /**< RX DMA configuration. */ +#endif /* BSP_SPI_RX_USING_DMA */ +#ifdef BSP_SPI_TX_USING_DMA + const struct stm32_dma_config *dma_tx; /**< TX DMA configuration. */ +#endif /* BSP_SPI_TX_USING_DMA */ }; +/** + * @brief Board-level SPI device attachment information. + */ struct stm32_spi_device { - rt_uint32_t pin; - char *bus_name; - char *device_name; + rt_uint32_t pin; /**< Chip-select pin number. */ + char *bus_name; /**< SPI bus name used for attachment. */ + char *device_name; /**< SPI device name registered on the bus. */ }; -#define SPI_USING_RX_DMA_FLAG (1<<0) -#define SPI_USING_TX_DMA_FLAG (1<<1) - -/* stm32 spi dirver class */ +/** + * @brief Runtime context for one STM32 SPI bus. + */ struct stm32_spi { - SPI_HandleTypeDef handle; - struct stm32_spi_config *config; - struct rt_spi_configuration *cfg; - + SPI_HandleTypeDef handle; /**< STM32 HAL SPI handle. */ + struct stm32_spi_config *config; /**< Static bus configuration. */ + struct rt_spi_configuration *cfg; /**< Active RT-Thread SPI configuration. */ + struct rt_spi_bus spi_bus; /**< RT-Thread SPI bus object. */ + rt_uint16_t spi_xfer_flags; /**< RT_DEVICE_FLAG_DMA_* and RT_DEVICE_FLAG_INT_* transfer flags. */ +#ifdef BSP_SPI_USING_IRQ + struct rt_completion cpt; /**< Completion used by asynchronous SPI transfers. */ +#endif /* BSP_SPI_USING_IRQ */ +#ifdef BSP_SPI_USING_DMA struct { - DMA_HandleTypeDef handle_rx; - DMA_HandleTypeDef handle_tx; - } dma; - - rt_uint8_t spi_dma_flag; - struct rt_spi_bus spi_bus; - - struct rt_completion cpt; +#ifdef BSP_SPI_RX_USING_DMA + DMA_HandleTypeDef handle_rx; /**< STM32 HAL RX DMA handle. */ +#endif /* BSP_SPI_RX_USING_DMA */ +#ifdef BSP_SPI_TX_USING_DMA + DMA_HandleTypeDef handle_tx; /**< STM32 HAL TX DMA handle. */ +#endif /* BSP_SPI_TX_USING_DMA */ + } dma; /**< DMA handles associated with this SPI bus. */ +#endif /* BSP_SPI_USING_DMA */ }; #endif /*__DRV_SPI_H__ */