Cómo actualizar de manera confiable el ciclo de trabajo a PWM en arduino debido a SAM3XE

1

Tengo arduino debido, que tiene Atmel SAM3XE MCU.

Quiero generar una señal PWM y quiero cambiar el ciclo de trabajo de manera confiable en cada ciclo de PWM Puedo generar una señal de salida como el seno en el pin de salida. ¿Cómo puedo implementar esto usando una interrupción? Necesito agregar una rutina de interrupción, que se ejecutará a tiempo antes comienza el siguiente ciclo de PWM.

Tengo este código hasta ahora:

// Output 50% duty cycle PWM at 10kHz on digital pins D4 and D5 using TC6
void setup()
{

  REG_PMC_PCER1 |= PMC_PCER1_PID33;                 // Enable peripheral TC6 (TC2 Channel 0)
  REG_PIOC_ABSR |= PIO_ABSR_P26 | PIO_ABSR_P25;     // Switch the multiplexer to peripheral B for TIOA6 and TIOB6
  REG_PIOC_PDR |= PIO_PDR_P26 | PIO_PDR_P25;        // Disable the GPIO on the corresponding pins

  REG_TC2_CMR0 = TC_CMR_BCPC_SET |                  // Set TIOB on counter match with RC0
                 TC_CMR_ACPC_SET |                  // Set TIOA on counter match with RC0
                 TC_CMR_BCPB_CLEAR |                // Clear TIOB on counter match with RB0
                 TC_CMR_ACPA_CLEAR |                // Clear TIOA on counter match with RA0
                 TC_CMR_WAVE |                      // Enable wave mode
                 TC_CMR_WAVSEL_UP_RC |              // Count up with automatic trigger on RC compare
                 TC_CMR_EEVT_XC0 |                  // Set event selection to XC0 to make TIOB an output
                 TC_CMR_TCCLKS_TIMER_CLOCK1;        // Set the timer clock to TCLK1 (MCK/2 = 84MHz/2 = 48MHz)

  REG_TC2_RC0 = 1400;                               // Load the RC0 register, 30 kHz PWM
  REG_TC2_RA0 = 350;                               // Load the RB0 register
  REG_TC2_RB0 = 700+350;                               // Load the RB0 register

  REG_TC2_CCR0 = TC_CCR_SWTRG | TC_CCR_CLKEN;       // Enable the timer TC6

}

void loop() {}
    
pregunta Matttoni

1 respuesta

0

Puedes hacer algo como esto. Esto habilita el controlador de interrupción y puede actualizar los valores de registro R * en el controlador de interrupción. Sin embargo, no estoy completamente seguro de si esta es la forma más segura de hacerlo.

    // Output 50% duty cycle PWM at 10kHz on digital pins D4 and D5 using TC6
void setup() {

  REG_PMC_PCER1 |= PMC_PCER1_PID33;                 // Enable peripheral TC6 (TC2 Channel 0)
  REG_PIOC_ABSR |= PIO_ABSR_P26 | PIO_ABSR_P25;     // Switch the multiplexer to peripheral B for TIOA6 and TIOB6
  REG_PIOC_PDR |= PIO_PDR_P26 | PIO_PDR_P25;        // Disable the GPIO on the corresponding pins

  REG_TC2_CMR0 = TC_CMR_BCPC_SET |                  // Set TIOB on counter match with RC0
                 TC_CMR_ACPC_SET |                  // Set TIOA on counter match with RC0
                 TC_CMR_BCPB_CLEAR |                // Clear TIOB on counter match with RB0
                 TC_CMR_ACPA_CLEAR |                // Clear TIOA on counter match with RA0
                 TC_CMR_WAVE |                      // Enable wave mode
                 TC_CMR_WAVSEL_UP_RC |              // Count up with automatic trigger on RC compare
                 TC_CMR_EEVT_XC0 |                  // Set event selection to XC0 to make TIOB an output
                 TC_CMR_TCCLKS_TIMER_CLOCK1;        // Set the timer clock to TCLK1 (MCK/2 = 84MHz/2 = 48MHz)

  REG_TC2_RC0 = 1400;                               // Load the RC0 register, 30 kHz PWM
  REG_TC2_RA0 = 350;                               // Load the RB0 register
  REG_TC2_RB0 = 700+350;                               // Load the RB0 register

  // enable interrupts
  TC2 -> TC_CHANNEL[0].TC_IER = TC_IER_CPAS       // interrupt on RA compare match
                            | TC_IER_CPBS         // interrupt on RB compare match
                            | TC_IER_CPCS;        // interrupt on RC compare match

  // enable interrupt vector
  NVIC_EnableIRQ(TC6_IRQn);
  REG_TC2_CCR0 = TC_CCR_SWTRG | TC_CCR_CLKEN;       // Enable the timer TC6

}

void loop() {}

//TC6 interrupt handler
void TC6_Handler() {

  // read interrupt status
  uint32_t status = TC2 -> TC_CHANNEL[0].TC_SR;

  if (status & TC_SR_CPAS) {
    // RA compare match
  } else if (status & TC_SR_CPBS) {
    // RB compare match
  } else if (status & TC_SR_CPCS) {
    // RC compare match
    TC2 -> TC_CHANNEL[0].TC_RC = 2000;
  }

}

También puede programar una señal de PMW usando el controlador PWM en el Due. De esta manera puede dejar que el DMA del PDC actualice los valores del ciclo de trabajo automáticamente. Si es necesario, puedo hacer un boceto rápido para probarlo.

    
respondido por el Swedgin

Lea otras preguntas en las etiquetas