ATTiny with Arduino IDE
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:
- A MAKE article on using the ATtiny range of microcontrollers.
- An MIT article on programming an ATTiny via an Arduino.
- A project to develop an ATTiny core for the Arduino platform.
- An Instructable on the same process.
- http://tronixstuff.wordpress.com/2011/11/23/using-an-attiny-as-an-arduino/
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:
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:
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.
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:
- Install the ATTiny core from here
- Use Arduino IDE 1.0.1 (v1.0.2 does not work)
- Without the ATTiny attached to the Arduino Uno, upload File -> Examples -> ArduinoISP
- 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)
- Change the programmer to ‘Arduino as ISP’ (Tools -> Programmer -> Arduino as ISP)
- Choose the correct board from the list of boards (in my case, Tools -> Board -> ATTiny45 @ 8MHz)
- 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:
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:
Commands available in the Arduino IDE
As mentioned in this article, the following Arduino commands should be supported:
- pinMode()
- digitalWrite()
- digitalRead()
- analogRead()
- analogWrite()
- shiftOut()
- pulseIn()
- millis()
- micros()
- delay()
- delayMicroseconds()
- SoftwareSerial (has been updated in Arduino 1.0)
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:
- http://funduino.blogspot.co.uk/2012/02/attiny45-software-serial.html
- http://arduino.cc/forum/index.php?topic=118048.0
- http://code.google.com/p/arduino-tiny/source/browse/trunk/hardware/tiny/cores/tiny/TinyDebugSerial.h?r=70
- http://www.kobakant.at/DIY/?p=3408
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 "SoftwareSerial" #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/avr25libgcc.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.
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.
Zu “Serial output”
#include ??what
pinMode(rxPin, INPUT); not necessary
pinMode(txPin, OUTPUT); not necessary
Hi,
The include is the software serial library, as this IC for not have an in-built serial port.
I think the Tx and Rx must be defined or else the code dies not know what pins to implement the serial port on.
Regards,
Matt
Good afternoon!
I need a help, please, I try this code but I’m getting >⸮>~⸮>>⸮>⸮⸮>>⸮>⸮⸮⸮> on the serial output.
I changed the baud rate to 4800 and 9200, but it’s keep returning error.
My attiny works on a lot of others codes, like a simple blink led, sleep mode, SSD1306 OLed, RTC DS1307.
Others serial tutorial return error either.
Thanks !!
Hi,
The Attiny 85 does not automatically support serial at a baud rate of 9600 without an external crystal for timing (16 MHz).
So without knowing much more about your applciation, I would suggest it is due to lack of external clock freq control.
The internal clock is 8MHz which might work for 9600, but also might not.
Hope thats some help…