Skip to content

[stm32][drivers] Add BDMA support for SPI - #11689

Open
moment-NEW wants to merge 4 commits into
RT-Thread:masterfrom
moment-NEW:feat/spi-bdma
Open

[stm32][drivers] Add BDMA support for SPI#11689
moment-NEW wants to merge 4 commits into
RT-Thread:masterfrom
moment-NEW:feat/spi-bdma

Conversation

@moment-NEW

@moment-NEW moment-NEW commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

拉取/合并请求描述:(PR description)

[

为什么提交这份PR (why to submit this PR)

对于H7系列的SPI,其缺失BDMA驱动,因此制作了相关驱动使其正常工作

你的解决方案是什么 (what is your solution)

仿照drv_dma的设计,在驱动层单独设计了一套bdma驱动,而上层spi处基本复用dma逻辑。

请提供验证的bsp和config (provide the config and bsp)

已在DM-MC02 上完成验证工作,验证使用自行编写的WS2812驱动软件包,测试正常点亮,效果与阻塞一致,且不影响串口等其他外设。该BSP以及相关软件包会稍后进行格式清理等后推送。此外进行了scons -j8等编译均通过。

  • BSP:bsp/stm32/stm32h723-DM-MC02
  • .config:
  • action:

]

当前拉取/合并请求的状态 Intent for your PR

必须选择一项 Choose one (Mandatory):

  • 本拉取/合并请求是一个草稿版本 This PR is for a code-review and is intended to get feedback
  • 本拉取/合并请求是一个成熟版本 This PR is mature, and ready to be integrated into the repo

代码质量 Code Quality:

我在这个拉取/合并请求中已经考虑了 As part of this pull request, I've considered the following:

  • 已经仔细查看过代码改动的对比 Already check the difference between PR and old code
  • 代码风格正确,包括缩进空格,命名及其他风格 Style guide is adhered to, including spacing, naming and other styles
  • 没有垃圾代码,代码尽量精简,不包含#if 0代码,不包含已经被注释了的代码 All redundant code is removed and cleaned up
  • 所有变更均有原因及合理的,并且不会影响到其他软件组件代码或BSP All modifications are justified and not affect other components or BSP
  • 对难懂代码均提供对应的注释 I've commented appropriately where code is tricky
  • 代码是高质量的 Code in this PR is of high quality
  • 已经使用clang-format 源码格式化工具确保格式符合RT-Thread代码规范 This PR has been formatted with clang-format and complies with RT-Thread code specification
  • 如果是新增bsp, 已经添加ci检查到.github/ALL_BSP_COMPILE.json 详细请参考链接BSP自查

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

👋 感谢您对 RT-Thread 的贡献!Thank you for your contribution to RT-Thread!

为确保代码符合 RT-Thread 的编码规范,请在你的仓库中执行以下步骤运行代码格式化工作流(如果格式化CI运行失败)。
To ensure your code complies with RT-Thread's coding style, please run the code formatting workflow by following the steps below (If the formatting of CI fails to run).


🛠 操作步骤 | Steps

  1. 前往 Actions 页面 | Go to the Actions page
    点击进入工作流 → | Click to open workflow →

  2. 点击 Run workflow | Click Run workflow

  • Use workflow from 保持默认分支(通常为 master
    Keep the default branch (usually master) in Use workflow from
  • branch 输入框填写 PR 分支 feat/spi-bdma
    Enter PR branch feat/spi-bdma in the branch field
  • 设置需排除的文件/目录(目录请以"/"结尾)
    Set files/directories to exclude (directories should end with "/")
  1. 等待工作流完成 | Wait for the workflow to complete
    格式化后的代码将作为独立提交推送至你的分支。
    The formatting changes will be pushed to your branch as a separate commit.

完成后,提交将自动更新至 feat/spi-bdma 分支,关联的 Pull Request 也会同步更新。
Once completed, commits will be pushed to the feat/spi-bdma branch automatically, and the related Pull Request will be updated.

如有问题欢迎联系我们,再次感谢您的贡献!💐
If you have any questions, feel free to reach out. Thanks again for your contribution!

@github-actions github-actions Bot added BSP: STM32 BSP related with ST/STM32 BSP labels Aug 9, 2026
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

📌 Code Review Assignment

🏷️ Tag: bsp_stm32

Reviewers: @Liang1795 @hamburger-os @wdfk-prog

Changed Files (Click to expand)
  • bsp/stm32/libraries/HAL_Drivers/drivers/Kconfig
  • bsp/stm32/libraries/HAL_Drivers/drivers/SConscript
  • bsp/stm32/libraries/HAL_Drivers/drivers/config/h7/dma_config.h
  • bsp/stm32/libraries/HAL_Drivers/drivers/config/h7/spi_config.h
  • bsp/stm32/libraries/HAL_Drivers/drivers/drv_dma.c
  • bsp/stm32/libraries/HAL_Drivers/drivers/drv_dma.h
  • bsp/stm32/libraries/HAL_Drivers/drivers/drv_spi.c
  • bsp/stm32/libraries/HAL_Drivers/drivers/drv_spi.h

📊 Current Review Status (Last Updated: 2026-08-29 08:55 CST)


📝 Review Instructions

  1. 维护者可以通过单击此处来刷新审查状态: 🔄 刷新状态
    Maintainers can refresh the review status by clicking here: 🔄 Refresh Status

  2. 确认审核通过后评论 LGTM/lgtm
    Comment LGTM/lgtm after confirming approval

  3. PR合并前需至少一位维护者确认
    PR must be confirmed by at least one maintainer before merging

ℹ️ 刷新CI状态操作需要具备仓库写入权限。
ℹ️ Refresh CI status operation requires repository Write permission.

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

stm32f407-rt-spark

  • CODE: .text +212 B (+0.2%, 85,976 B / 1,048,576 B, total: 8% used)

stm32l475-atk-pandora-llvm

  • ROM: .text +336 B (+0.4%, 83,764 B / 524,288 B, total: 16% used)

@moment-NEW

Copy link
Copy Markdown
Contributor Author

现在还是草稿阶段...稍后整理一下BSP部分,开启一个BSP的PR再推上来吧

@wdfk-prog

wdfk-prog commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

现在还是草稿阶段...稍后整理一下BSP部分,开启一个BSP的PR再推上来吧

  • 这个bdma没有必要单独开展一个文件的;
struct stm32_bdma_config
{
    void *Instance;                      /**< BDMA channel instance pointer. */
    rt_uint32_t dma_rcc;                 /**< RCC enable bit for the BDMA controller. */
    IRQn_Type dma_irq;                   /**< NVIC IRQ number for the BDMA channel. */
    rt_uint32_t priority;                /**< BDMA transfer priority. */
    rt_uint8_t preempt_priority;         /**< NVIC preempt priority for the BDMA IRQ. */
    rt_uint8_t sub_priority;             /**< NVIC sub priority for the BDMA IRQ. */
    rt_uint32_t request;                 /**< BDMA request selector. */
    rt_uint32_t direction;               /**< BDMA transfer direction. */
    rt_uint32_t periph_inc;              /**< Peripheral address increment mode. */
    rt_uint32_t mem_inc;                 /**< Memory address increment mode. */
    rt_uint32_t periph_data_alignment;   /**< Peripheral data alignment. */
    rt_uint32_t mem_data_alignment;      /**< Memory data alignment. */
    rt_uint32_t mode;                    /**< BDMA transfer mode. */
};
  • 就像stm32_dma_config中关于GPDMA的特殊处理这样对BDMA进行处理就好了
  • stm32_dma_config中也有channel
  • 你可以看看BDMA中有什么特殊的结构体添加到stm32_dma_config中用宏隔开即可.
  • 这样子可以不再需要一个BDMA的文件了
  • 虽然这样子还是不够简洁,但是把dma逻辑散落到不同文件里面也是更难维护的
/**
 * @brief Static DMA endpoint description used by board-level config headers.
 *
 * This descriptor stores one complete DMA endpoint configuration so peripheral
 * drivers can initialize DMA directly from the board-level config tables.
 */
struct stm32_dma_config
{
    DMA_INSTANCE_TYPE *Instance;        /**< DMA controller instance pointer. */
    rt_uint32_t dma_rcc;                /**< RCC enable bit for the DMA controller. */
    IRQn_Type dma_irq;                  /**< DMA global IRQ number. */
    rt_uint32_t priority;               /**< DMA transfer priority. */
    rt_uint8_t preempt_priority;        /**< NVIC preempt priority for the DMA IRQ. */
    rt_uint8_t sub_priority;            /**< NVIC sub priority for the DMA IRQ. */

#if defined(STM32_DMA_USES_GPDMA)
    rt_uint32_t request;                /**< DMA request selector for the GPDMA channel. */
    rt_uint32_t blk_hw_request;         /**< GPDMA block hardware request mode. */
    rt_uint32_t direction;              /**< DMA transfer direction. */
    rt_uint32_t src_inc;                /**< GPDMA source increment mode. */
    rt_uint32_t dest_inc;               /**< GPDMA destination increment mode. */
    rt_uint32_t src_data_width;         /**< GPDMA source data width. */
    rt_uint32_t dest_data_width;        /**< GPDMA destination data width. */
    rt_uint32_t src_burst_length;       /**< GPDMA source burst length. */
    rt_uint32_t dest_burst_length;      /**< GPDMA destination burst length. */
    rt_uint32_t transfer_allocated_port;/**< GPDMA allocated port selection. */
    rt_uint32_t transfer_event_mode;    /**< GPDMA transfer event mode. */
    rt_uint32_t mode;                   /**< DMA transfer mode. */
#else
#ifdef STM32_DMA_USES_CHANNEL
    rt_uint32_t channel;                /**< DMA channel selector for stream-based DMA. */
#endif /* STM32_DMA_USES_CHANNEL */

#ifdef STM32_DMA_USES_REQUEST
    rt_uint32_t request;                /**< DMA request selector for DMAMUX/request-based DMA. */
#endif /* STM32_DMA_USES_REQUEST */

    rt_uint32_t direction;              /**< DMA transfer direction. */
    rt_uint32_t periph_inc;             /**< Peripheral address increment mode. */
    rt_uint32_t mem_inc;                /**< Memory address increment mode. */
    rt_uint32_t periph_data_alignment;  /**< Peripheral data alignment. */
    rt_uint32_t mem_data_alignment;     /**< Memory data alignment. */
    rt_uint32_t mode;                   /**< DMA transfer mode. */

#if defined(STM32_DMA_SUPPORTS_FIFO)
    rt_uint32_t fifo_mode;              /**< FIFO enable state. */
    rt_uint32_t fifo_threshold;         /**< FIFO threshold selection. */
    rt_uint32_t mem_burst;              /**< Memory burst transfer mode. */
    rt_uint32_t periph_burst;           /**< Peripheral burst transfer mode. */
#endif /* defined(STM32_DMA_SUPPORTS_FIFO) */
#endif /* defined(STM32_DMA_USES_GPDMA) */
};
  • 我看了一些结构体的不同之处,好像并没有不同的地方?所有bdma可以使用Koconfig选择后把STM32_DMA_USES_REQUEST宏一并选择即可;这样BDMA的结构体就完成定义了
  • 至于具体的函数代码还有什么不同,我还没有查看;我认为应该可以在现有的dma代码中进行通过宏定义?或者flag?方案进行对于不同逻辑的使用和转接

@moment-NEW

moment-NEW commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

现在还是草稿阶段...稍后整理一下BSP部分,开启一个BSP的PR再推上来吧

  • 这个bdma没有必要单独开展一个文件的;
struct stm32_bdma_config
{
    void *Instance;                      /**< BDMA channel instance pointer. */
    rt_uint32_t dma_rcc;                 /**< RCC enable bit for the BDMA controller. */
    IRQn_Type dma_irq;                   /**< NVIC IRQ number for the BDMA channel. */
    rt_uint32_t priority;                /**< BDMA transfer priority. */
    rt_uint8_t preempt_priority;         /**< NVIC preempt priority for the BDMA IRQ. */
    rt_uint8_t sub_priority;             /**< NVIC sub priority for the BDMA IRQ. */
    rt_uint32_t request;                 /**< BDMA request selector. */
    rt_uint32_t direction;               /**< BDMA transfer direction. */
    rt_uint32_t periph_inc;              /**< Peripheral address increment mode. */
    rt_uint32_t mem_inc;                 /**< Memory address increment mode. */
    rt_uint32_t periph_data_alignment;   /**< Peripheral data alignment. */
    rt_uint32_t mem_data_alignment;      /**< Memory data alignment. */
    rt_uint32_t mode;                    /**< BDMA transfer mode. */
};
  • 就像stm32_dma_config中关于GPDMA的特殊处理这样对BDMA进行处理就好了
  • stm32_dma_config中也有channel
  • 你可以看看BDMA中有什么特殊的结构体添加到stm32_dma_config中用宏隔开即可.
  • 这样子可以不再需要一个BDMA的文件了
  • 虽然这样子还是不够简洁,但是把dma逻辑散落到不同文件里面也是更难维护的
/**
 * @brief Static DMA endpoint description used by board-level config headers.
 *
 * This descriptor stores one complete DMA endpoint configuration so peripheral
 * drivers can initialize DMA directly from the board-level config tables.
 */
struct stm32_dma_config
{
    DMA_INSTANCE_TYPE *Instance;        /**< DMA controller instance pointer. */
    rt_uint32_t dma_rcc;                /**< RCC enable bit for the DMA controller. */
    IRQn_Type dma_irq;                  /**< DMA global IRQ number. */
    rt_uint32_t priority;               /**< DMA transfer priority. */
    rt_uint8_t preempt_priority;        /**< NVIC preempt priority for the DMA IRQ. */
    rt_uint8_t sub_priority;            /**< NVIC sub priority for the DMA IRQ. */

#if defined(STM32_DMA_USES_GPDMA)
    rt_uint32_t request;                /**< DMA request selector for the GPDMA channel. */
    rt_uint32_t blk_hw_request;         /**< GPDMA block hardware request mode. */
    rt_uint32_t direction;              /**< DMA transfer direction. */
    rt_uint32_t src_inc;                /**< GPDMA source increment mode. */
    rt_uint32_t dest_inc;               /**< GPDMA destination increment mode. */
    rt_uint32_t src_data_width;         /**< GPDMA source data width. */
    rt_uint32_t dest_data_width;        /**< GPDMA destination data width. */
    rt_uint32_t src_burst_length;       /**< GPDMA source burst length. */
    rt_uint32_t dest_burst_length;      /**< GPDMA destination burst length. */
    rt_uint32_t transfer_allocated_port;/**< GPDMA allocated port selection. */
    rt_uint32_t transfer_event_mode;    /**< GPDMA transfer event mode. */
    rt_uint32_t mode;                   /**< DMA transfer mode. */
#else
#ifdef STM32_DMA_USES_CHANNEL
    rt_uint32_t channel;                /**< DMA channel selector for stream-based DMA. */
#endif /* STM32_DMA_USES_CHANNEL */

#ifdef STM32_DMA_USES_REQUEST
    rt_uint32_t request;                /**< DMA request selector for DMAMUX/request-based DMA. */
#endif /* STM32_DMA_USES_REQUEST */

    rt_uint32_t direction;              /**< DMA transfer direction. */
    rt_uint32_t periph_inc;             /**< Peripheral address increment mode. */
    rt_uint32_t mem_inc;                /**< Memory address increment mode. */
    rt_uint32_t periph_data_alignment;  /**< Peripheral data alignment. */
    rt_uint32_t mem_data_alignment;     /**< Memory data alignment. */
    rt_uint32_t mode;                   /**< DMA transfer mode. */

#if defined(STM32_DMA_SUPPORTS_FIFO)
    rt_uint32_t fifo_mode;              /**< FIFO enable state. */
    rt_uint32_t fifo_threshold;         /**< FIFO threshold selection. */
    rt_uint32_t mem_burst;              /**< Memory burst transfer mode. */
    rt_uint32_t periph_burst;           /**< Peripheral burst transfer mode. */
#endif /* defined(STM32_DMA_SUPPORTS_FIFO) */
#endif /* defined(STM32_DMA_USES_GPDMA) */
};
  • 我看了一些结构体的不同之处,好像并没有不同的地方?所有bdma可以使用Koconfig选择后把STM32_DMA_USES_REQUEST宏一并选择即可;这样BDMA的结构体就完成定义了
  • 至于具体的函数代码还有什么不同,我还没有查看;我认为应该可以在现有的dma代码中进行通过宏定义?或者flag?方案进行对于不同逻辑的使用和转接
  • 关于重复的配置:
    确实是如此。BDMA绝大部分配置都是在HAL库上和DMA通用的。但是我还是没有采取dma加宏定义的方式,因为DMA里面宏定义太多了,FIFO,Channel,等等有大量的宏编译分支(重新看了一下其实也不算很多,把下游SPI的条件编译看进去了),虽然BDMA基本上不用考虑这些,但是再加进去,我觉得会让DMA的可读性大大下降,此外我不是很清楚改动会对其他使用DMA的产生什么影响,比如uart等。
  • 关于结构体不同之处:
    也是正因如此,我觉得如果要合并,更合适的可能是单独开一个bdma类型,其能复用setup等逻辑,作为没有FIFO等特殊功能的普通DMA使用,不需要单独走编译分支

@moment-NEW

moment-NEW commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

@wdfk-prog 您好!我根据您的意见大概修改了一下,不过我选择的是实现了个简单的DMA的类来继承,把原来的DMA和BDMA逻辑都转发到通用的DMA内部处理函数里面。不知道可以可以不可以?

  • 似乎因为本地的formatting过时了所以导致有很大的格式问题。对于可能存在的review干扰非常抱歉

@wdfk-prog

Copy link
Copy Markdown
Contributor

@wdfk-prog 您好!我根据您的意见大概修改了一下,不过我选择的是实现了个简单的DMA的类来继承,把原来的DMA和BDMA逻辑都转发到通用的DMA内部处理函数里面。不知道可以可以不可以?

  • 似乎因为本地的formatting过时了所以导致有很大的格式问题。对于可能存在的review干扰非常抱歉
  • 你能合并一些commit吗?只保留最新两个commit进行提交即可
  • 可以使用git push -f强推一下.

const struct stm32_dma_config *dma_config,
rt_bool_t abort_first);

#endif /* HAL_DMA_MODULE_ENABLED */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • 新增的代码应该包括到这个宏里面


#endif /* BSP_USING_BDMA && (SOC_SERIES_STM32H7 || SOC_SERIES_STM32H7RS) */

#if defined(BSP_USING_BDMA) && (defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32H7RS))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • 这个宏不是跟上面的一样的吗?为什么单独又来一个#if


#endif /* HAL_DMA_MODULE_ENABLED */

#if defined(BSP_USING_BDMA) && (defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32H7RS))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • L374~L482 这些需要特地区分出来吗?
  • 如果只是为了体现BDMA却跟DMA用法一样的话,不需要额外多这么多定义

if (dma_rcc == 0)
{
LOG_E("bdma enable clock failed, dma_rcc is 0");
__HAL_RCC_BDMA_CLK_ENABLE();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • 这个没看懂,这里是要异常退出吧?为什么还使能BDMA CLK了?

{
rt_uint32_t tmpreg = 0x00U;

#if defined(BSP_USING_BDMA) && (defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32H7RS))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • 这一段能跟下面的#if defined(STM32_DMA_USES_RCC_AHBENR)判断逻辑一样放在同一个IF ELIF里面吗?这样子会更好

#if defined(BSP_USING_BDMA) && (defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32H7RS))
if (is_bdma)
{
if (dma_rcc == 0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • dma_rcc = 0是异常吗?那可以未所有dma都做判断,而不只是bdma
  • 或者也可以不限制用户的自由?否则的话这里异常退出没有返回值

* @param is_bdma RT_TRUE for BDMA clock enable, RT_FALSE for regular DMA.
*/
static void stm32_dma_enable_clock(rt_uint32_t dma_rcc)
static void stm32_dma_enable_clock(rt_uint32_t dma_rcc, rt_bool_t is_bdma)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • 我看不需要增加is_bdma的变量吧?可以在dma_config中增加一个变量传入即可,这样子不需要改动这么多函数和定义

@moment-NEW

Copy link
Copy Markdown
Contributor Author

@wdfk-prog 您好!根据您的意见我又修改了一版,PTAL

@wdfk-prog

Copy link
Copy Markdown
Contributor

@wdfk-prog 您好!根据您的意见我又修改了一版,PTAL

  • LOG_TAG或者使用"drv.dma"传入可以不用这样子做

  • 以及在cfg里面有type作为可以识别的变量了

  • 所有bdma和dma的代码可以统一为一套代码为函数;在函数内部根据type进行识别做处理与日志打印即可,不再需要分开做两套函数

  • 如果可以话,把GDMA的也修改到同一套框架里面会更好

  • 还有就是你能合并一些commit吗?只保留最新两个commit进行提交即可;一个修改的,另一个格式化代码的,这样比较好审核,可以使用git push -f强推一下.

@moment-NEW

Copy link
Copy Markdown
Contributor Author

@wdfk-prog PTAL

@wdfk-prog

Copy link
Copy Markdown
Contributor

@wdfk-prog PTAL

重新按当前版本复审了一遍,也结合上一轮 review 再确认了一下修改方向。

相比最初版本,现在已经开始把 BDMA 收到现有 DMA framework 中,这个方向是对的。这里我补充一下我对最终结构的建议:这次允许同时调整现有 DMA / GPDMA,不要求为了减少 diff 而完全保持旧实现;但既然要重构,就建议一次把 DMA / BDMA / GPDMA 的公共层次整理清楚,避免形成新的临时兼容层。

当前版本我仍然建议继续修改后再 review,主要有以下问题。

1. stm32_dma_type 当前定义有类型错误

范围:

bsp/stm32/libraries/HAL_Drivers/drivers/drv_dma.h

当前:

typedef enum
{
    STM32_DMA_TYPE_DMA = 0,
    STM32_DMA_TYPE_BDMA,
} stm32_dma_type;

但是结构体成员写成:

enum stm32_dma_type type;

这里定义的是匿名 enum 的 typedef,并不存在 enum stm32_dma_type

直接使用:

stm32_dma_type type;

或者给 enum 增加 tag。

这个属于需要直接修复的编译问题。


2. 建议真正整理成 common + special + dma_type,而不是现在的 prefix-compatible 强转

范围:

  • drv_dma.h

    • stm32_dma_config_common
    • stm32_dma_config
    • stm32_bdma_config
  • drv_dma.c

    • stm32_dma_apply_common_config()
    • stm32_dma_apply_config()
  • drv_spi.h / drv_spi.c

    • DMA / BDMA descriptor 与 handle

现在虽然抽出了:

struct stm32_dma_config_common

但是最后仍然形成:

stm32_dma_config_common
    ├── stm32_dma_config
    └── stm32_bdma_config

然后 SPI 再把:

const struct stm32_bdma_config *

强转成:

const struct stm32_dma_config *

传给公共 API。

我不建议依赖“两个结构体第一个成员一致”这种 prefix-compatible contract。

既然这次允许一起调整 DMA/GPDMA,我建议直接把 descriptor 收敛成一套:

enum stm32_dma_type
{
    STM32_DMA_TYPE_DMA,
    STM32_DMA_TYPE_BDMA,
    STM32_DMA_TYPE_GPDMA,
};

struct stm32_dma_config
{
    struct stm32_dma_config_common common;

    union
    {
        struct stm32_dma_classic_config classic;
        struct stm32_gpdma_config gpdma;
    } config;
};

其中真正所有类型都有的字段放 common,例如:

Instance
type
dma_rcc
dma_irq
priority
preempt_priority
sub_priority
direction
mode

request 如果希望统一也可以放公共层;如果考虑部分老系列没有 request,也可以继续根据 capability 宏组织。

而:

PeriphInc
MemInc
PeriphDataAlignment
MemDataAlignment

属于 classic DMA / BDMA 配置。

GPDMA 则使用:

SrcInc
DestInc
SrcDataWidth
DestDataWidth
BlkHWRequest
SrcBurstLength
DestBurstLength
TransferAllocatedPort
TransferEventMode

DMA Stream 自身 FIFO / channel 等能力再按现有 capability 宏处理。

重点是:结构差异应该由 descriptor 自身表达,而不是通过不同结构体后再强转。


3. 当前 stm32_dma_config_common 的字段划分还不正确

范围:

drv_dma.c::stm32_dma_apply_common_config()

现在:

dma_handle->Init.PeriphInc = common->periph_inc;
dma_handle->Init.MemInc = common->mem_inc;
dma_handle->Init.PeriphDataAlignment = common->periph_data_alignment;
dma_handle->Init.MemDataAlignment = common->mem_data_alignment;

这些实际上并不是 DMA / BDMA / GPDMA 的真正公共字段。

U5 / H5 / H7RS 的 GPDMA 对应的是:

SrcInc
DestInc
SrcDataWidth
DestDataWidth

所以如果这次准备把 GPDMA 一起重构,我认为没有问题,但需要把这个抽象完整做完,不能只是把 classic DMA 字段搬到 common 里面。

建议最后:

static void stm32_dma_apply_config(...)
{
    /* common fields */

    switch (dma_config->common.type)
    {
    case STM32_DMA_TYPE_DMA:
        /* classic DMA specific */
        break;

    case STM32_DMA_TYPE_BDMA:
        /* BDMA/classic channel specific */
        break;

    case STM32_DMA_TYPE_GPDMA:
        /* GPDMA specific */
        break;
    }
}

这样后续再增加不同 DMA controller 时,结构也比较清晰。

我之前提到的 GPDMA 问题不是要求不能改 GPDMA,而是当前版本的 common abstraction 还没有覆盖 GPDMA 的真实 HAL 数据结构

既然这次可以一起调整,就建议直接把这部分重构完整。


4. stm32_bdma_config 可以删除,统一使用 stm32_dma_config

当前:

struct stm32_bdma_config
{
    struct stm32_dma_config_common common;
};

没有任何 BDMA 自己独有的成员。

这种情况下没有必要存在一个新的 descriptor 类型。

建议:

static const struct stm32_dma_config spi6_bdma_tx = SPI6_TX_BDMA_CONFIG;
static const struct stm32_dma_config spi6_bdma_rx = SPI6_RX_BDMA_CONFIG;

initializer 中设置:

.type = STM32_DMA_TYPE_BDMA

即可。

这样也不再需要:

(const struct stm32_dma_config *)spi_drv->config->bdma_rx

这种强制转换。


5. SPI 层也没有必要维护 DMA / BDMA 两套 handle

范围:

drv_spi.h

当前新增:

dma_rx
dma_tx

bdma_rx
bdma_tx

以及:

spi_drv->dma.handle_rx
spi_drv->dma.handle_tx

spi_drv->bdma.handle_rx
spi_drv->bdma.handle_tx

我认为这里还是把底层 controller 类型暴露给 SPI driver 了。

SPI 层真正关心的是:

TX 是否使用 DMA transport
RX 是否使用 DMA transport
对应 DMA descriptor 是什么

至于是:

DMA1
DMA2
BDMA
GPDMA

应该由 drv_dma 根据 dma_type 处理。

因此建议 SPI 侧继续只保留:

const struct stm32_dma_config *dma_rx;
const struct stm32_dma_config *dma_tx;

以及:

dma.handle_rx
dma.handle_tx

SPI6 如果选择 BDMA:

dma_tx->type = STM32_DMA_TYPE_BDMA;

即可。

这样:

stm32_spi_dma_rollback()
stm32_spi_init()
stm32_get_xfer_info()

也都不需要分别维护 DMA/BDMA 两套逻辑。


6. BSP_USING_BDMA 与现在 SPI BDMA 宏的配置链路需要整理

范围:

  • drv_dma.h
  • drv_dma.c
  • drv_spi.h
  • Kconfig/config

当前能够看到:

BSP_SPI6_TX_USING_BDMA
BSP_SPI6_RX_USING_BDMA
BSP_SPI6_USING_BDMA
BSP_SPI_USING_BDMA

但是 DMA driver 使用:

BSP_USING_BDMA

例如:

#if defined(BSP_USING_BDMA) && defined(SOC_SERIES_STM32H7)

目前没有看到这两个层级之间明确的选择/定义关系。

这个需要统一,否则有可能出现:

SPI 已经启用了 BDMA,但:

stm32_dma_enable_clock()

中的 BDMA AHB4 RCC 分支没有编译进去。

尤其 H7 普通 DMA 使用 AHB1,而 BDMA 使用 AHB4,所以这里不能依赖一个没有闭合的宏链路。

建议不要让:

BSP_USING_BDMA
BSP_SPI_USING_BDMA

成为互不关联的两套状态。

可以由 SPI BDMA 配置统一 select/define 底层 BDMA capability。


7. DMA / BDMA 配置需要明确互斥

范围:

  • SPI Kconfig
  • drv_spi.h
  • stm32_get_xfer_info()

对于 SPI6 TX/RX,不应该允许同一个方向同时配置:

BSP_SPI6_TX_USING_DMA
BSP_SPI6_TX_USING_BDMA

或者 RX 对应组合。

因为 RT-Thread 这一层最终仍然只有:

RT_DEVICE_FLAG_DMA_TX
RT_DEVICE_FLAG_DMA_RX

同一个 SPI HAL handle 也只有:

hdmatx
hdmarx

因此建议配置层直接互斥。

例如概念上:

SPI6 TX DMA backend:
    - DMA
    - BDMA
    - none

RX 同理。

不要允许两套 controller 同时初始化以后,再依赖 setup 顺序覆盖 hdmatx/hdmarx


8. BDMA request 宏定义了以后应该真正使用

范围:

config/h7/dma_config.h

已经定义:

#define SPI6_TX_BDMA_REQUEST BDMA_REQUEST_SPI6_TX
#define SPI6_RX_BDMA_REQUEST BDMA_REQUEST_SPI6_RX

但是 spi_config.h 又直接传:

BDMA_REQUEST_SPI6_TX
BDMA_REQUEST_SPI6_RX

建议改成:

SPI6_TX_BDMA_REQUEST
SPI6_RX_BDMA_REQUEST

否则前面的 config 宏没有实际意义,也无法由 BSP override。


9. RCC 分流方向正确,但建议跟新的 dma_type 分发保持一致

范围:

drv_dma.c::stm32_dma_enable_clock()

现在:

if (type == STM32_DMA_TYPE_BDMA)
{
    SET_BIT(RCC->AHB4ENR, dma_rcc);
    ...
    return;
}

这个方向本身没有问题。

BDMA 与 H7 DMA1/DMA2 的 RCC domain 确实不同,所以这里通过 type 区分是合理的。

但建议最后统一成清晰的 controller/type dispatch。

另外当前注释:

/*while using BDMA,careful for the return,because you cant visit the FIFO member*/
/*if you did so there would be some illegal access.*/

与这个函数的职责不匹配。

这里 return 的原因是:

BDMA clock -> RCC AHB4
normal H7 DMA clock -> RCC AHB1

FIFO 应该在 config apply 阶段根据 controller type 控制,不应该跟 RCC helper 混在一起。


我建议最终结构

Descriptor

stm32_dma_config
│
├── common
│   ├── Instance
│   ├── type
│   ├── RCC
│   ├── IRQ
│   ├── priority
│   ├── direction
│   └── mode
│
└── special
    ├── classic DMA / BDMA
    │   ├── PeriphInc
    │   ├── MemInc
    │   ├── PeriphDataAlignment
    │   └── MemDataAlignment
    │
    └── GPDMA
        ├── SrcInc
        ├── DestInc
        ├── SrcDataWidth
        ├── DestDataWidth
        ├── BlkHWRequest
        ├── BurstLength
        └── ...

再通过:

STM32_DMA_TYPE_DMA
STM32_DMA_TYPE_BDMA
STM32_DMA_TYPE_GPDMA

统一 dispatch。

DMA helper

继续只保留:

stm32_dma_init()
stm32_dma_setup()
stm32_dma_deinit()

内部根据 type 处理 controller 差异。

SPI

继续只维护:

dma_rx
dma_tx
dma.handle_rx
dma.handle_tx

SPI driver 不区分底层到底是 DMA / BDMA / GPDMA。


这次我不要求为了减少 diff 而保留现有 GPDMA 实现,如果按照上述结构把 GPDMA 一起整理掉是可以接受的。

同样,本轮不把 BDMA buffer 所在 memory domain / SRAM4 限制作为 blocker;这部分如果后续真实使用场景遇到问题,再单独完善 buffer policy 即可。

代码格式化和非功能性变化也不要求专门回退,只要 commit 分层清晰,例如能区分:

DMA abstraction refactor
BDMA support
SPI6 BDMA integration
format/style

保证后续 review 和 git history 可追踪即可。

修改完成后,我建议至少确认:

  1. STM32H723 SPI6 TX BDMA 编译/运行;
  2. STM32H723 SPI6 RX BDMA;
  3. 原 STM32H7 DMA1/DMA2 路径回归;
  4. U5/H5/H7RS GPDMA 编译回归;
  5. DMA/BDMA 配置互斥;
  6. init/setup/deinit/rollback 路径;
  7. 提供实际验证使用的 .config

整体上我认为现在主要不是 BDMA 功能本身的问题,而是 DMA abstraction 还处于一半新、一半旧的状态

既然已经决定调整公共层,建议这次直接把 common + special + dma_type 做完整,再让 SPI 层回到单一 DMA abstraction。这样后面继续扩展 DMA controller 会更容易维护。

This update integrates SPI6 BDMA support into the unified DMA interface, allowing for a consistent handling of DMA and BDMA configurations. The changes include modifications to the DMA configuration structures and the SPI driver to accommodate both DMA types seamlessly. Additionally, Kconfig adjustments ensure proper selection between DMA and BDMA for SPI6.

- Updated DMA type definitions and configurations.
- Refactored SPI driver to route SPI6 BDMA through the unified DMA interface.
- Adjusted Kconfig to prevent mutual exclusivity issues between DMA and BDMA for SPI6.

Signed-off-by: moment-NEW
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BSP: STM32 BSP related with ST/STM32 BSP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants