STM32f103 DMA con valores de repetición de PWM

0

Tengo una píldora azul (STM32F103) y conecté a ella una tira led ws2812b. Estoy intentando enviar datos a la tira de LED a través de PWM a través del periférico TIM2 (Pin A0). Para cambiar el ciclo de trabajo del TIM2 PWM, uso un canal DMA. Esto funciona perfectamente a velocidades más bajas (por ejemplo, 100 kHz) pero tan pronto como me acerque a los 800 kHz requeridos de los leds, la MCU parece enviar algunos pulsos dos veces, esto tendría sentido si sobrecargo el bus, pero de lo que he salido de la hoja de datos debería poder manejar 800 kbyte / s.

Lo que hace que todo sea más complicado, es que estoy tratando de escribir esto en Rust y no hay un código que pueda comparar el mío también. Intentaré publicar las partes relevantes del código y explicarlo lo mejor que pueda.

Código principal:

// setup pwm
let mut pwm = p.TIM2
    .pwm(
        c1,
        &mut afio.mapr,
        800.khz(),
        clocks,
        &mut rcc.apb1,
    );

let max = pwm.get_max_duty();

let one_duty = (max * 16 / 25) as u8;


let buf = singleton!(: [u8; 25] = [one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, one_duty, 0]).unwrap();

// set duty to zero
pwm.set_duty(0);
// enable pwm output
pwm.enable();
// enable the dma and wait for it to finish
pwm.write_all(channels.5, buf).wait();

Código de función WriteAll:

pub fn write_all<A, B>(
    self,
    mut chan: $c1_chan,
    buffer: B,
    ) -> Transfer<R, B, $c1_chan, Self>
where
    A: Unsize<[u8]>,
    B: Static<A>,
{
    {
        unsafe { (*$TIMX::ptr()).dier.modify(|_, w| {
            w   .tde().set_bit()
                .cc1de().set_bit()
        }); }

        let buffer: &[u8] = buffer.borrow();
        chan.cmar().write(|w| unsafe {
            w.ma().bits(buffer.as_ptr() as usize as u32)
        });
        chan.cndtr().write(|w| unsafe{
            w.ndt().bits(u16(buffer.len()).unwrap())
        });
        chan.cpar().write(|w| unsafe {
            w.pa().bits(&(*$TIMX::ptr()).ccr1 as *const _ as usize as u32)
        });

        atomic::compiler_fence(Ordering::SeqCst);

        chan.ccr().modify(|_, w| {
            w.mem2mem().clear_bit()
                // priority
                .pl().high()
                // size in memory
                .msize().bit8()
                .psize().bit32()
                .minc().set_bit()
                .pinc().clear_bit()
                .circ().clear_bit()
                .dir().set_bit()
                .teie().set_bit()
                .htie().set_bit()
                .tcie().set_bit()
                // enable
                .en().set_bit()
        });
    }
}

Mi pregunta es: ¿por qué el DMA no es lo suficientemente rápido a pesar de que debería ser como lo indica la documentación?

    
pregunta user9162088

1 respuesta

1

Encontré una solución al escribir esta pregunta. Pensé que lo publicaba de todos modos ya que podría ayudar a otras personas. Después de llamar a write_all, llamo a esperar, que constantemente sondea el resultado. Esto ocupó el autobús y ralentizó la transferencia de DMA.

Editar: no configuré el multiplicador de reloj correcto, por lo que la MCU funcionó a solo 8 mhz. Cuando se ejecuta más rápido, funciona muy bien.

    
respondido por el user9162088

Lea otras preguntas en las etiquetas