[SOLVED] ATtiny402 TCB0 - aiming for "single shot" on WO but can't get anything on PA6/7/1/2/3

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

Hi,

 

I'm still new to much of this, so please guide me on posting if I need it. 

Aim: I'm trying to create a low power LED driving gadget. The driver is a simple MOSFET/Inductor, driven by a microcontroller. I know this could be done by many uCs other than the 402 but I'm using this as I have had some success with it on other functions and am using it as a vehicle to learn more about AVRs and the 0/1 series tiny devices in general. To drive the LED, I need the uC to drive the MOSFET with a short pulse, wait for the inductor to discharge current through the LEDs and then when the inductor voltage drops, to drive the MOSFET again. The voltage source varies wildly with discharge of the store, so the pulse length of the MOSFET has to be adjustable. 

 

Approach: I realise that there may be other ways of generating these pulses dynamically, but it looks like the single shot TCB0 connected to the Waveform Output pin (if it exists) would be good. I might even be able to use Event System to detect the fall in voltage at the inductor terminal and trigger the next pulse before the inductor's ringing kicks in and the voltage rises again (can attach SPICE trace if really necessary but I hope it's not required).

 

Initially I tried doing everything at once, because sometimes you get lucky that way. I have gradually stripped back functions and I am still unable to get any TCB0 output on W0. I realise that there are other threads on here that show the datasheets etc for these new 0 series uCs are woefully confusing but I would really appreciate a sanity check on my test code, as well as any insights into the 0 series discoverys that others may be making. I'm willing to try stuff on my 402 if it will help others work through issues with the datasheet etc. I also note that many people just "give up" and switch to TCA0. This doesn't appear to have the single shot mode so I would prefer to try and keep learning about TCB0 and hopefully get that working. If we can improve the known operation of TCB0, I think it would be a good thing to share for the benefit of others. If you are reading this and getting frustrated that I'm not using "a more appropriate chip", my apologies but I hope you understand that I am trying to learn and help others by persisting with this.

 

This is my "stripped down" code, attempting to export the TCB0 output to any pin so I can pick it up with my oscilloscope. I have managed to program this 402 with non-TCB0 code both in AS7 and the Arduino IDE using the new megaTinyCore from Spence Konde. I have also managed to get pins operating with interrupts from TCB0 using the Arduino IDE too. However, the conversion from interrupts to the waveform output has eluded me and would be needed for the application I'm working on:

#ifndef F_CPU
#define F_CPU 3300000UL // 20 MHz clock speed / 6 prescaler
#endif

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

int main(void)
{
/* This first step is to ensure we have correct clock settings
 * as we may have changed the clock source, frequency or prescaler 
 * in a previously uploaded program */    
/* Set the Main clock to internal 20MHz oscillator*/
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSC20M_gc);

/* Set the Main clock division factor to 6X and keep the Main clock prescaler enabled. */
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_6X_gc | CLKCTRL_PEN_bm);    
    
    PORTMUX_CTRLD = 1 << PORTMUX_TCB0_bm;    
       TCB0.CCMP = 0x7FFF; /* Compare or Capture: 0x0 */
       // TCB0.CNT = 0x0; /* Count: 0x0 */
       TCB0.CTRLB = 0 << TCB_ASYNC_bp /* Asynchronous Enable: disabled */
       | 1 << TCB_CCMPEN_bp /* Pin Output Enable: enabled */
       //     | 0 << TCB_CCMPINIT_bp /* Pin Initial State: disabled */
       | TCB_CNTMODE_INT_gc; /* Periodic Interrupt */
       // TCB0.DBGCTRL = 0 << TCB_DBGRUN_bp; /* Debug Run: disabled */
       // 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 = 1 << TCB_CAPT_bp; /* Capture or Timeout: enabled */
       TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc /* CLK_PER (No Prescaling) */
       | 1 << TCB_ENABLE_bp; /* Enable: enabled */
       //     | 0 << TCB_RUNSTDBY_bp /* Run Standby: disabled */
       //     | 0 << TCB_SYNCUPD_bp; /* Synchronize Update: disabled */
      
       PORTA.DIRSET = PIN6_bm; // initialize digital pin as an output. This is the datasheet-identified WO pin
       PORTA.DIRSET = PIN7_bm; // initialize digital pin as an output. Just in case it's actually this one!
       PORTA.DIRSET = PIN1_bm; // initialize digital pin as an output. Just in case!
       PORTA.DIRSET = PIN2_bm; // initialize digital pin as an output. Just in case!
       PORTA.DIRSET = PIN3_bm; // initialize digital pin as an output. Just in case
       sei();
       
    while (1) 
    {
        PORTA.OUTSET = PIN6_bm;
    }
}

In AS7 I get no compile warnings or errors but the LED (checked with oscilloscope) at PA6 never comes on and all other pins are held at GND. When I comment out all the timer register stuff, we get light on PA6. Which might not mean much but is probably worth saying.

I have also tried without the PORTMUX_CTRLD term but figured it would be worth a try, based on some of the other threads noting the absence of PORTMUX CTRLD in the datasheet but present in the AS device pack.

 

As I said, please let me know what else you would want to know/see before helping me. Thanks

 

This topic has a solution.
Last Edited: Wed. Jul 17, 2019 - 01:04 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Been there, done that cheeky. The only timer B modes that actually output an I/O signal are "single shot" and "8 bit PWM". The other modes will just continuously output whatever is in the CCMPINIT bit.

This may not be entirely obvious from the datasheet, but notice the figures illustrating the modes: only the above mentioned show an output trace.

See also table 21-3.

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

notice the figures illustrating the modes:

I did - but DIDN'T read that into it! Thanks for confirming that I needn't waste my time with periodic interrupt. Forgive me but I'm going to have a crack now and post my code back here when it doesn't work! Any thoughts on what to use as the easiest source for triggering the "single shot" for testing?

Last Edited: Tue. Jul 16, 2019 - 11:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The timer can retrigger itself via the event system, see the code by kabasan here (post #1): https://www.avrfreaks.net/commen...

Later in that thread (post #9) I triggered timer B with the PIT (sample code also provided).

 

 

edit:

now I remember that kabasan uses a different timer B1 to tigger B0 but I think it can trigger itself... testing is needed.

Also note that the code provided is for Mega AVR-0 which is a bit different, because the I/O is taken over by the timer automatically (you don't need to set the pins as outputs).

But on the tiny you do need to set pins as output. Anyway, I think you can adapt the code easily.

 

Last Edited: Tue. Jul 16, 2019 - 11:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

El Tangas wrote:
(sample code also provided).

Thank you!

 

I have a question about the event_init(). AS7 doesn't recognise several of the terms in there, (because the project is for the 402 target?), so does this look like a sensible replacement?

void event_init() {
	EVSYS.CHANNEL1 = EVSYS_GENERATOR_RTC_PIT3_gc; 
	EVSYS.USERTCB0 = EVSYS_CHANNEL_CHANNEL1_gc; 
	EVSYS.USEREVOUTB = EVSYS_CHANNEL_CHANNEL1_gc;
}

// CHANGE TO:

void event_init() {	
	EVSYS.ASYNCCH0 = EVSYS_ASYNCCH0_RTC_CMP_gc;
	EVSYS.ASYNCUSER0 = EVSYS_ASYNCCH0;
}

I need to get a grip on the event system if I want to use a voltage controlled-reset for the single shot timer.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Edit 18 Jul 19: My setup was wrong for using the other pins as outputs - specifically turning on the interrupt in TCB0 but not setting an ISR to clear the flags... Commented out now. Can confirm sei() is not needed (TCB0 is outputting on the pin without relying on interrupts)

Edit 17 Jul 19: I have tested without the PORTMUX_CTRLD line and it appears to work the same, so I have now commented it out. This obviously is ATtiny402/202-specific.

 

So I tried to get the GPIO event system input working first, as neither looked obvious to me and I want to move towards GPIO triggers. I got it working! Here's the code that worked for me in AS7 on the tiny402. There are some TODO tests in there to see if elements are redundant (probably are).

#ifndef F_CPU
#define F_CPU 3300000UL // 20 MHz clock speed / 6 prescaler
#endif

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

int main(void)
{
/* This first step is to ensure we have correct clock settings
 * as we may have changed the clock source, frequency or prescaler
 * in a previously uploaded program */
/* Set the Main clock to internal 20MHz oscillator*/
	_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSC20M_gc);

/* Set the Main clock division factor to 6X and keep the Main clock prescaler enabled. */
	_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_6X_gc | CLKCTRL_PEN_bm);	

	//PORTMUX_CTRLD = 1 << PORTMUX_TCB0_bm;	// TODO: test if redundant UPDATE: tested and appears redundant, so now commented out.

       //TCB0.CCMP = 0x7FFF; /* Compare or Capture: 0x0 */
	   TCB0.CCMP = 0x0001; /* Compare or Capture: 0x0 */
       // TCB0.CNT = 0x0; /* Count: 0x0 */
       TCB0.CTRLB = 0 << TCB_ASYNC_bp /* Asynchronous Enable: disabled */
       | 1 << TCB_CCMPEN_bp /* Pin Output Enable: enabled */
       //     | 0 << TCB_CCMPINIT_bp /* Pin Initial State: disabled */
       | TCB_CNTMODE_SINGLE_gc; /* Single shot */
       // TCB0.DBGCTRL = 0 << TCB_DBGRUN_bp; /* Debug Run: disabled */
        TCB0.EVCTRL = 1 << TCB_CAPTEI_bp; /* Event Input Enable: enabled */
       //     | 0 << TCB_EDGE_bp /* Event Edge: disabled */
       //     | 0 << TCB_FILTER_bp; /* Input Capture Noise Cancellation Filter: disabled */
       //TCB0.INTCTRL = 1 << TCB_CAPT_bp; /* Capture or Timeout: enabled */
       TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc /* CLK_PER (No Prescaling) */
       | 1 << TCB_ENABLE_bp; /* Enable: enabled */
       //     | 0 << TCB_RUNSTDBY_bp /* Run Standby: disabled */
       //     | 0 << TCB_SYNCUPD_bp; /* Synchronize Update: disabled */

	   EVSYS.ASYNCUSER0 = EVSYS_ASYNCUSER0_ASYNCCH0_gc;	//enable TCB0 input to take channel 0
       EVSYS.ASYNCCH0 = EVSYS_ASYNCCH0_PORTA_PIN7_gc;	//enable event sys to take PA7 logig edge as an input 

       PORTA.DIRSET = PIN6_bm;	// initialize digital pin as an output.
	   PORTA.DIRCLR = PIN7_bm;	// initialize digital pin as an input.
	   PORTA.PIN7CTRL = 1 << 3; // and set PULLUPEN bit in PINCTRL register
	   PORTA.DIRSET = PIN1_bm;	// initialize digital pin as an output.
	   PORTA.DIRSET = PIN2_bm;	// initialize digital pin as an output.
	   PORTA.DIRSET = PIN3_bm;	// initialize digital pin as an output.
       //sei();					// enable interrupts (just in case - TODO: test if redundant)

    while (1)
    {

    }
}

This was tested with an LED and current limiting resistor on PA6, connected to the oscilloscope probe. PA7 is pulled up internally. I tried this without the pullup code and the floating input seems to be the cause of apparent constant resets of the single shot timer, to the extent that it just looks like a periodic interrupt. Once the PULLUPEN bit went in, everything calmed down and I only got pulses when I toggled the voltage on PA7 with a jumper wire. Because my pulses were so fast, I got a couple of bounce pulses too, so I couldn't be sure if we were getting only rising edge triggers or both rising and falling.

 

At the main clock speed of 3.3MHz, this code achieved a pulse of 600nS for a TCB0.CCMP = 0x0001. Adding ones to that increases the pulse duration by 300nS, which I'm very happy with! I may even be able to get my application down to 1MHz. Thanks again to El Tangas - I'm sure I'll be back, especially if I find some more code which works on the 402s.

Last Edited: Thu. Jul 18, 2019 - 07:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

probably late, but this is for a tiny416-

https://github.com/cv007/ATTiny416XplainedNano/blob/master/tcb0-singleshot-test.cpp

100us pulse every second

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

curtvm wrote:
probably late, but this is for a tiny416-

Not at all too late, it makes the thread a better resource for someone else hunting for this stuff, thank you. I also will be able to learn something from your code.