PWM resolution and dual/single slope

I could see many pieces of PWM code for the Zero here by the great MartinL, and there are 2 things I think i missed here.

1.Before many of them Martin says "this is a 6 bits PWM", or "this is a 11bits PWM", but I cant see anywhere he set the resolution. is this done just by the timer counter number presentation ?

2.How would you do a single slop PWM on TCC0 ? Do you loose resolution on dual slop ? because you actually set the CC0 register for a smaller value(divided by 2)

This is the code I have for PWM , dual slop, by Martin, wonder how to turn it to single slop, and change resolution:

   REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) |          // Divide the 48MHz clock source by divisor 1: 48MHz/1=48MHz
                            GCLK_GENDIV_ID(4);            // Select Generic Clock (GCLK) 4
            while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization
            
            REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                             GCLK_GENCTRL_GENEN |         // Enable GCLK4
                             GCLK_GENCTRL_SRC_DFLL48M |   // Set the 48MHz clock source
                             GCLK_GENCTRL_ID(4);          // Select GCLK4
            while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization
            
            // Enable the port multiplexer for the digital pin D7 
            PORT->Group[g_APinDescription[7].ulPort].PINCFG[g_APinDescription[7].ulPin].bit.PMUXEN = 1;
            
            // Connect the TCC0 timer to digital output D7 - port pins are paired odd PMUO and even PMUXE
            // F & E specify the timers: TCC0, TCC1 and TCC2
            PORT->Group[g_APinDescription[6].ulPort].PMUX[g_APinDescription[6].ulPin >> 1].reg = PORT_PMUX_PMUXO_F;
            
            // Feed GCLK4 to TCC0 and TCC1
            REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC0 and TCC1
                             GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                             GCLK_CLKCTRL_ID_TCC0_TCC1;   // Feed GCLK4 to TCC0 and TCC1
            while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization
            
            // Dual slope PWM operation: timers countinuously count up to PER register value then down 0
            REG_TCC0_WAVE |= TCC_WAVE_POL(0xF) |         // Reverse the output polarity on all TCC0 outputs
                            TCC_WAVE_WAVEGEN_DSBOTH;    // Setup dual slope PWM on TCC0
            while (TCC0->SYNCBUSY.bit.WAVE);               // Wait for synchronization
            
             // Each timer counts up to a maximum or TOP value set by the PER register,
            // this determines the frequency of the PWM operation: 
            REG_TCC0_PER = n;         // Set the frequency of the PWM on TCC0 to 250kHz
            while (TCC0->SYNCBUSY.bit.PER);                // Wait for synchronization
            
            // Set the PWM signal to output 50% duty cycle
            REG_TCC0_CC3 = n/2;         // TCC0 CC3 - on D7
            while (TCC0->SYNCBUSY.bit.CC3);                // Wait for synchronization

            
            // Divide the 48MHz signal by 1 giving 48MHz (20.83ns) TCC0 timer tick and enable the outputs
            REG_TCC0_CTRLA |= TCC_CTRLA_PRESCALER_DIV1 |    // Divide GCLK4 by 1
                            TCC_CTRLA_ENABLE;             // Enable the TCC0 output
            while (TCC0->SYNCBUSY.bit.ENABLE);              // Wait for synchronization

I Must add, my intentions are :

1.produce a PWM from 200Khz to about 3.5Mhz (change frequency often) 2.Use the highest resolution possible.

I know the SAMD21 is capable of 24Bits, but I could see here that Martin said its only 8bits, I wonder what is my best approach here .

If you think about it, the highest frequencies always have the least resolution, and the lowest frequencies have higher res, so for 48Mhz clock, if you want 4Mhz PWM, you set CC to be 12, and you dont really care what is the highest value possible for the CC, because the first numbers-CC=1,2,3,4,5 will always divided the clock aggressively with a very bad resolution, is my point right ?

1.Before many of them Martin says "this is a 6 bits PWM", or "this is a 11bits PWM", but I cant see anywhere he set the resolution. is this done just by the timer counter number presentation ?

The resolution of a given PWM signal isn't the size of the timer and isn't set anywhere, but can be calculated for a given PWM set-up.

The resolution is determined by the following formula:

resolution = log(PER + 1)/log(2)

where PER = value in the PER (period) register

2.How would you do a single slop PWM on TCC0 ?

To activate single slope PWM you just need to change some bits in the Waveform Control (WAVE) register. Note that if you use single slope PWM, you don't need to reverse the waveform polarity anymore:

// Normal (single slope) PWM operation: timers countinuously count up to PER register value and then is reset to 0
  REG_TCC0_WAVE |= TCC_WAVE_WAVEGEN_NPWM;        // Setup single slope PWM on TCC0
  while (TCC0->SYNCBUSY.bit.WAVE);                // Wait for synchronization

Do you loose resolution on dual slope?

Yes, unless you double your timer frequency, you'll lose one bit of resolution.

I know the SAMD21 is capable of 24Bits, but I could see here that Martin said its only 8bits, I wonder what is my best approach here .

A larger timer, clocked at a higher frequency and generating a low frequency output gives you the greatest resolution, but using the highest resolution might not be beneficial, it all depends on what you're controlling with the signal.

Thank you Martin. Thanks for your help.

I really wonder how you learn all this things from the Atmel data sheet. For years i read data sheets and understand them all, but when it comes to MCU, I just couldn't find how you actually do things, for example where did you find all the registers names and how to actually right the code to set them. I coudn't even find the register names from your code in the Atmel data sheet when I searched.

It feels stupid to ask all this questions as an hardware engineer, but turning a data sheet into C code- I can't understand how you do that :)

The register definitions are a number of Atmel files that are supplied with the Arduino Zero code.

There are two directories "component" and "instance", each contains files for the specific peripherals, for instance gclk.h, tc.h, tcc.h, etc...

The peripheral files in the "component" directory describe the structure of each register and contains definitions for bit or bitfield that allow you to access, either the register itself, or its bitfields.

For example, to access a register's bitfield:

if (TC3->COUNT16.INTFLAG.bit.MC1)

To access the regsiter itself:

if (TC3->COUNT16.INTFLAG.reg | TC_INTFLAG_MC1)

The peripheral files in the "instance" directory define the contents and the location of the registers for each peripheral. So in this directory you'll find a separate file for each peripheral instance, for example tc3.h, tc4.h and tc5.h. Using these files you can access there register directly without using any pointer syntax.

An example of how to access a register using the "instance" definitions:

if (REG_TC3_INTFLAG | TC_INTFLAG_MC1)

The "instance" and "component" directories are currently located on my machine (yours might be slightly different) at:

C:\Users\Computer\AppData\Local\Arduino15\packages\arduino\tools\CMSIS\4.0.0-atmel\Device\ATMEL\samd21\include...

You have to dig down a long way to find them though. When register programming using the Arduino IDE, I keep these files open in an editor such as NotePad++ for easy reference.

where were you able to find the user manual for the micro on this MKR1010. I would like to get the register information so that I can edit it to work as I need.

Thanks Kas

Hi Kas,

The SAMD21 datasheet can be found on Microchip’s website here: ATSAMD21G18 - 32-bit Microcontrollers, under the documents tab.

The datasheet is the main source of information about the microcontroller’s registers.