C21: help configuring TCC for two outputs waveform generator

Go To Last Post
2 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I need to generate two synchronized waveform on two output pins. They are two PWM, for example 100us ON, 900us OFF. It's simple to configure TCC to generate PWM on one output.

 

The problem is on the second output. I need ON time of second output follows the ON time of the first output.

 

WO[0]: 111100000000000000111100000000000000111100000000000000111100000000000000...

WO[1]: 000011110000000000000011110000000000000011110000000000000011110000000000...

 

I studied the features of TCC, but I don't think it's possible to generate such waveforms, but I hope I'm wrong.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's at least possible if you use two TCC instances. You start the second TCC by an event from the first (at the compare time, i.e., when WO[0] goes low). The second TCC makes a one shot pulse when the event arrives.

 

#include "sam.h"

void init_TCC0(void);
void init_TCC1(void);

int main(void)
{
    SystemInit();
    
    init_TCC0();
    init_TCC1();
    
    MCLK->APBCMASK.bit.EVSYS_ = 1;
    EVSYS->USER[EVSYS_ID_USER_TCC1_EV_0].reg = 1; // Channel 0
    const EVSYS_CHANNEL_Type channel0Config = {
        .bit.EDGSEL = 0, // 0 when using async
        .bit.EVGEN = EVSYS_ID_GEN_TCC0_MCX_0,
        .bit.PATH = EVSYS_CHANNEL_PATH_ASYNCHRONOUS_Val
    };
    EVSYS->CHANNEL[0].reg = channel0Config.reg;

    static volatile int tick = 0;
    while (1) {
        tick++;
        TCC0->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val;
        TCC1->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val;
    }
}

void init_TCC0()
{
    GCLK->PCHCTRL[TCC0_GCLK_ID].bit.GEN = 0;
    GCLK->PCHCTRL[TCC0_GCLK_ID].bit.CHEN = 1;
    MCLK->APBCMASK.bit.TCC0_ = 1;
    
    // Output on PA08
    PORT->Group[0].PINCFG[8].reg = 0x1;
    PORT->Group[0].PMUX[8/2].bit.PMUXE = 'E'-'A';

    // Configure TCC0
    TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV1;
    //Configure Period and duty-cycle
    TCC0->PER.reg = 8000;
    // Duty cycle for PA08 and pulse start event time for TCC1
    TCC0->CC[0].reg = 800;
    TCC0->WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val;
    TCC0->EVCTRL.bit.MCEO0 = 1;
    // Enable TCC0
    TCC0->CTRLA.reg |= TCC_CTRLA_ENABLE;
}

void init_TCC1(void)
{
    GCLK->PCHCTRL[TCC1_GCLK_ID].bit.GEN = 0;
    GCLK->PCHCTRL[TCC1_GCLK_ID].bit.CHEN = 1;
    MCLK->APBCMASK.bit.TCC1_ = 1;
    
    // Output on PA10
    PORT->Group[0].PINCFG[10].reg = 0x1;
    PORT->Group[0].PMUX[10/2].bit.PMUXE = 'E'-'A';
    
    // Configure TCC1
    // One-shot started by event
    TCC1->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV1;
    TCC1->WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val;
    TCC1->CTRLBSET.reg = TCC_CTRLBCLR_ONESHOT;
    TCC1->CC[0].reg = 800;
    TCC1->PER.reg = 800;
    TCC1->EVCTRL.bit.EVACT0 = TCC_EVCTRL_EVACT0_RETRIGGER_Val;
    TCC1->EVCTRL.bit.TCEI0 = 1;
    // Enable TCC1
    TCC1->CTRLA.reg |= TCC_CTRLA_ENABLE;
}

/Lars