help with blinking LED using timer interrupt [attiny817]

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

Hello,

 

I am new here and am just a beginner in learning to use/program the ATtiny817. (I am using the ATTINY817 XPLAINED mini board at the moment). I was just attempting to write a short program that would blink the onboard yellow LED using a timer interrupt. My attempt is below, and right now, the yellow LED0 on the board is  simply turning on and not blinking and I am not sure why.

 

If anybody could help me figure out why my program is not doing what I wanted it to do, I would greatly appreciate it (and I'm hoping to learn things along the way as well).

 

 

Thank you in advance !

 

#define F_CPU (20000000UL) // 20 MHz system clock
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

//------------------------------------------------
//TCA - 16 bit Timer/Counter Type A initialization
void timerInit(void)
{
	// Write a TOP value to the Period register (TCA.PER)
	TCA0.SINGLE.PER = 0xA;

	// Enable the peripheral by writing a '1' to the ENABLE bit in the Control A register (TCA.CTRLA).
	// The counter will start counting clock ticks according to the prescaler setting in the Clock Select bit
	// field (CLKSEL) in TCA.CTRLA. 

	TCA0_SINGLE_CTRLA |= (TCA_SINGLE_CLKSEL_DIV1_gc) | (TCA_SINGLE_ENABLE_bm); // TCA0.SINGLE.CTRLA addresses the control A register for timer A, use system clock (no frequency division), timer enabled

	TCA0.SINGLE.INTCTRL |= (TCA_SINGLE_OVF_bm); // Enable timer interrupts on overflow on timer A

	// The counter value can be read from the Counter bit field (CNT) in the Counter register (TCA.CNT)
}

//------------------------------------------------
ISR(TCA0_OVF_vect)
{
	// We will toggle LED in this ISR.
	PORTC.OUTTGL = PIN0_bm; // toggle PIN 0, Port C state (should toggle the LED)

	// Clear the interrupt flag, to prevent instantly jumping back into the ISR again.
	TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm;
}

//------------------------------------------------
int main(void)
{
	PORTC.DIRSET = PIN0_bm;
	timerInit();
	sei(); // Enable global interrupts

	while(1){}
}

 

Last Edited: Mon. Feb 5, 2018 - 06:55 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How fast do you think that LED is being toggled?

 

Too fast for you to see, so it appears like it is always on.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

Last Edited: Mon. Feb 5, 2018 - 07:45 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Larry,

 

Sorry for later response, but thank you for the information. I guess I'll have to adjust the blink frequency to make the LED's slow down so the toggling process can be physically visible. Since I'm still in the learning process, let me know if there's a good way to thinking about such problems (even if it may seem trivial at this point in time to you). In the meantime, i suppose i'll keep going with the experimenting and testing.

Last Edited: Tue. Feb 6, 2018 - 07:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, for this particular problem, you need to figure out what is the frequency at which the MCU is running.

 

I happen to have an xplained mini like yours, so I loaded your program. Now lets see the frequency:

 

We enter debug mode on Atmel Studio and go to the I/O window. In the clock controller, we can see that the internal 20MHz oscillator is selected, with a 6x divisor:

 

Now, the 20MHz clock can be running at 20 or 16 MHz, depending on the state of fuse2. So next we check the fuses:

 

As you can see, fuse 2 has the value 0x02, meaning, according to the datasheet, that the oscillator is running at 20MHz:

 

So now, you calculate 20/6 = 3.33MHz. So the MCU is running at this speed, and this is the value you have to put in F_CPU in case you want to use the avr-libc delay functions.

Remember that F_CPU does not set the CPU speed. This is done via the fuses and registers mentioned above.

 

Now that you know the MCU frequency, you can program the timers to generate a reasonable blinking rate of 1 or 2 Hz.

Timer A0 works with the CLK_PER clock, meaning it is synchronous to the CPU, so it's base counting frequency is the same 3.33MHz.

 

edit:

You can set, for example, the divisor to 1024 and period to 1627, this will give 0.5s on and 0.5s off, which is a 1Hz blink.

Last Edited: Tue. Feb 6, 2018 - 11:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

El Tangas wrote:
You can set, for example, the divisor to 1024 and period to 1627, this will give 0.5s on and 0.5s off, which is a 1Hz blink.

I suppose the math goes as as follows: ....

1/((20MHz  / 6) / 1024 / 1627) = 0.5 seconds approximately which results in 1 Hz blink rate. I hope that's right, let me know if it isn't ... thanks!

 

In any case, here is my code as shown below. The yellow LED is now blinking as I wanted it to do, timer period and clock division values had to be adjusted. smiley

 

-----

#include <avr/io.h>
#include <avr/interrupt.h>

//------------------------------------------------
//TCA - 16 bit Timer/Counter Type A initialization
void timerInit(void)
{
	// Write a TOP value to the Period register (TCA.PER)
	TCA0.SINGLE.PER = 1627;

	// Enable the peripheral by writing a '1' to the ENABLE bit in the Control A register (TCA.CTRLA).
	// The counter will start counting clock ticks according to the prescaler setting in the Clock Select bit
	// field (CLKSEL) in TCA.CTRLA. 

	TCA0.SINGLE.CTRLA |= (TCA_SINGLE_CLKSEL_DIV1024_gc) | (TCA_SINGLE_ENABLE_bm);// TCA0.SINGLE.CTRLA addresses the control A register for timer A, system clock / 1024, timer enabled

	TCA0.SINGLE.INTCTRL |= (TCA_SINGLE_OVF_bm); // Enable timer interrupts on overflow on timer A
}

//------------------------------------------------
ISR(TCA0_OVF_vect)
{
	// LED Toggling
	PORTC.OUTTGL = PIN0_bm; // toggle PIN 0, Port C 

	// Clear the interrupt flag, to prevent instantly jumping back into the ISR again.
	TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm;
}

//------------------------------------------------
int main(void)
{
	PORTC.DIRSET = PIN0_bm;
	timerInit();
	sei(); // Enable global interrupts

	while(1){}
}

 

 

 

 

Last Edited: Wed. Feb 7, 2018 - 04:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for picking up on this El Tangas.

 

mc0134, don't get into the habit of using |=, causes a read-modify-write code sequence, when initially setting register values, = is all you need.  Really the only time you need to use |= is when you are modifying a value in a register that already has bits set that should not be changed.

 

void timerInit(void)
{
	// Write a TOP value to the Period register (TCA.PER)
	TCA0.SINGLE.PER = 1620; // value gives 1s period, 1Hz frequency, 50% duty cycle on my ATtiny1616

	// Enable the peripheral by writing a '1' to the ENABLE bit in the Control A register (TCA.CTRLA).
	// The counter will start counting clock ticks according to the prescaler setting in the Clock Select bit
	// field (CLKSEL) in TCA.CTRLA.

	TCA0_SINGLE_CTRLA = (TCA_SINGLE_CLKSEL_DIV1024_gc) | (TCA_SINGLE_ENABLE_bm); // TCA0.SINGLE.CTRLA addresses the control A register for timer A, system clock/1024, timer enabled

	TCA0.SINGLE.INTCTRL = (TCA_SINGLE_OVF_bm); // Enable timer interrupts on overflow on timer A

	// The counter value can be read from the Counter bit field (CNT) in the Counter register (TCA.CNT)
}

 

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius