I have a DrAzzy ATTiny1614 dev board running at 5V.
I'm attempting to setup TCB to have a approx 240Hz rate (~4.xx ms). I'm in the "Periodic Interrupt Mode" and expect the counter to reach a number initiate an interrupt and restart at 0. In my testing I changed to a CCMP of 16384 hoping to make the results easier for me to trouble shoot.
My issue is I can't calculate the actual results measured with a logic analyzer. I tested the analyzer with another instrument and it believe it to be accurate.
My results are way off the expected times.
I'm testing with 10Mhz and 8Mhz. The measured times change at a proportion that verifies a change of 10:8 in clock.
I think there is a prescaler that defaults to 8. Even if this is the case I can't reconcile this with my calculation.
Can anyone see my error?
Thanks
John
My code, be gentle I'm still learning the registers.
/*
* ATTiny1614 Timer B test
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#define PIN_LED_bp 7 // PA7
#define PIN_LED_bm (1 << PIN_LED_bp) // = 0b010000000
#define COMPARE 0x4000
int main(void) {
// LED
PORTA.DIRSET = PIN_LED_bm; // _bm is bit mask ??
// or PORTA.DIR |=0x80;
// TCB0 By default, the TCB is in Periodic Interrupt mode.
TCB0.CCMP = COMPARE;
TCB0.INTCTRL = TCB_CAPT_bm;
TCB0.CTRLA = 0x01; //TCB_ENABLE_bm; 0x03 = 251 HZ 0x01 = 502.4 Hz
sei();
while (1) {
}
}
volatile uint16_t count = 0;
ISR(TCB0_INT_vect) {
TCB0.INTFLAGS |= TCB_CAPT_bm; //clear the interrupt flag(to reset TCB0.CNT)
if (PORTA.OUT & PIN_LED_bm) {
PORTA.OUTCLR = PIN_LED_bm;
} else {
PORTA.OUTSET = PIN_LED_bm;
}
}
I have been using the 10Mhz clock and the 8Mhz clock (set as you show in Post #2)
When testing with these two clock settings, the measured values change in a 10:8 proportion, as one would expect.
I was under the impression the MCLKCTRLB defaulted to the "reset" settings shown below.
That's also my impression. When not using Setup and Loop, you skip the Arduino core initialization and you have the MCU in reset condition as per the datasheet.
BTW, if you want a 250Hz interrupt, you can also do that with the RTC. Frees up TCB0 again and the RTC is running at it's own speed independent of any CPU clock speed.
It has a selectable 32KHz or 1KHz oscillator.
In below example sketch I set the PIT at 258Hz and the RTC at 250Hz.
for the PIT you can choose from 14 values (see comment) and for the RTC you let it count to a 16bit number, so that's way more flexible. Because of the 32KHz oscillator the RTC uses you cannot get high frequencies.
int main(void) {
VPORTA_DIR |= PIN7_bm; // set pin PA7 as output
VPORTB_DIR |= PIN0_bm; // set pin PB0 as output
F_CPU_init (); // reconfigure CPU clock prescaler
//Configure clock source used by both PIT and RTC
RTC_CLKSEL = RTC_CLKSEL_INT32K_gc; /* Internal 32kHz OSC */
//RTC_CLKSEL = RTC_CLKSEL_INT1K_gc; /* Internal 1kHz OSC */
//Configure RTC
while (RTC_STATUS & RTC_PERBUSY_bm) {} // wait until RTC_PER is available for writing
RTC_PER = 65; // write period (16bit) to period
// RTC_PER = 50000; // write period (16bit) to period
RTC_INTCTRL |= RTC_OVF_bm; // activate overflow interrupts
RTC_CTRLA |= RTC_RTCEN_bm; // turn on RTC
//Configure PIT
RTC_PITINTCTRL |= RTC_PI_bm; // activate PIT Interrupt enable
RTC_PITCTRLA |= RTC_PERIOD_CYC64_gc | RTC_PITEN_bm;// set PIT period and enable
//The Realtimer-Counter (RTC) have a own 32,768KHz Cristal.
// 32.768KHz / CYCprescale = periodtime in mS
//
// BIN NAME TIME
// 0b00001001 CYC4 0,122 mS
// 0b00011001 CYC8 0,244 mS
// 0b00011001 CYC16 0,488 mS
// 0b00100001 CYC32 0,977 mS
// 0b00101001 CYC64 1,953 mS
// 0b00110001 CYC128 3,906 mS
// 0b00111001 CYC256 7,813 mS
// 0b01000001 CYC512 15,63 mS
// 0b01001001 CYC1024 31,25 mS
// 0b01010001 CYC2048 62,50 mS
// 0b01011001 CYC4096 125,00 mS
// 0b01100001 CYC8192 250,00 mS
// 0b01101001 CYC16384 500,00 mS
// 0b01110001 CYC32768 1000,00 mS
sei(); // turn on global interrupts
while (1); // nothing to do here
}
ISR(RTC_PIT_vect) { // RTC Interrupt
RTC_PITINTFLAGS = RTC_PI_bm; // clear Interrupt Flag
PORTA_OUTTGL = PIN7_bm; // toggle Pin/A6
}
ISR(RTC_CNT_vect) { // RTC Interrupt
RTC_INTFLAGS = RTC_OVF_bm; // clear Interrupt Flag
PORTB_OUTTGL = PIN0_bm; // toggle Pin/B5
}
void F_CPU_init () {
// reconfigure CPU clock prescaler
#if (F_CPU == 20000000)
/* No division on clock */
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 0x00);
#elif (F_CPU == 16000000)
/* No division on clock */
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 0x00);
#elif (F_CPU == 10000000) // 20MHz prescaled by 2
/* Clock DIV2 */
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_2X_gc));
#elif (F_CPU == 8000000) // 16MHz prescaled by 2
/* Clock DIV2 */
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_2X_gc));
#elif (F_CPU == 5000000) // 20MHz prescaled by 4
/* Clock DIV4 */
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_4X_gc));
#elif (F_CPU == 4000000) // 16MHz prescaled by 4
/* Clock DIV4 */
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_4X_gc));
#elif (F_CPU == 1000000) // 16MHz prescaled by 16
/* Clock DIV16 */
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_16X_gc));
#else
#ifndef F_CPU
#error "F_CPU not defined"
#else
#error "F_CPU defined as an unsupported value for untuned internal oscillator"
#endif
#endif
}