need help with PWM [ATtiny817]

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

Hi,

 

I am using the xplained mini atTiny 817 board at the moment. 

 

I'm trying to get the yellow LED on the xplained mini board to be able to dim on and off (gradually turn on and off) using PWM but I need help! 

 

My code attempt is below.

 

I tried to set up registers and then attempted to adjust the duty cycle, but I'm stuck, so need some help Been trying for too long :(

 

(Thought I'd just make my own post on PWM to get help with my own code that I'm attempting to put together and learn how this should work at the same time.  )

 

Thanks, and I appreciate all the help to get this working. 

 

// Program to change brightness of an LED
// demonstration of PWM

#define F_CPU 2660000
#include <avr/io.h>
#include <util/delay.h>

//---------------------------------------------------
// initialize PWM
void PWM_init()
{
	// timer initialization [using timer B]

	PORTA.DIRSET = PIN5_bm;

	// TCA0.SINGLE.CTRLA addresses the control A register for timer A
	// System clock / 64 -> 250 kHz
	// Timer enabled
	TCA0.SINGLE.CTRLA = (TCA_SINGLE_CLKSEL_DIV64_gc) | (TCA_SINGLE_ENABLE_bm);

	//Use Clock from TCA
	// Timer enabled
	// PWM frequency = 250 kHz / 260 = 1kHz
	TCB0.CTRLA = ( TCB_CLKSEL_CLKTCA_gc) | (TCB_ENABLE_bm);	

	// TCB_CCMPEN_bp:enable the output "Compare/Capture"
	// TCB_CNTMODE_PWM8_gc: 8-bit PWM mode
	TCB0.CTRLB = (1 << TCB_CCMPEN_bp) | (TCB_CNTMODE_PWM8_gc);

	// Write compare/capture register to {CCMPH, CCMPL}
	TCB0.CCMPH=255;
	TCB0.CCMPL=0;
	TCB0.CNT=0x0000; // Write 0x0000 to count register
}

void main()
{
	uint8_t brightness;

	PWM_init();

	while(1)
	{
		// increasing brightness
		for (brightness = 0; brightness < 255; brightness++)
		{
			// set the brightness as duty cycle

			// delay so as to make the user "see" the change in brightness
			_delay_ms(10);
		}

		// decreasing brightness
		for (brightness = 255; brightness > 0; --brightness)
		{
			// set the brightness as duty cycle

			// delay so as to make the user "see" the change in brightness
			_delay_ms(10);
		}
	}
}

 

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

Umm your two for() loops in main() do nothing but delay()?? Were they supposed to have code to influence the timer's duty cycle?

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

HI and welcome to the forum!

 

How does the brightness value get written to the pwm duty cycle control reg in the code above?

 

Otherwise, the structure looks fine.

 

Jim

 

 

FF = PI > S.E.T

 

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

@ki0bk

ki0bk wrote:

 

How does the brightness value get written to the pwm duty cycle control reg in the code above?

Jim

 

That was one thing I was not sure, I guess I should've made that more clear in my original post. Can you help me get on the right track with that?

 

 

@Clawson

Thanks for the reply.

 

Last Edited: Wed. Mar 7, 2018 - 05:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

try adding:

// set the brightness as duty cycle
TCB0.CCMP=brightness;

 

untested, YMMV.

 

Jim

 

 

FF = PI > S.E.T

 

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

Hi Jim,

 

I quote myself in my original post:

 

I did write the following the code attempt, what would we do with that ccmph, ccmpl and cnt part? I thought I might have needed it, but not sure how to use it now that I think of it. And yes I'll try the brightness suggestion you added.

 

 

mc0134 wrote:

 

// Write compare/capture register to {CCMPH, CCMPL}
	TCB0.CCMPH=255;
	TCB0.CCMPL=0;
	TCB0.CNT=0x0000; // Write 0x0000 to count register

 

Clawson did say "Were they supposed to have code to influence the timer's duty cycle?" as well. :|

Last Edited: Wed. Mar 7, 2018 - 05:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't know 817 but most timers use the "compare" register to set the point at which the pulse switches state. I see you do:

	TCB0.CCMPH=255;
	TCB0.CCMPL=0;

(which I'm pretty sure you can probably do as a combined 16 bit write to TCB0.CCMP (no H or L)). It would be varying this that would vary the duty cycle I think. But the datasheet also mentions a "PER" (that is "Period") register too. I don't see you setting that. It will dictate the period and hence frequency of the timer - that is the complete counting range. So you set PER to the total period and then vary the Compare register between 0 and that.

 

EDIT: BTW I see you access TCA0 and then later TCB0. I don;t know 817 but are those really registers of a single timer or two separate timers?

Last Edited: Wed. Mar 7, 2018 - 05:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, Clawson

 

For the  817, TCA0 and TCB0 are two separate timers.

 

Also:

 

I quote directly off the datasheet:

The TCB.CCMPL and TCB.CCMPH register pair represents the 16-bit value TCB.CCMP. The low byte
[7:0] (suffix L) is accessible at the original offset. The high byte [15:8] (suffix H) can be accessed at offset
+ 0x01. For more details on reading and writing 16-bit registers, refer to Accessing 16-bit Registers.
This register has different functions depending on the mode of operation:
• For capture operation, these registers contain the captured value of the counter at the time the
capture occurs
• In periodic interrupt/timeout and single shot mode this register acts as the TOP value.
• In 8-bit PWM mode, TCB.CCMPL and TCB.CCMPH act as two independent compare registers.
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Then why are you apparently starting timer TCA...

TCA0.SINGLE.CTRLA = (TCA_SINGLE_CLKSEL_DIV64_gc) | (TCA_SINGLE_ENABLE_bm);

(the DIV64 there is almost certainly what starts the timer counting) but then later you do:

	TCB0.CCMPH=255;
	TCB0.CCMPL=0;

which appears to be setting the compare value for TCB. I do see you doing:

TCB0.CTRLA = ( TCB_CLKSEL_CLKTCA_gc) | (TCB_ENABLE_bm);	

is this some "clever trickery" in these new AVRs where you start one timer then use it to clock another? Why would you do that? Surely  for the simple PWM case you just start one timer, set a period and then set/vary a compare. Oh and in the d/sheet I couldn't help noticing the bit that said:

 

I think it's actually saying some of those are optional (presumably you don't need to touch CPUINT if not using interrupts for example, same for the even system) but I have a sneaking suspicion that CLKCTRL may be necessary/important.

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

ok still working on pwm but hopefully it'll work finally. if somebody else got a good suggestion, let me know. thanks ...

 

i didn't expect things to get complicated on my end regarding getting pwm to dim and bright lights ! :(

Last Edited: Wed. Mar 7, 2018 - 07:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Google for "ATtiny817 pwm"

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

Hey jstampfl,

 

 

Two things happened so far:

 

 

1. I've ditched TCB for now, and went for TCA and here is the result: can get the brightness to go up slowly like I wanted.

// 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)
	PORTB.DIRSET = 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);
		}
	}
}

 

2. I also went to the avrfreaks tutorial section where you posted tutorial on PWM regarding servo motor using TCD0, and that seems to work too to get LED to stay on a certain brightness level.

 

So now I'm thinking, how can I change the pin to use, let's say PB0 or PB4 or PB5 are all taken and you have to use other pins to do the PWM to get the LED to light up gradually, what would you recommend doing given what I've already got so far working above?

 

Thanks!

Last Edited: Thu. Mar 8, 2018 - 12:12 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
TCA0.SINGLE.CMP0 += brightness;

Why "+="? Surely the for loop variable is already incrementing so this should just be:

TCA0.SINGLE.CMP0 = brightness;

Otherwise if "brightness" counts 0..256 you are setting

 

0 = 0

0 + 1 = 1

0 + 1 + 2 = 3

0 + 1 + 2 + 3 = 6

0 + 1 + 2 + 3 + 4 = 10

 

I bet you just wanted 0, 1, 2, 3, 4 ... ?

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

Hi Clawson,

 

Thanks for the information.Yeah, making the TCA CMP0 increment by one is the awy to go. Otherwise timer speeds up every loop around which is no good.

 

Anyhow, I modded my code to use the tiny817's timer A split mode, allowing the use of the timer on the pin PA3 that I wanted to use for the wave output, seeing as the other available pins are alreadu being used b other stuff and it works great this time.

 

Regards,

 

mc0134

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

mc0134 wrote:
Anyhow, I modded my code to use the tiny817's timer A split mode, allowing the use of the timer on the pin PA3 that I wanted to use for the wave output, seeing as the other available pins are alreadu being used b other stuff and it works great this time.

 

Hi mc0134,

 

i hope you're still looking in this thread. I have a similiar problem and want to use another PIN than PB0 for PWM as well. Can you supply me with some tips or even code for this task?

 

Thanks a lot,

Chris

 

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

You can create a new thread for your problem without waking up the thread two years ago.

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

Try reading Microchip's getting started guides.

http://www.microchip.com//wwwApp...

https://github.com/MicrochipTech...

I think there's sample code on Atmel START as well. Google is your friend.

-Sam