I have set RCC on STM32F767ZI to 48 MHz (when setting to a higher frequency an error occurs, although in CubeMX with the same settings there is no error).
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");
When the PWM runs at 2 MHz, everything works as it should:
tim.arr.write(|w| w.bits(23));
and let dma_buf = [8, 12, 12, 16, 0, 0, 0, 0];
PWM pulses at 2 MHz
But if the PWM operates at 4 MHz, the second pulse is duplicated
tim.arr.write(|w| w.bits(11));
and let dma_buf = [4, 6, 6, 8, 0, 0, 0, 0];
PWM pulses at 4 Mhz, that is, corresponds to dma_buf = [4, 6, 6, 6, 6, 8, 0, 0, 0, 0];
Timers and dma are configured as follows:
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()
);
}
The remedy is simple, don't trigger DMA from CC, but from Update, i.e. don't set CC1DE, but UDE. And select the Stream where TIMx_UP is set. I also write DMAR address instead of the CCR1 address to the 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()
);
}