Hey folks, Crow here. This issue has probably been raised and solved many times prior to my experience with it, but I will make a note of it here for anyone similar in coding practices to the way I do things. I am not really a C programmer. I am an assembly language programmer, from the olden days of the COSMAC CDP1802 (“Olduino” — it was CMOS and would run on a 9V battery in 1976!) through the Zilog Z8 and Z80 and finally things like the MC68000. Then I discovered PICs, and learning that MCU’s strange little instruction set taught me some things are sort of meant to have their code built from a compiler, which brings me to the AVR parts.
My single-board Crowminius instrument has a MIDICV circuit that uses an ATMEGA328P along with a pair of MCP4822 DAC chips to provide the control voltages and gates to operate the analog synthesizer. Also buried in the code is a direct-digital synthesis PWM sine wave generator programmed to provide a single tone at 440.00Hz as a tuning reference. Since the Crowminius Euro module set I am designing will not have a built-in MIDICV circuit, the local 440Hz reference would need its own dedicated microcontroller. Using an Adafruit Trinket with its ATTINY85 MCU, I chopped the code down to just that needed for the tone generator. The ATTINY85 has one 8-bit timer, “Timer 0,” as opposed the the 328P’s Timer 0 and Timer 2. (Timer 1 in both parts is a 16-bit unit). I had been using Timer 2 in the ATMEGA328P for the DDS phase accumulator interrupt routine, which is unclaimed by the Arduino toolkit.
Except I wanted to use Timer 0 on the ATTINY85, which led to a compile-time issue. Timer 0 is reserved by the Arduino environment for use in the delay() and millis() functions. If I try to declare my own timer 0 interrupt header ISR(TIMER0_OVF_VECT) Everything seems to compile fine until the core module linker later starts complaining:
core.a(wiring.c.o): In function `__vector_5′:
C:\Users\Crow\Arduino\arduino-1.0.5\hardware\arduino\cores\arduino/wiring.c:49: multiple definition of `__vector_5′
Duplicate vector? “__vector__5” is not exactly descriptive but I only declared the one interrupt vector so some kind of black magic was being invoked during the compile. This starts getting into why I never warmed up much to C: too many files to keep track of, particularly when one is not used to ‘just knowing’ where stuff tends to be located. At least the compiler tells me where to look, line 49 of this ‘wiring.c’ file buried several layers into the directory tree in which a Timer0 ISR is declared for the delay stuff and which explains the multiple definition error. Now if I were writing the compiler, my pre-processor would allow the option to just pick the first declaration and ignore any subsequent ones, not just error out on the fact more than one exists. I get that sometimes this is needed, but as I said I would at least have the option.
I still wanted to use Timer0, so I decided to make the code as generic as possible with no hooks into non-AVR files. It turns out if I do not use the setup() or loop() statements and instead just declare main(), avr-gcc compiles the code without linking to things like wiring.c.o. Of course this means all the handy function calls the Arduino IDE offers are off the table, but I am just wanting to generate a PWM sine wave and do not need much beyond basic K&R C and a couple of AVR’s library functions to use a data table stored in the program flash area.
This may all seem obvious to a veteran embedded C programmer, but for folks like me who live “close to the hardware” it is always a learning experience. I’ve since googled further about the issue and learned others also ditched setup() & loop() for main(), have modified alternate versions of wiring.c and implemented things like vector list pointers. That last one is somewhat like interrupt server chaining I did 25 years ago on the Amiga in 68000 assembly, but interrupt service chaining is a bit highbrow for a program that just generates a single 440.00Hz PWM sine tone. The code snippet below shows the important parts. I’ll post the code for anyone who cares once I test it on the actual circuit it is meant for.
Cheers,
Crow
/**/
bGrab is just a #define bGrab pgm_read_byte_near as too many variables and functions seem to have_names_as_long_as_my_forearm.