stm32dmapwmrust-embedded

How to control duty cycle via DMA on Rust?


I wrote my code based on this topic, but it is not work. I'm using the stm32f7xx_hal crate, but I think the logic of my program is similar to the code from the example. My problem is that the duty cycle retains its duty cycle, which is configured in this line buzz_pwm.set_duty(Channel::C1, 0). I run this code on the STM32F767ZI:

    let mut rcc = dp.RCC.constrain();
    let clocks = rcc
        .cfgr
        .set_defaults()
        .freeze();

    let gpioa = dp.GPIOA.split();
    let buzz = gpioa.pa6.into_alternate();
    let mut buzz_pwm = dp.TIM3.pwm_hz(buzz, 4_000_000.Hz(), &clocks);

    let max_duty = buzz_pwm.get_max_duty();
    buzz_pwm.set_duty(Channel::C1, max_duty / 3);
    buzz_pwm.enable(Channel::C1);

    let dma_buf = [max_duty / 3 * 2, max_duty / 3, 0];

    unsafe {
        let tim3 = &*TIM3::ptr();
        let rcc_ptr = &*RCC::ptr();
        let dma1 = &*DMA1::ptr();

        rcc_ptr.ahb1enr.modify(|_, w| w.dma1en().set_bit());

        let ccr1_addr = tim3.ccr1() as *const _ as u32;

        tim3.dier.write(|w| w
            .tde().enabled()
            .cc1ie().enabled()
            .ude().enabled()
        );

        tim3.dcr.write(|w| w.dba().bits(15));

        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()
        );
    }

Show me where I'm wrong, please.


Solution

  • My mistake is that i didn't enable capture/compare 1 DMA request. Here is a main loop that works for me:

        let dp = pac::Peripherals::take().unwrap();
        let mut rcc = dp.RCC.constrain();
        let clocks = rcc.cfgr
            .hse(HSEClock::new(8.MHz(), HSEClockMode::Oscillator))
            .pllm(4)
            .plln(96)
            .pllp(PLLP::Div4)
            .use_pll()
            .sysclk(48.MHz())
            .freeze();
    
        let gpioa = dp.GPIOA.split();
        let buzz = gpioa.pa6.into_alternate();
        let mut buzz_pwm = dp.TIM3.pwm_hz(buzz, 2_000_000.Hz(), &clocks);
    
        let max_duty = buzz_pwm.get_max_duty() as i32;
        buzz_pwm.set_duty(Channel::C1, 0);
        buzz_pwm.enable(Channel::C1);
    
        let dma_buf = [max_duty / 6, max_duty / 4, max_duty / 4, max_duty / 3, 0, 0, 0];
    
        unsafe {
            let tim3 = &*TIM3::ptr();
            let rcc_ptr = &*RCC::ptr();
            let dma1 = &*DMA1::ptr();
    
            rcc_ptr.ahb1enr.modify(|_, w| w.dma1en().set_bit());
    
            let ccr1_addr = tim3.ccr1() as *const _ as u32;
    
            tim3.dier.write(|w| w
                .tde().enabled()
                .cc1de().enabled() //enable capture/compare 1 DMA request
                .ude().enabled()
            );
    
            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()
            );
        }