SAMD21J18A PWM examples

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

Hi All

 

I am very new to SAM devices as  been using AVR and XMEGA till now.

 

I need to generate a PWM signal , is there any ASF libraries or any examples i can look at?

 

If i am correct, PWM can be done using both TC and TCC timers, what would the difference.

 

I need a 25khz PWM signal, with a variable duty cycle. 

 

 

 

 

Thanks

Regards

DJ

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

I dont know about ASF4/Atmel start, but I saw a PWM example for SAMB11 in ASF3 sourcecode - maybe its an example that you could adapt for your needs

 

Ilya

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

djoshi wrote:
is there any ASF libraries or any examples

Have you looked?

 

You simply put in the part number, and it'll list all available examples ...

 

Or go to the Product Page:

 

https://www.avrfreaks.net/commen...

 

https://www.avrfreaks.net/commen...

 

 

djoshi wrote:
SAMD21J18A

So the SAMD21 Xplained-Pro would be the obvious place to start ...

 

https://www.microchip.com/developmenttools/ProductDetails/ATSAMD21-XPRO

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, i got the SAMD21 Xplained-Pro

 

I am working with the WINC3400 based project so i need to make sure my timer do not cause any conflict.

 

 

Thanks

Regards

DJ

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

I got something working till a point based on an example found on the Microchips website (ASF Source Code Documentation (microchip.com), but I had to change the default pin of PB30 to PA17 and I can no longer change the duty cycle. My frequency is set to 20kHz.

 

This is my code, once it working as intended I will need to tidy it the define.

 

#define LED_A_PWM4CTRL_MODULE     TCC2
#define LED_A_PWM4CTRL_CHANNEL    0
#define LED_A_PWM4CTRL_OUTPUT     0
#define LED_A_PWM4CTRL_PIN        PIN_PA17E_TCC2_WO1
#define LED_A_PWM4CTRL_MUX        MUX_PA17E_TCC2_WO1
#define LED_A_PWM4CTRL_PINMUX     PINMUX_PA17E_TCC2_WO1

#define CONF_PWM_MODULE      LED_A_PWM4CTRL_MODULE
#define CONF_PWM_CHANNEL     LED_A_PWM4CTRL_CHANNEL
#define CONF_PWM_OUTPUT      LED_A_PWM4CTRL_OUTPUT
#define CONF_PWM_OUT_PIN     LED_A_PWM4CTRL_PIN
#define CONF_PWM_OUT_MUX     LED_A_PWM4CTRL_MUX

static void tcc_callback_to_change_duty_cycle(
struct tcc_module *const module_inst)
{
	int dutyvalue= (0xFFFF/100) * duty_cycle;
	tcc_set_compare_value(module_inst,
	(enum tcc_match_capture_channel)
	(TCC_MATCH_CAPTURE_CHANNEL_0 + CONF_PWM_CHANNEL),
	32000);
}
static void configure_tcc(void)
{
	struct tcc_config config_tcc;
	tcc_get_config_defaults(&config_tcc, CONF_PWM_MODULE);

	config_tcc.counter.period = 1200;
	//config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM;
	config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_NORMAL_FREQ;

	config_tcc.compare.match[CONF_PWM_CHANNEL] = 0xFFFF;
	config_tcc.pins.enable_wave_out_pin[CONF_PWM_OUTPUT] = true;
	config_tcc.pins.wave_out_pin[CONF_PWM_OUTPUT]        = CONF_PWM_OUT_PIN;
	config_tcc.pins.wave_out_pin_mux[CONF_PWM_OUTPUT]    = CONF_PWM_OUT_MUX;
	tcc_init(&tcc_instanceb, CONF_PWM_MODULE, &config_tcc);
	tcc_enable(&tcc_instanceb);
}
static void configure_tcc_callbacks(void)
{
	tcc_register_callback(
	&tcc_instanceb,
	tcc_callback_to_change_duty_cycle,
	(enum tcc_callback)(TCC_CALLBACK_CHANNEL_0 + CONF_PWM_CHANNEL));
	tcc_enable_callback(&tcc_instanceb,
	(enum tcc_callback)(TCC_CALLBACK_CHANNEL_0 + CONF_PWM_CHANNEL));
}

void pwm_timer_set(void)
{
	    configure_tcc();
	    configure_tcc_callbacks();
	    system_interrupt_enable_global();
}

int main (void)
{
  	pwm_timer_set();

while(1)
{

}

}

 

 

 

 

Thanks

Regards

DJ

Last Edited: Mon. May 10, 2021 - 02:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define LED_A_PWM4CTRL_CHANNEL    0
#define LED_A_PWM4CTRL_OUTPUT     0

Change this, your are using output 1 and channel 1.

/Lars

 

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

Lajon wrote:

#define LED_A_PWM4CTRL_CHANNEL    0
#define LED_A_PWM4CTRL_OUTPUT     0

Change this, your are using output 1 and channel 1.

/Lars

 

 

Ok This helps, i can now change the duty cycle, but i can not change the frequency. 

 

I had to also set

	config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM;

 

Thanks

Regards

DJ

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

I am very new to the SAM devices...

 

To get a duty cycle of 50% @ 20 Khz i am doing following: I am setting 

config_tcc.counter.period = 2400;

config_tcc.compare.match[CONF_PWM_CHANNEL] = 2400;

 

Therefore i get a 50% duty cycle setting compare to 1200.

 

Does this seem right?

struct tcc_module *const module_inst)
{
	

	tcc_set_compare_value(module_inst,
	(enum tcc_match_capture_channel)
	(TCC_MATCH_CAPTURE_CHANNEL_0 + CONF_PWM_CHANNEL),
	1200);		

}

static void configure_tcc(void)
{
	struct tcc_config config_tcc;
	tcc_get_config_defaults(&config_tcc, CONF_PWM_MODULE);

	config_tcc.counter.period = 2400;
	config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM;
	//config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_NORMAL_FREQ;

	config_tcc.compare.match[CONF_PWM_CHANNEL] = 2400;
	config_tcc.pins.enable_wave_out_pin[CONF_PWM_OUTPUT] = true;
	config_tcc.pins.wave_out_pin[CONF_PWM_OUTPUT]        = CONF_PWM_OUT_PIN;
	config_tcc.pins.wave_out_pin_mux[CONF_PWM_OUTPUT]    = CONF_PWM_OUT_MUX;
	tcc_init(&tcc_instanceb, CONF_PWM_MODULE, &config_tcc);
	tcc_enable(&tcc_instanceb);
}

 

Thanks

Regards

DJ

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

Just out of curiosity you can have multiple PWM channels to a TCC timer, does this mean all would work on a same clock/ frequency but can have variation in duty cycle?

Thanks

Regards

DJ

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

Hi All

 

When i reduce the duty cycle to 0 and then i set it back to a much higher values, it seems like PWM is no longer outputting

Thanks

Regards

DJ

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

0 and what values? Maybe show the code.

/Lars

 

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

Hi Lajon

 

This is my code

static void pwm_fan_tcc_callback_to_change_duty_cycle(struct tcc_module *const module_inst)
{		   	   
	tcc_set_compare_value(module_inst,
	(enum tcc_match_capture_channel)
	(TCC_MATCH_CAPTURE_CHANNEL_0 + FAN_PWM_CHANNEL),
	fan_speed_duty);	
}


static void pwm_fan_set_configure_tcc(void)
{
	//struct tcc_config config_tcc;
	tcc_get_config_defaults(&config_tcc, FAN_PWM_MODULE);	
	//2200
	config_tcc.counter.period = 2200;	//20Khz
	config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM;		
	config_tcc.compare.match[FAN_PWM_CHANNEL] = 2200;
	config_tcc.pins.enable_wave_out_pin[FAN_PWM_OUTPUT] = true;
	config_tcc.pins.wave_out_pin[FAN_PWM_OUTPUT]        = FAN_PWM_OUT_PIN;
	config_tcc.pins.wave_out_pin_mux[FAN_PWM_OUTPUT]    = FAN_PWM_OUT_MUX;
	tcc_init(&fan_pwm_tcc_instance, FAN_PWM_MODULE, &config_tcc);
	tcc_enable(&fan_pwm_tcc_instance);	
}

void setcmpvalue(int a)
{
	

}
static void pwm_fan_set_configure_tcc_callbacks(void)
{
	tcc_register_callback(
	&fan_pwm_tcc_instance,
	pwm_fan_tcc_callback_to_change_duty_cycle,
	(enum tcc_callback)(TCC_CALLBACK_CHANNEL_0 + FAN_PWM_CHANNEL));
	tcc_enable_callback(&fan_pwm_tcc_instance,
	(enum tcc_callback)(TCC_CALLBACK_CHANNEL_0 + FAN_PWM_CHANNEL));
}
void pwm_fan_set(void) 
{
	    pwm_fan_set_configure_tcc();
	    pwm_fan_set_configure_tcc_callbacks();
	    system_interrupt_enable_global();
}

 

 

My duty cycle is set by a variable 

 

fan_speed_duty

 

When every this variable it set to 0, so that PWM output signal is always low, then the TCC counter does not output any PWM signal even if this variable was to increase.

 

I have found a fix , but not sure if this is the correct way.

tcc_reset(&fan_pwm_tcc_instance);

When every fan_speed_duty is set to 0, and i need to i need to increase this. I would preform this tcc_reset first.

 

fan_speed_duty when every i receive a appropriate message from the WINC3400 module.

 

Is it possible that the TCC timer can get looped or locked up, i am experiencing another issue, when i send multiple PWM message. I need to investigate further in regards to this issue. When i use a debugger and i am stepping in it seems to solve the issue. But i need to investigate further,

But would like to know can TCC lock up?

 

Thanks

Regards

DJ

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

There is no compare match when you have fan_speed_duty set to 0 hence no callback. Change the callback to overflow:
 

static void pwm_fan_set_configure_tcc_callbacks(void)
{
    tcc_register_callback(
        &fan_pwm_tcc_instance,
        pwm_fan_tcc_callback_to_change_duty_cycle, TCC_CALLBACK_OVERFLOW);
    tcc_enable_callback(&fan_pwm_tcc_instance, TCC_CALLBACK_OVERFLOW);
}

/Lars