samd21 pwm with waveform output 1 instead of 0

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
I am using a samd21g18a and I have the following working pwm:

	PORT->Group[0].DIRSET.reg = PORT_PA04;
	PORT->Group[0].OUTCLR.reg = PORT_PA04;
	PORT->Group[0].PINCFG[4].reg |= PORT_PINCFG_PMUXEN;
	PORT->Group[0].PMUX[4 >> 1].reg =  PORT_PMUX_PMUXE_E;
	
	/* power on the device */
	PM->APBCMASK.reg |= PM_APBCMASK_TCC0;
	GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(TCC0_GCLK_ID));
	while (GCLK->STATUS.bit.SYNCBUSY) {}
	
	/* reset TCC module */
	TCC0->CTRLA.reg = TCC_CTRLA_SWRST;
	while (TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_SWRST) {}
	TCC0->CTRLBCLR.reg = TCC_CTRLBCLR_DIR;     /* count up */
	while (TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {}
	
	/* configure the TCC device */
	TCC0->CTRLA.reg = (TCC_CTRLA_PRESCSYNC_GCLK_Val | TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV256_Val));
	/* select the waveform generation mode -> normal PWM */
	TCC0->WAVE.reg = (TCC_WAVE_WAVEGEN_NPWM);
	while (TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_WAVE) {}
	/* set the selected period */
	TCC0->PER.reg = (255 - 1);
	while (TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_PER) {}
	/* start PWM operation */
	TCC0->CTRLA.reg |= (TCC_CTRLA_ENABLE);

I would like to get PWM working on PA05, but I can't figure out how to add the waveform output, WO[1] instead of WO[0].  I am sure I just got lucky with PA04 with 0 being the default.  I tried to reverse engineer ASF but got lost in the mud.  Is there a value you add to the PMUX?

Any insight is appreciated...

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

I think if I just change the following it "should" work:

	PORT->Group[0].DIRSET.reg = PORT_PA05;
	PORT->Group[0].OUTCLR.reg = PORT_PA05;
	PORT->Group[0].PINCFG[5].reg |= PORT_PINCFG_PMUXEN;
	PORT->Group[0].PMUX[4 >> 1].reg =  PORT_PMUX_PMUXO_E;

But I must be missing something...

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

This works:

int main(void)
{
    /* Initialize the SAM system */
    SystemInit();
    
    PORT->Group[0].DIRSET.reg = PORT_PA05;
    PORT->Group[0].OUTCLR.reg = PORT_PA05;
    PORT->Group[0].PINCFG[5].reg |= PORT_PINCFG_PMUXEN;
    PORT->Group[0].PMUX[4 >> 1].reg =  PORT_PMUX_PMUXO_E;
        
    /* power on the device */
    PM->APBCMASK.reg |= PM_APBCMASK_TCC0;
    GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(TCC0_GCLK_ID));
    while (GCLK->STATUS.bit.SYNCBUSY) {}
    
    /* reset TCC module */
    TCC0->CTRLA.reg = TCC_CTRLA_SWRST;
    while (TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_SWRST) {}
    TCC0->CTRLBCLR.reg = TCC_CTRLBCLR_DIR;     /* count up */
    while (TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {}
    
    /* configure the TCC device */
    TCC0->CTRLA.reg = (TCC_CTRLA_PRESCSYNC_GCLK_Val | TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV256_Val));
    /* select the waveform generation mode -> normal PWM */
    TCC0->WAVE.reg = (TCC_WAVE_WAVEGEN_NPWM);
    while (TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_WAVE) {}
    /* set the selected period */
    TCC0->PER.reg = (255 - 1);
    while (TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_PER) {}
    TCC0->CC[1].reg = 10;
    /* start PWM operation */
    TCC0->CTRLA.reg |= (TCC_CTRLA_ENABLE);
    
    while (1) {
    }
}

I only added the CC setting.

If you setup multiple pins there could be an issue here
 

    PORT->Group[0].PMUX[4 >> 1].reg = PORT_PMUX_PMUXO_E;

i.e., use

    PORT->Group[0].PMUX[4 >> 1].reg |= PORT_PMUX_PMUXO_E;

/Lars

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

BTW, the presync setting here

TCC0->CTRLA.reg = (TCC_CTRLA_PRESCSYNC_GCLK_Val | TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV256_Val));

is not ok, TCC_CTRLA_PRESCSYNC(value) should be used. It is not an actual problem here since TCC_CTRLA_PRESCSYNC_GCLK_Val has the value 0.

/Lars

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

Thank you very much, it is very obvious now but I totally missed it.  And thanks for the future bug fix.

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

Grettings, I looked up at the code and run it on my generic samd21 board, but then when I tried to change the pin for making it work on a built in led it didn't work... I don't know what I am missing... And also I am a little confused about the "4 >> 1" on:

 

	PORT->Group[0].PMUX[4 >> 1].reg =  PORT_PMUX_PMUXO_E;

Could you please explain why is it put that way?

This is my code:

 

#include "sam.h"

int main(void)
{
	/* Initialize the SAM system */
	SystemInit();
	PORT->Group[0].DIRSET.reg = PORT_PA17;
	PORT->Group[0].OUTCLR.reg = PORT_PA17;
	PORT->Group[0].PINCFG[17].reg |= PORT_PINCFG_PMUXEN;
	PORT->Group[0].PMUX[4 >> 1].reg =  PORT_PMUX_PMUXO_F;

	/* power on the device */
	PM->APBCMASK.reg |= PM_APBCMASK_TCC0;
	GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(TCC0_GCLK_ID));
	while (GCLK->STATUS.bit.SYNCBUSY) {}

	/* reset TCC module */
	TCC0->CTRLA.reg = TCC_CTRLA_SWRST;
	while (TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_SWRST) {}
	TCC0->CTRLBCLR.reg = TCC_CTRLBCLR_DIR;     /* count up */
	while (TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {}

	/* configure the TCC device */
	TCC0->CTRLA.reg = (TCC_CTRLA_PRESCSYNC_GCLK_Val | TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV256_Val));
	/* select the waveform generation mode -> normal PWM */
	TCC0->WAVE.reg = (TCC_WAVE_WAVEGEN_NPWM);
	while (TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_WAVE) {}
	/* set the selected period */
	TCC0->PER.reg = (255 - 1);
	while (TCC0->SYNCBUSY.reg & TCC_SYNCBUSY_PER) {}
	TCC0->CC[1].reg = 10;
	/* start PWM operation */
	TCC0->CTRLA.reg |= (TCC_CTRLA_ENABLE);

	while (1) {
	}
}

Aprecciate your help and comments... thanks again.

**************EDIT**************

So I noticed that on the line:

	PORT->Group[0].PMUX[4 >> 1].reg =  PORT_PMUX_PMUXO_E;

The 4 >> 1 it's a fancy way of putting the PMUX register. So in my case I changed it to:

	PORT->Group[0].PMUX[8].reg =  PORT_PMUX_PMUXO_F;

Still not working...

********* SECOND EDIT *********

So I tested changing the line:

TCC0->CC[1].reg = 10;

I put:

TCC0->CC[3].reg = 10;

And it's working, so I selected the wrong  CC... the problem now is that I still can't find any reference on the pin mapping for each CC... It's a big datasheet! haha, anyone knows where is that part mentioned?

Victor

Last Edited: Wed. Jul 25, 2018 - 02:42 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looking at "I/O Multiplexing and Considerations" (the place to start for any pin mapping question) PA17 is WO[7] for TCC0 so not exactly the simplest configuration to use/understand since there are only 4 compare registers. It would be straight forward to use any of WO[0] - WO[3]. But in this case with more outputs than compare channels you will have to know that the channel outputs are replicated on the additional WO. Not sure this is explicitly stated in the datasheet other than that it is the default setup of the TCC waveform extension "Output Matrix Channel Pin Routing Configuration":

Configuration 0x0 is the default configuration. The channel location is the default one, and channels are distributed on outputs modulo the number of channels. Channel 0 is routed to the Output matrix output OTMX[0], and Channel 1 to OTMX[1]. If there are more outputs than channels, then channel 0 is duplicated to the Output matrix output OTMX[CC_NUM], channel 1 to OTMX[CC_NUM+1] and so on. 

So in your case CC[3] will be on WO[3] and WO[7].

/Lars