Electronics -- Frequency Counter: Firmware
"We have frequency counter mode, event counter mode, two time measurement modes, all that with different enable modes (input B), different gate times, divider setting, reset, hold", you may say and add: "Furthermore, we want automatic range adaption when frequency is over range and allow manual fine-tuning of the frequency counter and (of course) store the parameters in the EEPROM. -- How can we fit all that into these few kilo-bytes of flash storage?"
Well, remember that they put a man on the moon with only a few kb of RAM! There is actually a lot more (than mentioned above) one can do with the 16kb flash inside the ATMega161: The first full-featured firmware (which had all the functionality mentioned above) only had 3210 bytes (in words: three thousand two hundred). It was compiled using AVR-GCC from 39181 bytes or 1669 lines of well-commented plain C source code. (Isn't that refreshing in a time where everybody is talking about mega and giga bytes?)
Writing the firmware
Actually coding the firmware is a critical part -- especially the first version. If one already has a working version it is generally relatively easy to improve it, but writing the initial version can be tough since there is some amount of initialisation and functionality which all has to work correctly. And in my case the only way of testing was actually downloading it on the device since I have no simulator -- and even if I had, it would not be easy to provide the same IO on the roughly 40 communication pins required for proper operation.
So how to start? Well, it's probably best to have a large (virtual) screen: Open your favourite editor (and a shell), open the microcontroller's data sheet and make sure it is quickly accessible, just as your circuit schematic. You need all the three all the time: The control registers and bits or symbolic names need to be looked up in the data sheet, the acutual pin assignments come from the circuit and make sure you know if the signal in question is using positive or negative logic (i.e. active LOW or active HIGH?). Double-check every critical line of code and write a comment about what it is meant to do.
Of course, most of the usual program design rules hold here, too. (Just forget all the over-engineered OOP stuff and don't hesitate to use global vars.) Especially it is essential to do some planning of the structure and workings in advance. Questions like "What signal triggers an interrupt and what needs to be done?", "Where are interrupts allowed, where do they have to be disabled?", "Where are the time-critical parts?" need to be clear before writing the first line. Otherwise one codes things with the initial plan's set of side effects in mind -- and changing some parts lateron is "opening a can of worms" (in form of changed side effects like interrupts) which will cause you sleepness nights (or a complete code re-write). You cannot quickly launch a debugger when the program dies from a SIGSEGV.
Frequency counter firmware
The firmware was written in C (compiler: AVR-GCC) and is only available upon
request. (I may make it available in the future, though.)