9 Getting Started with TCB

9 Introduction

Author: Marius Nicolae, Microchip Technology Inc.

The tinyAVR® 0- and 1-series, megaAVR® 0-series, and AVR® DA-series of microcontrollers are equipped with powerful timers that enable them to cover a wide area of applications. Timer/Counter type B (TCB) offers a variety of features and operation modes, from periodic interrupts to 8-bit PWM or time-out. The various operation modes of the TCB can be used in correlation with the event system. The scope of this technical brief is to show the configuration of three operation modes.

  • Using TCB in 8-bit PWM mode:

    TCB will be configured in this mode and will generate a PWM signal with a 50% duty cycle with a period of one second. A GPIO pin will be used as an output to showcase the signal.

  • Using TCB in Time-Out Check mode:

    TCB will be configured in this mode and will be used to measure the signal time (edge-to-edge) generated by a GPIO pin configured as an input. An interrupt will be generated if the time-out (the period from edge-to-edge) expires.

  • Using TCB in sleep mode:

    TCB will be configured to generate a periodic interrupt, even when the AVR® microcontroller is in Standby sleep mode.

Note: For each of the use cases described in this document, there are two code examples: One bare metal developed on ATmega4809, and one generated with MPLAB® Code Configurator (MCC) developed on AVR128DA48.

9.1 Overview

The capabilities of the 16-bit Timer/Counter type B (TCB) include frequency, waveform generation, and input capture on an event with time and frequency measurement of the digital signals. The TCB consists of a base counter and a control logic that can be set in one of the eight different modes, each mode providing unique functionality. The base counter is clocked by the peripheral clock with optional prescaling, as shown below.

Figure 9-103. Timer/Counter Type B Block Diagram

9.2 Using TCB in 8-Bit PWM Mode

Use case description: TCB (the TCB3 instance) will be configured in 8-bit PWM mode and generate a one second period PWM signal, at a 50% duty cycle. A GPIO pin (Port B pin 5 - PB5) will be used as an output to showcase the signal.

Result: TCB will generate a 50% duty cycle PWM signal with a period of one second. The on-board LED (the PB5 pin) will toggle every 500 ms.

This timer can be configured to run in 8-bit PWM mode where each of the register pairs in the 16-bit Capture/Compare register (TCBn.CCMPH and TCBn.CCMPL) is used as an individual Compare register. The counter will continuously count from zero to CCMPL and the output will be set at BOTTOM and cleared when the counter reaches CCMPH.

When this peripheral is in PWM mode and enabled, changing the value of the Capture/Compare register will change the output, but the transition may render invalid values. It is hence recommended to:
  1. Disable the peripheral.
  2. Write Capture/Compare register to {CCMPH, CCMPL}.
  3. Write 0x0000 to the Count register.
  4. Re-enable the module.
CCMPH is the number of cycles for which the output will be driven high, while CCMPL+1 is the period of the output pulse.
Figure 9-104. 8-Bit PWM Mode

For example, for a 256 Hz frequency clock that serves as input to the timer, the result is a period of one second (CCMPL is an 8-bit register, which means it can have values from 0 to 255).

Configuring a Pin as Output for Visualizing the PWM Signal

To visualize the PWM, a pin will be configured in the Output mode. The following code sets PB5 as output low.

PORTB_DIR |= PIN5_bm;
PORTB_OUT |= PIN5_bm;

Configuring the System Clock

According to the diagram in Figure 9-103, there are two main clock sources for TCB:
  • CLK_PER (the peripheral clock, derived from main clock CLK_MAIN)
  • CLK_TCA (the TCA clock, which can be derived from CLK_PER)
For this use case of TCB, the CLK_PER clock source and instance 3 of TCB will be used (TCB3). To get a period of one second, the input clock must be as low as possible. The following configuration must be made:
  • Internal 32 kHz ultra-low power oscillator for CLKSEL must be selected
  • The clock prescaler (PEN) must be enabled
  • The highest prescaler division (PDIV 64) must be used

To use the 32 kHz internal oscillator as the clock source for TCB, the user must configure the following registers and bits or bit fields in the following register.

Figure 9-105. MCLKCTRLB Register Configuration

The Main Clock and Prescaler Configuration (CLKCTRL.MCLKCTRLA, CLKCTRL.MCLKCTRLB) registers are protected by the Configuration Change Protection (CCP) mechanism, employing a timed-write procedure for changing these registers. To write to these registers, a certain key must be written to the CPU.CCP register first, followed by a write access to the protected bits within four CPU instructions.

Since the desired frequency is the lowest possible, the Prescaler (PEN) must be enabled and PDIV must be set to ‘64’ divider.

The key that must be written to the CPU.CPP register is IOREG. For more details, check the Configuration Change Protection (CCP) section in the megaAVR 0-series family data sheet.

Writing to a protected register is done by using the ccp_write_io function, which translates into the line of code from below for enabling the ‘64’ prescaler divider.

Note: To use the ccp_write_io function, the avr/cpufunc.h header file must be included.
ccp_write_io((void *) &(CLKCTRL.MCLKCTRLB), (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm));
Figure 9-106. MCLKCTRLA Register Configuration

OSCULP32K must be selected, which means the CLKSEL bit field must be set to the value 0x1. This translates into the following code.

ccp_write_io((void *) &(CLKCTRL.MCLKCTRLA) , (CLKCTRL_CLKSEL_OSCULP32K_gc));
Figure 9-107. MCLKSTATUS Register Configuration

The clock switching process is indicated by the SOSC bit. The program must halt during an undergoing switch of the clock source, so a wait until the switch is over will be implemented:

while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm)
{
    ;
}

Configuring the TCB Input Clock and Operation Mode

To generate the 8-bit PWM signal to PB5, the following registers must be changed:
  • TCBn.CCMP
  • TCBn.CTRLA
  • TCBn.CTRLB

The TCBn.CCMPL and TCBn.CCMPH register pair represents the 16-bit value TCBn.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. In 8-bit PWM mode, TCBn.CCMPL and TCBn.CCMPH act as two independent registers.

Figure 9-108. TCBn.CCMP Register Configuration

When running TCB in 8-bit PWM mode, TCBn.CCMPL must be loaded with the PWM signal period, of one second in this case. Since the period of the output pulse is defined by TCBn.CCMPL+1, the value that must be loaded into the TCBn.CCMPL register is 0xFF (255 in decimal).

Subsequently, TCBn.CCMPH must be loaded with the number of cycles for which the output will be driven high. The goal is to set the duty cycle at 50% to make PB5 toggle every 500 ms.

C C M P H = ( C C M P L + 1 ) × 50 100 C C M P H = 128 This results in TCBn.CCMPH = 128 = 0x80

This means that TCBn.CCMP must be loaded with the following value, obtained from TCBn.CCMPH and TCBn.CCMPL:

TCB3.CCMP = 0x80FF;
Figure 9-109. TCBn.CTRLA Register Configuration

TCB3 can be enabled by setting the ENABLE bit to ‘1’ in the TCB3.CTRLA register. This translates into the following code.

TCB3.CTRLA |= TCB_ENABLE_bm;

To get the lowest possible frequency, CLK_PER will be further divided by 2, by configuring the CLKSEL bit field in the TCB3.CTRLA register. The corresponding value for CLKSEL, in this case, is 0x1. This translates into the following code.

TCB3.CTRLA |= TCB_CLKSEL_CLKDIV2_gc;
Figure 9-110. TCBn.CTRLB Register Description

CCMPEN must be enabled. This translates into the following code.

TCB3.CTRLB |= TCB_CCMPEN_bm;

TCB must be configured for the 8-bit PWM mode. This translates into the following code.

TCB3.CTRLB |= TCB_CNTMODE_PWM8_gc;
Tip: The full code example is also available in the Appendix section.

An MCC generated code example for AVR128DA48, with the same functionality as the one described in this section, can be found here:

9.3 Using TCB in Time-Out Check Mode

Use case description: Configure TCB in Time-Out Check mode and measure the signal time generated by a GPIO (configured as an input). The time-out will be set to one second and the event system will be used to detect the rising and falling edges of the signal generated by a GPIO (e.g., a push button in a real application). If the time-out expires, another GPIO (e.g., an LED in a real application) will be toggled in the interrupt.

Result: Use a GPIO as input to generate an event that serves as the input signal for TCB. Generate an interrupt when the time-out expires.

In the Time-Out Check mode, TCB relies on the interaction with the event system, as displayed in the figure below. In this mode, the counter counts to MAX and wraps around. On the first edge, the counter is restarted. On the second edge, the counter is stopped. If the Count (TCBn.CNT) register reaches TOP before the second edge, an interrupt will be generated. In the Freeze state, the counter will restart on a new edge. Reading count (TCBn.CNT) or the Capture/Compare (TCBn.CCMP) register, or writing the RUN bit (RUN in TCBn.STATUS) in Freeze state will have no effect.

Figure 9-111. Time-Out Check Mode

Configuring the System Clock

To obtain a period of one second for the 16-bit TCB timer, the input frequency must be as low as possible. For this, the internal 32 kHz oscillator can be used. There is no need to use a frequency divider, so the prescaler for CLK_PER must be disabled. There are three steps in the configuration process:

  1. Disable the CLK_PER prescaler - The following code snippet will demonstrate how to disable the CLK_PER prescaler.
    ccp_write_io( (void *) &CLKCTRL.MCLKCTRLB , (0 << CLKCTRL_PEN_bp));
  2. Select the internal 32 kHz oscillator - The following code snippet will switch the system clock source to the internal 32 kHz oscillator.
    ccp_write_io( (void *) &CLKCTRL.MCLKCTRLA , (CLKCTRL_CLKSEL_OSCULP32K_gc));
  3. Wait for the clock switch process to complete - The following code snippet will demonstrate how to wait for the clock source switching process to finish.
    while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm)
    {
        ;
    }
Note:
  1. Writing to the MCLKCTRLA and MCLKCTRLB registers requires the IOREG key to be written to the CPU.CCP register. This is done by using the ccp_write_io function from the avr/cpufunc.h header file.
  2. The Clock Control registers are described in 9.2 Using TCB in 8-Bit PWM Mode.

Configuring TCB in Time-Out Check Mode

To generate a signal using a GPIO pin, the event system must be set up accordingly. Port B Pin 2 (PB2) will be used as an example in this document.

The following registers must be configured:

  • TCB0.CCMP
  • TCBn.INTCTRL
  • TCBn.EVCTRL
  • EVSYS.CHANNEL
  • EVSYS.USER
  1. TCB0.CCMP Configuration

    The TCB Capture/Compare register must be loaded with the value of the time-out. For this document, a value of one second for the time-out has been chosen. With an input frequency of 32.768 kHz, the 16-bit counter will make a complete cycle in two seconds (the maximum value of a 16-bit number is 65535).

    The reload value of TCB0.CCMP can be calculated, as shown below:

    C C M P = C N T max 2 C C M P = 65535 2 C C M P = 32767.5

    A value of 32767.5 cannot be translated into hex, so 32767 will be used instead.

    C C M P = 32767.5 = 32767 = 0 × 7 F F F

    The following code snippet will load TCB0.CCMP with 0x7FFF time-out value.

    TCB0.CCMP = 0x7fff;
  2. TCBn.INTCTRL Configuration
    Figure 9-112. TCBn.INTCTRL Register Configuration

    TCB0.CNT will start increasing as soon as a signal edge is detected on the event system bus. If the complementary edge of the signal is not detected within the time-out, TCB0 will trigger an interrupt. In this regard, capture or time-out interrupt must be enabled in the TCB0.INCTRL register. The following code snippet enables the interrupt.

    TCB0.INTCTRL = TCB_CAPT_bm;
    Note: The global interrupts must also be enabled. This can be done at a later step in the software program.
  3. TCBn.EVCTRL Configuration
    Figure 9-113. TCBn.EVCTRL Register Configuration

    The target is to measure the signal time between the falling edge and the rising edge of the PB2 input pin (in Idle, the pin is kept in high state). This means both CAPTEI and EDGE bits must be set to ‘1’. The following code snippet enables both bits in the TCB0.EVCTRL register.

    TCB0.EVCTRL = TCB_CAPTEI_bm | TCB_EDGE_bm;
  4. EVSYS.CHANNEL Configuration

    Each channel can be connected to a one-event generator. Not all generators can be connected to all channels. Refer to the table below to see which generator sources can be routed onto each channel and the generator value that must be written to EVSYS.CHANNELn to achieve this routing. The value 0x00 in EVSYS.CHANNELn turns the channel off.

    Figure 9-114. EVSYS.CHANNEL Register Configuration

    EVSYS.CHANNEL must be loaded with the value 0x4A for PB2 to generate an input event, as represented in the following code snippet.

    EVSYS.CHANNEL0 = EVSYS_GENERATOR_PORT1_PIN2_gc;
  5. EVSYS.USER Configuration

    Each event user can be connected to one channel. Several users can be connected to the same channel. The following table lists all event system users, with their corresponding user ID number. This ID number corresponds to the USER register index, e.g., the user with ID 2 is controlled by the EVSYS.USER2 register.

    Figure 9-115. EVSYS.USERTCB0 Register Configuration

    The user channel must be linked to the event channel already configured previously (in EVSYS.CHANNEL). The following code snippet illustrates how this can be done.

    EVSYS.USERTCB0 = EVSYS_CHANNEL_CHANNEL0_gc;
Tip: The full code example is also available in the Appendix section.

An MCC generated code example for AVR128DA48, with the same functionality as the one described in this section, can be found here:

9.4 Using TCB in Sleep Mode

Use case description: Configure TCB to generate an overflow interrupt every second, even when the microcontroller is in Standby sleep mode, and toggle a GPIO pin (PB5).

Result: TCB overflow interrupt will be triggered every one second, regardless of the running mode of the microcontroller (Idle/Standby). In the Interrupt Service Routine (ISR), the on-board LED, corresponding to PB5, will be toggled.

TCBn is by default disabled in Standby sleep mode; as soon as the microcontroller enters sleep mode, TCB will be halted. The module can stay fully operational in Standby sleep mode if the Run In Standby (RUNSTDBY) bit in the TCBn.CTRLA register is written to ‘1’.

Configuring the System Clock for Sleep Mode

To obtain an interrupt of one second for the 16-bit TCB timer, the input frequency must be as low as possible. For this, the internal 32 kHz oscillator can be used. There is no need to use a frequency divider, so the prescaler for CLK_PER must be disabled. There are three steps in the configuration process:

  1. Disable the CLK_PER prescaler - The following code snippet will demonstrate how to disable the CLK_PER prescaler.
    ccp_write_io( (void *) &CLKCTRL.MCLKCTRLB , (0 << CLKCTRL_PEN_bp)); 
  2. Select the internal 32 kHz oscillator - The following code snippet will switch the system clock source to the internal 32 kHz oscillator.
    ccp_write_io( (void *) &CLKCTRL.MCLKCTRLA, (CLKCTRL_CLKSEL_OSCULP32K_gc));
  3. Wait for the clock switch process to complete - The following code snippet will demonstrate how to wait for the clock source switching process to finish.
    while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm)
    {
        ;
    }
    

Configuring the Sleep Mode Operation

Sleep modes are used to shut down peripherals and clock domains in the device to save power. The Sleep Controller (SLPCTRL) controls and handles the transitions between Active and sleep mode. Four modes are available: One Active mode in which software is executed and three sleep modes. The available sleep modes are Idle, Standby, and Power-Down.

The interrupts are used to wake the device from sleep. The available interrupt wake-up sources depend on the configured sleep mode. When an interrupt occurs, the device will wake up and execute the interrupt service routine before continuing normal program execution from the first instruction following the SLEEP instruction.
Figure 9-116. SLPCTRL.CTRLA Register

The TCB module can run while the microcontroller is in Standby sleep mode. The Power-Down sleep mode disables TCB completely.

For this use case, the ATmega4809 microcontroller will be configured to enter sleep in Standby sleep mode. Entering sleep must also be enabled. The following code enables the sleep operation and configures the ATmega4809 microcontroller to enter Standby sleep mode when the SLEEP instruction is executed.
SLPCTRL.CTRLA = SLPCTRL_SMODE_gm | SLPCTRL_SMODE_STDBY_gc;

Configuring TCB in Periodic Interrupt Mode

The following configuration must be made to the registers:
  • TCBn.CCMP
  • TCBn.CTRLA

The TCB Capture/Compare register must be loaded with a comparison value which will trigger an interrupt. For this document, a value of one second for the periodic interrupt has been chosen. With an input frequency of 32.768 kHz, the 16-bit counter will make a complete cycle in two seconds (the maximum value of a 16-bit number is 65535). Since the maximum value the 16-bit TCB counter can achieve is 65535 for the two seconds maximum period, the CCMP register must be loaded with half of the maximum value – 32768 (0x7FFF). The following code snippet loads the TCB0.CCMP register with 0x7FFF.

TCB0.CCMP = 0x7fff; 
Figure 9-117. TCBn.CTRLA Register Configuration

Prescaling is not needed, so the divider value will be ‘0’. Also, the timer must be enabled. For the TCB to still generate an interrupt while in Standby sleep mode, the RUNSTDBY bit must also be enabled. The following code snippet sets the clock divider to ‘0’, enables the timer, and allows the timer to run in Standby sleep mode.

TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc | TCB_ENABLE_bm | TCB_RUNSTDBY_bm;

To trigger a periodic interrupt, the CAPT bit of the TCB0.INTCTRL register must be enabled. The following code snippet enables the interrupt.

TCB0.INTCTRL = TCB_CAPT_bm;
Note:
  1. The global interrupts must be also enabled. This can be done at a later step in the software program.
  2. All operations are halted in Power-Down sleep mode.

Configuring a Pin as Output for Visualizing Interrupt Occurrence

To visualize the periodic interrupt occurrence, the PB5 pin will be configured in Output mode. The following code sets PB5 as output low.

PORTB_DIR |= PIN5_bm;
PORTB_OUT |= PIN5_bm;
Tip: The full code example is also available in the Appendix section.

An MCC generated code example for AVR128DA48, with the same functionality as the one described in this section, can be found here:

9.5 References

9.6 Appendix

TCB 8-Bit PWM Mode Code Example

#include <avr/io.h>

#define TCB_CMP_EXAMPLE_VALUE   (0x80FF)

void CLOCK_init (void);
void PORT_init (void);
void TCB3_init (void);

void CLOCK_init (void)
{
    /* Enable Prescaler and set Prescaler Division to 64 */
    ccp_write_io((void *) &(CLKCTRL.MCLKCTRLB), (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm));
    
    /* Select 32KHz Internal Ultra Low Power Oscillator (OSCULP32K) */
    ccp_write_io((void *) &(CLKCTRL.MCLKCTRLA) , (CLKCTRL_CLKSEL_OSCULP32K_gc));

    /* Wait for system oscillator changing to finish */
    while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm)
    {
        ;
    }
}

void PORT_init (void)
{
    PORTB_DIR |= PIN5_bm;
    PORTB_OUT |= PIN5_bm;
}

void TCB3_init (void)
{
    /* Load CCMP register with the period and duty cycle of the PWM */
    TCB3.CCMP = TCB_CMP_EXAMPLE_VALUE;

    /* Enable TCB3 and Divide CLK_PER by 2 */
    TCB3.CTRLA |= TCB_ENABLE_bm;
    TCB3.CTRLA |= TCB_CLKSEL_CLKDIV2_gc;
    
    /* Enable Pin Output and configure TCB in 8-bit PWM mode */
    TCB3.CTRLB |= TCB_CCMPEN_bm;
    TCB3.CTRLB |= TCB_CNTMODE_PWM8_gc;
}

int main(void)
{
    CLOCK_init();
    PORT_init();
    TCB3_init();
    
    while (1)
    {
        ;
    }
}

TCB Time-Out Check Mode Code Example

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

void CLOCK_init (void);
void PORT_init (void);
void EVENT_SYSTEM_init (void);
void TCB0_init (void);

void CLOCK_init (void)
{
    /* Disable CLK_PER Prescaler */
    ccp_write_io( (void *) &CLKCTRL.MCLKCTRLB , (0 << CLKCTRL_PEN_bp));
    
    /* Select 32KHz Internal Ultra Low Power Oscillator (OSCULP32K) */
    ccp_write_io( (void *) &CLKCTRL.MCLKCTRLA , (CLKCTRL_CLKSEL_OSCULP32K_gc));
   
    /* Wait for system oscillator changing to finish */
    while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm)
    {
        ;
    }
}

void PORT_init (void)
{
    PORTB.DIR |= PIN5_bm;  /* Configure PB5 as digital output */
    PORTB.OUT |= PIN5_bm;  /* Set initial level of PB5 */
    PORTB.DIR &= ~PIN2_bm; /* Configure PB2 as digital input */
    PORTB.PIN2CTRL = PORT_PULLUPEN_bm; /* Enable the internal pullup */
}

void EVENT_SYSTEM_init (void)
{
    EVSYS.CHANNEL0 = EVSYS_GENERATOR_PORT1_PIN2_gc; /* Set Port 1 Pin 2 (PB2) as input event*/
    EVSYS.USERTCB0 = EVSYS_CHANNEL_CHANNEL0_gc; /* Connect user to event channel 0 */
}

void TCB0_init (void)
{
    /* Load the Compare or Capture register with the timeout value*/
    TCB0.CCMP = 0x7fff;
    
    /* Enable TCB and set CLK_PER divider to 1 (No Prescaling) */
    TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc | TCB_ENABLE_bm;
    
    /* Configure TCB in Periodic Timeout mode */
    TCB0.CTRLB = TCB_CNTMODE_TIMEOUT_gc;
    
    /* Enable Capture or Timeout interrupt */
    TCB0.INTCTRL = TCB_CAPT_bm;
    
    /* Enable Event Input and Event Edge*/
    TCB0.EVCTRL = TCB_CAPTEI_bm | TCB_EDGE_bm;
}

ISR(TCB0_INT_vect)
{
    TCB0.INTFLAGS = TCB_CAPT_bm; /* Clear the interrupt flag */
    PORTB.IN = PIN5_bm; /* Toggle PB5 GPIO */
}

int main(void)
{
    CLOCK_init();
    PORT_init();
    EVENT_SYSTEM_init();
    TCB0_init();

    sei(); /* Enable Global Interrupts */
    
    while (1)
    {
        ;
    }        
}

TCB Sleep Mode Operation Code Example

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

#define TCB_CMP_EXAMPLE_VALUE   (0x7fff)

void CLOCK_init (void);
void SLPCTRL_init (void);
void PORT_init (void);
void TCB0_init (void);

void CLOCK_init (void)
{
    /* Disable CLK_PER Prescaler */
    ccp_write_io( (void *) &CLKCTRL.MCLKCTRLB , (0 << CLKCTRL_PEN_bp));  
    
    /* Select 32KHz Internal Ultra Low Power Oscillator (OSCULP32K) */
    ccp_write_io( (void *) &CLKCTRL.MCLKCTRLA, (CLKCTRL_CLKSEL_OSCULP32K_gc));
    
    /* Wait for system oscillator changing to finish */
    while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm)
    {
        ;
    }
}

void SLPCTRL_init (void)
{
    /* Enable sleep mode and select Standby mode */
    SLPCTRL.CTRLA = SLPCTRL_SMODE_gm | SLPCTRL_SMODE_STDBY_gc;
}

void PORT_init (void)
{
    PORTB.DIR |= PIN5_bm; /* Configure PB5 as digital output */
    PORTB.OUT |= PIN5_bm; /* Set initial level of PB5 */
}

void TCB0_init (void)
{
    /* Load the Compare or Capture register with the timeout value*/
    TCB0.CCMP = TCB_CMP_EXAMPLE_VALUE;
   
    /* Enable TCB and set CLK_PER divider to 1 (No Prescaling) */
    TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc | TCB_ENABLE_bm | TCB_RUNSTDBY_bm;
    
    /* Enable Capture or Timeout interrupt */
    TCB0.INTCTRL = TCB_CAPT_bm;
}

ISR(TCB0_INT_vect)
{
    TCB0.INTFLAGS = TCB_CAPT_bm; /* Clear the interrupt flag */
    PORTB.IN = PIN5_bm; /* Toggle PB5 GPIO */
}

int main(void)
{
    CLOCK_init();
    SLPCTRL_init();
    PORT_init();
    TCB0_init();
    
    sei(); /* Enable Global Interrupts */
    
    while (1)
    {   
        sleep_mode();
    }
}