Sample project for ATTINY10

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

Dear Sir/Madam,

 

Just would like to know if there is anywhere i can download sample C example projects for Atmel Studio that shows different functionality of the ATTINY10?

Like ADC, IO setting, Timers etc.. 

I use STK600.

 

Regards,

 

Tony Siu

Tony Siu

Last Edited: Sat. Mar 21, 2020 - 09:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here's a short sample that read the ADC and uses the timer to generate two servo signals proportional to the ADC reading.

 

/*
  Read ADC2 (PB2) and output servo signal on PB0 and PB1.
  ATtiny5 or 10 at default 1MHz.
 */

#include <avr/io.h>

int main(void)
{
    // ADC channel 2
    ADMUX = 2;
    // Disable digital input on PB2
    DIDR0 = (1<<ADC2D);
    // Enable ADC, presc 1:8 for 125kHz ADC-clock
    ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);

    // PB0 and 1 output.
    DDRB = (1<<PB0) | (1<<PB1);

    // Timer0 50Hz PWM, 1us tick, mode 14 with ICR0 as TOP.
    ICR0 = 19999; // 1MHz / 50Hz - 1
    // Start with 1.5 ms pulse-width
    OCR0A = OCR0B = 1500;

    // OC0A and OC0B non inverting PWM, mode bit 1
    TCCR0A = (1<<COM0A1) | (1<<COM0B1) | (1<<WGM01);
    // mode bits 2 and 3, presc 1:1
    TCCR0B = (1<<WGM03) | (1<<WGM02) | (1<<CS00);
    

    while(1)
    {
	uint8_t i;
	uint16_t adc4;

	// Take four ADC samples, add them in adc4
	for (i = 0, adc4 = 0; i < 4; i++)
	{
	    // Start a conversion
	    ADCSRA |= (1<<ADSC);
	    // wait until it's finished
	    while (ADCSRA & (1<<ADSC))
		; // Nothing
	    adc4 += ADCL;
	}

	// Set PWM to 990 to 2010 ms from ADC.
	OCR0A = 990 + adc4;
	// OCR0B "inverted" servo signal
	OCR0B = 2010 - adc4;
    }
}

 

Last Edited: Fri. Jan 2, 2015 - 12:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wasn't that useful? Anyway, here's a couple of more examples from my t10/test directory.

 

Toggle a LED at 1Hz

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

int main(void)
{
    // PB2 output
    DDRB = 1<<2;

    while(1)
    {
	// Toggle PB2
	PINB = 1<<2;
	_delay_ms(500);
    }
}

 

Short 1Hz flash using the timer

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

int main(void)
{
    TCNT0 = 0;
    OCR0A = 0;
    // Start timer, free running with presc. 1:64
    TCCR0B = 1<<CS01 | 1<<CS00;
    
    DDRB = 1<<2;

    while(1)
    {
	// Short flash
	PORTB |= 1<<2;
	_delay_ms(1);
	PORTB &= ~(1<<2);

	// Add one second
	OCR0A += F_CPU / 64 - 1;
	// Wait for compare match
	while(!(TIFR0 & (1<<OCF0A)))
	    ;
	// Clear interrupt flag
	TIFR0 |= 1<<OCF0A;
    }
}

 

Short 1Hz flash using idle mode between flashes

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


EMPTY_INTERRUPT(TIM0_COMPA_vect)

int main(void)
{
    TCNT0 = 0;
    OCR0A = 0;
    // Enable compare match A interrupt
    TIMSK0 = 1<<OCIE0A;
    // Start timer, free running with presc. 1:64
    TCCR0B = 1<<CS01 | 1<<CS00;

    // PB2 output
    DDRB = 1<<2;

    set_sleep_mode(SLEEP_MODE_IDLE);

    sei();

    while(1)
    {
	// Short flash
	PORTB |= 1<<2;
	_delay_ms(1);
	PORTB &= ~(1<<2);

	// Add one second
	OCR0A += F_CPU / 64 - 1;

	// Idle mode until COMPA interrupt
	sleep_enable();
	sleep_cpu();
	sleep_disable();
    }
}

 

Short flash at about 1 Hz, powerdown and wakeup by watchdog interrupt.

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

// Wake up by WDT interrupt.
// Don't need to do anything here but (auto-) clearing the interrupt flag.
EMPTY_INTERRUPT(WDT_vect)


/*
  Delay in powerdown mode. Wake up by watchdog interrupt.
 */
void delay_power_down_wdt(uint8_t wdto)
{
    wdt_reset();
    wdt_enable(wdto);
    WDTCSR |= (1<<WDIE);
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    // Make sure interrups are enabled and the I flag is restored
    NONATOMIC_BLOCK(NONATOMIC_RESTORESTATE)
    {
	sleep_cpu();
	wdt_disable();
    }
    sleep_disable();
}

int main(void)
{
    DDRB = 1<<2;

    sei();

    while(1)
    {
	// Short flash
	PORTB |= 1<<2;
	_delay_ms(1);
	PORTB &= ~(1<<2);

	delay_power_down_wdt(WDTO_1S);
    }
}

 

 

Fade PB0 and PB1 up and down using PWM

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


int main(void)
{
    int i;
    
    // PB0 and PB1 outputs
    DDRB = (1<<PB0) | (1<<PB1);
    // Timer0 in mode 14, fast PWM with ICR0 as top.
    // Enable OC0A and OC0B, lower mode bits
    TCCR0A = (1<<COM0A1) | (1<<COM0B1) | (1<<WGM01);
    // Set top to 1000
    ICR0 = 1000;
    // Start timer with prescaler 1:8 and set upper mode bits
    TCCR0B = (1<<CS01)  | (1<<WGM03) | (1<<WGM02);

    while(1)
    {
	for (i = 0; i <= 1000; i++)
	{
	    OCR0A = i;
	    OCR0B = 1000-i;
	    _delay_ms(1);
	}
	for (i = 1000; i >= 0; i--)
	{
	    OCR0A = i;
	    OCR0B = 1000-i;
	    _delay_ms(1);
	}
    }
}

 

Toggle a LED when a button is pressed

/*
  Button on PB2 to GND, LED on PB0.
  Toggle led when button is pressed.
  Button is debounced using timer interrupt.
 */

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

// Variable to tell main that the button is pressed (and debounced).
// Main will clear it after a detected button press.
volatile uint8_t button_down;

// Check button state on PB2 and set the button_down variable if a debounced
// button down press is detected.
// Call this function about 100 times per second.
static inline void debounce(void)
{
    // Counter for number of equal states
    static uint8_t count = 0;
    // Keeps track of current (debounced) state
    static uint8_t button_state = 0;

    // Check if button is high or low for the moment
    uint8_t current_state = (~PINB & (1<<PINB2)) != 0;
    
    if (current_state != button_state) {
        // Button is about to be pressed or released, increase counter
        count++;
        if (count >= 4) {
            // The button have not bounced for four checks, change state
            button_state = current_state;
            // If the button was pressed (not released), tell main so
            if (current_state != 0) {
		button_down = 1;
                count = 0;
            }
        }
    } else {
        // Reset counter
        count = 0;
    }
}


// Called at 100Hz
ISR(TIM0_OVF_vect)
{
    debounce();
}

int main(void)
{
    // PB0 output
    DDRB = 1<<0;
    // Enable internal pullup on PB2
    PUEB = 1<<2;

    // Timer0 in CTC mode
    TCCR0A = (1<<WGM01) | (1<<WGM00);
    // Set TOP for 100 Hz overflow rate
    OCR0A = F_CPU / 8 / 100 - 1;
    // Enable overflow interrupt
    TIMSK0 = 1<<TOIE0;
    // Start timer with presc 1:8
    TCCR0B = 1<<CS01;
    // Enable global interrupts
    sei();

    while(1)
    {
        if (button_down) {
            // Clear flag
            button_down = 0;
	    // Toggle PB0
	    PORTB ^= (1<<0);
        }
    }
}

 

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

Here's one I played with a while ago. The anode of a yellow LED is hooked to a 100 ohm resistor to PB0, the cathode to ground. (This is the opposite of the traditional way to hook an LED.) Every minute or so, the program reads the voltage across the LED to decide if it's dark. If it is dark, it blinks like a firefly.

 

I was curious how long one of these would last on 2 AA batteries: About a month till a storm knocks it off the balcony railing, it smashes on the sidewalk below and the landlady sweeps up the debris and throws it away.

 

Uses ADC, Timer and Watchdog. 

/*
 * Firefly02.c
 *
 * Created: 4/21/2013 4:30:21 PM
 *  Author: Tom
 */ 

#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sleep.h>
#define F_CPU 1000000UL  // 1 MHz
#include<util/delay.h>

int IsDark(void)
{
	DDRB = 1 ;
	PORTB = PORTB & ~(1);
	_delay_ms(20);
	DDRB = 0 ;  // go to high impedance.
	ADMUX = 0;  // Read v across LED
	ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
	ADCSRA |= (1<<ADSC);
	while ((ADCSRA & (1<<ADIF))==0)
	{
		
	}
	ADCSRA = (1<<ADIF);
	if (ADCL < 5) return 1;
	return 0;
}

ISR(TIM0_OVF_vect)
{
	if ((TCCR0A & (1<<WGM00))==0) // Sleeping
	{
		
	}
	else  // Blinking
	{
		OCR0A = OCR0A-1 ;
	}
}

ISR(WDT_vect)
{
	
}

int main(void)
{
	DIDR0 = 0xf;
	sei();
    while(1)
    {
        if (IsDark()!=0)
		{
			DDRB = 1;
			TCCR0B = 0;
			TCCR0A = (1<<COM0A1) | (1<<WGM00);
			TCCR0B = (1<<WGM02) | (1<<CS01);
			OCR0A = 255 ;
			TIMSK0 = (1<<TOIE0) ;
			while (OCR0A>0)
			{
				
			}
			TCNT0 = 0;
			PORTB = 0 ;
			DDRB = 0;
			TCCR0B = 0;
		}
		for(uint8_t i = 0; i<8; i++)
		{
			// Set watch dog timer for about 8 seconds
			WDTCSR = (1<<WDIE) | (1<<WDP3) | (1<<WDP0) ;
			set_sleep_mode(SLEEP_MODE_PWR_DOWN);
			sleep_enable();
			sleep_cpu();			
		}
		WDTCSR = 0 ;  // Disable watch dog
    }
}

 

 

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

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

Just to note that there articles about timers and ADC in the tutorial forum here. Admittedly not for Tiny10 but on the whole a lot of these peripherals are very similar across the AVRs and the general techniques can be applied to all though you may need to determine the odd change in bit or register names between devices.

 

But the point is that the use of an ADC is fairly common in general: you init a voltage reference, you init a prescale value to run the ADC at a "sensible" speed, you actually enable the ADC then you set some "start" bit and either keep watching it or wait for an interrupt indication to show completion then you read the results register. That's true for pretty much all AVRs, Tiny10 included so don't limit yourself to only trying to find details about Tiny10 alone. In fact few people (except those using them in industrial quantities) choose to use Tiny 4,5,9,10,20,40 - the so called "brain dead" AVRs - because their only true features are low cost and small package size. "hobbyists" pick more fully featured AVRs to start with like Tiny2313 (previously), Tiny1634, Mega48/88/168, Mega164/324/644/1284 and so on.

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

Thanks.. I think I will use the full size chip for development first.

 

[The two extra copies of this post have been deleted. Ross]

Tony Siu

Last Edited: Sun. Jan 11, 2015 - 11:39 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I like tiny 10s because they're tiny and cheap. Annoying that you can't program them with a 3v supply though.

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

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

Hello,

 

I am trying to do the following.

 

 

Sleep for 1 minute.

Flash an LED.

then go back to sleep.

 

For some reason,  My code does not wake up after the sleep_cpu(); command.  does anyone have any idea's.  I am using an ATtiny 5 on the STK600 Dev system.

*

 * ModuleJunctionBoxV1.c

 *

 * Created: 4/4/2018 2:01:01 PM

 * Author : Dave Adams  Se-Kure Controls Inc.

 * Description:

 * This Module will wake up every X Seconds,  Flash the LED and Check the Battery Voltage.

 */ 

 

#define F_CPU 1000000UL // 1MHz

#include <avr/io.h>

#include <util/delay.h>

#include <avr/sleep.h>

#include <avr/wdt.h>

#include <avr/interrupt.h>

#include "MJBGlobals.h"

 

 

 

 

int main(void)

{

 

sysint();

adcint();

wdt_disable();

HORN_OFF;

LED_OFF;

 

while(1)

{

for(uint8_t i = 0; i<8; i++)

{

// Set watch dog timer for about 8 seconds

WDTCSR = (1<<WDIE) | (1<<WDP3) | (1<<WDP0) ;

set_sleep_mode(SLEEP_MODE_PWR_DOWN);

sleep_enable();

sleep_cpu();

}

WDTCSR = 0 ;  // Disable watch dog

led_flash();

}

}

 

 

/*

 * Function: sysint

 *

 * Created: 4/4/2018 2:01:01 PM

 * Author : Dave Adams  Se-Kure Controls Inc.

 * Description:

 * This function sets up the main processor ports

 */ 

 

void sysint(void)

{

CLKMSR = 0x00; // Set up internal 8MHz Clock

DDRB = 0x03; // PB3 = INPUT

// PB2 = INPUT

// PB1 = OUTPUT

// PB0 = OUTPUT

PUEB = 0; // Turn off week pullups

 

 

}

 

/*

 * Function: adcint

 *

 * Created: 4/4/2018 2:01:01 PM

 * Author : Dave Adams  Se-Kure Controls Inc.

 * Description:

 * This function initializes ADC2

 */ 

 

void adcint(void)

{

ADMUX = 2; //ADC Channel 2

DIDR0 = (1<<ADC2D); // Disable Digital Input on PB2  

ADCSRA = (0<<ADEN) | (1<<ADPS1) | (1<<ADPS0); // Disable ADC, presc 1:8 for 125kHz ADC-clock

 

}

 

 

/*

 * Function: readadc

 *

 * Created: 4/4/2018 2:01:01 PM

 * Author : Dave Adams  Se-Kure Controls Inc.

 * Description:

 * This function enables the ADC,  Starts the ADC and then takes 4 readings.

 */ 

 

/*void readadc(void)

{

uint8_t i;

uint16_t adc4;

ADCSRA = (1<<ADEN); // Enable the ADC

PRR = (0<<PRADC); //  Turning on the ADC

// Take four ADC samples, add them in adc4

for (i = 0, adc4 = 0; i < 4; i++)

{

ADCSRA |= (1<<ADSC); // Start a conversion

while (ADCSRA & (1<<ADSC)) // wait until it's finished

; // Nothing

adc4 += ADCL;

}

}*/

 

 

 

 

void led_flash(void)

{

LED_ON; // Turn LED On

_delay_ms(100); // Wait 100 ms

LED_OFF; // Turn LED Off

_delay_ms(100); // Wait 100 ms

}

 

 

 

 

 

Attachment(s): 

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

I don't think your WDT is being disabled as it requires a timed sequence to disable, gcc should have a built in for this.

I'm not a gcc user so maybe another freak will jump in with the correct incantation.

 

Jim

 

 

 

 

 

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

What happens it the processor enters into sleep with the sleep_cpu(); instruction and it never exits this instruction.  If I put a LED_OFF; instruction right after the sleep_cpu instruction,  the LED never turns off.  

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

As mentioned, others that have experience with this family may need to help.  But with a quick glance ...

 

-- learn how to use the Code <> tags on the formatting toolbar.  It makes source code much easier to understand.  Practice with editing your post, or make another.

-- I cannot tell whether the WDIE is taking effect; I suspect that the sequence is not correct.  I don't think that the built-in GCC functions are very good at watchdog interrupt.

-- ...but even if it does, there is a WDIE and no ISR for it.

-- "WDTCSR = 0 ;  // Disable watch dog" won't turn off the watchdog, will it?  But a moot point as I don't think the watchdog is enabled anyway.

10.3.2.1. Safety Level 1
In this mode, the Watchdog Timer is initially disabled, but can be enabled by writing the WDE bit to one
without any restriction. A special sequence is needed when disabling an enabled Watchdog Timer. To
disable an enabled Watchdog Timer, the following procedure must be followed:
1. Write the signature for change enable of protected I/O registers to register CCP
2. Within four instruction cycles, in the same operation, write WDE and WDP bits
 

-- I don't see any WDE in your code?  I guess that is OK in interrupt mode, so you might be closer than we think.

-- I don't see any SEI in your code.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

The simulator may be helpful here to see if WDT is setup correctly.

 

 

 

 

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

The CodeVisionAVR Wizard code is below.  Note several things:

-- CCP register handling

-- Global interrupts turned on after setup

-- Clear of WDIF (though I don't really know what that might be for -- cascading events?

 

There is also a corresponding empty ISR.

 

// Watchdog Timer initialization
// Watchdog Timer Prescaler: OSC/1024k
// Watchdog timeout action: Interrupt
#asm("wdr")
CCP=0xd8;
WDTCSR=(1<<WDIF) | (1<<WDIE) | (1<<WDP3) | (0<<WDE) | (0<<WDP2) | (0<<WDP1) | (1<<WDP0);
// Globally enable interrupts
#asm("sei")

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Torby, thank you for making the comment.  I was pulling my hair out tonight because I Had missed that detail while reading over the programming section on the datasheet and AtmelStudio doesn't warn you (at least with the AtmelICE)...  As soon as I changed my rail to 5V, it just worked...

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

hello and congratulations for the projects you have published, interested in trying this little cip, I tried to program it with one of your projects but I can't give me this error

Error. “Verifying Flash…Failed! address=0×0000 expected=0×0a actual=oxff

 

use avr studio 7 and as AVR ISP mk2 programmer

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

You already have your own thread on this: 

 

https://www.avrfreaks.net/forum/...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Topic locked