TC Timer Counter SAM D21 - NORMAL_PWM

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

Hi all,

 

I am having this issue.

I need to create in TC3 a waveform of 64Khz 50% duty cycle. . This signal is fixed, no variable duty cycle.

I selected the 8Mhz internal clock by GCLK_GENERATOR_0. 

 

My 'configure_tc(void)'  I created as below

 

void configure_tc(void)
{

    struct tc_config config_tc;
    tc_get_config_defaults(&config_tc);
    config_tc.counter_size = TC_COUNTER_SIZE_16BIT;
    config_tc.clock_source = GCLK_GENERATOR_0;
    config_tc.wave_generation = TC_WAVE_GENERATION_NORMAL_PWM;
    
     config_tc.pwm_channel[0].enabled = true;
     config_tc.pwm_channel[0].pin_out = PWM_OUT_PIN;
     config_tc.pwm_channel[0].pin_mux = PWM_OUT_MUX;
     
    tc_set_top_value(&tc_instance, 125);
    tc_init(&tc_instance, CONF_TC_MODULE, &config_tc);

    tc_enable(&tc_instance);
   }

 

My 'tc_top_value()' is 125. I am right? 8Mhz/64000 = 125 (top max value) .

 

In oscilloscope I am having an fixed signal of 61Hz when I erase the  'tc_set_top_value(&tc_instance, 125);' line, after I write this line getting none signal.

 

Best Regards ! thanks!

Paulo

 

This topic has a solution.

Franc

Last Edited: Tue. Sep 6, 2016 - 11:46 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try top value of (125-1), remember count starts at 0... so for 125 counts 0,1, ... 124, 0,...

 

Edit: typo

David (aka frog_jr)

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

TC (unlike TCC) has a fixed TOP value in 16-bit and 32-bit normal modes, change to 8-bit and it should work.

/Lars

 

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

Lajon wrote:
change to 8-bit and it should work
I missed that it was configured for 16-bit...

David (aka frog_jr)

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

Hi friends! 

 

I changed to 'config_tc.counter_size = TC_COUNTER_SIZE_8BIT;' my code but no success.

 

Maybe any wrong in clock configuration? Below my 'conf_clock.h ' file.

 

 

 

#include <clock.h>

#ifndef CONF_CLOCKS_H_INCLUDED
#  define CONF_CLOCKS_H_INCLUDED

 

/* System clock bus configuration */

#  define CONF_CLOCK_CPU_CLOCK_FAILURE_DETECT     false
#  define CONF_CLOCK_FLASH_WAIT_STATES            0
#  define CONF_CLOCK_CPU_DIVIDER                  SYSTEM_MAIN_CLOCK_DIV_1
#  define CONF_CLOCK_APBA_DIVIDER                 SYSTEM_MAIN_CLOCK_DIV_1
#  define CONF_CLOCK_APBB_DIVIDER                 SYSTEM_MAIN_CLOCK_DIV_1
#  define CONF_CLOCK_APBC_DIVIDER                 SYSTEM_MAIN_CLOCK_DIV_1

 

/* SYSTEM_CLOCK_SOURCE_OSC8M configuration - Internal 8MHz oscillator */

#  define CONF_CLOCK_OSC8M_PRESCALER              SYSTEM_OSC8M_DIV_1
#  define CONF_CLOCK_OSC8M_ON_DEMAND              true
#  define CONF_CLOCK_OSC8M_RUN_IN_STANDBY         false

 

/* SYSTEM_CLOCK_SOURCE_XOSC configuration - External clock/oscillator */

#  define CONF_CLOCK_XOSC_ENABLE                  false
#  define CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL        SYSTEM_CLOCK_EXTERNAL_CRYSTAL
#  define CONF_CLOCK_XOSC_EXTERNAL_FREQUENCY      12000000UL
#  define CONF_CLOCK_XOSC_STARTUP_TIME            SYSTEM_XOSC_STARTUP_32768
#  define CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL       true
#  define CONF_CLOCK_XOSC_ON_DEMAND               true
#  define CONF_CLOCK_XOSC_RUN_IN_STANDBY          false

 

/* SYSTEM_CLOCK_SOURCE_XOSC32K configuration - External 32KHz crystal/clock oscillator */

#  define CONF_CLOCK_XOSC32K_ENABLE               true
#  define CONF_CLOCK_XOSC32K_EXTERNAL_CRYSTAL     SYSTEM_CLOCK_EXTERNAL_CRYSTAL
#  define CONF_CLOCK_XOSC32K_STARTUP_TIME         SYSTEM_XOSC32K_STARTUP_65536
#  define CONF_CLOCK_XOSC32K_AUTO_AMPLITUDE_CONTROL  false
#  define CONF_CLOCK_XOSC32K_ENABLE_1KHZ_OUPUT    false
#  define CONF_CLOCK_XOSC32K_ENABLE_32KHZ_OUTPUT  true
#  define CONF_CLOCK_XOSC32K_ON_DEMAND            true
#  define CONF_CLOCK_XOSC32K_RUN_IN_STANDBY       false

 

/* SYSTEM_CLOCK_SOURCE_OSC32K configuration - Internal 32KHz oscillator */

#  define CONF_CLOCK_OSC32K_ENABLE                false
#  define CONF_CLOCK_OSC32K_STARTUP_TIME          SYSTEM_OSC32K_STARTUP_130
#  define CONF_CLOCK_OSC32K_ENABLE_1KHZ_OUTPUT    true
#  define CONF_CLOCK_OSC32K_ENABLE_32KHZ_OUTPUT   true
#  define CONF_CLOCK_OSC32K_ON_DEMAND             true
#  define CONF_CLOCK_OSC32K_RUN_IN_STANDBY        false

 

/* SYSTEM_CLOCK_SOURCE_DFLL configuration - Digital Frequency Locked Loop */

#  define CONF_CLOCK_DFLL_ENABLE                  false
#  define CONF_CLOCK_DFLL_LOOP_MODE               SYSTEM_CLOCK_DFLL_LOOP_MODE_OPEN
#  define CONF_CLOCK_DFLL_ON_DEMAND               false

 

/* DFLL open loop mode configuration */

#  define CONF_CLOCK_DFLL_FINE_VALUE              (512)

 

/* DFLL closed loop mode configuration */

#  define CONF_CLOCK_DFLL_SOURCE_GCLK_GENERATOR   GCLK_GENERATOR_1
#  define CONF_CLOCK_DFLL_MULTIPLY_FACTOR         6
#  define CONF_CLOCK_DFLL_QUICK_LOCK              true
#  define CONF_CLOCK_DFLL_TRACK_AFTER_FINE_LOCK   true
#  define CONF_CLOCK_DFLL_KEEP_LOCK_ON_WAKEUP     true
#  define CONF_CLOCK_DFLL_ENABLE_CHILL_CYCLE      true
#  define CONF_CLOCK_DFLL_MAX_COARSE_STEP_SIZE    (0x1f / 4)
#  define CONF_CLOCK_DFLL_MAX_FINE_STEP_SIZE      (0xff / 4)

 

/* SYSTEM_CLOCK_SOURCE_DPLL configuration - Digital Phase-Locked Loop */

#  define CONF_CLOCK_DPLL_ENABLE                  false
#  define CONF_CLOCK_DPLL_ON_DEMAND               true
#  define CONF_CLOCK_DPLL_RUN_IN_STANDBY          false
#  define CONF_CLOCK_DPLL_LOCK_BYPASS             false
#  define CONF_CLOCK_DPLL_WAKE_UP_FAST            false
#  define CONF_CLOCK_DPLL_LOW_POWER_ENABLE        false

#  define CONF_CLOCK_DPLL_LOCK_TIME               SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_DEFAULT
#  define CONF_CLOCK_DPLL_REFERENCE_CLOCK         SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_XOSC32K
#  define CONF_CLOCK_DPLL_FILTER                  SYSTEM_CLOCK_SOURCE_DPLL_FILTER_DEFAULT

#  define CONF_CLOCK_DPLL_REFERENCE_FREQUENCY     32768
#  define CONF_CLOCK_DPLL_REFERENCE_DIVIDER       1
#  define CONF_CLOCK_DPLL_OUTPUT_FREQUENCY        48000000

 

/* DPLL GCLK reference configuration */

#  define CONF_CLOCK_DPLL_REFERENCE_GCLK_GENERATOR  GCLK_GENERATOR_1

/* DPLL GCLK lock timer configuration */

#  define CONF_CLOCK_DPLL_LOCK_GCLK_GENERATOR     GCLK_GENERATOR_1

 

/* Set this to true to configure the GCLK when running clocks_init. If set to

 * false, none of the GCLK generators will be configured in clocks_init(). */

#  define CONF_CLOCK_CONFIGURE_GCLK               true

 

/* Configure GCLK generator 0 (Main Clock) */

#  define CONF_CLOCK_GCLK_0_ENABLE                true
#  define CONF_CLOCK_GCLK_0_RUN_IN_STANDBY        false
#  define CONF_CLOCK_GCLK_0_CLOCK_SOURCE          SYSTEM_CLOCK_SOURCE_OSC8M
#  define CONF_CLOCK_GCLK_0_PRESCALER             1
#  define CONF_CLOCK_GCLK_0_OUTPUT_ENABLE         false

 

/* Configure GCLK generator 1 */

#  define CONF_CLOCK_GCLK_1_ENABLE                false
#  define CONF_CLOCK_GCLK_1_RUN_IN_STANDBY        false
#  define CONF_CLOCK_GCLK_1_CLOCK_SOURCE          SYSTEM_CLOCK_SOURCE_XOSC32K
#  define CONF_CLOCK_GCLK_1_PRESCALER             1
#  define CONF_CLOCK_GCLK_1_OUTPUT_ENABLE         false

 

/* Configure GCLK generator 2 (RTC) */

#  define CONF_CLOCK_GCLK_2_ENABLE                false
#  define CONF_CLOCK_GCLK_2_RUN_IN_STANDBY        false
#  define CONF_CLOCK_GCLK_2_CLOCK_SOURCE          SYSTEM_CLOCK_SOURCE_OSC32K
#  define CONF_CLOCK_GCLK_2_PRESCALER             32
#  define CONF_CLOCK_GCLK_2_OUTPUT_ENABLE         false

 

/* Configure GCLK generator 3 */

#  define CONF_CLOCK_GCLK_3_ENABLE                false
#  define CONF_CLOCK_GCLK_3_RUN_IN_STANDBY        false
#  define CONF_CLOCK_GCLK_3_CLOCK_SOURCE          SYSTEM_CLOCK_SOURCE_OSC8M
#  define CONF_CLOCK_GCLK_3_PRESCALER             1
#  define CONF_CLOCK_GCLK_3_OUTPUT_ENABLE         false

 

/* Configure GCLK generator 4 */

#  define CONF_CLOCK_GCLK_4_ENABLE                false
#  define CONF_CLOCK_GCLK_4_RUN_IN_STANDBY        false
#  define CONF_CLOCK_GCLK_4_CLOCK_SOURCE          SYSTEM_CLOCK_SOURCE_OSC8M
#  define CONF_CLOCK_GCLK_4_PRESCALER             1
#  define CONF_CLOCK_GCLK_4_OUTPUT_ENABLE         false

 

/* Configure GCLK generator 5 */

#  define CONF_CLOCK_GCLK_5_ENABLE                false
#  define CONF_CLOCK_GCLK_5_RUN_IN_STANDBY        false
#  define CONF_CLOCK_GCLK_5_CLOCK_SOURCE          SYSTEM_CLOCK_SOURCE_OSC8M
#  define CONF_CLOCK_GCLK_5_PRESCALER             1
#  define CONF_CLOCK_GCLK_5_OUTPUT_ENABLE         false

 

/* Configure GCLK generator 6 */

#  define CONF_CLOCK_GCLK_6_ENABLE                false
#  define CONF_CLOCK_GCLK_6_RUN_IN_STANDBY        false
#  define CONF_CLOCK_GCLK_6_CLOCK_SOURCE          SYSTEM_CLOCK_SOURCE_OSC8M
#  define CONF_CLOCK_GCLK_6_PRESCALER             1
#  define CONF_CLOCK_GCLK_6_OUTPUT_ENABLE         false

 

/* Configure GCLK generator 7 */

#  define CONF_CLOCK_GCLK_7_ENABLE                false
#  define CONF_CLOCK_GCLK_7_RUN_IN_STANDBY        false
#  define CONF_CLOCK_GCLK_7_CLOCK_SOURCE          SYSTEM_CLOCK_SOURCE_OSC8M
#  define CONF_CLOCK_GCLK_7_PRESCALER             1
#  define CONF_CLOCK_GCLK_7_OUTPUT_ENABLE         false

 

/* Configure GCLK generator 8 */

#  define CONF_CLOCK_GCLK_8_ENABLE                false
#  define CONF_CLOCK_GCLK_8_RUN_IN_STANDBY        false
#  define CONF_CLOCK_GCLK_8_CLOCK_SOURCE          SYSTEM_CLOCK_SOURCE_OSC8M
#  define CONF_CLOCK_GCLK_8_PRESCALER             1
#  define CONF_CLOCK_GCLK_8_OUTPUT_ENABLE         false

 

#endif /* CONF_CLOCKS_H_INCLUDED */

 

 

Franc

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

I missed that you don't set a compare value, that is needed also (I don't think you would see anything with the default 0 compare value). Try

void configure_tc(void)
{
	struct tc_config config_tc;
	tc_get_config_defaults(&config_tc);
	config_tc.counter_size = TC_COUNTER_SIZE_8BIT;
	config_tc.clock_source = GCLK_GENERATOR_0;
	config_tc.wave_generation = TC_WAVE_GENERATION_NORMAL_PWM;
	config_tc.counter_8_bit.period = 124;
	config_tc.counter_8_bit.compare_capture_channel[0] = 62;
	config_tc.pwm_channel[0].enabled = true;
	config_tc.pwm_channel[0].pin_out = PWM_OUT_PIN;
	config_tc.pwm_channel[0].pin_mux = PWM_OUT_MUX;
	
	tc_init(&tc_instance, CONF_TC_MODULE, &config_tc);
	tc_enable(&tc_instance);
}

tc_set_top_value is ok to use also but you have to call it after tc_init.
/Lars

 

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

Dear Lars, first thank you!!

 

I tried exactly as you told but now I got a waveform with 32Khz. 

I tried with 'GCLK_GENERATOR_1' also but same issue, with this 131Hz out. 

 

maybe an internal clock division / 2 ? Maybe the out function 'ioport_toggle_pin_level(LED0_PIN);' divide / 2?

 

 

Thank you!

Franc

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

Sorry, confused now, are you not looking at the pwm output when checking the frequency? Where is the ioport_toggle_pin_level call?

/Lars

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank so much Sir Lajon / Frog. Today I finished this code.

Conclusion, Atmel ASF has no speed for high frequency in IO port. I did it with bare code. 

ALso, for high frequency is not possible use interruptions because are unstable. I used the TC3_Handler only for measure the difference between PA18 and LED0. 

I used DFLL clock as below.

Regards!

 

#include "samd21.h"
#include <string.h>
#include <stdlib.h>
#include <stdint.h>


   uint32_t caldata[4];
   uint32_t dfll_fine_cal;
   uint32_t dfll_coarse_cal;
   uint32_t osc32_cal;
   
  
   void init_TC3();
     



void init_TC3()
{
	PM->APBCMASK.reg |= PM_APBCMASK_TC3;

	GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0) | GCLK_CLKCTRL_ID_TCC2_TC3;
 
	TC3->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_MFRQ |
	TC_CTRLA_PRESCALER_DIV1 | TC_CTRLA_PRESCSYNC_RESYNC;

	TC3->COUNT16.COUNT.reg = 0;
    TC3->COUNT16.CC[0].reg = 364; 
    
      
	TC3->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;
	TC3->COUNT16.DBGCTRL.reg = TC_DBGCTRL_DBGRUN;
	TC3->COUNT16.INTENSET.reg = TC_INTENSET_MC0;
	NVIC_EnableIRQ(TC3_IRQn); 
	PORT->Group[0].DIRSET.reg=18;
	PORT->Group[0].PINCFG[18].bit.PMUXEN=1;
	PORT->Group[0].PMUX[9].bit.PMUXE = 4;
}


void TC3_Handler()
{
	// Overflow interrupt triggered
	if ( TC3->COUNT16.INTFLAG.bit.OVF == 1 )
	{
		REG_PORT_OUTTGL1 = PORT_PB30;
		TC3->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0;
	}
	
}

void clock_48(void)
{
	/**** read some cal data from NVRAM ****/
	caldata[0] = *((uint32_t *)(0x806020));
	caldata[1] = *((uint32_t *)(0x806024));
	caldata[2] = *((uint32_t *)(0x806028));
	caldata[3] = *((uint32_t *)(0x80602C));
	dfll_coarse_cal = ((caldata[2] & 0xFC000000) >> 26);
	dfll_fine_cal = (caldata[3] & 0x3F);
	osc32_cal = ((caldata[1] & (0x7F << 6)) >> 6);
	
	// Clock 0 Output (for debug)
	PORT->Group[1].PINCFG[14].bit.PMUXEN = 1;     // allow pmux to set pin configuration
	PORT->Group[1].PMUX[7].bit.PMUXE = 7;        // PB14 = gclk 0
	
	// Clock 1 Output (for debug)
	PORT->Group[1].PINCFG[15].bit.PMUXEN = 1;     // allow pmux to set pin configuration
	PORT->Group[1].PMUX[7].bit.PMUXO = 7;        // PB15 = gclk 1
	
	
	/****** set up gclk 1 as a 32K reference for the DFLL ******/
	
	//32K source : enable and calibrate
	SYSCTRL->OSC32K.bit.ENABLE = 1;
	SYSCTRL->OSC32K.bit.EN32K = 1;
	SYSCTRL->OSC32K.bit.CALIB = osc32_cal;
	
	// gclk 1   : Divide by 1
	GCLK->GENDIV.reg = 1 | (1 << 8);
	
	// gclk 1  : Enable, Output to IO, Use 32K source
	GCLK->GENCTRL.reg = 1 | (GCLK_GENCTRL_OE) | (GCLK_GENCTRL_GENEN) | (4 << GCLK_GENCTRL_SRC_Pos) ;
	
	// Clock Multiplexer : Send gclk1 output to DFLL ref input
	GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | (1 << GCLK_CLKCTRL_GEN_Pos) | (0x00 << GCLK_CLKCTRL_ID_Pos);
	
	
	/***** initialise the DFLL ******/
	
	// 48M Source  : errata fix
	SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0 ;
	
	// 48M Source  : initialise value
	SYSCTRL->DFLLVAL.reg = 0x27F;
	
	// 48M Source  : set seek parameters and mul factor (32K * 1464 = 48MHz)
	SYSCTRL->DFLLMUL.reg = ( 2 << 26) | (2 << 16) | (1464);
	
	// 48M Source  : enable in close loop mode
	SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE | SYSCTRL_DFLLCTRL_MODE;  // closed loop
	
	/*** wait for the DFLL to lock ****/
	while((SYSCTRL->PCLKSR.bit.DFLLLCKC == 0) || (SYSCTRL->PCLKSR.bit.DFLLLCKC == 0));
	
	/*****  before setting core to 48MHz, increase flash wait states *****/
	NVMCTRL->CTRLB.bit.RWS = 2;
	
	// gclk 0  : Enable, Output to IO, Use DFLL source
	GCLK->GENCTRL.reg = 0 | (GCLK_GENCTRL_OE) | (GCLK_GENCTRL_GENEN) | (7 << GCLK_GENCTRL_SRC_Pos) ;
	
}


int main(void)
{
	SystemInit(); // Initialize the SAM system
	init_TC3();
	clock_48();
	PORT->Group[1].DIRSET.reg |= PORT_PB30;

	
	while (1)
	{
		
	}
}

 

Franc