I have a lot of Raspberry Pi's laying around, so I want to use those to program my attiny85 chips. The problem is that most of the code examples, libraries, and documentation out there assume you're using Arduino. Can I run Arduino commandline software on my Raspberry Pi, and use that to program the attiny85?

I'm trying to compile an RF24 program for the attiny using avr-g++, but I'm running into too many dependency errors, and I wonder if things will just be easier if I use Arduino software.`

  • 1
    I would suggest that things might be easier if you don't use the Arduino software. The AVR toolchain should work well in just about any *nix environment, as well as the command line programming tools.
    – uint128_t
    Apr 16 '17 at 2:00
  • The answer is s simple and plain yes. I know this is not a very useful answer, but you did not provide enough details about your problem to enable people to write useful answers. Apr 16 '17 at 7:25
  • Can I run Arduino commandline software on my Raspberry Pi? - what command line software are you referring to? The Arduino IDE has a GUI interface.
    – Nick Gammon
    Apr 16 '17 at 7:29
  • 2
    By "program the attiny85", do you mean "upload an already build program to the attiny85" or do you mean "build an executable program for attiny85 from source code", or both?
    – jfpoilpret
    Apr 16 '17 at 8:00

Why wouldn't you be able to?

The compiler runs on the computer, not on the Arduino board. You don't need a board to be connected to compile either. If you enable verbose output during compile in the Arduino IDE settings it will tell you where it puts the resulting .hex file, after which you can use avr-dude to upload it to the target MCU.

If you want to use Arduino libraries you'll need to use an core for ATTiny devices (e.g. ATTinyCore). But either way you don't need an Arduino board to compile.

I'd also echo what @Marcus says, for the small devices you are better off completely ditching the Arduino stuff (it's such badly written, bloated, and inefficient), and simply starting with a nice clean C file.

There is nothing stopping you using the Arduino IDE or the avr-libc tools which it uses. If you add your own main() function in a C file and don't put anything in the .ino file you will be able to compile without any of the bloat.


"Arduino" makes a statement on the mcu in use.

Technologically, it's extremely unlikely you could run most sketches on devices with less than 1kB of RAM (largest SRAM in Attiny85 is 512 B; most models are smaller).

So, no. The idea "microcontrollers are by now capable enough to run a C++ subset on them directly" behind arduino simply doesn't seem to apply to the Attiny85.

However, there's the "cuteduino", which actually should work with a small set of basic Arduino libraries. It's based on the Attiny85.

I'd argue that you simply don't want to use Arduino on Attinies; these devices are so resource-constrained, that you probably want to keep in control.

Now, the RF24 lib comes with non-arduino attiny85 support, so go for that? http://tmrh20.github.io/RF24/ATTiny.html


You can disregard the answers that say you can't compile for the ATtiny85 using the Arduino IDE. I have done so many times, for example my torch locator project which uses the ATtiny85 and the Arduino IDE to compile for it.

Here's my "board":

Torch locator (1)

View from other side:

Torch locator (2)


// ATtiny85 torch detector
// Author: Nick Gammon
// Date: 25 February 2015

// Pin 1 is /RESET
//                  +-\/-+
// Ain0 (D 5) PB5  1|    |8  Vcc
// Ain3 (D 3) PB3  2|    |7  PB2 (D 2) Ain1 
// Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
//            GND  4|    |5  PB0 (D 0) pwm0
//                  +----+


  Pin 2 (PB3) <-- LDR (GL5539) --> Pin 7 (PB2) <----> 56 k <----> Gnd

  Pin 5 (PB0) <---- LED ---> 100 R <-----> Gnd


#include <avr/sleep.h>    // Sleep Modes
#include <avr/power.h>    // Power management
#include <avr/wdt.h>      // Watchdog timer

const byte LED = 0;          // pin 5 
const byte LDR_ENABLE = 3;   // pin 2
const byte LDR_READ = 1;     // Ain1 (PB2) pin 7
const int LIGHT_THRESHOLD = 200;  // Flash LED when darker than this

 // when ADC completed, take an interrupt 

// Take an ADC reading in sleep mode (ADC)
float getReading (byte port)
  power_adc_enable() ;
  ADCSRA = bit (ADEN) | bit (ADIF);  // enable ADC, turn off any pending interrupt

  // set a2d prescale factor to 128
  // 8 MHz / 128 = 62.5 KHz, inside the desired 50-200 KHz range.

  ADCSRA |= bit (ADPS0) | bit (ADPS1) | bit (ADPS2); 

  if (port >= A0)
    port -= A0;

#if defined(__AVR_ATtiny85__)  
  ADMUX = (port & 0x07);  // AVcc   
  ADMUX = bit (REFS0) | (port & 0x07);  // AVcc   

  noInterrupts ();
  set_sleep_mode (SLEEP_MODE_ADC);    // sleep during sample

  // start the conversion
  ADCSRA |= bit (ADSC) | bit (ADIE);
  interrupts ();
  sleep_cpu ();     
  sleep_disable ();

  // reading should be done, but better make sure
  // maybe the timer interrupt fired 

  // ADSC is cleared when the conversion finishes
  while (bit_is_set (ADCSRA, ADSC))
    { }

  byte low  = ADCL;
  byte high = ADCH;

  ADCSRA = 0;  // disable ADC

  return (high << 8) | low;

  }  // end of getReading

// watchdog interrupt
ISR (WDT_vect) 
   wdt_disable();  // disable watchdog
}  // end of WDT_vect

#if defined(__AVR_ATtiny85__)  
  #define watchdogRegister WDTCR
  #define watchdogRegister WDTCSR

void setup ()
  pinMode (LED, OUTPUT);
  ADCSRA = 0;            // turn off ADC
  power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
  }  // end of setup

void loop ()
  // power up the LDR, take a reading
  digitalWrite (LDR_ENABLE, HIGH);
  int value = getReading (LDR_READ);
  // power off the LDR
  digitalWrite (LDR_ENABLE, LOW);

  // if it's dark, flash the LED for 2 mS
  if (value < LIGHT_THRESHOLD)
    power_timer0_enable ();
    delay (1);  // let timer reach a known point
    digitalWrite (LED, HIGH);
    delay (2); 
    digitalWrite (LED, LOW);
    power_timer0_disable ();

  goToSleep ();
  }  // end of loop

void goToSleep ()
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  noInterrupts ();       // timed sequence coming up

  // pat the dog

  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset, clear existing interrupt
  watchdogRegister = bit (WDCE) | bit (WDE) | bit (WDIF);
  // set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
  watchdogRegister = bit (WDIE) | bit (WDP2) | bit (WDP1) | bit (WDP0);    // set WDIE, and 2 seconds delay

  sleep_enable ();       // ready to sleep
  interrupts ();         // interrupts are required now
  sleep_cpu ();          // sleep                
  sleep_disable ();      // precaution
  }  // end of goToSleep 

Compiled under the IDE it uses 16% of program memory:

Sketch uses 1,370 bytes (16%) of program storage space. Maximum is 8,192 bytes.
Global variables use 9 bytes of dynamic memory.

Claims that the Arduino IDE is badly written and inefficient are not generally true. To a certain extent the Arduino libraries favour ease-of-use over compactness, however you don't have to use them.

The IDE is just a front-end to the avr-g++ compiler. It is easy to use, and produces a .hex file which you can then upload to your chip using a suitable ICSP interface.

The avr-g++ compiler itself does aggressive code optimization. You won't get any advantage from ditching the IDE and using the avr-g++ compiler yourself - it's the same compiler. And if you think you can do better in assembler, good luck! The compiler-writers know all the tricks for storing variables in registers, and minimizing code in various ways. You will be hard pressed to write better code than the compiler generates anyway.

Claims that the IDE generates bloated code are Complete Nonsense. Take this sketch:

int main ()
  DDRB = bit (2);  // pin 7 on chip

  while (true)
    PINB = bit (2); // blink it

Compiled for the ATtiny85 under the IDE 1.6.9 I get this program memory usage:

Sketch uses 60 bytes (0%) of program storage space. Maximum is 8,192 bytes.
Global variables use 0 bytes of dynamic memory.

There are 15 interrupt vectors at the start of program memory, for which space has to be reserved. So 30 of those bytes are accounted for by that unavoidable overhead.

Here is the full disassembly of the above:

Disassembly of section .text:

00000000 <__vectors>:
   0:   0e c0           rjmp    .+28        ; 0x1e <__ctors_end>
   2:   15 c0           rjmp    .+42        ; 0x2e <__bad_interrupt>
   4:   14 c0           rjmp    .+40        ; 0x2e <__bad_interrupt>
   6:   13 c0           rjmp    .+38        ; 0x2e <__bad_interrupt>
   8:   12 c0           rjmp    .+36        ; 0x2e <__bad_interrupt>
   a:   11 c0           rjmp    .+34        ; 0x2e <__bad_interrupt>
   c:   10 c0           rjmp    .+32        ; 0x2e <__bad_interrupt>
   e:   0f c0           rjmp    .+30        ; 0x2e <__bad_interrupt>
  10:   0e c0           rjmp    .+28        ; 0x2e <__bad_interrupt>
  12:   0d c0           rjmp    .+26        ; 0x2e <__bad_interrupt>
  14:   0c c0           rjmp    .+24        ; 0x2e <__bad_interrupt>
  16:   0b c0           rjmp    .+22        ; 0x2e <__bad_interrupt>
  18:   0a c0           rjmp    .+20        ; 0x2e <__bad_interrupt>
  1a:   09 c0           rjmp    .+18        ; 0x2e <__bad_interrupt>
  1c:   08 c0           rjmp    .+16        ; 0x2e <__bad_interrupt>

0000001e <__ctors_end>:
  1e:   11 24           eor r1, r1
  20:   1f be           out 0x3f, r1    ; 63
  22:   cf e5           ldi r28, 0x5F   ; 95
  24:   d2 e0           ldi r29, 0x02   ; 2
  26:   de bf           out 0x3e, r29   ; 62
  28:   cd bf           out 0x3d, r28   ; 61
  2a:   02 d0           rcall   .+4         ; 0x30 <main>
  2c:   05 c0           rjmp    .+10        ; 0x38 <_exit>

0000002e <__bad_interrupt>:
  2e:   e8 cf           rjmp    .-48        ; 0x0 <__vectors>

00000030 <main>:
  30:   84 e0           ldi r24, 0x04   ; 4
  32:   87 bb           out 0x17, r24   ; 23
  34:   86 bb           out 0x16, r24   ; 22
  36:   fe cf           rjmp    .-4         ; 0x34 <main+0x4>

00000038 <_exit>:
  38:   f8 94           cli

0000003a <__stop_program>:
  3a:   ff cf           rjmp    .-2         ; 0x3a <__stop_program>

I can't see much bloat there.

I wonder if things will just be easier if I use Arduino software

Yes, much easier.

  • Although your answer is OK, I think it does not answer the main OP question: is it possible to program ATtiny85 chips on a Raspberry Pi?
    – jfpoilpret
    Apr 16 '17 at 6:48
  • Does the Pi not use Unix? The Arduino IDE runs under Unix. I run it myself under Ubuntu.
    – Nick Gammon
    Apr 16 '17 at 7:25
  • @jfpoilpret The question was actually Can I run Arduino commandline software on my Raspberry Pi? - what Arduino commandline software?
    – Nick Gammon
    Apr 16 '17 at 7:27
  • Well I would say this one: github.com/arduino/Arduino/blob/master/build/shared/…
    – jfpoilpret
    Apr 16 '17 at 7:53
  • That's because you are bypassing all of the bloat by adding your own main() function. Try doing the same with loop() instead you'll end up with 326 bytes - that's a 400% overhead on top of the simple one. But also you are using direct port access rather than digitalWrite() which is again bypassing the bloat. Try doing digitalWrite() in loop() and you'll end up with 812 bytes - a 1200% overhead! Tell me, would you consider that bloat? Apr 16 '17 at 7:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.