need help with getting a 1 sec timer [ATtiny817]

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

Hi,

 

I am now trying to get a 1 second timer working. The code attempt I made is baelow, trying to use Timer B. But I'm kind of stuck. II think where I am going wrong is how to figure out the calculation to get the proper 1 second delay (i.e., what TOP value is going to give me the 1 second?). One reason I'm a confused is by the CLKSEL that Timer B comes with. I'm not going to be synchronizing with TCA so that's out.

 

So any suggestions of how to get the proper clock and calculation to get a 1 sec delay out of timer B now so then we can do a periodic interrupt every 1 second to check for something within the associated ISR?

 

Thanks!

 

void timer(void)

    /*    By default, TCB is in Periodic interrupt mode
        In the periodic interrupt mode the counter counts to the capture value and restarts from zero. Interrupt is
        generated when counter is equal to TOP.
    */

    //    Write a TOP value to the Compare/Capture register (TCB.CC)
    // What should TCBO.CCMP be set to?
    TCB0.CCMP = ??? ;

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

       WHAT CLKSEL should I choose?
    */
    TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc | TCA_SINGLE_ENABLE_bm;

    // Compare/Capture Output has a valid value
    // Periodic interrupt mode;
    TCB0.CTRLB = TCB_CCMPEN_bm | TCB_CNTMODE_INT_gc

    /*
        The counter value can be read from the Count register (TCB.CNT). The peripheral will generate an
        interrupt when the CNT value reaches TOP
    */
}

 

Last Edited: Thu. Mar 8, 2018 - 11:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mc0134 wrote:
...kind of stuck. Where am I going wrong?
What does that mean, what results are you seeing.  Do you have an ISR for this?  Do us all a favor and post the most complete program that you can.

 

Working from the section of code that you think is causing the problem is for us like having our hands tied behind our backs while trying to drive.  Cut the ropes, post your code.

"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

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

 

Please do not edit your posted code as you did in post #1.  What was the formula that was originally there for TCB0.CCMP?

"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

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

Hi Larry,

 

Thank you for replying to my post.

 

I had done a simple code to get a LED to blink at roughly 1 Hz frequency using Timer A on the 817.

 

To get a 1 Hz blink rate, I did had this following calculation, and determined that TOP would be 1628 (had 1024 clock div)

1/((20MHz  / 6) / 1024 / 1628) = 0.5 seconds

 

 

But right now, I'm going to be using Timer B instead of timer A. So thought the formula to get TOP should be same but not sure.

 

When I said I was kind of stuck, I meant that I was not sure how the math to get the 1 second to come about and what would be a proper clock sel to use.

 

I currently have an empty ISR but I'll be adding code to do something in there later, probably just setting a flag so that main can do something. (That's the easy part to add) after I get the 1 sec timer part working.

ISR(TCB0_INT_vect)
{

}

And yes, I posted pretty much the code that I have for you anyhow.

 

Thanks

Last Edited: Thu. Mar 8, 2018 - 11:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mc0134 wrote:
I am now trying to get a 1 second timer working. The code attempt I made is baelow, trying to use Timer B. But I'm kind of stuck. II think where I am going wrong is how to figure out the calculation to get the proper 1 second delay (i.e., what TOP value is going to give me the 1 second?). One reason I'm a confused is by the CLKSEL that Timer B comes with. I'm not going to be synchronizing with TCA so that's out.   So any suggestions of how to get the proper clock and calculation to get a 1 sec delay out of timer B now so then we can do a periodic interrupt every 1 second to check for something within the associated ISR?  

 

Is this homework ?

You need to draw a divide chain on paper - The MCU start from 16/20MHz and you want 1s, so somewhere you need to apply (just under) 25 binary bits of division.

 

There is a CLK_PER divider that can give you a few bits, but that applies to all peripherals, so you may decide that's too much compromise.

If you cannot chain with TCA, can you see a problem, in trying to get directly to 1 second ?

 

One possible divide chain would be SysClk/1 -> /2 at TCB in -> /N(Max 2^16) -> /M (152.587890625 @ 2^16,20M)

N,M need to be integers, and N as large as practical, but you may want some calibrate headroom.

Possible is 62500 & 160, many other solutions exist, eg 191 & 52356 has 0.4ppm numeric error, or you might like 50,000 & 200 as that gives a nice round 5ms interrupt.

 

Last Edited: Fri. Mar 9, 2018 - 12:24 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Who-me

 

No, this isn't homework of any kind. I'm just trying to get things working is all.

 

Also was just trying to get TCB to do it's thing without having to be bothered with TCA and such (I've gotten PWM to work using TCA but if I wanted TCB to be it's own thing that's completely independent of TCA)

 

So there's where I'm at.

 

 

Thanks for the information you provided, I appreciate it and will see where I end up.

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

One reason I'm a confused is by the CLKSEL that Timer B comes with.

 

I've not used a Tiny817, so take this for what its worth.

 

It would appear that if you are using a 20 MHz clock source, you then have the option of dividing that by  a number of divisors, from 1 to 64, using the Main Clock Prescaler.

 

Within the Timer/counter B you then have an additional optional Div / 2 available.

 

Those two, cascaded, tell you the input frequency to the T/CB module.

 

Knowing the input, and that T/CB is a 16-bit module, you can set the TOP value to roll over when desired.

 

Finally, set Top to N-1, as the actual roll over from Top back to zero also counts as one tic.

 

So, as an example:

 

20 MHz Clock, set Main Clock Prescaler for Div by 64.

This gives 20 MHz / 64 = 312,500 Hz output.

 

Now set the T/CB for Div by 2

So the 312,500 Hz input is divided by 2 giving: 156,250 Hz as the actual input into the 16-Bit counter.

 

Now set TOP to 156,250 / 10 = 15,625

 

So now the T/CB will generate an interrupt 10 times / second, (Almost!).

 

But, recall that the roll over from Top to Zero counts as 1 clock tic, so actually you want to set Top = 15,625 - 1 = 15,624.

 

This will now generate 10 interrupts / second, with the accuracy of the original 20 MHz clock source.

 

You still have to configure the T/CB to generate the interrupt for you, (Periodic Interrupt Mode, (Used to be called CTC Mode)), but the above should help you set the T/C's Top value.

 

JC

 

 

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

Great answers above.

 

I created a project in Start and went from the defaults for the Main Clock of (20MHz / 6) = 3.333333MHz.  Selected TCB settings of CLK_PER/2, Periodic Interrupt (default, no code needed), Capture Interrupt Enable.

 

The calculated capture value for a 10ms interrupt tick was (20MHz / 6 / 2 / 200) = 8333, testing with my ATtiny817 required a value of 8200 for a perfect 10ms.  This value will vary with temperature and is different for each chip.

 

This is what you need to make a 10ms interrupt tick.

 

void timer(void)

    /*    By default, TCB is in Periodic interrupt mode
        In the periodic interrupt mode the counter counts to the capture value and restarts from zero. Interrupt is
        generated when counter is equal to TOP.
    */

    // Set the TOP value in the Compare/Capture register (TCB.CCMP)

    TCB0.CCMP = 8200;

    /*
        Enable the counter by writing a '1' to the ENABLE bit in the Control A register (TCB.CTRLA).
        The counter will start counting clock ticks according to the prescaler setting in the Clock Select bit
        field (CLKSEL in TCB.CTRLA).
    */
    TCB0.CTRLA = TCB_CLKSEL_CLKDIV2_gc | TCA_SINGLE_ENABLE_bp;

    // Enable the capture interrupt
    TCB0.INTCTRL = 1 << TCB_CAPT_bp;

}

 

Use that 10ms interrupt tick as a time base for producing your 1s pulse by incrementing a shared volatile counter variable in the ISR and an if block, either in the ISR or in main, that executes on a specific value of that variable.

 

For a 1 second tick

 

I have this in my ISR:

ISR(TCB0_INT_vect)
{
	/* Insert your TCB interrupt handling code */

	 extern volatile uint8_t TCB0_isr_count;

	 TCB0_isr_count++;

	/**
	 * The interrupt flag is cleared by writing 1 to it, or when the Capture register
	 * is read in Capture mode
	 */
	TCB0.INTFLAGS = TCB_CAPT_bm;
}

and this in main:

#include <atmel_start.h>

volatile uint8_t TCB0_isr_count = 0;

int main(void)
{
	/* Initializes MCU, drivers and middleware */

	atmel_start_init();

	/* Replace with your application code */
	while (1) {

		if (TCB0_isr_count == 100) {

​                        // we toggle some port pins every 1s 

			VPORTA.OUT ^= PIN5_bm;  // FYI - VPORTA.OUT ^= is faster than PORTA.OUTTGL
			VPORTB.OUT ^= PIN4_bm;

			// Reset the ISR count
​                        TCB0_isr_count = 0;
		}

	}
}

 

"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: Fri. Mar 9, 2018 - 06:48 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the help  @ larryvc

 

I'll give it a whirl later when I got some more time.

 

 

One other question, but this is relating to split mode of the Timer Counter A, if I decide to use that mode of that counter,  I see that the original 16 bit timer is split into two 8 bit.

 

Just wondering, if I used say, high byte timer for PWM, and then wanted to use low byte timer for say, an independent 1 sec or 10 ms timer, would I would need to configure each timer independently (i.e., two separate timer init functions that are independent of one another or does Hbyte timer settings get used into the LByte settings or vice versa?)

Last Edited: Fri. Mar 9, 2018 - 07:51 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm new to the 0- and 1- series, so I'm browsing the forum. "The calculated capture value for a 10ms interrupt tick was (20MHz / 6 / 2 / 200) = 8333" - where does 200 come from? Shouldn't it be 100?