ATtiny202 - How to start TCB in Single-Shot Mode repeatedly ?

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

I don't fully understand how to repatedly start TCB in Single-Shot Mode to generate exact pause each 500 ms.

 

The test program generate 29 us pulses instead of 78.64 ms (1/833000*65535):

 

#define F_CPU 833333

#include <atmel_start.h>
#include <util/delay.h>

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

    PORTA.DIR |= PIN1_bm;
    PORTA.OUTCLR |= PIN1_bm;

    /* Replace with your application code */
    while (1) {
        PORTA.OUTSET |= PIN1_bm;
        TCB0.CTRLA |= TCB_ENABLE_bm;
        while ((TCB0.STATUS & TCB_RUN_bm))
            ;
        TCB0.CTRLA &= ~TCB_ENABLE_bm;
        PORTA.OUTCLR |= PIN1_bm;
        _delay_ms(500);
    }
}

 

TCB init:

 

int8_t TIMER_0_init()
{

	TCB0.CCMP = 0xffff; /* Compare or Capture: 0xffff */

	// TCB0.CNT = 0x0; /* Count: 0x0 */

	TCB0.CTRLB = 0 << TCB_ASYNC_bp        /* Asynchronous Enable: disabled */
	             | 0 << TCB_CCMPEN_bp     /* Pin Output Enable: disabled */
	             | 0 << TCB_CCMPINIT_bp   /* Pin Initial State: disabled */
	             | TCB_CNTMODE_SINGLE_gc; /* Single Shot */

	TCB0.DBGCTRL = 1 << TCB_DBGRUN_bp; /* Debug Run: enabled */

	// TCB0.EVCTRL = 0 << TCB_CAPTEI_bp /* Event Input Enable: disabled */
	//		 | 0 << TCB_EDGE_bp /* Event Edge: disabled */
	//		 | 0 << TCB_FILTER_bp; /* Input Capture Noise Cancellation Filter: disabled */

	TCB0.INTCTRL = 0 << TCB_CAPT_bp /* Capture or Timeout: disabled */;

	// TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc /* CLK_PER (No Prescaling) */
	//		 | 0 << TCB_ENABLE_bp /* Enable: disabled */
	//		 | 0 << TCB_RUNSTDBY_bp /* Run Standby: disabled */
	//		 | 0 << TCB_SYNCUPD_bp; /* Synchronize Update: disabled */

	return 0;
}

 

What I am doing wrong ?

This topic has a solution.
Last Edited: Mon. Mar 29, 2021 - 01:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think you need to use an event channel to start the timer in single-shot mode.  And then I don't think you can remove the CTRLA enable disable statements in your loop.

 

EDIT:

It looks like the following at the beginning of the loop:

      EVSYS.ASYNCUSER0 = EVSYS_SYNCCH0_TCB0_gc;

 

where you have enabled input events via

    TCB0.EVCTRL = TCB0_CAPTEI_bm;

in your init routine.

Last Edited: Sun. Mar 28, 2021 - 07:50 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fixed already. It needs some time after enabling TCB, asm("nop") and reset TCB0.CNT = 0 before reenabling TCB (CNT remains at TCB0.CCMP = 5500 after counting)  

 

I need to start TCB "manually" by program.

 

Fixed code:

 

#define F_CPU 833333

#include <atmel_start.h>
#include <util/delay.h>

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

    PORTA.DIR |= PIN1_bm;
    PORTA.OUTCLR |= PIN1_bm;

    /* Replace with your application code */
    while (1) {
        PORTA.OUTSET |= PIN1_bm;
        TCB0.CTRLA |= TCB_ENABLE_bm;
        
        asm("nop");
        
        while ((TCB0.STATUS & TCB_RUN_bm))
            ;
        TCB0.CTRLA &= ~TCB_ENABLE_bm;
        TCB0.CNT = 0;
        PORTA.OUTCLR |= PIN1_bm;
        _delay_ms(500);
    }
}

 

 

 

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

Did you read the datasheet?  The way you are using it doesn't seem consistent with the intent I read in the datasheet.

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

Yes, maybe. The problem with the datasheet is that it does not answer all your questions, that you may have. But if you have a deep technical knowledge and right equipment (oscilloscope) you can test it and find out how to fix the problem.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
    PORTA.DIR |= PIN1_bm;
    PORTA.OUTCLR |= PIN1_bm;

 

Not related, but you are defeating the purpose of the SET/CLR registers in a number of places (and missing that DIRSET is also available). These require the use of only = to get an atomic write to a specific bit or bits. When you do |= you are getting more information than you bargained for (pin information you do not need/want), and potentially corrupt the register which the SET/CLR registers were created to avoid. You want specific bit(s) set/cleared, and all the others can be written as 0 so as not to touch them, therefore the = only.

 

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

Thank you for your advice, you are right with PORTA.OUTCLR = PIN1_bm. I was using PORTA.OUT |= PIN1_bm previously so it was a little overkilled wink.