I'm crossposting (well, pasting) this from my new blog, but....I wanted to see if this, and the previous installments, would help:
Part 3 is the ultimate conclusion...the post is too long to fit here, soo....
..and the last lap? We would like to use an Arduino as a generic AVR programming device: leverage the low-end tools that come with Linux and the Arduino IDE to do stuff the gods of high-level programming never intended.
And there are other benefits of programming on the bare metal this way, if one's willing to do a little homework. It is certainly cheaper: a bare Mega328 costs $5 or less, as compared to $10 for the cheapest possible Arduino; and the tiny45 can be bought in volume at $0.99 a device! And knowing a little bit more about how AVRs work, and how the programming tools do their job, can't hurt.
One of the problems with the Arduino IDE is it DOES bloat the code a bit; this isn't a problem on most Arduinos, which have a relatively large amount of flash and static RAM compared to the size of the bootloader and the more routine sample programs. On the older and smaller devices, though, program and static RAM space is a major issue.
<code not included, see https://burntcouch.blogspot.com/ >
This is about as simple a program as you can write on an AVR, no matter how you do it....and with the IDE you still end up using 808 bytes of program space and 9 bytes of RAM. I suspect that the delay() function takes up the bulk of that.
A few days earlier, I'd spent about half a day installing and cramming the WinAVR package on an old Dell Inspiron 7000 (Windows 2000, 128 MB of RAM, 4GB HD!), because it was one of the few PC's my junk pile furnished with a useful parallel port. Up until I discovered the Arduino I had been using AVR assembler, Atmel's AVR Studio on a PC, and an old homebuilt SP12 programmer for all my ancient AVR devices. I have several AT90S2313's and 8515's, a mega16, a mega8515, and a number of tiny26's (ancestor of the 261/461/861), all of which I wanted to continue to use.
I didn't have too much trouble working with WinAVR, and in the process managed to muddle through the rather complicated 'demo.c' program on the AVR-libc support site.....which example DOES (more or less), implement the 'fader' program in my previous post on this subject. I modified the demo, working over the various macros embedded in the 'iocompat.h' file, and got it to work with the PWM stuff on the tiny26. All good....
But...I didn't want to lug out that old clunk programmer and yet another computer when I wanted to use my old uC's, dammit! And I wanted to use Linux as well...so what next?
While using the WinAVR stuff, I used the command line, as illustrated in the AVR-libc tutorials for 'demo.c' above, to do everything by hand, like so:
Insp7000 c:\code\> avr-gcc -g -Os -mmcu=attiny26 demo.c -o demo.o
Insp7000 c:\code\> avr-objcopy -j .text -j .data -O ihex demo.o demo.hex
This built me a 300+ byte file in 'demo.hex', and with the SP12 dongle I uploaded it like so:
Insp7000 c:\code\> avrdude -p t26 -c sp12 -U flash:w:demo.hex
(Notice that avr-gcc and AVR-libc know the ATtiny26 as 'atttiny26', while avrdude believes it is called 't26'. Gotta keep our wits about us, kids...)
Which was probably no more that 70-80 bytes on the tiny26....Impressive! And more to the point, it worked. And note that the much simpler 'blink' program for the tiny45 above, letting the Arduino IDE do the heavy lifting, was 10 times the size.
Size matters; the tiny26 has 2K of flash, while the Mega328P (the core of the Arduino Uno) has 32K to waste. We can do better, for not much in the way of pain.
So, this last example should give us some proper hackerly ideas, right? Avr-gcc and avrdude are already there with the Arduino IDE installed; and unlike the IDE, avrdude has the full pin descriptions and functions defined for EVERY AVR clear back to the microcontroller stone age. In theory, at least, if we have the ArduinoISP software loaded up on the Uno, we should be able to make the Arduino program ANY AVR device, as long as AVR-libc and avrdude know the device exists.
First, let's look in 'programmers.txt' in the Arduino IDE install folder (/hardware/arduino/avr/) and see what kind of directives are sent to avrdude for the 'Arduino as ISP' programmer defined there:
<not included, see https://burntcouch.blogspot.com/ >
And so we see. Unlike when hitting the Arduino directly through the IDE, we must talk DIRECTLY to the serial.port (not with the pseudodevice 'usb'), as well as define a baud rate to talk through the Arduino (as if it was a serial port itself rather than the destination for the code we want to write).
So that's one piece of the pie. The other piece is....which programmer do we use on the avrdude command line if we aren't going out on the parallel port with the SP12 dongle? Entering 'avrdude -c ?' gives us a list of programmers that it knows about:
<not included, see https://burntcouch.blogspot.com/ >
The only one the looks even close is, well 'arduino', so let's use the command line options we found above in combination with what we've got here, and just try talking to the gadget and see:
<not included, see https://burntcouch.blogspot.com/ >
So wow, it just works! That is, indeed, the correct sig for the ATtiny45. The Arduino Uno passes our request right through using the ArduinoISP software (with the jumpered on capacitor across the Reset line) to get to our 'legacy' device.
So now, how about a new version of the blink program? Let's see here:
<code not included, see https://burntcouch.blogspot.com >
Compile it with avr-gcc and use avr-objcopy to create the hex file, then avrdude can write it. 100 bytes used total!
So how did I concoct the above? Among other things, I looked for (and at) the main header files that the IDE loads when you create a new program...i.e. at the Arduino.h file, which is stored at /hardware/arduino/avr/cores/. LOTS of handy macros in there, and a nice list of other files that are included in all IDE builds by default. Since we are trying to program on the bare metal, making as few assumptions as possible about the device, we can muck and pare at that list a bit, drill down through a few #includes to find what they do and what we need, guess what we don't need. Eventually we can just go with:
#include <inttypes.h>
#include <avr/io.h>
#define F_CPU 8000000UL // 8Mhz on t45 - this needs to be defined BEFORE including util/delay.h
#include <util/delay.h> // for _delay_us(double) and _delay_ms(double)
There was one gotcha in my first attempt at this: avr-gcc bitched incessantly that F_CPU was NOT something it knew about, thus the #define for the CPU frequency there....I tried just including util/delay.h without it, and immediate had a wake up call. OBVIOUSLY (right? right?) the delay functions wouldn't work right if they were based on the clock speed of the device, and didn't know what that number WAS. An arbitrary AVR device can't be assumed to have an RTC or a PLL clock built-in, so the only other way to have a time base is to run it off the CPU clock, and....
IN any case...paring the #includes down to a bare minimum shows us what we can safely leave out, while still giving us some nice short cuts, and a handy template for building more complicated stuff later on.