I got hooked with how easy it was to get a Tiny85 running with the Arduino IDE: Drop a directory of stuff (including core libs) in the “hardware” directory, hook a couple of wires up to an Arduino running ArduinoISP as a programmer, touch up the Blink sketch to use the 85’s pins, pick a new board that magically appeared under the Tools tab, upload – and it works!
Those core libs already supported the Tiny2313, so how hard could it be to get the 4313 I need for a short-deadline project up and running? (Even optimist that I am, I should be able to recognize famous last words by now.) I kludged a little breadboard adapter so I could use(/test!) my 6-pin Arduino style ICSP programmer cable and stuffed that, a 4313, and some LEDs into a breadboard. I found the pin definitions mapping Arduino style names (like “1” for digital pin 1) to logical hardware ports (like PD1) and to physical pins on the 2313 in \users\jim\documents\arduino\hardware\tiny\cores\tiny\arduino_pins.c (an augmented version of the one in the normal Arduino distribution in hardware\arduino\cores\arduino). That’s essential info for writing to a non-standard chip! Then I modified Blink to use some of the 2313/4313’s pins.
The datasheet says “The ATtiny2313A and ATtiny4313 differ only in memory sizes.” Worst case I lie and say it’s a 2313 and give up half the memory, right? Well, no. The statement above isn’t quite right: They also differ in the device signature bytes in read only memory. Try to program a 4313 claiming it’s a 2313 and the avrdude programmer driver software used by the Arduino IDE complains
avrdude: Expected signature for ATtiny2313 is 1E 91 0A Double check chip, or use -F to override this check.
and quits. Nice. (I did a quick check for the makefile that invokes avrdude to see if I could add the Force no check switch, but couldn’t find it.)
So I created a new board definition for 4313 in \users\jim\documents\arduino\hardware\tiny\boards.txt (the one in \program files\arduino-0022 is partly overridden by the local one) mostly copied from a 2313 entry, with new names. I did double attiny4313at1.upload.maximum_size up to 4096. Same error. Oops – I missed attiny4313at1.build.mcu=attiny2313. Changed to attiny4313. More interesting error this time:
unknown MCU 'attiny4313' specified Known MCU names: <long list of known processors> _4313Blink:-1: error: MCU 'attiny4313' supported for assembler only
Time to give up. Back to attiny4313at1.build.mcu=attiny2313 – and off to look for the signature bytes. Searching turned up lots of #ifdefined (__AVR_ATtiny2313__). Am I going to have to define a new processor in a whole bunch of places? Ugh. After lots of digging and grumbling, I found the signature bytes in \program files\arduino-0022\hardware\tools\etc\avrdude.conf. Looks like it’s really only a “courtesy check” in avrdude. Changing the signature definition for 2313 like this
# signature = 0x1e 0x91 0x0a; signature = 0x1e 0x92 0x0d;
allowed Blink to load and run. Of course the IDE won’t work for 2313s any more, but since I don’t have any 2313s at the moment…
But I needed to run with a 16MHz crystal – so I also had to change some fuses. For a not-too-dangerous starter, I thought I’d try to turn off the divide-by-8 prescaler that’s enabled by default to make the internal 8MHz RC oscillator provide a CPU clock of 1MHz. The datasheet showed I needed to change the Low Fuse from 0x64 to 0xE4. There are fuse entries in boards.txt, so I played with
(changed from “=0x64”) for quite a while with no visible results before I noticed the “bootloader” word. Of course there’s no bootloader in the Tinys, and maybe those are only in effect for using (or burning?) a bootloader. How else can I force burning of fuses? (<google, google…>) You use your programmer, of course. Well, arduinoisp isn’t really a standalone programmer, so that didn’t help.
But it obviously uses (actually is used by) avrdude. And this nice tutorial from Ladyada says avrdude can read or write fuses no problem. I found avrdude.exe in \program files\arduino-0022\hardware\tools\avr\bin, but couldn’t get it to talk (thru arduinoisp) to my 4313. Turning on verbose mode with “upload.verbose=true” in \users\jim\appdata\roaming\arduino\preferences.txt and looking at the output while loading a working sketch helped a lot. Looks like arduinoisp emulates an STK500V1. That, along with the fact that you have to override the baud rate with 19200 got me to the point that I could see avrdude using arduinoisp to query the target 4313. And verbose mode showed sure enough low fuse was 0x64. After only a few syntax stumbles I got it to write 0xE4 into low fuse. And my sketch started blinking a lot (presumably 8x) faster! Here’s the goavrdude.bat script I used:
avrdude -P COM6 -b 19200 -p t2313 -C ../etc/avrdude.conf -c stk500v1 -v -U lfuse:w:0xE4:m
OK – I can write fuses. Can I get it running with my target 16MHz crystal? Looks like I need to change CKSEL in the low fuse for a final value 0xEE. Punched that value into my script, and – it works! (Yeah, even with that SMT crystal kludged in.)
Recap of lessons learned (besides a review of the “nothing’s ever as simple as it looks rule”):
– The ArduinoISP sketch is a STK500V1 emulator that can program Tinys as well as program and burn bootloaders into various AVR devices.
– Under some circumstances, the DTR pulse that resets an Arduino when you load code into it interferes with ArduinoISP. A 10uF cap from Reset to Gnd or 120Ω resistor from Reset to +5 will disable auto-reset (by brute force).
– Adding a “hardware” directory in your Arduino sketch directory overrides some/most of what’s in the hardware directory in the Arduino installation. In particular, I’ve added support for Tinys by dropping additional core libraries there.
– One of the things in that new hardware library is a new boards.txt file that defines the boards you can select from under the IDE’s Tools->Boards tab. Hacking that file is sometimes helpful.
– There’s a WHOLE lot of stuff in #ifdefined sections to make it all work with lots of processors, speeds, etc.
– The signature bytes check by avrdude is only a safety check. Disabling it by spoofing the signature byte values in avrdude.conf (or presumably adding -F in the makefile, if you can find it) is only dangerous, not harmful.
– It’s not too scary to run avrdude manually once you find the magic command line switches. The -n “don’t really do anything” switch is a nice safety feature for playing around with it. So far it’s the only way I’ve found to burn fuses without a “real” programmer.
– Low voltage serial programming (by bringing Reset low) works (about?) the same on quite a few AVR family chips using the built-in SPI facilities and the SCK, MOSI, and MISO pins. You can program an ATMega328 that way whether it has a bootloader or not. You can also use it to burn a bootloader. You can also burn fuses with it.
– High voltage (bringing Reset to +12 or something with specific timing requirements) serial programming should (almost?) always work, including on chips which have had the RSTDISBL fuse programmed (which allows the Reset pin to be used for I/O).
– We owe a great debt of gratitude to the folks who have added support for other AVR processors (like the Tinys!) to the Arduino environment. It’s a substantial effort to add processors, poring thru the datasheets and making LOTS of decisions like “Which hardware timer shall I use to implement Arduino function X?” and then writing #ifdef’d code to make it work without breaking anything else.
– Sorry – I still don’t know where I got the core libs I’m using. They’re NOT from the HLT page link, nor from avr-developers. They seem to be based on arduino-0022 from the name of the directory: arduino-tiny-0022-0008. I’ll find the source eventually…
Update 12/6/11: The core libs I’m using are from Google code here: http://code.google.com/p/arduino-tiny/downloads/list Finally!
Update 1/2/12: Two areas of “progress”.
Arduino 1.0 and avrdude
The avr stuff from Arduino 1.0 includes support for 4313, and the tiny core has just (within days) been upgraded to support 1.0. Unfortunately, I can’t get even my test programs to compile (for tiny) under 1.0. They’ve succeeded in making a “disruptive change”. I need progress not disruptive roadblocks, so 1.0 is a non-starter for me.
That’s not to say 1.0 doesn’t have some good stuff: The avrdude with 1.0 has actual support for tiny4313! Unfortunately, I still have no clue how the IDE calls avrdude, so I can’t hack it to use the 4313 entry. The tiny core still doesn’t support 4313, so I still have to lie and say I’m running a 2313. That’s OK – I’ve made a new board type for 4313@16MHz with the larger memory size, but still with build.mcu=attiny2313. But that means avrdude also thinks it’s a 2313. So I’ve copied the whole hardware\tools\avr directory from 1.0 to my 0023 install and hacked its avrdude.conf file to change the 4313 stanza’s part->desc entry to “ATtiny2313”. (The part->id entry doesn’t seem to matter. I also changed the 2313’s part->desc entry to “ATtiny4313”, which will never be used, but will keep avrdude from finding duplicate entries.)
The 1.0 install also includes the “NewSoftSerial” library, now renamed with the old standard “SoftwareSerial” name. Unfortunately, I can’t get that to work with the tiny core.
Next step is to get some kind of serial working, since the RF gun needs it.
The 313 has a real UART, so I thought with a crystal I could get good, fast serial for minimum latency. But I haven’t been able to get it to support the regular serial stuff for 2313. If I use Serial.begin(9600) with or without #including <HardwareSerial.h>, the code compiles and loads, but hangs as soon as I issue a Serial.print().
If I #include <SoftwareSerial.h> and instantiate
I can get mysoft.begin() and mysoft.print() to work, but only up to 19200. It’s total gibberish (to ptelnet on my Palm Centro) at 38400, and about half correct chars at 115200.
I hoped NewSoftSerial – which I understand is interrupt based – might do better. I downloaded ver 10C, but it wouldn’t compile, with errors about TIMSK0 and TIFR0 not being defined. I spent a lot of energy trying once again to get 1.0 to work just so I could try the NewSoftSerial, but ran into too many incompatibilities.
With 1.0 being no help, I was more desperate to get it to work with 0023. I chased thru the code, and based on a note in tiny\cores\tiny\core_timers.h, it looks like the 2313/4313 only have one timer, so the mask and flag registers are TIMSK and TIFR rather than the TIMSK0 and TIFR0 expected by NewSoftSerial. A couple of hacks later, I found that by adding #define TIFR0 TIFR and #define TIMSK0 TIMSK right after the #definitions of the latter in arduino-0023\hardware\tools\avr\avr\include\avr\iotn2313.h it would actually compile. And it even seems to work up to 115200! It’s a pretty gross hack, and it’s a shame not to be able to use the UART, but at least now I have enough serial to try to make a little progress in getting the processors to talk to the radios.
TinyDebugSerial would be nice to have as well, but it defaults to D2/PA1/pin 4, which is one side of the crystal! I tried hacking TinyDebugSerial.h to point to port D bit 1 (pin 3), but couldn’t ever get it to work. Looks like it always? compiles HardwareSerial.cpp, which jumps in to declare the Serial class as HardwareSerial (by including HardwareSerial.h) if any baud rate register is defined – which should be the case for 2313. I even tried defeating that declaration in HardwareSerial.h, but it didn’t help. So zero luck getting tinyDebugSerial to work with 4313s, at least so far.
This is a lot harder than I expected.
Update 1/15/12: Some progress! I hope I can remember and write down all the important stuff I’ve done. In any event, I’ve got HardwareSerial running at least at 38400 and the TX and RX boards showing they can hear each other (at least TX->RX so far)!
Skipping past days of frustration, here’s some more critical stuff (beyond what’s already described above):
- Commenting out #includes is tricky While I was trying to get some kind of bidirectional serial to work with the 4313, I tried several serial libs – HardwareSerial, SoftwareSerial, NewSoftSerial, regular Serial, and at times TinyDebugSerial. I wanted to switch among them (since none worked right), so I put in a few blocks like this:
#define NSS ... #ifdef NSS #include <NewSoftSerial.h> #define myserial NewSoftSerial myserial myserial(0,1); #endif
The plan was to turn on which ever block I wanted to play with and use print commands that looked like myserial.println(“whatever”);. Not quite. Apparently you can’t comment out #includes that way. Neither can you comment them out with multi-line /*…*/. You can’t even get rid of them with #if 0 … #endif. And of course including headers you don’t want can cause trouble – even if the IDE clearly shows them as commented out! Single line comment marks like //#include <whatever.h> do seem to work. Who knew?
- You have to lie about “memory” I chose the attiny4313 over the 2313 because it had more “memory”. I didn’t expect to have much problem using all its “memory” – wrong. Each type of memory – flash, RAM, EEPROM is a separate battle.My first issue was being able to compile programs larger than 2K. That was easy – in boards.txt just hack attiny4313at16.upload.maximum_size=4096 instead of the 2048 from the attiny2313 stanza I copied it from.
Next was being able to actually upload that much to the chip. After I got past the signature, it was a small step to further hack the 2313 stanza in avrdude.conf to set ‘part->memory “flash”->size=4096’ (up from 2048). Actually, by running a later version of the avr tools, there was a stanza for 4313, though I had to hack that one so it was used to load a “2313”, since I still have no way to change the command line params to avrdude, so it still thinks it’s loading to a 2313. I think you have to rebuild the IDE to change the avrdude invocation.
RAM was hard. I suspect many of my problems of bizarre behaviors (like valid C syntax not working) were because I was out of RAM. The Arduino environment is singularly unhelpful in helping you troubleshoot RAM problems. Basically the stack and heap overwrite each other and bad things happen when the program runs, with no clues at build time.
The compiler starts at the bottom of RAM with .bss and then the heap. The stack starts at the top of RAM and works down. Since I’d told it I was using a 2313, it assumed there was only 128 bytes of RAM, and so started the stack in the middle of the 4313’s 256 bytes – making the top half useless. How can I find where the stack really starts?
Since I couldn’t get any serial lib to print values of variables (only short character strings) I couldn’t just print the address of the first local variable (which lives on the stack) or use the helpful freeMemory() function I found in this forum post. But you can print the symbol table by running hardware\tools\avr\bin\avr-nm against the binary elf file, which lives (after the most recent compile) in the most recent directory with a name like \Users\Jim\AppData\Local\Temp\build4951313939990712133.tmp as *.elf. Avr-nm‘s output includes a nice line like “000000df W __stack”. (That 0xDF is the 128 bytes in a 2313 plus 0x60 bytes of various registers.) OK – I can see it. How to change it to the 0x15f value the 4313 needs to use its 256 bytes?
I found references to the stack being started at the symbol RAMEND – which is set to the top of RAM for the chip in use. RAMEND is clearly defined in hardware\tools\avr\avr\include\avr\iotn2313.h. I changed that #define (of course restarting the IDE after the change) – but __stack remained at 0xdf. So it doesn’t actually use the RAMEND symbol to set where the stack starts.
It turns out it’s compiled into hardware\tools\avr\avr\lib\avr25\crttn2313.o. In a startling bit of good fortune, using a hex editor on the .o file I found the string “__stack” (starting at offset 0x0642), and an instance of the value DF 00 at an offset of 0x0504 (in the version I’m running). From the appearance of the junk in the area, it looked like those might go together. Fingers crossed, I changed that to 5F 01, restarted the IDE, recompiled the sketch, re-found the latest build directory, and reran avr-nm. The line was now “0000015f W __stack” – success!
- By default TinyDebugSerial uses on of the crystal pins for output Since I’m using the crystal, that made TDS not helpful. But this hack to <sketchbook>\hardware\tiny\cores\TinyDebugSerial.h changed that to use the same pin as the UART TX (since I couldn’t get HardwareSerial to work at the time):
#if defined( __AVR_ATtiny2313__ ) /* port A bit 1 (pin 4 - xtal!) - jw #define TINY_DEBUG_SERIAL_REGISTER 0x1B #define TINY_DEBUG_SERIAL_BIT 1 */ /* new: port D bit 1 (pin 3) */ #define TINY_DEBUG_SERIAL_REGISTER 0x12 #define TINY_DEBUG_SERIAL_BIT 1 #elif ...
- The 2313 support defaults to NOT use the UART In hardware\tiny\cores\tiny\core_build_options.h for 2313 is “#define DEFAULT_TO_TINY_DEBUG_SERIAL 1”. To use the HardwareSerial lib, this has to be turned off (changed to 0). It looks like the timer interrupt flag and mask registers TIFR0 and TIMSK0 I’d hacked in are only needed for NewSoftSerial. If I use HardwareSerial, they’re not needed.
That’s all I’m aware of right now.