Thursday, April 18, 2013

Reading Serial Data from an ATtiny85

I just jumped into the world of ATtiny chips using the Tiny Programmer from SparkFun.  It's amazingly easy to use and I whipped up a bunch of blinkin' lights at first, but when it came to reading and using analog data in a program I was totally stumped. I generally have no idea what I'm doing, so figuring out what I've done wrong is a challenge.  Being able to see what's going on and debug the thing would be a huge help. Unfortunately, the Tiny Programmer has no ability to read serial data, so I had to switch to an Arduino for that task.
I found a stack of blogs that demonstrate how to program and read serial data from an ATtiny, but none of them had everything in one place.  Mostly this blog entry exists so I can refer back to it, but perhaps it will help someone else as well.
I borrowed heavily from the following blogs to develop these instructions:
http://hellowoo.com/hardware/serial-monitor-with-attiny85-and-arduino/#comment-76
http://hlt.media.mit.edu/?p=1695

Materials:

  • Arduino Duemilanove or similar board based around the ATmega328
  • Jumpers
  • 220 Ohm resistor
  • LED
  • Linear POT (2K Ohm or similar)
  • 10uF capacitor
  • ATtiny85 
  • Breadboard
  • Assorted jumper wires x 7

Part One - Getting Ready:

You will need to install the development environment and provide several board definitions for the IDE to use in order to properly program the ATtiny85 from a Duemilanove.
  1. Download and install the Arduino IDE: http://arduino.cc/en/main/software
    • Run the IDE at least once and allow it to setup the sketchbook location somewhere in your path (or set it under the preferences menu)
    • Additional board definitions and libraries will be placed in this structure.
    • Create a sub directory of the sketch directory called 'hardware'
  2. Older boards will require the FTDI drivers to connect: http://www.ftdichip.com/Drivers/VCP.htm
  3. Download the arduino-tiny-0100-0015 set of board definitions here: https://code.google.com/p/arduino-tiny/downloads/list 
    • Unzip the archive and locate the 'tiny' directory inside the archive
    • Copy only the 'tiny' directory the files to the Arduino/hardware sketch directory in your path
  4. Patch the AVR libraries used for compiling and linking.  As of April 2013, the Arduino IDE is still shipping with a buggy version of the compiler and linker.  Some sketches that are over 4K compiled will not fully compile and link properly.  I don't understand the specifics, but a fix can be found over at the Arduino forums (registration required to download the patch).  Download the appropriate files and follow the directions in the forum.
  5. Download the TinyDebugKnockBang libraries: http://hellowoo.com/wp-content/uploads/2012/12/TinyDebugKnockBang.zip
    • Copy the extracted files to your Arduino/libraries/TinyDebugKnockBang/
  6. Download the serial debugging libraries here (choose the 'zip' option): https://github.com/Coding-Badly/TinyISP
    • Copy the entire TinyISP directory into your Arduino/libraries/ path
    • Once downloaded and copied, the serial relay option needs to be enabled change the following lines in 'TinyISP_SelectBuildOptions.h'
-- #define RELAY_KNOCK_BANG_ENABLED 1
++ #define RELAY_KNOCK_BANG_ENABLED 0

-- #define RELAY_SERIAL_ENABLED 1
++ #define RELAY_SERIAL_ENABLED 0



Part Two - Setting up the Programer

The Arduino board has to be setup as an ISP (in system programer) to push programs off to the ATtiny.  
  1. Open the Arduino IDE and open the File > Examples > ArdunioISP sketch
  2. Find the heartbeat() function and make sure it matches the code below:
    • // this provides a heartbeat on pin 9, so you can tell the software is running.
      uint8_t hbval=128;
      int8_t hbdelta=8;
      void heartbeat() {
        if (hbval > 192) hbdelta = -hbdelta;
        if (hbval < 32) hbdelta = -hbdelta;
        hbval += hbdelta;
        analogWrite(LED_HB, hbval);
        delay(20);
      }
  3. Select the appropriate board (Duemilanove or whatever board you are using) under Tools > Board
  4. Plug in your board and select the appropriate serial port under Tools > Serial Port
    • If you do not see your board listed, you may not have installed the FTDI drivers.  See step 2 above.
  5. Push the sketch to the Arduino using the upload command.
  6. Connect the Arduino to your breadboard and ATtiny as shown below.  Make sure there is a 10uF cap properly inserted between the reset and ground pins (negative side in the ground pin)
Image courtesy of MIT High-Low Tech: http://hlt.media.mit.edu/?p=1706

Part Three - Burning a BootLoader

The next step is to get the ATtiny ready to accept Arduino code.  From what I understand, this is not the most efficient way to program an ATtiny, but it is certainly easy and there is already tons of code written for the Arduino that will work on the ATtiny.  The Arduino will act as the programmer and the ATtiny is the target.

  1. Double check your connections, plug in the Arduino and open the Arduino environment.
  2. In the IDE select Tools > Board > ATtiny85 @ 8 MHz
    • The ATtiny85 only supports serial debugging when running at 8MHz
  3. Select Tools > Programmer > ArduinoISP
  4. Then Tools > Burn Bootloader 
    • the TX, RX and L lights should blink furiously on the Arduino for a few seconds and the message "Done burning bootloader" should appear in the IDE window.
    • If you do not get that message, check all the connections and try turning on "Show verbose output during upload" to get a better idea of any problems.  
  5. The ATtiny is now ready to receive Arduino sketches.

Part Four - Writing Sketches, Reading Serial Output

The ATtiny should be ready to program and read using the Arduino.
  1. Add a 220 Ohm resistor to pin 2 of the ATtiny and jump that back to pin 1 (TX) on the Arduino board 
  2. Setup for serial reading. Image courtesy of Hellowoo blog.
  3. Connect an LED between ground (pin 4) and Digital Out 0 (pin 5) on the ATtiny.  
  4. Upload the sketch below to test that the Arduino is writing sketchs to the AT85 properly.  Again the Arduino lights should flash madly for a few seconds. Then, the LED should start blinking steadily.
    • /* Blink without Delay

      Turns on and off a light emitting diode(LED) connected to a digital
      pin, without using the delay() function.  This means that other code
      can run at the same time without being interrupted by the LED code.

      The circuit:
      * LED attached from ATtiny pin 5 to ground.

      created 2005
      by David A. Mellis
      modified 8 Feb 2010
      by Paul Stoffregen
      modified 18 April 2013
      by Aaron Ciuffo for use with ATtiny85

      This example code is in the public domain.


      http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
      */

      // constants won't change. Used here to
      // set pin numbers:
      const int ledPin =  0;      // internally assigned pin value, actual pin on ATtiny=5

      // Variables will change:
      int ledState = LOW;             // ledState used to set the LED
      long previousMillis = 0;        // will store last time LED was updated

      // the follow variables is a long because the time, measured in miliseconds,
      // will quickly become a bigger number than can be stored in an int.
      long interval = 1000;           // interval at which to blink (milliseconds)

      void setup() {
        // set the digital pin as output:
        pinMode(ledPin, OUTPUT);
      }

      void loop()
      {
        // here is where you'd put code that needs to be running all the time.

        // check to see if it's time to blink the LED; that is, if the
        // difference between the current time and last time you blinked
        // the LED is bigger than the interval at which you want to
        // blink the LED.
        unsigned long currentMillis = millis();

        if(currentMillis - previousMillis > interval) {
          // save the last time you blinked the LED
          previousMillis = currentMillis;  

          // if the LED is off turn it on and vice-versa:
          if (ledState == LOW)
            ledState = HIGH;
          else
            ledState = LOW;

          // set the LED with the ledState of the variable:
          digitalWrite(ledPin, ledState);
        }
      }
  5. After you have confirmed that you can properly upload a sketch, remove the LED and push the following sketch to the AT85.  Hook up the POT as described in the instructions.
    • int analogPin = 2;     // potentiometer wiper (middle terminal) connected to analog pin 3 -- Physical pin 3
                             // outside leads to ground and +5V
      int val = 0;           // variable to store the value read

      void setup()
      {
        Serial.begin(9600);          //  setup serial
      }

      void loop()
      {
        val = analogRead(analogPin);    // read the input pin
        Serial.println(val);             // debug value
      }
  6. To read serial debug data, you must push the "reset" button on the Arduino.
  7. Once the sketch is uploaded and running open up the Serial Monitor (Tools > Serial Monitor)  hold down the reset button on the Arduino board and adjust the POT.  The values should range between 0 and 1023 depending on the POT you use.

Important Notes

I did not realize that the ATtiny pins have different assignment values depending on what they are being used for.  For example, physical pin 3 can be called in the code as pin 4 for digital IO and pin 2 for analog IO.  See the table below for a quick reference.  The physical pins are those that are listed directly next to the pin diagram.

ATMEL ATTINY85 / ARDUINO
                           +-\/-+
  Ain0       (D  5)  PB5  1|*   |8   VCC
  Ain3       (D  3)  PB3  2|    |7   PB2  (D  2)  INT0  Ain1
  Ain2       (D  4)  PB4  3|    |6   PB1  (D  1)        pwm1
                     GND  4|    |5   PB0  (D  0)        pwm0
                           +----+

2 comments:

  1. I can get the blink sketch working but I can not get serial to work. I get

    sketch_jul06c.ino: In function 'void setup()':
    sketch_jul06c:7: error: 'Serial' was not declared in this scope
    sketch_jul06c.ino: In function 'void loop()':
    sketch_jul06c:13: error: 'Serial' was not declared in this scope

    ReplyDelete
    Replies
    1. I'm away from home on holiday, and don't have a compiler handy; but it looks like you aren't loading the serial library. Or possibly don't have it in your path. I will have to look at it when I get ho,e in a week or so.

      Delete

Thanks for thinking of us and leaving a comment!
Please leave your name so we know who you are!
If you want to remain an Anonymous Coward you can do that of course, but we like you guys and want to know who we're talking to!