16-bit PWM, SAMD20

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

Hi Everyone.

I'm using AS7 with ASF 3.3 and I've successfully been using 8-bit PWM up to this point. I find myself in a position where I need more resolution (10-bits is desirable) so I am playing with a 16-bit Atmel TC example (internal RC 8MHz). Maybe I am wrong, but it seems as though in TC_WAVE_GENERATION_NORMAL_PWM mode the counter counts up to TOP which is MAX (0xFFFF) and I can't define a TOP? In which case, I find counting down from a counter value I set, and overflow occurs at 0x0000, and this seems to give me the period I like. The example below gives me a 50% duty cycle, and it seems to work for most duty cycles... except, I can't get any better than 98% duty cycle (I would prefer an output frequency close to 2KHz since I have a PWM to voltage conversion circuit which works best at this frequency). So, my problem is, if duty_cycle = 0 to 0x3FF it all seems fine and generates a good PWM. When duty_cycle = 0x400, then I get my max of 98% duty cycle... probably because of the time required to set the counter back to 0x400 and then compare it to the compare value. Is there a better way to do this? I don't really see a lot of documentation on this, or I'm not sophisticated enough to understand it :-) - Thanks

 

static uint16_t duty_cycle;

​#define TOP 0x400

void tc_callback_to_set_top(struct tc_module *const module_inst)
{
 tc_set_count_value(module_inst, TOP);
}

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.wave_generation = TC_WAVE_GENERATION_NORMAL_PWM;
 config_tc.clock_prescaler = TC_CLOCK_PRESCALER_DIV4;
 config_tc.count_direction = TC_COUNT_DIRECTION_DOWN;

 config_tc.pwm_channel[0].enabled = true;
 config_tc.pwm_channel[0].pin_out = PIN_PA30F_TC1_WO0;
 config_tc.pwm_channel[0].pin_mux = MUX_PA30F_TC1_WO0;
 tc_init(&tc_instance, TC1, &config_tc);
 tc_enable(&tc_instance);
}

void configure_tc_callbacks(void)
{

tc_register_callback(&tc_instance, tc_callback_to_set_top, TC_CALLBACK_OVERFLOW);
tc_enable_callback(&tc_instance, TC_CALLBACK_OVERFLOW);
}

int main(void)
{
 system_init();

 configure_tc();
 configure_tc_callbacks();

 system_interrupt_enable_global();
 
 duty_cycle = 0x200;
 tc_set_compare_value(&tc_instance, TC_COMPARE_CAPTURE_CHANNEL_0, duty_cycle);

 while (true)
 {
 }
}

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

https://community.atmel.com/forum...

should help (you can configure a TOP value).

/Lars