Go Down

Topic: PWM RAMP2 Operation (Read 135 times) previous topic - next topic


Hello! I decided make my own thread becose can be usefull to future ramp2 aplications.
I'm trying to make a code for pwm 2 outputs(pin 5 and pin 6), XXhz pwm frec.
Reading atmel SAMD21G datasheet found RAMP2 operation could be a solution, but is difficult due to huge register configuration needed of matches, modes, etc.
Upload picture show my idea how output should be work and that 90° off phases needed between W[5] and W[6] output. Only change % PWM and frec is constant.
I have problem to implement output idea due can't make a correct register configuration.
Someone can tell me if i'm in a right way, or suggest other solution, code examples, edit my code, etc? Any help is welcome.


Code: [Select]

#include <Adafruit_NeoPixel.h>

#define Pin13LED 13
#define NEOPIXEL 8  // Neopixel

int PERx = 32000; // PER=TOP value just for example

volatile int cont =0;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(1, NEOPIXEL);   // Create an strip object

void setup()
  strip.show(); // neopixel off
  REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Generic clock divisor D = 1
    GCLK_GENDIV_ID(4);          // Selecciono el clock gen 4
  while (GCLK->STATUS.bit.SYNCBUSY);    // Espero sincronizacion

    GCLK_GENCTRL_GENEN |        // habilito gclk4
    GCLK_GENCTRL_SRC_XOSC32K |    // selecciono clock de 32Khz
    GCLK_GENCTRL_ID(4);         // Selecciono el clock gen 4
  while (GCLK->STATUS.bit.SYNCBUSY);    // Espero sincronizacion

  // Habilito el multiplexor para 2 canales de PWM con Timer TCC0
  const uint8_t CHANNELS = 2;
  const uint8_t Pin_5 = 5;  // TCC0;CCB1;Odd
  const uint8_t Pin_6 = 6;  // TCC0;CCB2;Even
  PORT->Group[g_APinDescription[Pin_5].ulPort].PINCFG[g_APinDescription[Pin_5].ulPin].bit.PMUXEN = 1;
  PORT->Group[g_APinDescription[Pin_6].ulPort].PINCFG[g_APinDescription[Pin_6].ulPin].bit.PMUXEN = 1;

  // Conecto el timer TCC0 con los puertos de salida
  PORT->Group[g_APinDescription[5].ulPort].PMUX[g_APinDescription[5].ulPin >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F;
  PORT->Group[g_APinDescription[6].ulPort].PMUX[g_APinDescription[6].ulPin >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F;

  // Conecto el GCLK con TCC0
  while (GCLK->STATUS.bit.SYNCBUSY);    // Espero sincronizacion

  // Single slope PWM: timer TCC0
    //TCC_WAVE_CIPEREN |  // Diferentes PER en ciclo A y B
    TCC_WAVE_POL0 | // Change polarity output
    TCC_WAVE_RAMP_RAMP2;  // RAMP2 operation
  while (TCC0->SYNCBUSY.bit.WAVE);    // Espero sincronizacion

  // Configuro valor PER
  while(TCC0->SYNCBUSY.bit.PER)   // Espero sincronizacion


  // Configuro valor CCBx
  REG_TCC0_CC1 = (PERx/2);       // TCC0 CCB1 - 50% PWM on PIN 5
  REG_TCC0_CC2 = (PERx/2);    // TCC0 CCB2 - 50% PWM on PIN 6

  // Configuro preescaler y habilito las salidasTCC_CTRLBSET_IDXCMD_DISABLE |
    TCC_CTRLA_CPTEN0 |  // capture channel 0 enable
  while (TCC0->SYNCBUSY.bit.ENABLE);  // Espero por sincronizacion


void loop()
  REG_TCC0_CCB1 = (PERx/2);                       // OUTPUT pin 5
  REG_TCC0_CCB2 = (PERx/2);                     //OUTPUT pin 6  



Hello b0rn4,

I'm a new user to the M0 pro as well. I try not to use any of the Arduino libraries because they are super slow and I need really high performance. I found a few resources that can help:
1. Install Atmel studio. You can find it here: https://www.microchip.com/development-tools/atmel-studio-7

2. After installing Atmel studio,  in your computer (windows) you can go here:
C:\Program Files (x86)\Atmel\Studio\7.0\packs\atmel\SAMD21_DFP\1.2.276\samd21a\include\component
This folder lists the component definitions for all the peripherals. This is super useful when you want to configure a timer, ADC, RTC etc.

3. This wiki will help you to read and understand the component definitions if you're new to them:
Once you understand the component definitions structure, its relatively simple to configure registers and peripherals just from reading the datasheet. Your code will also be very readable and easy to understand.

4. Understand and use the Arduino pin definitions here:
For example, this is a more readable way to code:
Code: [Select]

    PORT->Group[PORTA].PINCFG[14].bit.PMUXEN = 1; // Peripheral mux enable PWM
    PORT->Group[PORTA].PINCFG[15].bit.PMUXEN = 1; // Peripheral mux enable PWM 
    PORT->Group[PORTA].PMUX[7].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F; // Enable PMUX group F both Odd and Even pins

This is not:
Code: [Select]

 PORT->Group[g_APinDescription[Pin_5].ulPort].PINCFG[g_APinDescription[Pin_5].ulPin].bit.PMUXEN = 1;
  PORT->Group[g_APinDescription[Pin_6].ulPort].PINCFG[g_APinDescription[Pin_6].ulPin].bit.PMUXEN = 1;
  PORT->Group[g_APinDescription[5].ulPort].PMUX[g_APinDescription[5].ulPin >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F;
  PORT->Group[g_APinDescription[6].ulPort].PMUX[g_APinDescription[6].ulPin >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F;

Both code samples do the exact same thing, but the first example is easier to debug.


Hello parsec326,

I need too high performance in my proyect and you make me curious about atmel studio.
I read many atmel application notes about pwm, all their examples are in atmel studio.
But my problem is that code is a small part of a big program to make a firmware for a stimulator. In other words, i also have made lot of interrups, functions, etc.
Its that all posible in atmel studio, and what about the time to learn??

Hope your response. Thanks!!

Go Up