Arduino M0 PWM library

M0, M0 Pro, Zero Pro

Moderators: crx2312, alfran

User avatar
Muschasgrazias1
Posts: 16
Joined: 19 Jul 2016, 16:06
Status: Offline

Arduino M0 PWM library

Postby Muschasgrazias1 » 10 Aug 2016, 10:03

Hi,
I'am working on a PWM library that sets duty cycle (0-100%) and frequency (1..20kHz).
I kinda fused Toner.h with analogWrite. I would appreciate some help and maybe we could publish it somewhere in the forum for other users to use?
Best regards

User avatar
Muschasgrazias1
Posts: 16
Joined: 19 Jul 2016, 16:06
Status: Offline

Re: Arduino M0 PWM library

Postby Muschasgrazias1 » 10 Aug 2016, 13:47

My first attempt: Works for me on PIN 13. PINs with TC counters aren't tested yet if needed maybe later
PWM.c

  1. #include "PWM.h"
  2. #include "wiring_digital.h"
  3.  
  4. #ifdef __cplusplus
  5. extern "C" {
  6. #endif
  7.  
  8.     unsigned char pwm(unsigned char pin, unsigned char duty, unsigned int frequency){
  9.         // need to check if 4,5,10,12 are working,
  10.         if((pin < 2) ||(pin > 13)){
  11.             return NO_PWM_PIN;
  12.         }
  13.         if(duty > 100){
  14.             return NO_DUTY_CYCLE;
  15.         }
  16.         if(frequency==0 || frequency>500000){
  17.             return NO_FREQ;
  18.         }
  19.  
  20.         unsigned int presc_tc=0, presc_tcc=0;
  21.         unsigned int duty_reg = 0;
  22.         unsigned int resolution = 0;
  23.  
  24.         uint8_t isTC = 0 ;
  25.         uint8_t Channelx ;
  26.         Tc* TCx ;
  27.         Tcc* TCCx ;
  28.         uint32_t attr = g_APinDescription[pin].ulPinAttribute ;
  29.  
  30.         if ( (attr & PIN_ATTR_PWM) == PIN_ATTR_PWM )
  31.         {
  32.             if ( (g_APinDescription[pin].ulPinType == PIO_TIMER) || g_APinDescription[pin].ulPinType == PIO_TIMER_ALT )
  33.             {
  34.                 pinPeripheral( pin, g_APinDescription[pin].ulPinType ) ;
  35.             }
  36.  
  37.             switch ( g_APinDescription[pin].ulPWMChannel )
  38.             {
  39.                 case PWM3_CH0 :
  40.                 TCx = TC3 ;
  41.                 Channelx = 0 ;
  42.                 isTC = 1 ;
  43.                 break;
  44.  
  45.                 case  PWM3_CH1:
  46.                 TCx = TC3 ;
  47.                 Channelx = 1;
  48.                 isTC = 1;
  49.                 break;
  50.  
  51.                 case  PWM0_CH0 :
  52.                 TCCx = TCC0;
  53.                 Channelx = 0;
  54.                 break;
  55.  
  56.                 case  PWM0_CH1 :
  57.                 TCCx = TCC0;
  58.                 Channelx = 1;
  59.                 break;
  60.  
  61.                 case  PWM0_CH4 :
  62.                 TCCx = TCC0;
  63.                 Channelx = 0;
  64.                 break;
  65.  
  66.                 case  PWM0_CH5 :
  67.                 TCCx = TCC0;
  68.                 Channelx = 1;
  69.                 break;
  70.  
  71.                 case  PWM0_CH6 :
  72.                 TCCx = TCC0;
  73.                 Channelx = 2;
  74.                 break;
  75.  
  76.                 case  PWM0_CH7 :
  77.                 TCCx = TCC0;
  78.                 Channelx = 3;
  79.                 break;
  80.  
  81.                 case  PWM1_CH0 :
  82.                 TCCx = TCC1;
  83.                 Channelx = 0;
  84.                 break;
  85.  
  86.                 case  PWM1_CH1 :
  87.                 TCCx = TCC1;
  88.                 Channelx = 1;
  89.                 break;
  90.  
  91.                 case  PWM2_CH0 :
  92.                 TCCx = TCC2;
  93.                 Channelx = 0;
  94.                 break;
  95.  
  96.                 case  PWM2_CH1 :
  97.                 TCCx = TCC2;
  98.                 Channelx = 1;
  99.                 break;
  100.             }
  101.  
  102.  
  103.             // Enable clocks according to TCCx instance to use
  104.             switch ( GetTCNumber( g_APinDescription[pin].ulPWMChannel ) )
  105.             {
  106.                 case 0: // TCC0
  107.                 //Enable GCLK for TCC0 (timer counter input clock)
  108.                 GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK3 | GCLK_CLKCTRL_ID( GCM_TCC0_TCC1 )) ;
  109.                 break;
  110.  
  111.                 case 1: // TCC1
  112.                 //Enable GCLK for TCC1 (timer counter input clock)
  113.                 GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK3 | GCLK_CLKCTRL_ID( GCM_TCC0_TCC1 )) ;
  114.                 break;
  115.  
  116.                 case 2: // TCC2
  117.                 //Enable GCLK for TCC2 (timer counter input clock)
  118.                 GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK3 | GCLK_CLKCTRL_ID( GCM_TCC2_TC3 )) ;
  119.                 break;
  120.  
  121.                 case 3: // TC3
  122.                 //Enable GCLK for TC3 (timer counter input clock)
  123.                 GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK3 | GCLK_CLKCTRL_ID( GCM_TCC2_TC3 ));
  124.                 break;
  125.  
  126.                 case 4: // TC4
  127.                 //Enable GCLK for TC4 (timer counter input clock)
  128.                 GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK3 | GCLK_CLKCTRL_ID( GCM_TC4_TC5 ));
  129.                 break;
  130.  
  131.                 case 5: // TC5
  132.                 //Enable GCLK for TC5 (timer counter input clock)
  133.                 GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK3 | GCLK_CLKCTRL_ID( GCM_TC4_TC5 )) ;
  134.                 break;
  135.             }
  136.             //-------------------------------------------//
  137.             //----------- Formular for Frequency---------//
  138.             //--------- µC-Clock = 48 000 0000 ----------//
  139.             //-------------- Prescaler = 6---------------//
  140.             //---- Resolution = 8 000 000/Frequency -----//
  141.             resolution = 8000000/frequency;
  142.  
  143.             presc_tcc=TCC_CTRLA_PRESCALER_DIV1;
  144.             presc_tc=TC_CTRLA_PRESCALER_DIV1;
  145.            
  146.  
  147.             // duty is percent, now determine the value for the register
  148.             duty_reg = (resolution/100.0)*duty;
  149.            
  150.             if ( isTC )
  151.             {
  152.                 // -- Configure TC
  153.                 //DISABLE TCx
  154.                 TCx->COUNT8.CTRLA.reg &=~(TC_CTRLA_ENABLE);
  155.                 //Set Timer counter Mode to 8 bits
  156.                 TCx->COUNT8.CTRLA.reg |= TC_CTRLA_MODE_COUNT8;
  157.                 // Prescaler
  158.                 TCx->COUNT8.CTRLA.reg |=presc_tc;
  159.                 //Set TCx as normal PWM
  160.                 TCx->COUNT8.CTRLA.reg |= TC_CTRLA_WAVEGEN_NPWM;
  161.                 //Set TCx in waveform mode Normal PWM
  162.                 TCx->COUNT8.CC[Channelx].reg = (0xFF/100)*duty;
  163.                 //Set PER to maximum counter value (resolution : 0xFF)
  164.                 TCx->COUNT8.PER.reg = 0xFF;
  165.                 // Enable TCx
  166.                 TCx->COUNT8.CTRLA.reg |= TC_CTRLA_ENABLE;
  167.             }
  168.             else
  169.             {
  170.                 // -- Configure TCC
  171.                
  172.                 //DISABLE TCCx
  173.                 TCCx->CTRLA.reg &=~(TCC_CTRLA_ENABLE);
  174.                 //Set TCx as normal PWM
  175.                 TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM;
  176.                 // Prescaler
  177.                 TCCx->CTRLA.reg |=presc_tcc;
  178.                
  179.                 //Set TCx in waveform mode Normal PWM
  180.                 TCCx->CC[Channelx].reg = duty_reg;
  181.                 //Set PER to maximum counter value (resolution : 0xFF)
  182.                 TCCx->PER.reg = resolution;
  183.                 //ENABLE TCCx
  184.                 TCCx->CTRLA.reg |= TCC_CTRLA_ENABLE ;
  185.             }
  186.             return SET_PWM;
  187.         }
  188.  
  189.     }
  190.  
  191.     #ifdef __cplusplus
  192. }
  193. #endif


PWM.h :

  1. #ifndef _PWM_
  2. #define _PWM_
  3.  
  4. #define SET_PWM         0
  5. #define NO_PWM_PIN      1
  6. #define NO_DUTY_CYCLE   2
  7. #define NO_FREQ         3
  8.  
  9. #ifdef __cplusplus
  10. extern "C" {
  11. #endif
  12.  
  13. // pin 4,5,10,12 TC still need to work on it
  14. unsigned char pwm(unsigned char pin, unsigned char duty, unsigned int frequency) ;
  15.  
  16.  
  17. #ifdef __cplusplus
  18. }
  19. #endif
  20.  
  21. #endif

What do you think?
Best regards


Return to “ZERO”

Who is online

Users browsing this forum: No registered users and 2 guests

DISCOVER OUR

WHOLE STORY

About us


GET IN TOUCH

WITH US

Contact us


FIND ALL OUR OPEN POSITIONS AND JOIN US!
 

JOB SEARCH