PWM using TCA [ATTiny817]

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

Hi everyone,

I am trying to start the on board LED using PWM and TCA on ATTiny817.

I am actually trying to use a code example shared in this forum already, but for some reason the LED never starts.

 

Any help would be greatly appreciated.

 

// PWM test using timer A
#define F_CPU 2660000 // 2.66 MHz
#include <avr/io.h>
#include <util/delay.h>

#define PWM_DUTY_CYCLE	0
#define PWM_PERIOD 256

//------------------------------------------------
void timer_Init(void)
{
	// Set PB0 as output (waveform output, pg. 204)
	PORTC.DIR = PIN0_bm;

	// Frequency: Fpwm_ss = Fclk_per/(N(PER+1))
	// Max resolution: Rpwm_ss = (log(PER+1))/(log(2))

	TCA0.SINGLE.PER = PWM_PERIOD;

	// CMP sets the duty cycle of the PWM signal -> CT = CMP0 / PER
	// DUTY CYCLE is approximately 50% when CMP0 is PER / 2
	TCA0.SINGLE.CMP0 = PWM_DUTY_CYCLE;

	// Counter starts at 0
	TCA0.SINGLE.CNT = 0x00;

	// Configuring CTRLB register
	// Compare 0 Enabled: Output WO0 (PB0) is enabled
	// Single slope PWM mode is selected
	TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_WGMODE_SINGLESLOPE_gc; 

	// Using system clock (no frequency division, the timer clock frequency is Fclk_per)
	// Enable the timer peripheral
	TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm;
}

//------------------------------------------------
int main(void)
{
	timer_Init();

	while(1)
	{
		for(uint8_t brightness = 0; brightness < PWM_PERIOD; brightness++)
		{
			TCA0.SINGLE.CMP0 += brightness;

			// wait to see the LED brightness change effect
			_delay_ms(150);
		}
	}
}

 

Thanks!

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

Tamirell wrote:

	// Set PB0 as output (waveform output, pg. 204)
	PORTC.DIR = PIN0_bm;

 

PB0 isn't on PORTC wink

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

Don't mind the comment, the old user used PB0, I am trying to use the on board LED which is on port C0

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

>Don't mind the comment, the old user used PB0, I am trying to use the on board LED which is on port C0

 

PC0 is WO0 for TCB0, and cannot be used with TCA0, so that would be the reason PB0 was used for TCA0 since it is WO0 for TCA0. Check out chapter 5 in the datasheet for which pins can be used for TCA0.

 

You could jumper PC0 to PB0- leave PC0 alone (default input) so you can use the led on PC0 via PB0 pwm.

 

 

You may want to change your loop code. First the PWM_PERIOD is 256 so your loop will never exit (uint8_t brightness will always be < 256 no matter what you do to brightness), not a big deal here as it does not matter in this case (you remain in the loop, brightness overflows and wraps to 0). Second, increasing cmp0 by brightness will soon get cmp0 beyond the pwm period since cmp0 is a 16bit register, which means your pwm compare will not match and the led will not turn off (if high=on). I assume you simply wanted to do 'TCA0.SINGLE.CMP0 = brightness;'

 

        for(uint8_t brightness = 0; brightness < PWM_PERIOD; brightness++)
        {
            TCA0.SINGLE.CMP0 += brightness;

            // wait to see the LED brightness change effect
            _delay_ms(150);
        }

 

I'll also add that the compare registers have a buffer version you can write to. Not too important in this case, but there may come a time when you want that pwm to not 'glitch' when changing the compare value- the buffer versions take care of loading the compare registers at the proper time.

Last Edited: Sun. Jan 19, 2020 - 10:49 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ahhhhhhhhhh you are the best!

thank you very much, now everything makes sense.

I'm a total noob and still trying to understand what is going on, so this helps a lot.