Skip to content

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

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

[stm32][drivers] Add BDMA support for SPI#11689
moment-NEW wants to merge 2 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/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-23 11:02 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 +272 B (+0.3%, 86,012 B / 1,048,576 B, total: 8% used)

stm32l475-atk-pandora-llvm

  • ROM: .text +304 B (+0.4%, 83,696 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强推一下.

@@ -346,9 +371,117 @@ rt_err_t stm32_dma_deinit(DMA_HandleTypeDef *dma_handle,

#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 会更容易维护。

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