STM32H743 TIM触发ADC+DMA三协同采样实战
发布时间:2026/10/16 3:49:05 锦皓数字建站

简介本资源是一套基于STM32H743芯片的定时器触发ADC采样完整工程实现面向嵌入式开发初学者与进阶工程师重点解决高精度、固定频率、低CPU占用的模拟信号采集需求适用于电机控制、传感器数据采集、实时监测等典型工业场景。压缩包共163个文件涵盖59个头文件h定义外设寄存器与函数接口、28个C源码c含HAL库驱动与主逻辑、29个编译中间文件o及29个依赖文件d另有uvprojx工程配置、ioc初始化配置、sct链接脚本、axf可执行镜像等关键构建文件整体8.56MB结构完整、开箱即用。已有1557人学习下载。读者可直接导入Keil MDK环境运行获得TIMADCDMA协同工作的全流程代码范例包括HAL_TIM_IC_Start_IT、HAL_ADC_Start_DMA等关键调用逻辑以及stm32h7xx_hal_adc.c、stm32h7xx_hal_tim.c等核心驱动层适配细节便于深入理解H7系列时钟树配置、DMA双缓冲机制与中断优先级协同设计。1. STM32H743 的 TIMADCDMA 三合一采样不是“能跑就行”而是“微秒级同步不丢点、不溢出、不抖动”的硬实时闭环基础你手头那块刚焊好的 H743 开发板接上高精度传感器后用 HAL_Delay(1) 做采样间隔或者靠 while (HAL_ADC_PollForConversion() HAL_OK) 死等别急着烧录——这俩做法在 H743 上大概率已经埋下隐性故障ADC 转换完成中断里改 TIM 比较值DMA 半传输中断里清标志位却漏了清除 ADC EOC更隐蔽的是当主频跑 480MHz、ADC 配 36MHz 时钟、TIM 触发源设为内部时钟而非 TRGODMA 请求被屏蔽一拍……数据就静默错位了。这不是代码逻辑错是硬件时序链路上的“黑匣子”失配。这份STM32H743_TIM_ADC_DMA.rar不是教学 Demo而是一套经某高校电机控制实验室实测验证的可复位、可量化、可嵌入 PID 闭环的底层采样骨架它把 TIM 触发、ADC 扫描、DMA 双缓冲搬运、CPU 非阻塞处理这四层耦合动作压进 3 个寄存器配置 2 个中断服务函数 1 个环形缓冲区管理结构体里。适合正在做伺服驱动、音频前端、高频振动分析的工程师也适合被“ADC 数据跳变”“DMA 传输中断不触发”“TIM 触发延迟忽大忽小”反复折磨的新手——它不教你 HAL 库怎么点灯只解决“为什么我按例程抄波形就是不对”这个终极问题。2. 为什么必须用 TIM 触发 ADC 扫描 DMA 三协同从时序图到寄存器级选型依据2.1 时序不可妥协为什么不用软件触发 ADCH743 的 ADC 支持多种触发源软件触发ADSTART、外部引脚、TIMx_TRGO。若用软件触发CPU 必须在精确时刻执行SET_BIT(ADCx-CR, ADC_CR_ADSTART)。但 Cortex-M7 的指令流水线、分支预测、Cache Miss 都会引入±3~12 个周期抖动实测在 480MHz 下达 25ns 量级。而工业场景中常见 100kHz 采样率10μs 间隔这点抖动已导致相位漂移。更致命的是若此时发生 SysTick 中断或 PendSVADSTART 指令可能被延后数微秒——ADC 就错过一个触发窗口。TIM 触发则完全不同TIM 计数器是独立于 CPU 的硬件模块其更新事件UEV或比较匹配事件CCx生成的 TRGO 信号经内部总线直达 ADC 触发控制器全程无 CPU 干预抖动 1ns。这是硬实时采样的物理基础。2.2 为什么必须启用 ADC 扫描模式而非单通道单通道模式下每次触发只转换 1 个通道。若需采集 4 路传感器如电流 Ia/Ib、母线电压 Vdc、温度 T就得配置 4 个独立 ADC 实例或频繁切换通道——前者耗资源后者引入通道切换时间H743 典型值 1.5μs。扫描模式允许将多通道按顺序编入 ADC_SQRx 寄存器一次触发完成全部通道转换且各通道间采样时刻严格等间隔由 ADC_SMPR1/2 的采样时间字段决定。本资源默认配置 4 通道扫描CH0Ia、CH1Ib、CH2Vdc、CH3T每通道采样时间设为 24.5 个 ADC 周期对应 36MHz ADC 时钟下约 0.68μs确保信号完整性。2.3 为什么 DMA 必须用双缓冲 循环模式单缓冲 DMA 在传输完成TC中断中CPU 需立即重装内存地址并重启 DMA此过程存在空窗期。当采样率 50kHz 时该空窗易导致新数据覆盖未读取旧数据DMA OVR 标志置位。双缓冲模式DMA_CPARx DMA_CMARx让 DMA 自动在两个内存区域间切换当 Buffer A 填满时DMA 切换至 Buffer B 并触发 TC 中断CPU 在中断中处理 Buffer A同时 DMA 继续向 Buffer B 写入。循环模式CIRC1则保证 DMA 地址自动回绕避免手动重装。本资源采用双缓冲循环 DMA每个 Buffer 深度为 1024 个 uint16_t即 2048 字节足以容纳 256 次完整扫描4 通道 × 256 1024 个样本。提示H743 的 ADC 和 DMA 属于不同 AHB 总线域ADC 在 APB2DMA 在 AHB1需确认 RCC-AHB1ENR 中 DMA2EN 已置位且 RCC-APB2ENR 中 ADC12EN/ADC34EN 根据所用 ADC 实例开启。3. 从寄存器配置到 HAL 封装三步构建可复现的初始化链3.1 第一步TIM2 初始化作为 ADC 触发源TIM2 选择为触发源因其支持高级定时器特性虽非高级定时器但 H743 的 TIM2 具备完整的 TRGO 输出能力。关键参数时钟源APB1 时钟H743 默认 120MHz经 PSC 分频后计数器时钟为 120MHz / (PSC1)自动重装载值 ARR决定采样周期。例如目标采样率 100kHz → 周期 10μs → 若 TIM2 时钟为 120MHz则 ARR (120e6 × 10e-6) - 1 1199TRGO 信号源配置为更新事件UG或比较匹配事件CC1IF。本资源选用 CC1IF捕获/比较 1 匹配因可灵活调整触发相位// TIM2 初始化生成 100kHz 触发信号CC1 匹配 htim2.Instance TIM2; htim2.Init.Prescaler 0; // PSC0 → TIM2CLK 120MHz htim2.Init.CounterMode TIM_COUNTERMODE_UP; htim2.Init.Period 1199; // ARR 1199 → 溢出周期 (11991)/120e6 10μs htim2.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; htim2.Init.RepetitionCounter 0; if (HAL_TIM_Base_Init(htim2) ! HAL_OK) { Error_Handler(); } // 配置通道 1 为比较输出仅用于触发不接 GPIO sConfigOC.OCMode TIM_OCMODE_TIMING; // 纯定时不输出电平 sConfigOC.Pulse 600; // CCR1 600 → 在计数器600 时触发相位可调 sConfigOC.OCPolarity TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode TIM_OCFAST_DISABLE; if (HAL_TIM_OC_ConfigChannel(htim2, sConfigOC, TIM_CHANNEL_1) ! HAL_OK) { Error_Handler(); } // 启用 CC1 中断实际触发由硬件完成中断仅用于调试 __HAL_TIM_ENABLE_IT(htim2, TIM_IT_CC1); // 启动 TIM2 并使能 CC1 输出TRGO 将在 CC1IF 置位时发出 HAL_TIM_OC_Start(htim2, TIM_CHANNEL_1);参数说明sConfigOC.Pulse 600表示在计数器到达 600 时产生 CC1IF 事件进而通过 TRGO 触发 ADC。若需调整采样起始相位如避开电源开关噪声峰值只需修改此值无需动 ARR。3.2 第二步ADC1 初始化含扫描与触发配置ADC1 配置核心在于触发源选择和扫描序列定义。H743 的 ADC 支持多实例同步本资源仅用 ADC1对应 CH0~CH3故需关闭 ADC2/3 避免干扰。// ADC1 初始化4 通道扫描TIM2 CC1 触发 hadc1.Instance ADC1; hadc1.Init.ClockPrescaler ADC_CLOCK_SYNC_PCLK_DIV4; // ADCCLK 120MHz / 4 30MHz实际用 36MHz见 RCC 配置 hadc1.Init.Resolution ADC_RESOLUTION_16B; // 16 位精度 hadc1.Init.DataAlign ADC_DATAALIGN_RIGHT; // 右对齐低位补 0 hadc1.Init.ScanConvMode ENABLE; // 必须开启扫描 hadc1.Init.EOCSelection ADC_EOC_SEQ_CONV; // 扫描结束才置 EOC非单次 hadc1.Init.LowPowerAutoWait DISABLE; hadc1.Init.ContinuousConvMode DISABLE; // 由 TIM 触发非连续 hadc1.Init.NbrOfConversion 4; // 4 个通道 hadc1.Init.DiscontinuousConvMode DISABLE; hadc1.Init.ExternalTrigConv ADC_EXTERNALTRIGCONV_T2_CC1; // 关键指定 TIM2 CC1 hadc1.Init.ExternalTrigConvEdge ADC_EXTERNALTRIGCONVEDGE_RISING; hadc1.Init.DMAContinuousRequests ENABLE; // DMA 请求持续有效 hadc1.Init.Overrun ADC_OVR_DATA_OVERWRITTEN; // 溢出时覆盖旧数据防锁死 hadc1.Init.SamplingTimeCommon1 ADC_SAMPLETIME_COMMON_1_24CYCLES_5; // 所有通道共用采样时间 hadc1.Init.SamplingTimeCommon2 ADC_SAMPLETIME_COMMON_2_24CYCLES_5; hadc1.Init.OversamplingMode DISABLE; if (HAL_ADC_Init(hadc1) ! HAL_OK) { Error_Handler(); } // 配置扫描序列CH0→CH1→CH2→CH3 sConfig.Channel ADC_CHANNEL_0; sConfig.Rank ADC_RANK_CHANNEL_1; // 第 1 个转换 sConfig.SingleDiff ADC_SINGLE_ENDED; sConfig.SamplingTime ADC_SAMPLETIME_COMMON_1; sConfig.OffsetNumber ADC_OFFSET_NONE; sConfig.Offset 0; if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK) { Error_Handler(); } sConfig.Channel ADC_CHANNEL_1; sConfig.Rank ADC_RANK_CHANNEL_2; // 第 2 个转换 if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK) { Error_Handler(); } sConfig.Channel ADC_CHANNEL_2; sConfig.Rank ADC_RANK_CHANNEL_3; // 第 3 个转换 if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK) { Error_Handler(); } sConfig.Channel ADC_CHANNEL_3; sConfig.Rank ADC_RANK_CHANNEL_4; // 第 4 个转换 if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK) { Error_Handler(); }参数说明ExternalTrigConv ADC_EXTERNALTRIGCONV_T2_CC1是硬连接点若此处写成ADC_EXTERNALTRIGCONV_T1_CC1而实际用 TIM2则 ADC 永远不会启动。EOCSelection ADC_EOC_SEQ_CONV确保整个扫描序列完成后才置 EOC 标志避免单通道误判。3.3 第三步DMA2 初始化双缓冲 循环模式DMA2_Stream0 用于 ADC1H743 Reference Manual 明确指定。双缓冲需手动设置两个内存地址并启用 DMA_SxCR_DBM 位。// 定义双缓冲区全局变量确保 32 字节对齐以满足 DMA 要求 uint16_t adc_dma_buffer_a[1024] __attribute__((aligned(32))); uint16_t adc_dma_buffer_b[1024] __attribute__((aligned(32))); // DMA2_Stream0 初始化双缓冲循环模式 hdma_adc1.Instance DMA2_Stream0; hdma_adc1.Init.Request DMA_REQUEST_ADC1; // 关联 ADC1 hdma_adc1.Init.Direction DMA_PERIPH_TO_MEMORY; hdma_adc1.Init.PeriphInc DMA_PINC_DISABLE; // 外设地址不增ADC_DR 固定 hdma_adc1.Init.MemInc DMA_MINC_ENABLE; // 内存地址递增 hdma_adc1.Init.PeriphDataAlignment DMA_PDATAALIGN_HALFWORD; hdma_adc1.Init.MemDataAlignment DMA_MDATAALIGN_HALFWORD; hdma_adc1.Init.Mode DMA_CIRCULAR; // 循环模式 hdma_adc1.Init.Priority DMA_PRIORITY_HIGH; hdma_adc1.Init.FIFOMode DMA_FIFOMODE_DISABLE; hdma_adc1.Init.FIFOThreshold DMA_FIFO_THRESHOLD_HALFFULL; hdma_adc1.Init.MemBurst DMA_MBURST_SINGLE; hdma_adc1.Init.PeriphBurst DMA_PBURST_SINGLE; if (HAL_DMA_Init(hdma_adc1) ! HAL_OK) { Error_Handler(); } // 关联 DMA 到 ADC1 __HAL_LINKDMA(hadc1, DMA_Handle, hdma_adc1); // 启用双缓冲模式关键 hdma_adc1.Instance-CR | DMA_SxCR_DBM; // 设置双缓冲地址先加载 Buffer ABuffer B 自动生效 hdma_adc1.Instance-M0AR (uint32_t)adc_dma_buffer_a; hdma_adc1.Instance-M1AR (uint32_t)adc_dma_buffer_b; // 启用 DMA 传输完成中断TCIE和半传输中断HTIE __HAL_DMA_ENABLE_IT(hdma_adc1, DMA_IT_TC | DMA_IT_HT); // 启动 ADC此时 DMA 尚未启动需在 ADC 启动后手动启动 DMA if (HAL_ADC_Start_DMA(hadc1, (uint32_t)adc_dma_buffer_a, 1024, HAL_ADC_FORMAT_16_BITS, DMA_PINC_ENABLE) ! HAL_OK) { Error_Handler(); }参数说明M0AR和M1AR分别指向 Buffer A 和 Buffer B 的首地址。DMA_SxCR_DBM位必须在HAL_DMA_Init()后、HAL_ADC_Start_DMA()前置位否则双缓冲无效。HAL_ADC_Start_DMA()的第 4 个参数HAL_ADC_FORMAT_16_BITS对应 16 位数据宽度与uint16_t缓冲区严格匹配。4. 中断服务函数与数据搬运如何让 CPU 不卡在数据处理上4.1 DMA 传输完成TC与半传输HT中断处理双缓冲模式下DMA 在 Buffer A 填满时触发 HT 中断此时已写入 512 个 uint16_t在 Buffer A 完全填满1024 个时触发 TC 中断。但注意H743 的 ADC 扫描模式下1024 个样本 256 次完整扫描4 通道 × 256因此 HT 中断对应 128 次扫描TC 中断对应 256 次扫描。本资源在 TC 中断中处理 Buffer A在 HT 中断中处理 Buffer B实现流水线作业。// DMA2_Stream0 中断服务函数TC HT void DMA2_Stream0_IRQHandler(void) { uint32_t isrflags DMA2-HISR; uint32_t crflags DMA2-S0CR; // 检查传输完成TC标志 if (isrflags DMA_HISR_TCIF0) { // 清除 TC 标志 DMA2-HIFCR DMA_HIFCR_CTCIF0; // 此时 Buffer A 已满处理 Buffer A 数据 ProcessAdcBuffer(adc_dma_buffer_a, 1024); // 自定义处理函数 } // 检查半传输HT标志 if (isrflags DMA_HISR_HTIF0) { // 清除 HT 标志 DMA2-HIFCR DMA_HIFCR_CHTIF0; // 此时 Buffer B 已半满512 个但为简化我们等它全满再处理 // 实际中可在此处启动 Buffer B 的预处理如 FFT 分段 } } // 简化版数据处理函数示例计算每通道均值 void ProcessAdcBuffer(uint16_t* buffer, uint16_t size) { uint32_t sum_i_a 0, sum_i_b 0, sum_v_dc 0, sum_t 0; uint16_t i; for (i 0; i size; i 4) { sum_i_a buffer[i 0]; // CH0: Ia sum_i_b buffer[i 1]; // CH1: Ib sum_v_dc buffer[i 2]; // CH2: Vdc sum_t buffer[i 3]; // CH3: T } // 存入全局变量供主循环使用避免在中断中做复杂运算 g_adc_avg_i_a sum_i_a / (size / 4); g_adc_avg_i_b sum_i_b / (size / 4); g_adc_avg_v_dc sum_v_dc / (size / 4); g_adc_avg_t sum_t / (size / 4); }逻辑说明ProcessAdcBuffer()仅做轻量计算求和、除法结果存入全局变量。主循环如while(1)中再读取这些变量进行 PID 运算或通信发送。此举避免中断嵌套过深或执行时间超标H743 中断响应时间典型值 12 个周期但长中断会阻塞其他高优先级任务。4.2 ADC 溢出OVR与注入通道冲突排查虽然配置了ADC_OVR_DATA_OVERWRITTEN但 OVR 标志仍需定期清除否则会锁死 ADC。H743 的 OVR 标志位于 ADC_ISR 寄存器需在 ADC 中断中清除// ADC1 中断服务函数仅处理 OVR void ADC1_2_IRQHandler(void) { uint32_t isr ADC1-ISR; // 检查溢出标志OVR if (isr ADC_ISR_OVR) { // 清除 OVR 标志写 1 清零 ADC1-ICR ADC_ICR_OVRC; // 可选记录溢出次数用于调试 g_adc_ovr_count; } }参数说明ADC_ICR_OVRC是溢出清除位。若未清除下次转换完成时 OVR 会再次置位导致 ADC 停止工作。此中断优先级应低于 TIM2 中断因 TIM2 触发 ADCADC 中断是结果建议设为NVIC_SetPriority(ADC_IRQn, 1);数值越小优先级越高。5. 避坑指南那些让你怀疑人生、查三天手册才发现的 H743 特性陷阱5.1 现象DMA 传输中断不触发ADC_DR 寄存器值恒为 0原因ADC 时钟未正确使能或 ADC 实例与 DMA 请求映射错误。H743 的 ADC1 对应 DMA2_Stream0_Request0ADC2 对应 DMA2_Stream1_Request1ADC3 对应 DMA2_Stream2_Request2。若误将 ADC1 配置为 DMA2_Stream1则 DMA 永远收不到请求。解决检查RCC-APB2ENR中ADC12EN是否置位ADC1/2 共享使能位并确认hdma_adc1.Instance DMA2_Stream0与DMA_REQUEST_ADC1严格匹配。用 ST-Link Utility 读取RCC-AHB1ENR确认DMA2EN1。5.2 现象采样数据出现规律性跳变如每 16 个点重复一次原因ADC 扫描模式下NbrOfConversion设为 4但ADC_SQR1寄存器中L[3:0]字段扫描长度未同步更新。HAL 库的HAL_ADC_ConfigChannel()函数会自动设置L但若多次调用HAL_ADC_Init()而未重置 ADCL可能残留旧值如 L1 导致只扫 CH0。解决在HAL_ADC_Init()前强制复位 ADC__HAL_ADC_RESET_HANDLE_STATE(hadc1);并在HAL_ADC_ConfigChannel()后用调试器查看ADC1-SQR1的L字段是否为 0b0011即 4 通道。5.3 现象TIM2 触发正常但 ADC 转换延迟波动达 1μs原因ADC 时钟分频系数ADC_CLOCK_SYNC_PCLK_DIVx与实际 PCLK 频率不匹配。H743 的 ADC 最高支持 36MHz若 PCLK2120MHz则DIV4得 30MHz安全但若误设DIV2得 60MHz则 ADC 内部时序紊乱。解决用示波器测量 TIM2 的 TRGO 引脚PA0 或 PA1需配置为 AF与 ADC 的 EOC 引脚PB0 或 PB1计算实际延迟。若超 100ns立即检查hadc1.Init.ClockPrescaler值并在SystemClock_Config()中确认PeriphClkInitStruct.PeriphClockSelection包含RCC_PERIPHCLK_ADC且PeriphClkInitStruct.AdcClockSelection RCC_ADCCLKSOURCE_PLL2PLL2 可配 36MHz。5.4 现象双缓冲模式下Buffer A 和 Buffer B 数据混杂如 Buffer A 中出现 Buffer B 的数据原因DMA 的双缓冲地址未在HAL_ADC_Start_DMA()前正确载入。H743 的 DMA_SxAR 寄存器M0AR/M1AR必须在 DMA 启动前写入且DMA_SxCR_DBM位必须置位。若在HAL_ADC_Start_DMA()后才写 M1AR则 DMA 可能忽略该地址。解决严格按顺序执行①HAL_DMA_Init()→ ②hdma_adc1.Instance-CR | DMA_SxCR_DBM→ ③hdma_adc1.Instance-M0AR ...; hdma_adc1.Instance-M1AR ...→ ④HAL_ADC_Start_DMA()。用调试器观察DMA2_Stream0-M0AR和M1AR是否为预期地址。5.5 现象系统运行一段时间后ADC 数据全为 0xFFFF饱和值原因ADC 输入信号超出参考电压范围或模拟输入引脚未正确配置为模拟模式仍为 GPIO_INPUT。H743 的 ADC 输入耐压为 VREF若 VREF 3.3V 而传感器输出 5V则 ADC 永远饱和。解决用万用表测量 ADC 输入引脚电压确认在 0~VREF 范围内检查 GPIO 初始化中GPIO_MODE_ANALOG是否设置如GPIO_InitStruct.Mode GPIO_MODE_ANALOG;并确认无上拉/下拉电阻启用Pull GPIO_NOPULL。6. 验证与调优用 Scope 抓波形、用 CubeMX 做反向校验、用真实负载压测6.1 用示波器验证时序链路TRGO → EOC → DMA 写入最硬核的验证不是看串口打印而是用示波器抓三个信号通道 1TIM2 的 TRGO 输出需将 PA0 配置为 AF0GPIO_InitStruct.Alternate GPIO_AF0_TIM2;通道 2ADC1 的 EOC 信号PB0GPIO_InitStruct.Alternate GPIO_AF9_ADC12;通道 3DMA 写入 Buffer A 的首个地址如adc_dma_buffer_a[0]需用 DAP-Link SWO 或 GPIO 模拟理想波形应显示TRGO 上升沿后固定延迟H743 典型值 120ns出现 EOC 上升沿EOC 上升沿后约 200ns 出现 DMA 写入信号。若 TRGO 与 EOC 间隔波动 50ns检查 TIM2 时钟源是否受 PLL 稳定性影响若 EOC 与 DMA 写入间隔 1μs检查 DMA 优先级是否被其他高流量外设如 ETH抢占。6.2 用 STM32CubeMX 反向生成配置比对关键寄存器CubeMX 是 H743 的“寄存器翻译器”。将本资源的配置导入 CubeMXFile → Import Settings在 “Pinout Configuration” 中确认 TIM2 的 Clock Source 为 Internal ClockChannel 1 的 Mode 为 PWM Generation CH1Trigger Output 为 Update Event在 “Configuration” → “ADC” 中确认 External Trigger 为 TIM2_CC1Scan Conversion Mode 为 EnabledNumber of Conversions 为 4在 “Configuration” → “DMA” 中确认 ADC1 的 Request 为 DMA Request 0Mode 为 CircularData Width 为 Half Word导出代码后对比MX_ADC1_Init()中hadc1.Init.ExternalTrigConv和MX_DMA2_Init()中hdma_adc1.Init.Mode是否与手动配置一致。CubeMX 生成的代码常因版本差异漏掉DMA_SxCR_DBM此步骤可快速定位配置偏差。6.3 真实负载压测在 200kHz 采样率下跑满 4 通道 FFTH743 的标称性能是 480MHz但 ADCDMA 满载时CPU 仍需处理中断和算法。本资源预留了g_adc_ovr_count和g_adc_ht_count全局计数器。在主循环中添加while(1) { if (g_adc_tc_flag) { // TC 中断置位标志 g_adc_tc_flag 0; // 执行 256 点 FFT使用 ARM CMSIS-DSP 库 arm_cfft_f32(S, fft_input, 0, 1); // S 为预初始化的 FFT 实例 arm_cmplx_mag_f32(fft_input, fft_magnitude, 256); } }用逻辑分析仪监测g_adc_tc_flag置位间隔若偏离 10μs100kHz超过 ±0.5μs则说明 FFT 占用 CPU 过多。此时应① 将 FFT 移至 DMA HT 中断中分段计算② 启用 FPU__FPU_PRESENT 1并链接arm_cortexM7lfsp_math.lib③ 将fft_input数组声明为__attribute__((section(.ccmram)))放入 CCM-SRAM64KB零等待避免 Flash 访问延迟。从那以后我每次搭建新的 ADC 采样链都强制走一遍这三步验证先用示波器抓 TRGO-EOC 延迟再用 CubeMX 反向校验寄存器最后挂真实算法压测 OVR 计数器。少走一次就可能在量产阶段收到客户“电机异响”的紧急电话——而根源只是 TIM2 的 PSC 算错了 1。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。