定时器触发的 DMA 循环模式

[复制链接]
903|5
和下土 发表于 2025-9-29 14:41 | 显示全部楼层 |阅读模式
利用硬件机制实现无中断依赖的连续传输,适用于固定模式或周期性更新的场景:
c
运行
// STM32 DMA循环模式配置
void dma_circular_mode_init() {
    // 配置DMA为循环模式
    DMA_InitTypeDef DMA_InitStruct;
    DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;  // 循环模式
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&TIM2->CCR1;
    DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)pwm_buffer;
    DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE;
    // 其他配置...
    HAL_DMA_Init(&hdma_tim2_ch1, &DMA_InitStruct);

    // 配置定时器触发DMA
    TIM_SelectDMAOutput(TIM2, TIM_DMABase_CCR1);
    TIM_DMACmd(TIM2, TIM_DMA_CC1, ENABLE);

    // 启动定时器和DMA
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
    HAL_DMA_Start(&hdma_tim2_ch1, (uint32_t)pwm_buffer,
                 (uint32_t)&TIM2->CCR1, BUFFER_SIZE);
}

// 后台更新循环缓冲区(非中断方式)
void update_circular_buffer() {
    // 计算安全更新位置(避开当前DMA正在访问的地址)
    uint32_t current_pos = BUFFER_SIZE - DMA_GetCurrDataCounter(hdma_tim2_ch1.Instance);
    uint32_t safe_pos = (current_pos + BUFFER_SIZE/2) % BUFFER_SIZE;

    // 安全更新缓冲区后半部分
    generate_pwm_data(&pwm_buffer[safe_pos], BUFFER_SIZE/2);
}
适用场景:
电机控制等需要连续稳定 PWM 输出的场景
对实时性要求极高,不允许任何中断延迟的应用
数据变化周期长于缓冲区传输周期的情况

classroom 发表于 2025-9-30 11:47 | 显示全部楼层
BUFFER_SIZE 应为 2 的幂次
cr315 发表于 2025-9-30 11:48 | 显示全部楼层
无中断、低延迟、硬件自动处理数据传输。
flycamelaaa 发表于 2025-9-30 14:49 | 显示全部楼层
如果需要更复杂的缓冲管理,可以考虑结合 DMA 中断
powerantone 发表于 2025-9-30 17:50 | 显示全部楼层
定时器的DMA请求使能位是否设置。
powerantone 发表于 2025-9-30 17:50 | 显示全部楼层
定时器的DMA请求使能位是否设置。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

114

主题

1405

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部