I am fairly new to setting up event channels and users on the ATtiny series 0 - specifically the ATtiny402. Please may I have some help and guidance.
I have some code that successfully sets up the ADC to trigger in Window mode from RTC overflow in STANDBY mode and only generate an interrupt if the ADC result is within the window.
I want to extend this to use one of the counters available, TCA0 or TCB0 to cause an interrupt on overflow by counting the RTC overflow event.
I have read the spec sheet; it seems to imply that TCA0 can count events whereas TCB0 is unable to do so.
16-bit Timer/Counter Type A (TCA)
Features
• Count on Event
In the detail it said
Optional: By writing a ‘1’ to the Enable Count on Event Input bit (CNTEI) in the Event Control
register (TCAn.EVCTRL), event inputs are counted instead of clock ticks.
However, looking at the Event System config - whereas the ADC0 user multiplexer may be associated with Asynch User 1, TCA0 is not listed, instead TCB0 is against Ayynch User 0.
TCA0 seems to be associated with Synch User 0.
However the Synchronous channel generator selector does not list the RTC.
So switching to looking at the TCB0, which is listed against the Asynch User 0, the description in the device data sheet did not sound convincing about actually counting RTC overflow generated events
16-bit Timer/Counter Type B (TCB)
Features
– Input capture
• On event
I tried both approaches but managed only to get TCB0 generating an overflow interrupt on events but it seemed not to be counting RTC overflow generated events, but rather the underlying clock.
I have included my code below - I would be keen to know if I am on a hiding to nothing. Put another way, I am trying to count a long period of time (~120s) using events and only to trigger an interrupt (to take some action) at the end of this time. The RTC overflow event generates a suitable time base for measuring a light level in STANDBY mode so I was keen to some how count these also in STANDBY mode without starting up the processor. I have two counters to play with and I was hoping I could set one up to count the event generated by my RTC overflow in STANDBY and generate an interrupt on overflow (or compare match). Can you help?
Much of the ‘setup’ for the peripherals was generated then copied from a START Studio7 project.
/* ATtiny402EventHelp */
#ifdef F_CPU
#undef F_CPU
#define F_CPU 32000UL // Main clock is internal 32kHz oscillator - required for delay function
#endif
#include <avr/interrupt.h> // so we can use interrupt vector names
#include <avr/sleep.h> // useful macros for putting the unit into sleep mode
#include <util/delay.h> // needed for the delay functions
#define ADC_Threshold_High 1000 // 1024 is O/C at LDR = very dark
#define ADC_Threshold_Low 900
#define rtc_period 250 // sets the RTC overflow hence periodicity.
//Changing this changes the ADC sample rate but does not affect the TCB0 oveflow time
#define TCA0_period 500
#define TCB0_CCMP 0xFFFF // sets the value of TOP that generates an interrupt
uint16_t adc_result; // ADC light level in here (1024 = total dark)
volatile uint8_t INT_FLAG; // register of the following flags for communicating with ISR
#define ADC_conversion_bp 0 // an ADC conversion has occurred
#define PC_Interrupt_bp 1 // a Pin Change Interrupt has occurred
#define PIT_Interrupt_bp 2 // a Periodic Interrupt Timer interrupt has occurred
#define TCA0_Interrupt_bp 3 // TCA0 overflow has occurred
#define RTC_Overflow_bp 4 // a RTC Overflow interrupt has occurred
#define TCB0_Interrupt_bp 5 // a TCB0 periodic interrupt has occurred
#define RTC_CompareMatch_bp 6 // a RTC compare Match interrupt has occurred
/* Pin information
ATtiny402
----u---
VDD| |GND
LED PA6| |PA3 PWR
ADC PA7| |PA0 UDIP
LOW PA1| |PA2 SW
--------
*/
/* Notes on circuit
SW not involved in this sample code but will be a tremble switch to 0v
LED and PWR are connected to LEDs for debug
ADC has LDR connected to LOW and when measuring light level,
the internal pullup on PA7 is enabled but this bit of code has been omitted here.
*/
#define LOW_bp 1 // the only reason this pin is used is to make physical build easier - as a virtual 0v
#define PWR_bp 3
#define ADC_bp 7
#define SW_bp 2
#define LED_bp 6
void goToSleep();
void bip(uint8_t pin); // debug
void flash(uint8_t pin, uint8_t max); // debug
void enableTCB0();
void disableTCB0();
void system_init();
int main(void) {
// put your setup code here, to run once:
system_init(); // initialize the system
flash(LED_bp,3); // useful to see start up and to check delay versus clock setting
flash(PWR_bp,3); // useful to see start up and to check delay versus clock setting
goToSleep(); // STANDBY mode
while(1){
if (INT_FLAG & (1<<ADC_conversion_bp)){ // an ADC conversion has happened
INT_FLAG &= ~(1<<ADC_conversion_bp); // clear the flag
adc_result = ADC0.RES; // fetch the result
flash(LED_bp,1); // shows RTC overflow event triggers ADC in Window mode.
}
if (INT_FLAG & (1<<RTC_Overflow_bp)){ // a RTC overflow - but should not happen
INT_FLAG &= ~(1<<RTC_Overflow_bp); // clear the flag
flash(LED_bp,3); // shows no RTC interrupts generated - just events
}
if (INT_FLAG & (1<<PIT_Interrupt_bp)){ // a PIT interrupt has happened - so no light detected
INT_FLAG &= ~(1<<PIT_Interrupt_bp); // clear the flag
//flash(LED_bp,2); // shows that the PIT overflow triggers from RTC in standby
}
if (INT_FLAG & (1<<TCA0_Interrupt_bp)){
INT_FLAG &= ~(1<<TCA0_Interrupt_bp);
//flash(PWR_bp,1);
}
if (INT_FLAG & (1<<TCB0_Interrupt_bp)){
INT_FLAG &= ~(1<<TCB0_Interrupt_bp);
flash(PWR_bp,1); // seems to be based on underlying clock rather than desired RTC overflow events
}
goToSleep(); // STANDBY mode
}
}
// put function definitions here:
/* Interrupt Service Routines */
ISR(TCA0_OVF_vect){
/* Insert your TCA overflow interrupt handling code */
INT_FLAG |= (1<<TCA0_Interrupt_bp);
/* The interrupt flag has to be cleared manually */
TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bp;
}
ISR(TCB0_INT_vect)
{
/* Insert your PIT interrupt handling code here */
INT_FLAG |=(1<<TCB0_Interrupt_bp);
/* The interrupt flag has to be cleared manually */
TCB0.INTFLAGS = TCB_CAPT_bm;
}
ISR(PORTA_PORT_vect){
/* Insert your PORTA interrupt handling code here */
INT_FLAG |= (1<<PC_Interrupt_bp);
/* Clear interrupt flags */
VPORTA_INTFLAGS = (1<<SW_bp);
}
ISR(RTC_PIT_vect)
{
/* Insert your PIT interrupt handling code here */
INT_FLAG |=(1<<PIT_Interrupt_bp);
/* The interrupt flag has to be cleared manually */
RTC.PITINTFLAGS = RTC_PI_bm;
}
ISR(RTC_CNT_vect){
/* Insert your RTC Overflow interrupt handling code */
if (RTC.INTFLAGS & RTC_OVF_bm){
INT_FLAG |= (1<<RTC_Overflow_bp);
}
if (RTC.INTFLAGS & RTC_CMP_bm){
INT_FLAG |= (1<<RTC_CompareMatch_bp);
}
/* Overflow interrupt flag has to be cleared manually */
RTC.INTFLAGS = RTC_OVF_bm | RTC_CMP_bm;
}
ISR(ADC0_RESRDY_vect){
/* Insert your RTC Overflow interrupt handling code */
INT_FLAG |= (1<<ADC_conversion_bp); // signal to main.c that a conversion has occurred
// Clear the interrupt flag
ADC0.INTFLAGS = ADC_RESRDY_bm;
}
ISR(ADC0_WCOMP_vect){
/* Insert your RTC Overflow interrupt handling code */
INT_FLAG |= (1<<ADC_conversion_bp); // signal to main.c that a conversion has occurred
// Clear the interrupt flag
ADC0.INTFLAGS = ADC_WCMP_bm;
}
/* Other routines */
void bip(uint8_t pin){ // used for debug
disableTCB0(); // TCB0 seems to mess up the _delay_ms_() routine so this probably uses TCB0
VPORTA.OUT ^= (1<<pin); // toggle
_delay_ms(10);
VPORTA.OUT ^= (1<<pin); // toggle
_delay_ms(40);
enableTCB0(); // reenable TCB0
}
void flash(uint8_t pin, uint8_t max){ // used for debug
for (uint8_t i = 0; i < max; i++){
bip(pin);
}
}
void goToSleep(){ /* put the unit to sleep */
sleep_enable();
sleep_cpu();
sleep_disable();
}
void enableTCB0(){
// CLK_PER (No Prescaling), Enable: enabled, Run Standby: enabled, Synchronize Update: disabled
TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc | 1 << TCB_ENABLE_bp | 1 << TCB_RUNSTDBY_bp | 0 << TCB_SYNCUPD_bp;
}
void disableTCB0(){
// CLK_PER (No Prescaling), Enable: disabled, Run Standby: enabled, Synchronize Update: disabled
TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc | 0 << TCB_ENABLE_bp | 1 << TCB_RUNSTDBY_bp | 0 << TCB_SYNCUPD_bp;
}
/* Initialization routines */
void mcu_init(void) /* MCU initialization */
{
/* On AVR devices all peripherals are enable from power on reset, this
* disables all peripherals to save power. Driver shall enable
* peripheral if used */
/* Set all pins to low power mode */
for (uint8_t i = 0; i < 8; i++) {
*((uint8_t *)&PORTA + 0x10 + i) |= 1 << PORT_PULLUPEN_bp;
}
}
void pin_init(void){ /* PIN initialization */
// define PWR as output
VPORTA.DIR |= (1<<PWR_bp); // set pins as output
VPORTA.OUT &= ~(1<<PWR_bp); // set pins LOW
*((uint8_t *)&PORTA + 0x10 + PWR_bp) &= ~(1 << PORT_PULLUPEN_bp); // disable pullup for PWR pin
// define LED as output
VPORTA.DIR |= (1<<LED_bp); // set pins as output
VPORTA.OUT &= ~(1<<LED_bp); // set pins LOW
*((uint8_t *)&PORTA + 0x10 + LED_bp) &= ~(1 << PORT_PULLUPEN_bp); // disable pullup for LED pin
// define LOW as output used as a virtual ground to make hardware build easier
VPORTA.DIR |= (1<<LOW_bp); // set pins as output
VPORTA.OUT &= ~(1<<LOW_bp); // set pins LOW
*((uint8_t *)&PORTA + 0x10 + LOW_bp) &= ~(1 << PORT_PULLUPEN_bp); // disable pullup for PWR pin
uint8_t *SW_port_pin_ctrl = ((uint8_t *)&PORTA + 0x10 + SW_bp); // get port PINCTRL address for SW pin
*SW_port_pin_ctrl = (*SW_port_pin_ctrl & ~PORT_ISC_gm) | PORT_ISC_BOTHEDGES_gc; // enable interrupts for SW pin
uint8_t*ADC_port_pin_ctrl = ((uint8_t *)&PORTA + 0x10 + ADC_bp); // get port PINCTRL address for ADC pin
*ADC_port_pin_ctrl = (*ADC_port_pin_ctrl & ~PORT_ISC_gm) | PORT_ISC_INPUT_DISABLE_gc; // INPUT_DISABLED
}
void CLKCTRL_init(void){ /* Main clock initialization */
/* The following registers have Configuration Change Protection */
// CLKCTRL.MCLKCTRLB
// CLKCTRL.MCLKLOCK
// CLKCTRL.MCLKCTRLA
// CLKCTRL.OSC20MCTRLA
// CLKCTRL.OSC20MCALIBA
// CLKCTRL.OSC20MCALIBB
// CLKCTRL.OSC32KCTRLA
/* Set the Main clock to internal 32kHz oscillator*/
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCULP32K_gc);
/* Set the Main clock to internal 20MHz oscillator*/
//_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSC20M_gc);
/* run the 32kHz oscillator in standby mode*/
_PROTECTED_WRITE(CLKCTRL.OSC32KCTRLA, 1 << CLKCTRL_RUNSTDBY_bp);
/* Set the Main clock prescaler divisor to 2X and disable the Main clock prescaler */
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | 0 << CLKCTRL_PEN_bp); // without enable
/* ensure 20MHz isn't forced on*/
_PROTECTED_WRITE(CLKCTRL.OSC20MCTRLA, 0 << CLKCTRL_RUNSTDBY_bp);
/* wait for system oscillator changing to finish */
while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm) {
}
}
void RTC_0_init(void){ /* Realtime clock initialization */
/* Wait for all register to be synchronized */
while (RTC.STATUS > 0){}
/* 32KHz Internal Ultra Low Power Oscillator (OSCULP32K) */
//RTC.CLKSEL = RTC_CLKSEL_INT32K_gc;
/* 32KHz divided by 32 */
RTC.CLKSEL = RTC_CLKSEL_INT1K_gc;
/* Period: */
RTC.PER = rtc_period;
//RTC.CMP = rtc_compare;
/* Compare Match Interrupt disabled, Overflow Interrupt disabled */
RTC.INTCTRL = (0 << RTC_CMP_bp) | (0 << RTC_OVF_bp);
/* Compare Match Interrupt disabled, Overflow Interrupt enabled - */
//RTC.INTCTRL = (0 << RTC_CMP_bp) | (1 << RTC_OVF_bp);
/* Prescaler of 1, disable, run in standby */
//RTC.CTRLA = RTC_PRESCALER_DIV1_gc | (0 << RTC_RTCEN_bp) | (1 << RTC_RUNSTDBY_bp);
/* Prescaler of 1, enable, run in standby */
RTC.CTRLA = RTC_PRESCALER_DIV1_gc | (1 << RTC_RTCEN_bp) | (1 << RTC_RUNSTDBY_bp);
/* Wait for all register to be synchronized */
while (RTC.PITSTATUS > 0) {}
/* RTC Clock Cycles 8192, Enable: disabled */
//RTC.PITCTRLA = RTC_PERIOD_CYC8192_gc | (0 << RTC_PITEN_bp);
/* RTC Clock Cycles 8192, Enable: enabled */
RTC.PITCTRLA = RTC_PERIOD_CYC8192_gc | (1 << RTC_PITEN_bp);
/* Periodic Interrupt: enabled */
RTC.PITINTCTRL = 1 << RTC_PI_bp;
}
void VREF_0_init(void){ /* Voltage reference initialization */
/* Voltage reference at 0.55V */
//VREF_CTRLA = VREF_ADC0REFSEL_0V55_gc; // why is this different in Atmel START
//VREF.CTRLA = VREF_ADC0REFSEL_0V55_gc;
}
void ADC_0_initialization(void){ /* ACD initialization */
/* 1 ADC sample */
ADC0.CTRLB = ADC_SAMPNUM_ACC1_gc;
/* CLK_PER divided by 2, internal reference and Sample Capacitance - 0 recommended if ref voltage less than 1v */
//ADC0.CTRLC = ADC_PRESC_DIV2_gc | ADC_REFSEL_INTREF_gc | 0 << ADC_SAMPCAP_bp;
/* CLK_PER divided by 2, VDD reference and Sample Capacitance reduced for high ref voltages */
ADC0.CTRLC = ADC_PRESC_DIV2_gc | ADC_REFSEL_VDDREF_gc | 1 << ADC_SAMPCAP_bp;
/* CLK_PER divided by 128, VDD reference and Sample Capacitance reduced for high ref voltages */
//ADC0.CTRLC = ADC_PRESC_DIV128_gc | ADC_REFSEL_VDDREF_gc | 1 << ADC_SAMPCAP_bp;
/* Automatic Sampling Delay Variation disabled. Sampling Delay Selection: 0x0, Delay 0 CLK_ADC cycles */
ADC0.CTRLD = 0 << ADC_ASDV_bp | 0x0 << ADC_SAMPDLY_gp | ADC_INITDLY_DLY0_gc;
/* No Window comparison*/
//ADC0.CTRLE = ADC_WINCM_NONE_gc;
/* Below Window - use to detect when it's light*/
ADC0.CTRLE = ADC_WINCM_BELOW_gc;
/* Above Window - */
//ADC0.CTRLE = ADC_WINCM_ABOVE_gc;
/* Inside Window */
//ADC0.CTRLE = ADC_WINCM_INSIDE_gc;
/* Outside Window */
//ADC0.CTRLE = ADC_WINCM_OUTSIDE_gc;
/* Start Event Input Enable: enabled */
ADC0.EVCTRL = 1 << ADC_STARTEI_bp;
/* Result Ready Interrupt Disabled, Window Comparator Interrupt Enabled */
ADC0.INTCTRL = 0 << ADC_RESRDY_bp | 1 << ADC_WCMP_bp;
/* Result Ready Interrupt Enable, Window Comparator Interrupt Disabled */
//ADC0.INTCTRL = 1 << ADC_RESRDY_bp | 0 << ADC_WCMP_bp;
/* Result Ready Interrupt Enable, Window Comparator Interrupt Enabled */
//ADC0.INTCTRL = 1 << ADC_RESRDY_bp | 1 << ADC_WCMP_bp;
/* ADC input pin 7 */
ADC0.MUXPOS = ADC_MUXPOS_AIN7_gc;
/* Sample length: 0x0 */
//ADC0.SAMPCTRL = 0b00000 << ADC_SAMPLEN_gp;
/* Sample length: 0x0 */
ADC0.SAMPCTRL = 0b11111 << ADC_SAMPLEN_gp;
/* Window Comparator High Threshold*/
//ADC0.WINHT = ADC_Window_High_Threshold;
ADC0.WINHT = ADC_Threshold_High;
/* Window Comparator Low Threshold: */
//ADC0.WINLT = ADC_Window_Low_Threshold;
ADC0.WINLT = ADC_Threshold_Low;
/* ADC Enabled, ADC Freerun mode disabled, 10-bit mode, Run standby mode enabled */
ADC0.CTRLA = 1 << ADC_ENABLE_bp | 0 << ADC_FREERUN_bp | ADC_RESSEL_10BIT_gc | 1 << ADC_RUNSTBY_bp;
}
void EVENT_SYSTEM_0_initialization(void){ /* Event initialization */
/* Set up the Asynch Event Channel 0 to be connected to Real Time Counter overflow */
EVSYS.ASYNCCH0 = EVSYS_ASYNCCH0_RTC_OVF_gc; // this works
/* ADC0 is reserved for Asynch User 1 - Asynchronous Event Channel 0 */
EVSYS.ASYNCUSER1 = EVSYS_ASYNCUSER1_ASYNCCH0_gc; // this works
/* TCBO is reserved for Asynch User 0 - Asynchronous Event Channel 0 */
EVSYS.ASYNCUSER0 = EVSYS_ASYNCUSER0_ASYNCCH0_gc;
/* Set up the Synch Event Channel 0 to be connected to TCA0 overflow */
//EVSYS.SYNCCH0 = EVSYS_SYNCCH0_TCA0_OVF_LUNF_gc;
/* TCA0 is reserved for Synch User 0 */
//EVSYS.SYNCUSER0 = EVSYS_SYNCUSER0_SYNCCH0_gc;
}
void CPUINT_init(void){ /* Interrupt initialisation */
/* Enable interrupts */
sei();
}
void SLPCTRL_init(void){ /* Sleep controller initialization*/
/* Sleep disabled, Standby Mode */
//SLPCTRL.CTRLA = 0 << SLPCTRL_SEN_bp | SLPCTRL_SMODE_STDBY_gc;
//SLPCTRL.CTRLA = 0 << SLPCTRL_SEN_bp | SLPCTRL_SMODE_PDOWN_gc;
set_sleep_mode(SLEEP_MODE_STANDBY);
//set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}
void BOD_init(void) { /* Brown Out Detection initialization */
/* The following registers have Configuration Change Protection */
//SLEEP in BOD.CTRLA
/* Brown Out Detection disabled in sleep mode */
_PROTECTED_WRITE(BOD.CTRLA, BOD_SLEEP_DIS_gc);
}
void TIMER_0_init_TCA0(void){
// TCA0.SINGLE.CMP0 = 0x0; /* Compare Register 0: 0x0 */
// TCA0.SINGLE.CMP1 = 0x0; /* Compare Register 1: 0x0 */
// TCA0.SINGLE.CMP2 = 0x0; /* Compare Register 2: 0x0 */
// TCA0.SINGLE.CNT = 0x0; /* Count: 0x0 */
// TCA0.SINGLE.CTRLB = 0 << TCA_SINGLE_ALUPD_bp /* Auto Lock Update: disabled */
// | 0 << TCA_SINGLE_CMP0EN_bp /* Compare 0 Enable: disabled */
// | 0 << TCA_SINGLE_CMP1EN_bp /* Compare 1 Enable: disabled */
// | 0 << TCA_SINGLE_CMP2EN_bp /* Compare 2 Enable: disabled */
// | TCA_SINGLE_WGMODE_NORMAL_gc; /* */
// TCA0.SINGLE.CTRLC = 0 << TCA_SINGLE_CMP0OV_bp /* Compare 0 Waveform Output Value: disabled */
// | 0 << TCA_SINGLE_CMP1OV_bp /* Compare 1 Waveform Output Value: disabled */
// | 0 << TCA_SINGLE_CMP2OV_bp; /* Compare 2 Waveform Output Value: disabled */
// TCA0.SINGLE.DBGCTRL = 0 << TCA_SINGLE_DBGRUN_bp; /* Debug Run: disabled */
/* Count on Event Input: enabled Count on positive edge event */
TCA0.SINGLE.EVCTRL = 1 << TCA_SINGLE_CNTEI_bp | TCA_SINGLE_EVACT_POSEDGE_gc;
/* Compare 0 Interrupt: disabled Compare 1 Interrupt: disabled Compare 2 Interrupt: disabled Overflow Interrupt: disabled */
//TCA0.SINGLE.INTCTRL = 0 << TCA_SINGLE_CMP0_bp | 0 << TCA_SINGLE_CMP1_bp | 0 << TCA_SINGLE_CMP2_bp | 0 << TCA_SINGLE_OVF_bp;
/* Compare 0 Interrupt: disabled, Compare 1 Interrupt: disabled, Compare 2 Interrupt: disabled, Overflow Interrupt: enabled */
TCA0.SINGLE.INTCTRL = 0 << TCA_SINGLE_CMP0_bp | 0 << TCA_SINGLE_CMP1_bp | 0 << TCA_SINGLE_CMP2_bp | 1 << TCA_SINGLE_OVF_bp;
/* Period: 0xffff */
TCA0.SINGLE.PER = TCA0_period;
/* System Clock Module Enable: enabled */
TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | 1 << TCA_SINGLE_ENABLE_bp ;
}
void TIMER_0_init_TCB0(void){
/* Asynchronous Enable: enabled, Pin Output Enable: disabled, Periodic Interrupt */
TCB0.CTRLB = 1 << TCB_ASYNC_bp | 0 << TCB_CCMPEN_bp | 0 << TCB_CCMPINIT_bp | TCB_CNTMODE_INT_gc;
// TCB0.DBGCTRL = 0 << TCB_DBGRUN_bp; /* Debug Run: disabled */
/* Event Input Enable: enabled, Event Edge: enabled, Input Capture Noise Cancellation Filter: disabled */
TCB0.EVCTRL = 1 << TCB_CAPTEI_bp | 1 << TCB_EDGE_bp | 0 << TCB_FILTER_bp;
TCB0.INTCTRL = 1 << TCB_CAPT_bp /* Capture or Timeout: enabled */;
/* CLK_PER (No Prescaling), Enable: enabled, Run Standby: enabled, Synchronize Update: disabled */
TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc | 1 << TCB_ENABLE_bp | 1 << TCB_RUNSTDBY_bp | 0 << TCB_SYNCUPD_bp;
/* CLK_PER (Divide by 2), Enable: enabled, Run Standby: enabled, Synchronize Update: disabled */
//TCB0.CTRLA = TCB_CLKSEL_CLKDIV2_gc | 1 << TCB_ENABLE_bp | 1 << TCB_RUNSTDBY_bp | 0 << TCB_SYNCUPD_bp;
TCB0.CCMP = TCB0_CCMP;
}
void system_init(){ /* system initialization */
mcu_init();
pin_init();
CLKCTRL_init();
RTC_0_init();
TIMER_0_init_TCA0();
TIMER_0_init_TCB0();
EVENT_SYSTEM_0_initialization();
VREF_0_init();
ADC_0_initialization();
SLPCTRL_init();
BOD_init();
CPUINT_init();
}
Just for completeness, here’s my Platformio.ini
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:ATtiny402]
platform = atmelmegaavr
board = ATtiny402
;framework = arduino
upload_speed = 115200
upload_flags =
--tool
uart
--device
attiny402
--uart
$UPLOAD_PORT
--clk
$UPLOAD_SPEED
upload_command = pymcuprog write --erase $UPLOAD_FLAGS --filename $SOURCE