Getting Started with Atmel ATtiny10



Introduction


I like Atmel tinyAVRs because they are tiny computers that I can (almost) wrap my head around. The Atmel ATtiny4/5/9/10 are the cheapest in the tinyAVR line, and they come in two packages – SOT23 pictured above, and an even more stupendously small 2mm x 2mm USON package. This article will talk about programming these little chips. Though they may be tiny, they are still quite capable, and the right choice for many projects.


I’ve written about tinyAVRs before, and you can take a look at some of the articles before to get a feel for them.



One fundamental difference in programming ATtiny10 versus the above is that the former requires TPI (Tiny Programming Interface), which we will explore below.


The Circuit


To keep things interesting, we will program the ATtiny10 to drive a common cathode RGB LED. Here’s the schematic:


 


Above, you can see that the R, G and B leads of the LED are connected to PB0, PB1 and PB2 pins of the ATtiny10. You can also see the connections for the Tiny Programming Interface, which makes use of three signals – TPICLK, TPIDATA and RESET. The traditional MOSI in not connected. The pins are arranged in an indentical order to the standard 2×3 ICSP header. Another thing to remember is that TPI requires a 5V signal – 3.3V won’t cut it. (But after programming, your circuit can run at a lower voltage.)


Here’s what it looks like, hooked up:


 


I used an SOT23 to DIP adapter above so I could use the chip on a breadboard. To plugin the Atmel ICE 2×3 header on a breadboard easily, I used a handy AVR ISP adapter PCB – an open source design you can order from OSH Park.


Programming with Atmel Studio 7 and Atmel ICE


I have written before on using Atmel Studio 7 and ICE for programming tinyAVRs. The setup is similar here, except that we need to use TPI as the programming interface. Once the project is setup and compiled, here’s what the device programming settings look like:


 


As you can see above, the interface is TPI and the target voltage is read in as 5V, and the signature 0x1E9003 matches that of ATtiny10 from the datasheet. Use the Program option under Memories to upload the code, and you’re done.


I’ll say it again: The combination of Atmel Studio 7 and ICE is a fabulous toolset for programing Atmel microcontrollers. A long term Mac user, I was so impressed by this combination that I bit the bullet, took a pickaexe to my frozen wallet, and broke out the hard cash to buy myself a license of Windows 10 (ugh) and Parallels (wow), so I could use these tools from the comfort of my Macbook and OS X. I wish that Atmel Studio was cross platform, but then I also wish that the Aliens land soon. I ain’t holding my breath for either.


Note


The RGB LED connections interfere with TPI programming. So you need to disconnect the LED (just pull the ground) during programming.


Programming with USB ASP


I wanted to explore a cheaper option than Atmel ICE for programming the ATtiny10. I found some evidence (How is your Polish?) on the web that the cheap USB ASP programmer can be made to support TPI. But so far, I haven’t been able to make it work. I’ll update this section if I manage to do it.


In my view, it’s better to buy an Atmel ICE if you are working with their chips. They offer just the PCB for USD 35 if you are on a budget, and are brave enough to make your own cables.


The Code


The first thing you want to set is the clock speed. The ATtiny10 doesn’t have any fuses related to that, so you need to set that in the CLKPS register. The default is a prescaler of 8 which puts it at 1 MHz, but we want to run it at 8 MHz.


// Set CPU speed by setting clock prescalar:
// CCP register must first be written with the correct signature - 0xD8
CCP = 0xD8;
//  CLKPS[3:0] sets the clock division factor
CLKPSR = 0; // 0000 (1)

In the code, you want to ensure that F_CPU is set to 8 MHz so calls like _delay_ms() work correctly.


// define CPU speed - actual speed is set using CLKPSR in main()
#define F_CPU 8000000UL

The way we’re going to light up the RGB LED is to supply the correct PWM frequency to each channel, based on the colors. I’ve chosen these amazing colors for the LED, and they are stored in program memory as follows:


// cyan, magenta, orange, purple, yellow
const unsigned char red[]   PROGMEM = {  0, 255,  255, 127, 255};
const unsigned char green[] PROGMEM = {255,   0,  127,   0, 255};
const unsigned char blue[]  PROGMEM = {255, 255,    0, 127,   0};

The PWM for each channel is set in an interrupt function (more on setup below), which turns the channels on/off based on an 8-bit PWM counter variable:


// interrupt for Compare A
ISR(TIM0_COMPA_vect)
{
	// turn on/off according to PWM value
	if (pwmCount > rgb[0]) {
		PORTB &= ~(1 << PB0);
	}
	else {
		PORTB |= (1 << PB0);
	}
	if (pwmCount > rgb[1]) {
		PORTB &= ~(1 << PB1);
	}
	else {
		PORTB |= (1 << PB1);
	}
	if (pwmCount > rgb[2]) {
		PORTB &= ~(1 << PB2);
	}
	else {
		PORTB |= (1 << PB2);
	}
	// increment PWM count
	pwmCount++;

	// increment interval counter
	counter0++;
}

When the above function is called 256 times, we would have completed one cycle of the PWM. The interrupt is setup as follows:


// set up Output Compare A
// WGM[3:0] is set to 0010
// prescaler is set to clk/8 (010)
TCCR0A = 0;
TCCR0B = (1 << 1) | (1 << WGM02);
// set Output Compare A value
OCR0A = 39;
// enable Output Compare A Match interrupt
TIMSK0 |= (1 << OCIE0A);

In the above code (Yes, you need to read the datasheet!) we setup the 16-bit Timer0 of the ATtiny as follows:


  1. Set timer prescaler to divide by 8.
  2. Enable CTC mode for OCR0A.
  3. Set OCR0A value for comparison.
  4. Enable Output Compare A interrupt.

What the above does is to generate an interrupt every time the 16-bit counter value matches OCR0A. For the values chosen above, that happens every 

18000000839

 or 39 microseconds. So mutiply this by 256 and you get your PWM cycle = 0.01 seconds, or 100 Hz, which is fine to drive LEDs without flicker.


In the main code, the LED color is changed at regular intervals as follows:


// main loop
while (1)
{
  // change color every N cycles
  if(counter0 % colorInterval == 0) {
    colorIndex = (colorIndex + 1) % nColors;
	// set current RGB value
	rgb[0] = pgm_read_byte(&red[colorIndex]);
	rgb[1] = pgm_read_byte(&green[colorIndex]);
	rgb[2] = pgm_read_byte(&blue[colorIndex]);
  }
}

colorInterval is set to 32768, which gives an interval of 39 us * 32768 = 1.27 seconds. You can also see above how the colors are read in from program memory.


In Action


Here you can see the ATtiny10 in action, changing the colors of the RGB LED every second or so. (I put a tape on the LED because I was going blind staring at it all day.)


 


Downloads


You can get the complete source code for this project here:

https://github.com/electronut/attiny10-rgb-hello