ST STM32H723ZGTx - NUCLEO-H723ZG DMAMUX_RequestGen例程重现/消化/改进

ST STM32H723ZGTx - NUCLEO-H723ZG DMAMUX_RequestGen例程重现/消化/改进

概述

和同学讨论问题.
他要用CubeMX + STM32H723ZGTx 实现一个外中断0引发的DMA, 来根据外中断0触发MA自动拷贝 AD7606 FMC采样 的RAM地址的8通道的值到内存备用.

这个实现的知识点在官方例程中比较像的是DMAMUX_RequestGen, 以前正好用H743的官方板子做过实验(STM32H743I-EVAL2_DMAMUX_RequestGen), 同学正好找资料的时候看到了.
他就和我讨论如何在H723上实现这个功能(需要将DMA拷贝改成由EXTI0自动触发).

同学给了一个测试工程(他自己板子对应的工程, 将逻辑简化了, 只具体到外中断0自动触发DMA拷贝), 看了同学的代码, 知道他要解决的具体问题了.

搞了3天, 将这个问题搞定了.
对自己现在解决问题的能力真心满意, 是发自内心的:P

笔记

问题的难点

我们搞MCU编程时, 一般都是在用官方库, 而要实现的功能, 如果官方没给例程(官方没提到的知识点, 也没一点例子), 这个有点难搞, 大家都有体会, 基本下不了嘴.

如果手头要实现的功能和能找到的官方工程(例程, 知识点)能靠的上, 但是有区别(不同的程度, 相似度). 这时, 我们就可以通过实验, 来尝试能不能将这个功能实现.

如果将自己的初步想法实施了(按照官方例程思路), 但是初步实验效果达不到效果, 这时是要换个思路, 还是要继续硬啃这个知识点. 这时挺难下决定的.
因为官方提供的例程(e.g. DMA相关), 就那几个. 如果这个已经靠边的例程都不啃, 那找到另外合适的例程的机会也不大.

现在第三方库封装的比较复杂(不怪厂家, 芯片有那么复杂), 像ST家专门出了CubeMX, 就说明仅凭人工去配置芯片的功能实现代码, 基本已经不可能.

官方库/CubeMX也在不断进化, 官方例程可能是早期CubeMX生成的, 和当前最新版CubeMX生成的代码也不完全相同.
这时, 要参考官方例程的实现, 来使用最新版的CubeMX来配置芯片中的功能(DMA), 最后生成的配置代码虽然有点不一样, 但是可用.
只有当芯片配置好了, 写下的逻辑才好使.

如果不使用CubeMX去配置芯片, 即使按照官方例程, 将实现都迁移到自己工程, 也会不好使(大概率). 也不确定漏了些啥东西.
因为要研究CubeMX每一个配置具体使生成的代码工程哪里变了, 需要用BC4进行大量的双工程比对, 麻烦死了. 这不是搞应用的工程师该做的事情, 官方提供了工具(出了工具是有理由的)就要用(没有不用的理由).

为了确定程序流程, 加入ITM

在工程中加入ITM信息, 只需要在全速单步跑程序时, 看IDE(这个工程用的MDK5.37)中调试信息窗口的信息, 而不用去下断点来确定流程.

(H7 + MDK + ITM)已经做过笔记 ST - NUCLEO-H723ZG ITM不生效的问题

实验过了, 主时钟超过128MHZ, ITM信息就打印不出来了, 可能是板载STLINKV3的硬件速率限制.
所以这个实验, 将主时钟定位128MHZ.
等程序调试好了, 就可以将时钟提到最高, 不需要ITM了(可以注释掉ITM信息的printf)

将CubeMX升级到最新

当前版本为6.8.1
在这里插入图片描述

将CubeMX说明书翻一下

不用看太仔细, 从头到尾部粗粗的翻一遍, 有很多有用的细节使用内容.
在这里插入图片描述
在这里插入图片描述
用CubeMX生成DMAMUX_RequestGen例程作为参考
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
选择自己中意的IDE, 生成工程到自己本地.
查看工程是否自带.ioc, 如果有, 就知道官方例程怎么配置的芯片. 可惜, 大部分官方例程都没有自带.ioc.(估计官方不带.ioc的例程, 官方觉得可以通过readme的文本描述说清楚如何配置芯片, 但是有些细节真没说到啊).

查看工程自带的readme, 基本可以知道怎么配置芯片, 但是有些细节没说到, 需要自己去折腾.

/**
  @page DMAMUX_RequestGen DMA & DMAMUX request generator Example

  @verbatim
  ******************************************************************************
  * @file    DMA/DMAMUX_RequestGen/readme.txt
  * @author  MCD Application Team
  * @brief   Description of the DMA & DMAMUX request generator Example.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  @endverbatim

@par Example Description

How to use the DMA with the DMAMUX request generator to generate DMA transfer requests upon
LPTIM2 output signal, knowing that the LPTIM2 is configured in PWM with 2sec period.

The example uses the BDMA_Channel0 configured in memory to peripheral mode with the DMAMUX request generator 0.

At the beginning of the main program the HAL_Init() function is called to reset
all the peripherals, initialize the Flash interface and the systick.
The SystemClock_Config() function is used to configure the system clock for STM32H723xx devices:
The CPU at 520 MHz.
The HCLK for D1 Domain AXI and AHB3 peripherals , D2 Domain AHB1/AHB2 peripherals and D3 Domain AHB4  peripherals at 520 MHz/2.
The APB clock dividers for D1 Domain APB3 peripherals, D2 Domain APB1 and APB2 peripherals and D3 Domain APB4 peripherals to  run at 520 MHz/4.

The BDMA_Channel0 is configured in memory to peripheral mode to ensure data transfer from the source transmission
buffer (SRC_Buffer_LED1_Toggle) to the LED1 GPIO ODR register (in order to toggle LED1).
The DMA is configured in circular mode so the transfer will restart automatically each time the amount of data
to be transmitted has been reached.

@note the Domain 3 BDMA has access to this domain SRAM and peripherals only, thus the source buffer (SRC_Buffer_LED1_Toggle)
has been placed to the D3 SRAM (@0x38000000)

The DMAMUX request generator block is configured using function "HAL_DMAEx_ConfigMuxRequestGenerator"
with the following parameters :
- SignalID      : set to "HAL_DMAMUX2_REQUEST_GEN_LPTIM2_OUT" which corresponds to LPTIM2 output signal.
- Polarity      : Set to "RISING" to use rising edge of LPTIM2 output signal for DMA requests generation.
- RequestNumber : "1" i.e. on each rising edge of the LPTIM2 output signal, a DMA request is generated.

The DMA request generator is then enabled using function 揌AL_DMAEx_EnableMuxRequestGenerator?

The function "LPTIM_Config" is then used to configure the LPTIM2 to generate a PWM with a period of 2sec.
Note that the example doesn抰 need to configure a GPIO to LPTIM2 output alternate function as the LPTIM2 output signal
is used internally to trigger the DMAMUX request generator in order to generate DMA transfer requests every 2sec.

Then the DMA transfer is started in non-blocking mode using the HAL function "HAL_DMA_Start_IT"
On each LPTIM2 output event (i.e every 2sec) the DMAMUX request generator generates a DMA request.
As consequence the DMA will serve the request and write a new value to the LED1 GPIO ODR register to toggle the LED1
without any CPU intervention.
As consequence LED1 will toggle every 2sec.

The CPU is only used to intercept a DMA transfer interrupt error or a DMAMUX overrun interrupt error if any.
Then it sets the LED3 to On in this case.

NUCLEO-H723ZG board's LEDs can be used to monitor the transfer status:
 - LED1 toggles each 2 seconds when DMA transfers are achieved without any error.
 - LED3 is ON when there is an error during the DMA transfer.

@note Care must be taken when using HAL_Delay(), this function provides accurate delay (in milliseconds)
      based on variable incremented in SysTick ISR. This implies that if HAL_Delay() is called from
      a peripheral ISR process, then the SysTick interrupt must have higher priority (numerically lower)
      than the peripheral interrupt. Otherwise the caller ISR process will be blocked.
      To change the SysTick interrupt priority you have to use HAL_NVIC_SetPriority() function.

@note The application needs to ensure that the SysTick time base is always set to 1 millisecond
      to have correct HAL operation.

@Note If the  application is using the DTCM/ITCM memories (@0x20000000/ 0x0000000: not cacheable and only accessible
      by the Cortex M7 and the  MDMA), no need for cache maintenance when the Cortex M7 and the MDMA access these RAMs.
      If the application needs to use DMA(or other masters) based access or requires more RAM, then  the user has to:
              - Use a non TCM SRAM. (example : D1 AXI-SRAM @ 0x24000000)
              - Add a cache maintenance mechanism to ensure the cache coherence between CPU and other masters(DMAs,DMA2D,LTDC,MDMA).
              - The addresses and the size of cacheable buffers (shared between CPU and other masters)
                must be	properly defined to be aligned to L1-CACHE line size (32 bytes).

@Note It is recommended to enable the cache and maintain its coherence.
      Depending on the use case it is also possible to configure the cache attributes using the MPU.
      Please refer to the AN4838 "Managing memory protection unit (MPU) in STM32 MCUs"
      Please refer to the AN4839 "Level 1 cache on STM32F7 Series"

@par Keywords

System, DMA, DMAMUX, Request generator, Data Transfer, Stream

@par Directory contents

  - DMA/DMAMUX_RequestGen/Inc/stm32h7xx_hal_conf.h    HAL configuration file
  - DMA/DMAMUX_RequestGen/Inc/stm32h7xx_it.h          Interrupt handlers header file
  - DMA/DMAMUX_RequestGen/Inc/stm32h7xx_nucleo_conf.h    STM32H7xx_Nucleo board configuration file
  - DMA/DMAMUX_RequestGen/Inc/main.h                  Header for main.c module
  - DMA/DMAMUX_RequestGen/Src/stm32h7xx_it.c          Interrupt handlers
  - DMA/DMAMUX_RequestGen/Src/main.c                  Main program
  - DMA/DMAMUX_RequestGen/Src/system_stm32h7xx.c      STM32H7xx system source file

@par Hardware and Software environment

  - This example runs on STM32H723xx device.

  - This example has been tested with NUCLEO-H723ZG board and can be
    easily tailored to any other supported device and development board.

@par How to use it ?

In order to make the program work, you must do the following :
 - Open your preferred toolchain
 - Rebuild all files and load your image into target memory
 - Run the example


 */

尝试按照readme复现芯片功能的配置, 细节需要对照官方例程实现猜测和实验.

在这里插入图片描述
这是我实验好的工程的myDMAMUX_RequestGen.ioc, 笔记就照这个最终版本来, 从头来重现一次.

CubeMX配置芯片功能

我用的实验板子是官方的NUCLEO-H723ZG(主要是同学自己设计的实验板子也只焊接了一套, 想做实验, 就只能拿手头的官方板子了. 如果能将细节的具体问题抽象到和具体板子无关, 就可以在不同的板子上做实验)
在这里插入图片描述
为了这个实验, 已经将按钮接到了外中断0(SB58上有0R电阻, SB51断开), 有了用EXIT0按钮来实现边沿触发的条件.
在这里插入图片描述
用CubeMX生成NUCLEO-H723ZG板子的新实验工程.
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
有提示框, 问是否将所有外设都初始化为默认模式, 选择NO.
这样做是因为芯片还没配置呢, 另外是因为我们这个测试工程是为了解决特定的一个具体问题(EXTI0 => DMA auto copy), 不想使无关代码太多. CubeMX生成的无关代码越少, 我们越容易找到正确的那条路.
指定工程名称, 保存路径, 目录结构类型(这些在.ioc保存后, 就改不了了)
目录结构我看官方demo也选的是basic
在这里插入图片描述
在这里插入图片描述
打开断言, 有利于调试, 如果参数给错了, 会进入断言, 容易发现问题.
保存.ioc, 如果用CubeMX改配置了, 就要保存. 然后在IDE(e.g. MDK5)中再改代码.
在调试阶段, 一边开着CubeMX, 一边开着IDE(e.g MDK), 很方便, 哪里配置的不合适了, 修改配置, 生成工程, 可以无缝实验.
在这里插入图片描述

正确配置RCC
在这里插入图片描述
HSE, LSE禁止掉的原因是这个板子外部的HSE, LSE就没焊接全, 本来就不生效.
在这里插入图片描述

将PA0配置为外中断0
在这里插入图片描述
在这里插入图片描述

在NVIC中使能EXTI0.
在这里插入图片描述
配置产生EXTI0中断代码.
在这里插入图片描述
配置EXTI0为下降沿触发, 没有上下拉.
在这里插入图片描述
配置BDMA为外中断0触发
在这里插入图片描述
在这里插入图片描述
选择BDMA产生子0, BDMA通道0, 内存到设备, 优先级低.
模式为周期(会根据每次触发条件, 产生新的DMA操作, 而不是只一次)
内存地址为自增.
数据宽度 为 src = WORD, dst = WORD(4bytes)
DMA触发信号为EXTI0, 触发条件为中断下降边沿. 请求数量为1.

使能BDMA中断(否则注册DMA中断回调无效)
在这里插入图片描述
让CubeMX生成DMA中断代码.
在这里插入图片描述

配置主时钟为128MHZ
在这里插入图片描述
这步主要是为了使用ITM(如果在调试阶段, 有比ITM还方便的调试信息打印手段, 可以不用ITM).
产生工程
在这里插入图片描述
用MDK打开工程
打开MDK的ITM显示.
在这里插入图片描述
在这里插入图片描述
打开微库选项
在这里插入图片描述
将代码优化级别改为O0
在这里插入图片描述

工程中加入ITM, 测试一下是否可以收到ITM调试信息.
因为我们后续有可能再用CubeMX改配置, 重新生成工程. 为了防止CubeMX生成的代码抹掉我们手写的实现, 需要将自己手写的实现放在CubeMX生成的 USER CODE BEGIN/END的注释中间.

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h> // add .h for fputc
/* USER CODE END Includes */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f) {
  return (ITM_SendChar(ch)); // in fputc, call ITM_SendChar()
}
/* USER CODE END 0 */
  /* USER CODE BEGIN SysInit */
	// must call printf() after SystemClock_Config()
	printf("prj - myDMAMUX_RequestGen_V1 - build on 2023_0630_1617\r\n");

  /* USER CODE END SysInit */

编译工程, 跑一下, 看是否ITM信息已经可以在调试信息窗口看到.
在这里插入图片描述
在这里插入图片描述
如果在调试信息窗口看到ITM调试信息, 那我们就可以在工程中想要的地方, 加入printf将关心的信息打印出来.

在严重错误和断言处理函数中下断点, 等错误来.
在这里插入图片描述
在这里插入图片描述
现在准备工作做完了, 现在看看如何改CubeMX生成的工程.
CubeMX生成的工程只是将外设初始化了, 可能还没使能外设, 还没有启动外设, 具体外设咋干活, CubeMX不知道.

先在EXTI0回调中加代码, 使我们能确认按钮按下后, 确实进了EXTI0.

cubeMX生成的中断处理函数如下:

/**
  * @brief This function handles EXTI line0 interrupt.
  */
void EXTI0_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI0_IRQn 0 */

  /* USER CODE END EXTI0_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
  /* USER CODE BEGIN EXTI0_IRQn 1 */

  /* USER CODE END EXTI0_IRQn 1 */
}

这个函数中也有 USER CODE BEGIN/END 注释, 但是为了方便, 我们自己加EXIT0的回调实现.
进HAL_GPIO_EXTI_IRQHandler实现, 看回调是啥.
在这里插入图片描述
在这里插入图片描述
HAL_GPIO_EXTI_Callback是弱函数, 我们在main.c中是实现一个.

/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);

  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_GPIO_EXTI_Callback could be implemented in the user file
   */
	
	if (GPIO_PIN_0 == GPIO_Pin)
	{
		printf(">> HAL_GPIO_EXTI_Callback EXTI0\r\n");
	}
}

重新编译工程, 跑一下, 看按钮被按下时, 是否进EXTI0
在这里插入图片描述
看看CubeMX生成的代码, 看看怎么让EXTI0触发DMA自动拷贝.
在这里插入图片描述
可以看到, CubeMX帮我们做了GPIO和BDMA的初始化.

static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

	// 打开了所有用到的GPIO时钟
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOG_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();
	
	// 初始化了板子上所有预定义的有用的管脚

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, LED_GREEN_Pin|LED_RED_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(USB_FS_PWR_EN_GPIO_Port, USB_FS_PWR_EN_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : B1_Pin */
  GPIO_InitStruct.Pin = B1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : RMII_MDC_Pin RMII_RXD0_Pin RMII_RXD1_Pin */
  GPIO_InitStruct.Pin = RMII_MDC_Pin|RMII_RXD0_Pin|RMII_RXD1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin : PA0 */ // 这里初始化了PA0
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : RMII_REF_CLK_Pin RMII_MDIO_Pin RMII_CRS_DV_Pin */
  GPIO_InitStruct.Pin = RMII_REF_CLK_Pin|RMII_MDIO_Pin|RMII_CRS_DV_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : LED_GREEN_Pin LED_RED_Pin */
  GPIO_InitStruct.Pin = LED_GREEN_Pin|LED_RED_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : RMII_TXD1_Pin */
  GPIO_InitStruct.Pin = RMII_TXD1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
  HAL_GPIO_Init(RMII_TXD1_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : STLK_VCP_RX_Pin STLK_VCP_TX_Pin */
  GPIO_InitStruct.Pin = STLK_VCP_RX_Pin|STLK_VCP_TX_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  /*Configure GPIO pin : USB_FS_PWR_EN_Pin */
  GPIO_InitStruct.Pin = USB_FS_PWR_EN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(USB_FS_PWR_EN_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : USB_FS_OVCR_Pin */
  GPIO_InitStruct.Pin = USB_FS_OVCR_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(USB_FS_OVCR_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : USB_FS_ID_Pin */
  GPIO_InitStruct.Pin = USB_FS_ID_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF10_OTG1_HS;
  HAL_GPIO_Init(USB_FS_ID_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : RMII_TX_EN_Pin RMII_TXD0_Pin */
  GPIO_InitStruct.Pin = RMII_TX_EN_Pin|RMII_TXD0_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
  HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

  /*Configure GPIO pin : LED_YELLOW_Pin */
  GPIO_InitStruct.Pin = LED_YELLOW_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LED_YELLOW_GPIO_Port, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); // 设置了EXTI0的优先级
  HAL_NVIC_EnableIRQ(EXTI0_IRQn); // 使能了EXTI0

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

可以看到MX_GPIO_Init()中初始化了PA0, 设置了EXTI0优先级, 使能了EXTI0

static void MX_BDMA_Init(void)
{

  /* Local variables */
  HAL_DMA_MuxRequestGeneratorConfigTypeDef pRequestGeneratorConfig = {0};

  /* DMA controller clock enable */
  __HAL_RCC_BDMA_CLK_ENABLE();

  /* Configure DMA request hdma_bdma_generator0 on BDMA_Channel0 */
  hdma_bdma_generator0.Instance = BDMA_Channel0; // BDMA通道0
  hdma_bdma_generator0.Init.Request = BDMA_REQUEST_GENERATOR0; // BDMA请求子0
  hdma_bdma_generator0.Init.Direction = DMA_MEMORY_TO_PERIPH; // 内存到设备
  hdma_bdma_generator0.Init.PeriphInc = DMA_PINC_DISABLE; // 外设地址不自增
  hdma_bdma_generator0.Init.MemInc = DMA_MINC_ENABLE; // 内存地址自增
  hdma_bdma_generator0.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; // 外设数据为WORD
  hdma_bdma_generator0.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; // 内存数据为WORD
  hdma_bdma_generator0.Init.Mode = DMA_CIRCULAR; // DMA周期动作
  hdma_bdma_generator0.Init.Priority = DMA_PRIORITY_LOW; // 优先级低
  // 这些参数都能和CubeMX配置的值对的上.
  if (HAL_DMA_Init(&hdma_bdma_generator0) != HAL_OK)
  {
    Error_Handler( );
  }

  /* Configure the DMAMUX request generator for the selected BDMA channel */
  pRequestGeneratorConfig.SignalID = HAL_DMAMUX2_REQ_GEN_EXTI0; // 触发源为EXTI0
  pRequestGeneratorConfig.Polarity = HAL_DMAMUX_REQ_GEN_FALLING; // 下降沿触发
  pRequestGeneratorConfig.RequestNumber = 1;
  if (HAL_DMAEx_ConfigMuxRequestGenerator(&hdma_bdma_generator0, &pRequestGeneratorConfig) != HAL_OK)
  {
    Error_Handler( );
  }

}

可以看到 MX_BDMA_Init()中进行了DMA初始化, 进行了DMA请求子的配置.
但是, 没有使能BDMA和启动DMA传送操作. 我们要将这部分加上.
问题来了, 这部分咋加?
加啥内容?
这时, 就要看官方原始工程的BDMA初始化和启动代码, 来找区别了.
这也是我们要抱紧官方例程大腿的原因(官方没给例子, 我们作为使用者, 真不知道怎么弄…).

我按照这种方法找到了区别, 但是要添加在main函数中(因为写在MX_BDMA_Init尾部, 下次再用CubeMX生成工程, 我们手写的实现就被清掉了)

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_BDMA_Init();
  /* USER CODE BEGIN 2 */
	
	HAL_DMAEx_EnableMuxRequestGenerator (&hdma_bdma_generator0);
	HAL_DMA_Start_IT(&hdma_bdma_generator0, (uint32_t)SRC_Buffer_LED1_Toggle, (uint32_t)&LED1_GPIO_PORT->ODR, 2);

  /* USER CODE END 2 */

可以看到找到的补充代码有2条 先使能DMA请求产生子, 然后非阻塞方式启动DMA.

我们CubeMX配置时, 指定从内存到设备, HAL_DMA_Start_IT启动时, 参数1是 BDMA产生子, 然后2个参数是内存地址, 设备地址, DMA拷贝的数量(数量单位是WORD, 也是CubeMX配置的)

如果是我们自己的工程, 将地址换成自己的就行.
但是拷贝方式(内存到内存, 内存到设备, 设备到内存), 要按照自己板子实际情况用CubeMX配置.

按理说, 到这里, 这篇笔记的主要部分就完事了. 如果我自己以后要用DMA从外部设备的RAM地址拷贝值到主内存, 上面的内容就够了.
不过, 我们在调试中, 可能写错配置(或者有其他编码错误使DMA失败)的情况下, DMA操作不好使, 这时, 要加上DMA回调, 来指示DMA操作是否成功(这个在调试阶段有用).

但是因为是修正的官方工程, 我将剩下的细节补充上, 这个实验完整些.

我改的官方工程的效果, 按下按钮后, 触发EXTI0. 然后BDMA从指定内存中拷贝一个固定值1到GPIO的反转寄存器, 这样就达到了通过DMA拷贝, 使LED反转的效果. 官方原始工程是用LPTIM2来触发DMA操作.

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define LED1_GPIO_PORT                          GPIOB
#define LED1_PIN                                GPIO_PIN_0
uint32_t __attribute__((section (".RAM_D3"))) SRC_Buffer_LED1_Toggle[2]  =
                                      {  0,          /*Value for LED1 ON  */
                                         LED1_PIN    /*Value for LED1 OFF */  
                                      };
/* USER CODE END PTD */

SRC_Buffer_LED1_Toggle 定义看起来很怪, 是定义在指定内存中的一个数组.
数组前面的扇区名称定义在.sct(分散加载描述文件)中.
默认的MDK工程, 是将.sct生成在临时目录, 如果要在sct文件中指定自己定义的数组在内存中的确切位置, 需要改sct文件.
sct文件要有确定的位置.

指定和确认.sct文件的位置和内容.
在这里插入图片描述
在自己指定给工程用的sct文件中, 在有效内存范围内, 新增一片内存区定义, 在其中加入*(.RAM_D3)扇区定义.
具体sct文件中定义内存扇区, 以后再研究, 初步这样加内存扇区是可以的.

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
  RW_IRAM2 0x24000000 0x00050000  {
   .ANY (+RW +ZI)
  }
    RW_IRAM3 0x38000000 0x00004000  {  ; RW data
   *(.RAM_D3)
	}
}

MDK中也有内存区使用定义
在这里插入图片描述
如果自己修改了.sct文件, 应该就是按照自己定义的.sct描述来.
具体还没查确切资料, 先这样认为.
像是否可以在IRAM1/IRAM2中定义自己的内存扇区的实验还没做, 以后再实验.
如果不定义内存扇区, 却使用指定在内存扇区中的数组, 只是有警告.
在这里插入图片描述
在这里插入图片描述
但是却编译不报错, 但是跑起来, 是没有效果的, 因为这个.RAM_D4扇区内存是不存在的.
所以我们使用内存扇区, 要在.sct中定义, 在代码中使用.
假设在调试过程中, 我只在代码中指定了.RAM_D3内存扇区的数组, 但是.sct用的确是默认的定义(如果自己不注意, 是有可能出现这种情况的).
这会导致DMA操作失败.
像我这种实验场景, 用按钮和灯配合, 可以知道DMA操作是否成功. 如果是纯数据操作, 就不容易看出是否DMA操作成功.
这时, 我们加上DMA操作回调, 打印出ITM, 就很容易看出DMA操作和其他流程是否正确了.

加入DMA操作回调.
看DMA相关库实现, 发现有回调指针, 再搜索回调指针的参考点, 发现了HAL_DMA_RegisterCallback(), 看起来是DMA回调注册.

  */
HAL_StatusTypeDef HAL_DMA_RegisterCallback(DMA_HandleTypeDef *hdma, HAL_DMA_CallbackIDTypeDef CallbackID, void (* pCallback)(DMA_HandleTypeDef *_hdma))
{

  HAL_StatusTypeDef status = HAL_OK;

  /* Check the DMA peripheral handle */
  if(hdma == NULL)
  {
    return HAL_ERROR;
  }

  /* Process locked */
  __HAL_LOCK(hdma);

  if(HAL_DMA_STATE_READY == hdma->State)
  {
    switch (CallbackID)
    {
    case  HAL_DMA_XFER_CPLT_CB_ID:
      hdma->XferCpltCallback = pCallback;

在官方demo工程再找HAL_DMA_RegisterCallback()的例子, 或者找回调ID的定义, 自己猜着写, 那就知道如何给我们自己工程如何加DMA回调了.
先加2个DMA回调(成功, 失败).

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_BDMA_Init();
  /* USER CODE BEGIN 2 */
	HAL_DMA_RegisterCallback(&hdma_bdma_generator0, HAL_DMA_XFER_ERROR_CB_ID, &HAL_TransferError);
	HAL_DMA_RegisterCallback(&hdma_bdma_generator0, HAL_DMA_XFER_CPLT_CB_ID, &HAL_TransferOver);
	
	HAL_DMAEx_EnableMuxRequestGenerator (&hdma_bdma_generator0);
	HAL_DMA_Start_IT(&hdma_bdma_generator0, (uint32_t)SRC_Buffer_LED1_Toggle, (uint32_t)&LED1_GPIO_PORT->ODR, 2);
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
static void HAL_TransferError(DMA_HandleTypeDef *hdma);
static void HAL_TransferOver(DMA_HandleTypeDef *hdma);
/* USER CODE END PD */
static void HAL_TransferError(DMA_HandleTypeDef *hdma)
{
  printf(">> DMA HAL_TransferError\r\n");
}

static void HAL_TransferOver(DMA_HandleTypeDef *hdma)
{
	// 这里会不断的进来
	// 说明设置DMA吿, 就会根据触发条件不断的进行DMA
  printf(">> DMA HAL_TransferOver\r\n");
}

/* USER CODE END 4 */

假设, 我们还是使用不存在的内存扇区中的数组来作为DMA拷贝的地址, 这时, DMA操作后, 失败, 就会进去失败函数, 有TIM信息, 显示DMA操作失败, 这时, 我们就会去查DMA为啥失败, 可以将错误在早期消掉.
在这里插入图片描述

看来MCU应用工程, 保持编译后, 0错误, 0警告是很重要的. 能在编译期间消掉的警告(隐含错误), 不必要在运行后才去消掉.
将内存使用改为正确的.RAM_D3, 再跑一下, 看看效果
在这里插入图片描述
每次按一下按钮, 都会由DMA将灯反转. 在ITM信息打印时, 也能看到, 先发生了外中断0, 再DMA操作完成.
不过, 从ITM打印的信息看, 不是每次EXTI0都有对应的DMA完成操作.
但是, 从现象上看, 每次按一次按钮, LED灯都会反转, 说明DMA操作每次操作都是好使的,
估计是ITM信息打印的问题, ITM信息只能作为调试的辅助手段, 也是有限制的.

实验工程主要代码

.sct文件

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
  RW_IRAM2 0x24000000 0x00050000  {
   .ANY (+RW +ZI)
  }
    RW_IRAM3 0x38000000 0x00004000  {  ; RW data
   *(.RAM_D3)
	}
}


main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h> // add .h for fputc
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define LED1_GPIO_PORT                          GPIOB
#define LED1_PIN                                GPIO_PIN_0
uint32_t __attribute__((section (".RAM_D3"))) SRC_Buffer_LED1_Toggle[2]  =
                                      {  0,          /*Value for LED1 ON  */
                                         LED1_PIN    /*Value for LED1 OFF */  
                                      };
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
static void HAL_TransferError(DMA_HandleTypeDef *hdma);
static void HAL_TransferOver(DMA_HandleTypeDef *hdma);
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

DMA_HandleTypeDef hdma_bdma_generator0;
/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_BDMA_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f) {
  return (ITM_SendChar(ch)); // in fputc, call ITM_SendChar()
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
	// must call printf() after SystemClock_Config()
	printf("prj - myDMAMUX_RequestGen_V1 - build on 2023_0630_1617\r\n");

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_BDMA_Init();
  /* USER CODE BEGIN 2 */
	HAL_DMA_RegisterCallback(&hdma_bdma_generator0, HAL_DMA_XFER_ERROR_CB_ID, &HAL_TransferError);
	HAL_DMA_RegisterCallback(&hdma_bdma_generator0, HAL_DMA_XFER_CPLT_CB_ID, &HAL_TransferOver);
	
	HAL_DMAEx_EnableMuxRequestGenerator (&hdma_bdma_generator0);
	HAL_DMA_Start_IT(&hdma_bdma_generator0, (uint32_t)SRC_Buffer_LED1_Toggle, (uint32_t)&LED1_GPIO_PORT->ODR, 2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = 64;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 16;
  RCC_OscInitStruct.PLL.PLLP = 1;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV2;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * Enable DMA controller clock
  * Configure DMA for memory to memory transfers
  *   hdma_bdma_generator0
  */
static void MX_BDMA_Init(void)
{

  /* Local variables */
  HAL_DMA_MuxRequestGeneratorConfigTypeDef pRequestGeneratorConfig = {0};

  /* DMA controller clock enable */
  __HAL_RCC_BDMA_CLK_ENABLE();

  /* Configure DMA request hdma_bdma_generator0 on BDMA_Channel0 */
  hdma_bdma_generator0.Instance = BDMA_Channel0;
  hdma_bdma_generator0.Init.Request = BDMA_REQUEST_GENERATOR0;
  hdma_bdma_generator0.Init.Direction = DMA_MEMORY_TO_PERIPH;
  hdma_bdma_generator0.Init.PeriphInc = DMA_PINC_DISABLE;
  hdma_bdma_generator0.Init.MemInc = DMA_MINC_ENABLE;
  hdma_bdma_generator0.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  hdma_bdma_generator0.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
  hdma_bdma_generator0.Init.Mode = DMA_CIRCULAR;
  hdma_bdma_generator0.Init.Priority = DMA_PRIORITY_LOW;
  if (HAL_DMA_Init(&hdma_bdma_generator0) != HAL_OK)
  {
    Error_Handler( );
  }

  /* Configure the DMAMUX request generator for the selected BDMA channel */
  pRequestGeneratorConfig.SignalID = HAL_DMAMUX2_REQ_GEN_EXTI0;
  pRequestGeneratorConfig.Polarity = HAL_DMAMUX_REQ_GEN_FALLING;
  pRequestGeneratorConfig.RequestNumber = 1;
  if (HAL_DMAEx_ConfigMuxRequestGenerator(&hdma_bdma_generator0, &pRequestGeneratorConfig) != HAL_OK)
  {
    Error_Handler( );
  }

  /* DMA interrupt init */
  /* DMAMUX2_OVR_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMAMUX2_OVR_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMAMUX2_OVR_IRQn);
  /* BDMA_Channel0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(BDMA_Channel0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(BDMA_Channel0_IRQn);

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOG_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, LED_GREEN_Pin|LED_RED_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(USB_FS_PWR_EN_GPIO_Port, USB_FS_PWR_EN_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LED_YELLOW_GPIO_Port, LED_YELLOW_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : B1_Pin */
  GPIO_InitStruct.Pin = B1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : RMII_MDC_Pin RMII_RXD0_Pin RMII_RXD1_Pin */
  GPIO_InitStruct.Pin = RMII_MDC_Pin|RMII_RXD0_Pin|RMII_RXD1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : RMII_REF_CLK_Pin RMII_MDIO_Pin RMII_CRS_DV_Pin */
  GPIO_InitStruct.Pin = RMII_REF_CLK_Pin|RMII_MDIO_Pin|RMII_CRS_DV_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : LED_GREEN_Pin LED_RED_Pin */
  GPIO_InitStruct.Pin = LED_GREEN_Pin|LED_RED_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : RMII_TXD1_Pin */
  GPIO_InitStruct.Pin = RMII_TXD1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
  HAL_GPIO_Init(RMII_TXD1_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : STLK_VCP_RX_Pin STLK_VCP_TX_Pin */
  GPIO_InitStruct.Pin = STLK_VCP_RX_Pin|STLK_VCP_TX_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  /*Configure GPIO pin : USB_FS_PWR_EN_Pin */
  GPIO_InitStruct.Pin = USB_FS_PWR_EN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(USB_FS_PWR_EN_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : USB_FS_OVCR_Pin */
  GPIO_InitStruct.Pin = USB_FS_OVCR_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(USB_FS_OVCR_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : USB_FS_ID_Pin */
  GPIO_InitStruct.Pin = USB_FS_ID_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF10_OTG1_HS;
  HAL_GPIO_Init(USB_FS_ID_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : RMII_TX_EN_Pin RMII_TXD0_Pin */
  GPIO_InitStruct.Pin = RMII_TX_EN_Pin|RMII_TXD0_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
  HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

  /*Configure GPIO pin : LED_YELLOW_Pin */
  GPIO_InitStruct.Pin = LED_YELLOW_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LED_YELLOW_GPIO_Port, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI0_IRQn);

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);

  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_GPIO_EXTI_Callback could be implemented in the user file
   */
	
	if (GPIO_PIN_0 == GPIO_Pin)
	{
		printf(">> HAL_GPIO_EXTI_Callback EXTI0\r\n");
	}
}

static void HAL_TransferError(DMA_HandleTypeDef *hdma)
{
  printf(">> DMA HAL_TransferError\r\n");
}

static void HAL_TransferOver(DMA_HandleTypeDef *hdma)
{
	// 这里会不断的进来
	// 说明设置DMA吿, 就会根据触发条件不断的进行DMA
  printf(">> DMA HAL_TransferOver\r\n");
}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

中断实现文件 stm32h7xx_it.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    stm32h7xx_it.c
  * @brief   Interrupt Service Routines.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32h7xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */

/* USER CODE END TD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/* External variables --------------------------------------------------------*/
extern DMA_HandleTypeDef hdma_bdma_generator0;
/* USER CODE BEGIN EV */

/* USER CODE END EV */

/******************************************************************************/
/*           Cortex Processor Interruption and Exception Handlers          */
/******************************************************************************/
/**
  * @brief This function handles Non maskable interrupt.
  */
void NMI_Handler(void)
{
  /* USER CODE BEGIN NonMaskableInt_IRQn 0 */

  /* USER CODE END NonMaskableInt_IRQn 0 */
  /* USER CODE BEGIN NonMaskableInt_IRQn 1 */
  while (1)
  {
  }
  /* USER CODE END NonMaskableInt_IRQn 1 */
}

/**
  * @brief This function handles Hard fault interrupt.
  */
void HardFault_Handler(void)
{
  /* USER CODE BEGIN HardFault_IRQn 0 */

  /* USER CODE END HardFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_HardFault_IRQn 0 */
    /* USER CODE END W1_HardFault_IRQn 0 */
  }
}

/**
  * @brief This function handles Memory management fault.
  */
void MemManage_Handler(void)
{
  /* USER CODE BEGIN MemoryManagement_IRQn 0 */

  /* USER CODE END MemoryManagement_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
    /* USER CODE END W1_MemoryManagement_IRQn 0 */
  }
}

/**
  * @brief This function handles Pre-fetch fault, memory access fault.
  */
void BusFault_Handler(void)
{
  /* USER CODE BEGIN BusFault_IRQn 0 */

  /* USER CODE END BusFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_BusFault_IRQn 0 */
    /* USER CODE END W1_BusFault_IRQn 0 */
  }
}

/**
  * @brief This function handles Undefined instruction or illegal state.
  */
void UsageFault_Handler(void)
{
  /* USER CODE BEGIN UsageFault_IRQn 0 */

  /* USER CODE END UsageFault_IRQn 0 */
  while (1)
  {
    /* USER CODE BEGIN W1_UsageFault_IRQn 0 */
    /* USER CODE END W1_UsageFault_IRQn 0 */
  }
}

/**
  * @brief This function handles System service call via SWI instruction.
  */
void SVC_Handler(void)
{
  /* USER CODE BEGIN SVCall_IRQn 0 */

  /* USER CODE END SVCall_IRQn 0 */
  /* USER CODE BEGIN SVCall_IRQn 1 */

  /* USER CODE END SVCall_IRQn 1 */
}

/**
  * @brief This function handles Debug monitor.
  */
void DebugMon_Handler(void)
{
  /* USER CODE BEGIN DebugMonitor_IRQn 0 */

  /* USER CODE END DebugMonitor_IRQn 0 */
  /* USER CODE BEGIN DebugMonitor_IRQn 1 */

  /* USER CODE END DebugMonitor_IRQn 1 */
}

/**
  * @brief This function handles Pendable request for system service.
  */
void PendSV_Handler(void)
{
  /* USER CODE BEGIN PendSV_IRQn 0 */

  /* USER CODE END PendSV_IRQn 0 */
  /* USER CODE BEGIN PendSV_IRQn 1 */

  /* USER CODE END PendSV_IRQn 1 */
}

/**
  * @brief This function handles System tick timer.
  */
void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}

/******************************************************************************/
/* STM32H7xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32h7xx.s).                    */
/******************************************************************************/

/**
  * @brief This function handles EXTI line0 interrupt.
  */
void EXTI0_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI0_IRQn 0 */

  /* USER CODE END EXTI0_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
  /* USER CODE BEGIN EXTI0_IRQn 1 */

  /* USER CODE END EXTI0_IRQn 1 */
}

/**
  * @brief This function handles DMAMUX2 overrun interrupt.
  */
void DMAMUX2_OVR_IRQHandler(void)
{
  /* USER CODE BEGIN DMAMUX2_OVR_IRQn 0 */

  /* USER CODE END DMAMUX2_OVR_IRQn 0 */
  // Handle BDMA_Channel0
  HAL_DMAEx_MUX_IRQHandler(&hdma_bdma_generator0);
  /* USER CODE BEGIN DMAMUX2_OVR_IRQn 1 */

  /* USER CODE END DMAMUX2_OVR_IRQn 1 */
}

/**
  * @brief This function handles BDMA channel0 global interrupt.
  */
void BDMA_Channel0_IRQHandler(void)
{
  /* USER CODE BEGIN BDMA_Channel0_IRQn 0 */

  /* USER CODE END BDMA_Channel0_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_bdma_generator0);
  /* USER CODE BEGIN BDMA_Channel0_IRQn 1 */

  /* USER CODE END BDMA_Channel0_IRQn 1 */
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

.ioc

#MicroXplorer Configuration settings - do not modify
Bdma.BDMA_GENERATOR0.0.Direction=DMA_MEMORY_TO_PERIPH
Bdma.BDMA_GENERATOR0.0.EventEnable=DISABLE
Bdma.BDMA_GENERATOR0.0.Instance=BDMA_Channel0
Bdma.BDMA_GENERATOR0.0.MemDataAlignment=DMA_MDATAALIGN_WORD
Bdma.BDMA_GENERATOR0.0.MemInc=DMA_MINC_ENABLE
Bdma.BDMA_GENERATOR0.0.Mode=DMA_CIRCULAR
Bdma.BDMA_GENERATOR0.0.PeriphDataAlignment=DMA_PDATAALIGN_WORD
Bdma.BDMA_GENERATOR0.0.PeriphInc=DMA_PINC_DISABLE
Bdma.BDMA_GENERATOR0.0.Polarity=HAL_DMAMUX_REQ_GEN_FALLING
Bdma.BDMA_GENERATOR0.0.Priority=DMA_PRIORITY_LOW
Bdma.BDMA_GENERATOR0.0.RequestNumber=1
Bdma.BDMA_GENERATOR0.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber
Bdma.BDMA_GENERATOR0.0.SignalID=HAL_DMAMUX2_REQ_GEN_EXTI0
Bdma.BDMA_GENERATOR0.0.SyncEnable=DISABLE
Bdma.BDMA_GENERATOR0.0.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT
Bdma.BDMA_GENERATOR0.0.SyncRequestNumber=1
Bdma.BDMA_GENERATOR0.0.SyncSignalID=NONE
Bdma.Request0=BDMA_GENERATOR0
Bdma.RequestsNb=1
CAD.formats=
CAD.pinconfig=
CAD.provider=
File.Version=6
GPIO.groupedBy=Group By Peripherals
KeepUserPlacement=false
Mcu.CPN=STM32H723ZGT6
Mcu.Family=STM32H7
Mcu.IP0=BDMA
Mcu.IP1=CORTEX_M7
Mcu.IP2=NVIC
Mcu.IP3=RCC
Mcu.IP4=SYS
Mcu.IPNb=5
Mcu.Name=STM32H723ZGTx
Mcu.Package=LQFP144
Mcu.Pin0=PC13
Mcu.Pin1=PC14-OSC32_IN
Mcu.Pin10=PC4
Mcu.Pin11=PC5
Mcu.Pin12=PB0
Mcu.Pin13=PB13
Mcu.Pin14=PB14
Mcu.Pin15=PD8
Mcu.Pin16=PD9
Mcu.Pin17=PD10
Mcu.Pin18=PG7
Mcu.Pin19=PA9
Mcu.Pin2=PC15-OSC32_OUT
Mcu.Pin20=PA10
Mcu.Pin21=PA13(JTMS/SWDIO)
Mcu.Pin22=PA14(JTCK/SWCLK)
Mcu.Pin23=PG11
Mcu.Pin24=PG13
Mcu.Pin25=PB3(JTDO/TRACESWO)
Mcu.Pin26=PE1
Mcu.Pin27=VP_SYS_VS_Systick
Mcu.Pin3=PH0-OSC_IN
Mcu.Pin4=PH1-OSC_OUT
Mcu.Pin5=PC1
Mcu.Pin6=PA0
Mcu.Pin7=PA1
Mcu.Pin8=PA2
Mcu.Pin9=PA7
Mcu.PinsNb=28
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32H723ZGTx
MxCube.Version=6.8.1
MxDb.Version=DB.6.0.81
NVIC.BDMA_Channel0_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.DMAMUX2_OVR_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.EXTI0_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
NVIC.ForceEnableDMAVector=true
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:false
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
PA0.GPIOParameters=GPIO_PuPd,GPIO_ModeDefaultEXTI
PA0.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING
PA0.GPIO_PuPd=GPIO_NOPULL
PA0.Locked=true
PA0.Signal=GPXTI0
PA1.GPIOParameters=GPIO_Label
PA1.GPIO_Label=RMII_REF_CLK
PA1.Locked=true
PA1.Signal=ETH_REF_CLK
PA10.GPIOParameters=GPIO_Label
PA10.GPIO_Label=USB_FS_ID
PA10.Locked=true
PA10.Signal=USB_OTG_HS_ID
PA13(JTMS/SWDIO).GPIOParameters=GPIO_Label
PA13(JTMS/SWDIO).GPIO_Label=SWDIO
PA13(JTMS/SWDIO).Locked=true
PA13(JTMS/SWDIO).Signal=DEBUG_JTMS-SWDIO
PA14(JTCK/SWCLK).GPIOParameters=GPIO_Label
PA14(JTCK/SWCLK).GPIO_Label=SWCLK
PA14(JTCK/SWCLK).Locked=true
PA14(JTCK/SWCLK).Signal=DEBUG_JTCK-SWCLK
PA2.GPIOParameters=GPIO_Label
PA2.GPIO_Label=RMII_MDIO
PA2.Locked=true
PA2.Signal=ETH_MDIO
PA7.GPIOParameters=GPIO_Label
PA7.GPIO_Label=RMII_CRS_DV
PA7.Locked=true
PA7.Signal=ETH_CRS_DV
PA9.GPIOParameters=GPIO_Label
PA9.GPIO_Label=USB_FS_VBUS
PA9.Locked=true
PA9.Signal=USB_OTG_HS_VBUS
PB0.GPIOParameters=GPIO_Label
PB0.GPIO_Label=LED_GREEN
PB0.Locked=true
PB0.Signal=GPIO_Output
PB13.GPIOParameters=GPIO_Label
PB13.GPIO_Label=RMII_TXD1
PB13.Locked=true
PB13.Signal=ETH_TXD1
PB14.GPIOParameters=GPIO_Label
PB14.GPIO_Label=LED_RED
PB14.Locked=true
PB14.Signal=GPIO_Output
PB3(JTDO/TRACESWO).GPIOParameters=GPIO_Label
PB3(JTDO/TRACESWO).GPIO_Label=SWO
PB3(JTDO/TRACESWO).Locked=true
PB3(JTDO/TRACESWO).Signal=DEBUG_JTDO-SWO
PC1.GPIOParameters=GPIO_Label
PC1.GPIO_Label=RMII_MDC
PC1.Locked=true
PC1.Signal=ETH_MDC
PC13.GPIOParameters=GPIO_Label
PC13.GPIO_Label=B1 (Blue_User_Button)
PC13.Locked=true
PC13.Signal=GPIO_Input
PC14-OSC32_IN.Locked=true
PC14-OSC32_IN.Signal=RCC_OSC32_IN
PC15-OSC32_OUT.Locked=true
PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
PC4.GPIOParameters=GPIO_Label
PC4.GPIO_Label=RMII_RXD0
PC4.Locked=true
PC4.Signal=ETH_RXD0
PC5.GPIOParameters=GPIO_Label
PC5.GPIO_Label=RMII_RXD1
PC5.Locked=true
PC5.Signal=ETH_RXD1
PD10.GPIOParameters=GPIO_Label
PD10.GPIO_Label=USB_FS_PWR_EN
PD10.Locked=true
PD10.Signal=GPIO_Output
PD8.GPIOParameters=GPIO_Label
PD8.GPIO_Label=STLK_VCP_RX
PD8.Locked=true
PD8.Signal=USART3_TX
PD9.GPIOParameters=GPIO_Label
PD9.GPIO_Label=STLK_VCP_TX
PD9.Locked=true
PD9.Signal=USART3_RX
PE1.GPIOParameters=GPIO_Label
PE1.GPIO_Label=LED_YELLOW
PE1.Locked=true
PE1.Signal=GPIO_Output
PG11.GPIOParameters=GPIO_Label
PG11.GPIO_Label=RMII_TX_EN
PG11.Locked=true
PG11.Signal=ETH_TX_EN
PG13.GPIOParameters=GPIO_Label
PG13.GPIO_Label=RMII_TXD0
PG13.Locked=true
PG13.Signal=ETH_TXD0
PG7.GPIOParameters=GPIO_Label
PG7.GPIO_Label=USB_FS_OVCR
PG7.Locked=true
PG7.Signal=GPXTI7
PH0-OSC_IN.GPIOParameters=GPIO_Label
PH0-OSC_IN.GPIO_Label=MCO
PH0-OSC_IN.Locked=true
PH0-OSC_IN.Signal=RCC_OSC_IN
PH1-OSC_OUT.Locked=true
PH1-OSC_OUT.Signal=RCC_OSC_OUT
PinOutPanel.RotationAngle=0
ProjectManager.AskForMigrate=true
ProjectManager.BackupPrevious=false
ProjectManager.CompilerOptimize=6
ProjectManager.ComputerToolchain=false
ProjectManager.CoupleFile=false
ProjectManager.CustomerFirmwarePackage=
ProjectManager.DefaultFWLocation=true
ProjectManager.DeletePrevious=true
ProjectManager.DeviceId=STM32H723ZGTx
ProjectManager.FirmwarePackage=STM32Cube FW_H7 V1.11.0
ProjectManager.FreePins=false
ProjectManager.HalAssertFull=true
ProjectManager.HeapSize=0x200
ProjectManager.KeepUserCode=true
ProjectManager.LastFirmware=true
ProjectManager.LibraryCopy=0
ProjectManager.MainLocation=Src
ProjectManager.NoMain=false
ProjectManager.PreviousToolchain=
ProjectManager.ProjectBuild=false
ProjectManager.ProjectFileName=myDMAMUX_RequestGen_v1.ioc
ProjectManager.ProjectName=myDMAMUX_RequestGen_v1
ProjectManager.ProjectStructure=
ProjectManager.RegisterCallBack=
ProjectManager.StackSize=0x400
ProjectManager.TargetToolchain=MDK-ARM V5.32
ProjectManager.ToolChainLocation=
ProjectManager.UnderRoot=false
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_BDMA_Init-BDMA-false-HAL-true,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true
RCC.ADCFreq_Value=608000000
RCC.AHB12Freq_Value=64000000
RCC.AHB4Freq_Value=64000000
RCC.APB1Freq_Value=32000000
RCC.APB2Freq_Value=32000000
RCC.APB3Freq_Value=32000000
RCC.APB4Freq_Value=32000000
RCC.AXIClockFreq_Value=64000000
RCC.CECFreq_Value=32000
RCC.CKPERFreq_Value=64000000
RCC.CortexFreq_Value=128000000
RCC.CpuClockFreq_Value=128000000
RCC.D1CPRE=RCC_SYSCLK_DIV2
RCC.D1CPREFreq_Value=128000000
RCC.D1PPRE=RCC_APB3_DIV2
RCC.D2PPRE1=RCC_APB1_DIV2
RCC.D2PPRE2=RCC_APB2_DIV2
RCC.D3PPRE=RCC_APB4_DIV2
RCC.DFSDMACLkFreq_Value=64000000
RCC.DFSDMFreq_Value=32000000
RCC.DIVM1=4
RCC.DIVM2=1
RCC.DIVN1=16
RCC.DIVN2=19
RCC.DIVP1=1
RCC.DIVP1Freq_Value=256000000
RCC.DIVP2Freq_Value=608000000
RCC.DIVP3Freq_Value=129000000
RCC.DIVQ1=4
RCC.DIVQ1Freq_Value=64000000
RCC.DIVQ2Freq_Value=608000000
RCC.DIVQ3Freq_Value=129000000
RCC.DIVR1Freq_Value=128000000
RCC.DIVR2Freq_Value=608000000
RCC.DIVR3Freq_Value=129000000
RCC.FDCANFreq_Value=64000000
RCC.FMCFreq_Value=64000000
RCC.FamilyName=M
RCC.HCLK3ClockFreq_Value=64000000
RCC.HCLKFreq_Value=64000000
RCC.HPRE=RCC_HCLK_DIV2
RCC.HSE_VALUE=8000000
RCC.I2C123Freq_Value=32000000
RCC.I2C4Freq_Value=32000000
RCC.IPParameters=ADCFreq_Value,AHB12Freq_Value,AHB4Freq_Value,APB1Freq_Value,APB2Freq_Value,APB3Freq_Value,APB4Freq_Value,AXIClockFreq_Value,CECFreq_Value,CKPERFreq_Value,CortexFreq_Value,CpuClockFreq_Value,D1CPRE,D1CPREFreq_Value,D1PPRE,D2PPRE1,D2PPRE2,D3PPRE,DFSDMACLkFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVN1,DIVN2,DIVP1,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3Freq_Value,DIVQ1,DIVQ1Freq_Value,DIVQ2Freq_Value,DIVQ3Freq_Value,DIVR1Freq_Value,DIVR2Freq_Value,DIVR3Freq_Value,FDCANFreq_Value,FMCFreq_Value,FamilyName,HCLK3ClockFreq_Value,HCLKFreq_Value,HPRE,HSE_VALUE,I2C123Freq_Value,I2C4Freq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPTIM345Freq_Value,LPUART1Freq_Value,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,PLLFRACN,QSPIFreq_Value,RNGFreq_Value,RTCFreq_Value,SAI1Freq_Value,SAI4AFreq_Value,SAI4BFreq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SPI123Freq_Value,SPI45Freq_Value,SPI6Freq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,Tim1OutputFreq_Value,Tim2OutputFreq_Value,TraceFreq_Value,USART16Freq_Value,USART234578Freq_Value,USBCLockSelection,USBFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value
RCC.LPTIM1Freq_Value=32000000
RCC.LPTIM2Freq_Value=32000000
RCC.LPTIM345Freq_Value=32000000
RCC.LPUART1Freq_Value=32000000
RCC.LTDCFreq_Value=129000000
RCC.MCO1PinFreq_Value=64000000
RCC.MCO2PinFreq_Value=256000000
RCC.PLLFRACN=0
RCC.QSPIFreq_Value=64000000
RCC.RNGFreq_Value=48000000
RCC.RTCFreq_Value=32000
RCC.SAI1Freq_Value=64000000
RCC.SAI4AFreq_Value=64000000
RCC.SAI4BFreq_Value=64000000
RCC.SDMMCFreq_Value=64000000
RCC.SPDIFRXFreq_Value=64000000
RCC.SPI123Freq_Value=64000000
RCC.SPI45Freq_Value=32000000
RCC.SPI6Freq_Value=32000000
RCC.SWPMI1Freq_Value=32000000
RCC.SYSCLKFreq_VALUE=256000000
RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
RCC.Tim1OutputFreq_Value=64000000
RCC.Tim2OutputFreq_Value=64000000
RCC.TraceFreq_Value=64000000
RCC.USART16Freq_Value=32000000
RCC.USART234578Freq_Value=32000000
RCC.USBCLockSelection=RCC_USBCLKSOURCE_HSI48
RCC.USBFreq_Value=48000000
RCC.VCO1OutputFreq_Value=256000000
RCC.VCO2OutputFreq_Value=1216000000
RCC.VCO3OutputFreq_Value=258000000
RCC.VCOInput1Freq_Value=16000000
RCC.VCOInput2Freq_Value=64000000
RCC.VCOInput3Freq_Value=2000000
SH.GPXTI0.0=GPIO_EXTI0
SH.GPXTI0.ConfNb=1
SH.GPXTI7.0=GPIO_EXTI7
SH.GPXTI7.ConfNb=1
VP_SYS_VS_Systick.Mode=SysTick
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
board=NUCLEO-H723ZG
boardIOC=true

补充

感觉我们要是从官方例程上迁移知识点到我们自己工程之前, 还是要先复现一次官方例程, 没准就复现不出来效果.
如果不带效果的迁移进我们自己的工程, 有问题也不好排查.

如果自己重新完了, 步骤都清楚了(CubeMX配置细节? 需要自己在CubeMX生成的框架工程上补充哪些实现?), 再向自己工程迁移(修改), 难度就降低好多.

END

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F407ZGTX是一款高性能的微控制器,具有强大的外部中断功能。外部中断是通过引脚上的外部信号触发的,可以用于检测、处理外部事件。下面我将以300字回答关于STM32F407ZGTX外部中断实验的问题。 首先,我们需要准备好实验所需的硬件和软件。硬件方面,需要准备一块STM32F407ZGTX开发板和一些外部设备,如按钮或开关等。软件方面,需要使用STM32CubeMX和Keil MDK工具进行代码开发和编译。 接下来,我们可以使用STM32CubeMX来配置外部中断。打开STM32CubeMX,选择对应的芯片型号,创建一个新工程。在Pinout & Configuration选项中,选择需要使用的引脚作为外部中断触发引脚。然后,打开Configuration选项卡,选择相应引脚的GPIO模式为GPIO_EXTI和GPIO模式为EXTI Mode。配置完成后,点击生成代码按钮,并将生成的代码导入到Keil MDK中进行编译和烧录。 接下来,在Keil MDK中进行代码开发。打开生成的代码工程,找到main.c文件,在HAL_GPIO_EXTI_Callback函数中编写对外部中断的处理代码。在这个函数中,可以实现对外部中断触发事件的检测和相应的处理逻辑。例如,可以在按下按钮时,让LED灯亮起或发送一个响应的信号。 最后,编译并烧录代码到STM32F407ZGTX开发板上。连接好外部设备(如按钮)后,运行实验。当外部中断(按钮按下)发生时,相应的处理代码会被触发执行。 要注意的是,实验中还需要注意配置外部中断的触发模式,如上升沿触发、下降沿触发等,可根据实际需求进行配置。 总结来说,STM32F407ZGTX外部中断实验的步骤包括:硬件和软件准备、配置外部中断引脚、编写处理代码、编译和烧录代码,最后进行实验。希望以上回答能帮助到你对STM32F407ZGTX外部中断实验的理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值