Renewable Energy Innovation

  • Increase font size
  • Default font size
  • Decrease font size

No image

This is a post on getting the range of Atmel ATTiny microcontrollers working with the Arduino IDE. I was wanting a quick and easy way of programming smaller microcontrollers, for when the 28pin ATmega328 is just a bit too much. I looked at the range of 8-pin ATtiny microcontrollers via a comparison list here. I was already using the ATtiny-85 for the TV-B-Gone kit, so I had a few of those lying around.

Here are my collected notes on getting a ATtiny 45 and ATtiny 85 running via the Arduino IDE.

Getting started - 'Hello World'

There are a number of articles about doing exactly this, the main ones I used are here:

I decided to follow the MIT article, which has an Arduino core for the ATTiny45 and AtTiny85 (both 8-pin ICs but with different memory sizes (4kb and 8kb respectively)).

I downloaded this ATTiny core from the GitHub repository. This needed to be extracted to a new folder wihin my Sketchbook called 'hardware'.

I opened the latest version of the Arduino IDE (Integrated Development Environment) and then had a look at Tools -> Board and found there were lots more boards listed, including the range of ATTiny 45 and 85, all with different clock speeds (1MHz & 8MHz internal, 1,8 & 20MHz external).

We will be using the Arduino Uno as an ISP (In series programmer) for the ATTiny45. There is not enough room on the ATTiny45 to have a bootloader installed all the time, hence we use an additional Arduino as the ISP. This could also be one of the available ISP programmers. To do this we have to load the 'ArduinoISP' (from the Examples menu) onto the Uno board. There should not be any problems with this.

The next thing to do was to wire up an Arduino Uno board to an ATTiny45, following this article. This was done on prototyping board. The pin connections are:

  • ATtiny Pin 2 to Arduino Pin 13 (or SCK of another programmer)
  • ATtiny Pin 1 to Arduino Pin 12 (or MISO of another programmer)
  • ATtiny Pin 0 to Arduino Pin 11 (or MOSI of another programmer)
  • ATtiny Reset Pin to Arduino Pin 10 (or RESET of another programmer)
  • Arduino REST to GND  - use a 10uF capacitor.

Here is the Arduino Uno wired up to an ATTin45 on the right:

alt

 

alt

 I used the Arduino as an ISP to program the ATTiny45. This worked but AVRDude did return a couple of errors. Hopefully they are not an issue.... (update: They are nothing to worry about.)

The next thing to do was to upload a 'blinky' hello world program. This will just blink an LED on and off.

This did not work. After an hour or so of head-banging, I saw this comment: "Arduino 1.0.2 has a bug that stops it from working with this tutorial." I had recently upgraded to version 1.0.2, but it turns out this will not work. Luckily I still had version 1.0.1 installed, so I tried that.

Again - no luck. I am unsure what has gone wrong. I am using Windows 7 and an Arduino Uno. Various people have had the same problem. I decided to try again with another ATTiny core...

I finally used this ATTiny core downloaded from here. I reverted back to Arduino IDE v1.0.1. Again I put the 'ArduinoISP' onto the Uno, which worked as usual.

I then set the board to "ATTiny45 @ 8MHz" and the programmer as Arduino as ISP. I added a 10uF capacitor between reset and ground on the Uno board. I then selected 'Burn Bootloader'. This worked, but there were some errors, but apparently these do not matter:

alt

Then I opened the 'Blink' code and changed the output pin to be 0 (rather than 13). I added an LED and 1k resistor to this pin (pin 5 of the ATtiny45). Finally! It came to life and started blinking. I can now program ATTiny ICs with the Arduino as an ISP.

alt

alt

You will just have to trust me that it was blinking....

Steps required

So re-run through the steps required to program the ATTiny 25/45/85 range:

  1. Install the ATTiny core from here
  2. Use Arduino IDE 1.0.1 (v1.0.2 does not work)
  3. Without the ATTiny attached to the Arduino Uno, upload File -> Examples -> ArduinoISP
  4. Wire up the ATTiny as follows. Also need a 10uF capacitor from RESET to GND of the Arduino Uno
  • ATtiny Pin 2 to Arduino Pin 13 (or SCK of another programmer)
  • ATtiny Pin 1 to Arduino Pin 12 (or MISO of another programmer)
  • ATtiny Pin 0 to Arduino Pin 11 (or MOSI of another programmer)
  • ATtiny Reset Pin to Arduino Pin 10 (or RESET of another programmer)
  1. Change the programmer to 'Arduino as ISP' (Tools -> Programmer -> Arduino as ISP)
  2. Choose the correct board from the list of boards (in my case, Tools -> Board -> ATTiny45 @ 8MHz)
  3. Upload your code via the Arduino Uno to the ATTiny

Going further the the ATTiny

I set myself a little design challenge to test out this small device - I had been wanting a battery monitor which was visually interesting and easy to read. I had already produced a kit for a battery voltmeter, but wanted an even more simple device to read a voltage and display that information without using a number-based display. So my challenge was to read in an analogue value and then control an Red-Green LED using PWM to display that information. The idea was to have a glowing 'heart beat' for a battery based system. This would slowly glow in different colours if it was happy and then start flashing quicker if there was something wrong. A Red-Green LED was used as it would show red, yellow and green (by PWM of the various outputs), but only needing 2 outputs. It also needed to be very low power, so must go to sleep for quite a lot of the time.

I was using an ATTiny45, which might be upgraded to an ATTiny85 if I need more space. In the end I was wanting a number of I/O:

  • Green LED output PWM
  • Red LED output PWM
  • FET control - output PWM
  • Voltage - analogue input
  • Serial I/O of data - (optional)  2 digital lines I/O

The output pins for the ATTiny45/85 are here:

alt

We might just have enough I/O pins:

  • Green LED output PWM - PB0
  • Red LED output PWM - PB1
  • FET control - output PWM - PB4
  • Voltage - analogue input - ADC1
  • Serial I/O of data - (optional)  2 digital lines I/O - PB3 and PB5

Another solution for the future might be to use an ATTiny44 or 84 which have a few more output lines:

alt

Commands available in the Arduino IDE

As mentioned in this article, the following Arduino commands should be supported:

PWM outputs

First thing is to be able to have PWM outputs on three pins. Using the 'Fade' example I tested if the PWM worked on which pins.

/*
 Fade
 
 This example shows how to fade an LED on pin 9
 using the analogWrite() function.
 
 This example code is in the public domain.
 */
int led = 0;           // the pin that the LED is attached to
int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by
// the setup routine runs once when you press reset:
void setup()  { 
  // declare pin 9 to be an output:
  pinMode(led, OUTPUT);
} 
// the loop routine runs over and over again forever:
void loop()  { 
  // set the brightness of pin 9:
  analogWrite(led, brightness);    
  // change the brightness for next time through the loop:
  brightness = brightness + fadeAmount;
  // reverse the direction of the fading at the ends of the fade: 
  if (brightness == 0 || brightness == 255) {
    fadeAmount = -fadeAmount ; 
  }     
  // wait for 30 milliseconds to see the dimming effect    
  delay(30);                            
}

I found that this sketch worked for pins 0,1 and 4. I am sure that it would also work on 2,3 and 5, given some cleverness (Update: this would have to be implemented using software, as only pins 0,1 and 4 have native PWM outputs) , but I wanted to keep things simple and I only needed three output PWM channels.

I had a bag of Red/Green LEDs from Phenoptix which I was wanting to use in a project and this seemed like the ideal device. I decided to write code to change between red, green and yellow (via a mix of red and green). The resistors on the output need to be chosen carefully. I used 1k resistor for both red and green and , due to the lower ON voltage of the red LED, it overpowered the green LED. Here is the VERY simple code. Its designed as a starting point. (Note: I should work out the correct resistor values, along with brightness levels).

/*
 Fade
 
 This example shows how to fade an LED on pin 9
 using the analogWrite() function.
 
 This example code is in the public domain.
 */
int redled = 0;         // Red LED attached to here (0, IC pin 5)
int greenled = 1;       // Green LED attached to here (1, IC pin 6)
int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by
// the setup routine runs once when you press reset:
void setup()  { 
  // declare output:
  pinMode(redled, OUTPUT);
  pinMode(greenled, OUTPUT);
} 
// the loop routine runs over and over again forever:
void loop()  { 
  // set the output RED
  analogWrite(redled, 255);    
  analogWrite(greenled, 0);
  // wait for half a second    
  delay(500);   
  // set the output Yellow
  analogWrite(redled, 30);    
  analogWrite(greenled, 255);
  // wait for half a second    
  delay(500);  
  // set the output Green
  analogWrite(redled, 0);    
  analogWrite(greenled, 255);
  // wait for half a second    
  delay(500);    
}

So that meant I had PWM control sorted out.

Analog Input

The next thing was to read in a voltage and then switch On or Off an LED depending upon that voltage. To start with (as always) I set a very simple challenge. Read an analog input and control output LEDs depending upon that value. In the following example, if the input voltage is below 512 (of a maximum of 1023) then switch on the red LED, if the voltage is greater than 512 then switch on the green LED:

/*
  Analog Input
 Demonstrates analog input by reading an analog sensor on analog pin 0 and
 turning on and off a light emitting diode(LED)  connected to digital pin 13. 
 The amount of time the LED will be on and off depends on
 the value obtained by analogRead(). 
 
 The circuit:
 * Potentiometer attached to analog input 0
 * center pin of the potentiometer to the analog pin
 * one side pin (either one) to ground
 * the other side pin to +5V
 * LED anode (long leg) attached to digital output 13
 * LED cathode (short leg) attached to ground
 
 * Note: because most Arduinos have a built-in LED attached 
 to pin 13 on the board, the LED is optional.
 
 
 Created by David Cuartielles
 modified 30 Aug 2011
 By Tom Igoe
 
 This example code is in the public domain.
 
 http://arduino.cc/en/Tutorial/AnalogInput
 
 */
int sensorPin = A1;    // select the input pin for the potentiometer (ADC1, pin 7 on the IC)
int ledRedPin = 0;      // select the pin for the LED
int ledGreenPin = 1;      // select the pin for the LED
int sensorValue = 0;  // variable to store the value coming from the sensor
void setup() {
  // declare the ledPin as an OUTPUT:
  pinMode(ledRedPin, OUTPUT);
  pinMode(ledGreenPin, OUTPUT);  
}
void loop() {
  // read the value from the sensor:
  sensorValue = analogRead(sensorPin); 
  if(sensorValue>=512)
  {
    // turn the red on, green off
    digitalWrite(ledRedPin, HIGH);
      digitalWrite(ledGreenPin, LOW);    
  }
  else
  {      
    // turn the red off, green On:        
    digitalWrite(ledRedPin, LOW);
    digitalWrite(ledGreenPin, HIGH);   
  }
  
  delay(100);                  
}

This example proved that the analogRead() function worked well.

Serial output

I also wanted to be able to put out serial data so that I can easily monitor the function of the device. In doing a bit of research I came across these projects:

In order to implement serial data on the ATTiny range of ICs, we must implement software serial (there is no in-built USART). This also means, to get the timing correct, we must run at 8MHz, so we must use the ATTiny45 @ 8MHz. Also, due to the slow clock speed, the fastest data transfer rate we can use is 4800 baud (we can use 1200, 2400 or 4800 baud).

Another thing to note is that we cannot use the RESET pin on the ATTiny (PB5), as if it is held low for a length of time then the device will reset. I had thought I would use this pin, but I think I will just stream data out and then use other devices to read that data stream and act depending upon that.
I managed to get Software Serial working quite easily, using the code below. You can see that I am using pin 4 as the Tx cable. Pin 5 is the Rx, but I am not planning on using this. If you have other pins available I would use those.
I uploaded the code using the Arduino as an ISP. This seemed to work.

You must then remove the 10uF capacitor and reprogram the Arduino Uno with a blank sketch (remember to change the Tools ->  Board to Arduino Uno again). This will allow the Tx and Rx to work correctly so you can read the data from the ATTiny. I wired the Tx from the ATTiny45 to the Rx of the Arduino Uno.

Open the serial monitor and you should see data being transferred.

Here is a short and not very interesting video of it in action:

 

Here is the code I uploaded to the ATTiny45.

/*
  Serial
  This example code is in the public domain.
 */
#include 
#define rxPin 5
#define txPin 4
const int analogInPin = 3;  // Analog input pin that the potentiometer is attached to
int sensorValue = 0;        // value read from the pot
int outputValue = 0;        // value output to the PWM (analog out)
SoftwareSerial serial(rxPin, txPin);
void setup()  {
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  serial.begin(4800);
  serial.println("ATtiny45 Software serial");
}
void loop() {
  sensorValue = analogRead(analogInPin);          
  outputValue = sensorValue; //map(sensorValue, 0, 1023, 0, 255);          
  serial.print("sensor = " );                    
  serial.print(sensorValue);    
  serial.print("\t output = ");    
  serial.println(outputValue);
  delay(100);  
} 

(Edit: 13/5/13)

Using floats with ATTiny

Here is an update with regards to using floats within the ATTiny.

I needed to do a calculation which resulted in a float value. I might change how the calculation is done so I can just stay using integers, but for now I came across this issue. I was trying to implement a float along with a division calculation. This means including the "#include <stdlib.h>".

When compiled then it did not work and I got the following error:

e:/programs/arduino-1.0.4/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/lib/avr25/crttn45.o:(.init9+0x2): 
relocation truncated to fit: R_AVR_13_PCREL against symbol `exit' defined in .fini9 section in 
e:/programs/arduino-1.0.4/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/avr25\libgcc.a(_exit.o)

When searching for this error I found that, if the file is larger than 4kB, then there is a bug in the compiler which casuses this error. It happens with all the ATTiny8x series (with memory >4kB).

There is a fix which is available here: https://github.com/TCWORLD/ATTinyCore/tree/master/PCREL%20Patch%20for%20GCC

I downloaded the whole ATTinyCore and then followed the instructions from the link above. Basically you need to replace the ld.exe program which is hidden within the Arduino hardware folder. The actual location is: 'Arduino folder' -> 'Hardware' -> 'Tools' -> 'avr' -> 'avr' -> 'bin' and it should be there. I renamed the ld.exe file to ld_old.exe (as a back up just in case) and then copied and pasted the ld.exe file from the above link.

Then rather than the error above, I now get a new error, which is beacuse my code is too big for an ATTiny45 I am using (the ATTiny85 are on order). Much better...

Edit: 14/5/13

Using 8MHz clock - ATTiny85

I now have my ATTiny85 and was trying to program it. The problem is that the ATTiny range comes with 1MHz clock enabled. To change to 8MHz clock you must change some of the fuse settings. Its all noted here, but I did not think about it when first doing this.

To do this you must set up everything as if you were going to program the ATTiny85 (as shown above). You then have to set the board you require (in my case 'ATTiny85 @8MHz internal oscillator'). Click on Tools -> Burn Bootloader. This will set the fuses correctly. This step only needs to be done once with each IC.

You can then upload code and it should run at the correct speed and use Software Serial.

Using EEPROM with ATTiny25/45/85

One of (hopefully) the last things I needed to do was to write data to the EEPROM.

This was as simple as using the 'EERPOM read' and 'EEPROM write' examples. The ATTiny85 has 512 bytes of EEPROM.


Comments   

 
#1 Guest 2013-05-28 19:38
Thanks so much for posting the max serial speed of Attiny. I was trying to build a robot with three tiny chips acting as one and couldn't figure out why they would never work. It seems the arduino ISP will not warn you if you try running the SoftwareSerial at 9600 on tiny chips.
 

Add comment

Shop - Buy it here!

DataDuino - Arduino data acquisition unit
The DataDuino data acquisition (DAQ) kit is designed to be robust and configurable but relatively simple. It is based upon the Arduino platform... Read More...
Bat Detector
Welcome to fascinating world of bats! This bat detector device converts ultrasonic sounds created by bats and convert them down to a lower frequency... Read More...
6 Digit LED Display
This is an all-in-one six digit 7-segment led display unit with an ATmega328 programmed with the Arduino bootloader. The displays can be used to... Read More...
Serial LCD Display
This LCD display unit displays any data sent to it via a serial connection. It is based upon the ATmega328 and the Arduino Uno bootloader. This unit... Read More...
Thermocouple Amplifier
This is a K-type thermocouple amplifier which can be used to amplify the tiny voltage from a thermocouple to a higher voltage, readable by a... Read More...

If any of the information on this site has been useful, please consider buying us a cup of coffee...

Amount: 

Sign up to our newsletter

I sell on Tindie

Login

Login
Register