通过 DMA 配置的 PWM 在高速下无法正常工作

问题描述 投票:0回答:1

我已将STM32F767ZI上的RCC设置为48 MHz(当设置为更高频率时会发生错误,尽管在具有相同设置的CubeMX中没有错误)。

    rcc.cr.modify(|_, w| w.hsebyp().set_bit());
    rcc.cr.modify(|_, w| w.hseon().on());
    while rcc.cr.read().hserdy().is_not_ready() {}
    println!("{:b}", rcc.cr.read().bits());
    println!("Hse ready");

    rcc.pllcfgr.modify(|_, w| w.pllsrc().hse());
    rcc.pllcfgr.modify(unsafe {|_, w| w.pllm().bits(4)});
    rcc.pllcfgr.modify(unsafe {|_, w| w.plln().bits(96)});
    rcc.pllcfgr.modify(|_, w| w.pllp().div4());

    rcc.cr.modify(|_, w| w.pllon().on());
    while rcc.cr.read().pllrdy().is_not_ready() {}
    println!("Pll ready");

    rcc.cfgr.modify(|_, w| w.sw().pll());
    while !rcc.cfgr.read().sws().is_pll() {}
    println!("pll selectected");

当 PWM 以 2 MHz 运行时,一切正常:

tim.arr.write(|w| w.bits(23));
let dma_buf = [8, 12, 12, 16, 0, 0, 0, 0];
2 MHz 的 PWM 脉冲

但是如果 PWM 以 4 MHz 运行,则第二个脉冲会重复

tim.arr.write(|w| w.bits(11));
let dma_buf = [4, 6, 6, 8, 0, 0, 0, 0];
4 Mhz的 PWM 脉冲,即对应于
dma_buf = [4, 6, 6, 6, 6, 8, 0, 0, 0, 0];

定时器和dma配置如下:

    unsafe {
        tim.arr.write(|w| w.bits(11)); // frequency
        tim.ccr1().write(|w| w.bits(0));// duty cycle
    }

    // clear enable to zero just to be sure
    tim.ccmr1_output().modify(|_, w| w.oc1ce().clear_bit());
    //enable preload
    tim.ccmr1_output().modify(|_, w| w.oc1pe().enabled());
    // set pwm mode 1
    tim.ccmr1_output().modify(|_, w| w.oc1m().pwm_mode1());
    // enable output
    tim.ccer.write(|w| w.cc1e().set_bit());
    // enable auto-reload
    tim.cr1.modify(|_, w| w.arpe().set_bit());
    tim.dier.modify(|_, w| w.ude().set_bit());
    tim.dier.modify(|_, w| w.cc1de().set_bit());
    tim.dier.modify(|_, w| w.tde().set_bit());
    // enable update generation - needed at first start
    tim.egr.write(|w| w.ug().set_bit());
    tim.egr.write(|w| w.ug().set_bit());
    // start pwm
    tim.cr1.modify(|_, w| w.cen().set_bit());

    unsafe {
        let ccr1_addr = tim.ccr1() as *const _ as u32;
        let dma_buf = [4, 6, 6, 8, 0, 0, 0, 0];

        dma1.st[4].m0ar.write(|w| w.m0a().bits(dma_buf.as_ptr() as u32));
        dma1.st[4].ndtr.write(|w| w.ndt().bits(dma_buf.len() as u16));
        dma1.st[4].par.write(|w| w.pa().bits(ccr1_addr));

        dma1.st[4].cr.reset();
        dma1.st[4].cr.modify(|_, w| w
            .chsel().bits(5)
            .mburst().single()
            .pburst().single()
            .pl().high()
            .msize().bits32()
            .psize().bits32()
            .minc().set_bit()
            .pinc().clear_bit()
            .circ().enabled()
            .dir().memory_to_peripheral()
            .teie().set_bit()
            .htie().set_bit()
            .tcie().set_bit()
            .en().enabled()
        );
    }

stm32 dma pwm pac rust-embedded
1个回答
0
投票

补救办法很简单,不要从CC触发DMA,而是从Update触发DMA,即不要设置CC1DE,而是设置UDE。 并选择设置 TIMx_UP 的 Stream。我还将 DMAR 地址而不是 CCR1 地址写入 PAR。

    unsafe {
        tim.arr.write(|w| w.bits(17)); // frequency
        tim.ccr1().write(|w| w.bits(0));// duty cycle
    }

    // clear enable to zero just to be sure
    tim.ccmr1_output().modify(|_, w| w.oc1ce().clear_bit());
    //enable preload
    tim.ccmr1_output().modify(|_, w| w.oc1pe().enabled());
    // set pwm mode 1
    tim.ccmr1_output().modify(|_, w| w.oc1m().pwm_mode1());
    // enable output
    tim.ccer.write(|w| w.cc1e().set_bit());
    // enable auto-reload
    tim.cr1.modify(|_, w| w.arpe().set_bit());
    tim.dier.modify(|_, w| w.ude().set_bit());
    tim.dier.modify(|_, w| w.cc1de().clear_bit());
    tim.dcr.modify(|_, w| w.dba().bits(13));
    // enable update generation - needed at first start
    tim.egr.write(|w| w.ug().set_bit());
    tim.egr.write(|w| w.ug().set_bit());
    // start pwm
    tim.cr1.modify(|_, w| w.cen().set_bit());


    unsafe {
        let dmar_addr = tim.dmar.as_ptr() as u32;
        let dma_buf = [6, 9, 6, 9, 6, 9, 0, 0, 0];

        dma1.st[2].m0ar.write(|w| w.m0a().bits(dma_buf.as_ptr() as u32));
        dma1.st[2].ndtr.write(|w| w.ndt().bits(dma_buf.len() as u16));
        dma1.st[2].par.write(|w| w.pa().bits(dmar_addr));

        dma1.st[2].cr.reset();
        dma1.st[2].cr.modify(|_, w| w
            .chsel().bits(5)
            .mburst().single()
            .pburst().single()
            .pl().high()
            .msize().bits32() 
            .psize().bits32() 
            .minc().set_bit()
            .pinc().clear_bit()
            .circ().enabled()
            .dir().memory_to_peripheral()
            .teie().set_bit()
            .htie().set_bit()
            .tcie().set_bit()
            .en().enabled()
        );
    }
© www.soinside.com 2019 - 2024. All rights reserved.