If you've downloaded any of my code, you've most likely noticed a folder called "_commonCode-localized."
What Is It?
So, what is this...? Well, browse it!
I'll say right now, repeating my About Me, that I have a tendancy to reinvent the wheel... so it's *quite likely* there's a standard way of doing this, and I've come up with the most convoluted.
In the _commonCode-localized folder contains all the "common code" used by this particular project. It's kinda like libraries, except it gets recompiled for each project (since most of it isn't restricted to AVRs, I use multiple AVR architectures, and there are a ton of configurable options to e.g. reduce code-size based on the project's needs). (Check out "The Scheme" below, if you wish to get thoroughly confused).
The Stuff (aka things)
Currently my directory-listing of _commonCode contains:
(holy shit, a lot more than I remembered... I'mma strip this a bit)
things handled by, e.g. <stdio.h>, which I use regularly in specific ways... e.g. non-blocking serial I/O and my lame attempts at mimicking that functionality for stdin.
non-blocking input from stdin. E.G. a loop in main() needs to run continuously without waiting for keyboard-input, but needs to receive keyboard-input when it arrives.
Similar to stdin_nonBlock, but for the serial-port. This also handles configuration of serial-port parameters...
This is poorly-named, but basically it makes output to the serial-port similar in function to serIn_nonBlock
There's probably a more standard way of handling this... basically prints-out an error-number and its associated string
Displays a "spinner" on the screen, e.g. a single-character that cycles through: | / - \
This is used to indicate time, as well; after a full-cycle, it starts another in the next character on the line. So, e.g. "\\\\-" indicates that twenty-three seconds have passed.
Stringify handles several common string-related Preprocessor operations...
PASTE(number,1) -> number1 (this can be used, e.g. for creating variable names)
pinouts for particular PCBs I've designed and/or worked with.
This is where the common makefile snippets exist. It's not perfect. Currently I have individual .mk files for each AVR I've worked with. These usually have default FUSE values, and other things.
Compiling an AVR? This is where things like AVR-DUDE is handled/configured...
(I think this has been pretty much eliminated, in favor of reallyCommon2.mk)
I like my warnings... This adds 'em.
This is the stuff that's common for *all* my projects be they AVR or PC based. Puts stuff in _BUILD, handles localizing of commonFiles/, 'make tarball' (which is kinda outdated as-of 'make local') and certainly much more I'm forgetting. (see "The Scheme - thing.mk," below, for a better idea of what little idea I have)
now wait a minute... I thought we already handled this.
Use that AVR's ADC inputs!
Methods which *are* AVR-Specific, and means for handling them on a PC... (e.g. pgm_read_byte()) Mostly just a few hacks so I could create test-programs for other commonFiles (?)
Connect several pushbuttons to a single digital-I/O pin via resistors and a capacitor.
Now this has *everything* I'm *constantly* updating this with new functionality. MUCH of it is AVR-Specific, but most of it isn't.
e.g. A bunch of PORT macros, like "setinpuPORT(PA0, PORTA)"
A bunch of SHIFT macros, "SHIFT_LEFT_ONES(5)" -> 0b00011111
Methods for extracting a group of bits from an array of integers (across integer-boundaries)
Basically anything I've ever had to do that has dealt with bit-manipulation winds up here almost immediately
This is a one-off that somehow ended up "commonFiled" right off the bat. It's used in my "bluetooth-bee connector", which is the AVR-portion of my Wacom Tablet Bluetoother, which handles seamless communication between a simple serial peripheral and a computer's device-driver via the "BlueTooth Bee."
It's certainly got promise to be useful in the future, and should easily be ported to any uC.
Oy, once I really thought I'd be doing a heck of a lot with multiplexed 8-bit data-busses.
Wow, unfinished midi-stuff.
Bitmaps of text characters. Yes, in fact, I'm about 90% certain this was originally developed for my ancient LCD project and has been used many times since. There's a program to convert a bitmap image into header-data.
A simple circular-buffer implementation used by much of my code, both for AVR's and for PC stuff...
I *hate* using malloc, but I thought I'd give it a try, and ultimately decided it was too risky on the vast-majority of my AVR projects, whose memory-limits are constantly being pushed.
A means for displaying *every displayable color* on a 2D display. Kinda got crazy with some groovy effects. (As Seen in SDRAMThing)
32bit integer-based unlimited-axis coordinate-system used in my motion-control systems. Also usable for drawing, etc.
(Highly tied with gotoPoxn, gotoRamped, etc.)
A "deci-millisecond" timer (0.1ms resolution) Originally designed for an AVR's timer, it's long-since been adopted for many projects, and has many options.
Lately, I've been finding myself using tcnter (below) for new projects, as the precision and resolution is often unnecessary.
It is still used by much of my code, including heartBeat, gotoPoxn, etc.
just some wrapper-macros "So we don't have to typecast our eeprom locations"
Connect a quadrature-encoder to a couple pins on an AVR (as-opposed-to using an external encoder-counter chip like the hctl, listed below) Note that this gets risky if you *really* need to keep track of *every* step! (Noise on the line, interrupt jump time, etc.)
Oy, this is one that lingers... The original idea was to have some sort of standardized handling, such that if an error occurred each calling function could be informed of *where* it occurred,so eventually it could be passed up to main, where it could be indicated, e.g. via the heartBeat's heartBlink mode.I dunno if I ever got it working very well, and for most new functions there seem to be easier ways to handle it.
UNFORTUNATELY: Its not being fully/regularly-implemented means that if, e.g., you set a timer to a value it can't handle, there's really no indication.
Oy, another one that lingers... Actually, I think I might have gotten rid of it in most cases. I think I had higher hopes for where it would go, like to the level that bithandling is used. But as it stands all it is is a spin-loop delay that would probably be better handled by _delay_us(), etc.
You may have heard of the Goertzel Algorithm... It's similar to the FFT except frequency-specific. The result is a magnitude and phase value for a specific frequency. In college I used this in my research to detect dielectric properties of materials between two capacitive plates. In recent times, I intended to create a "Three Pin Identifier" which would give basic characteristics of a two or three-pin device (transistor, resistor, etc), e.g. to identify a transistor's functionality and pinout. The end-result I can't recall. I *believe* this code is actually the code used in my research project, but I vaguely remember its use in my TPID as being somewhat hokey, or maybe the output values were too vague to parse... ?
Multi-dimensional 32-bit integer positioning system... ideal for drawing lines, or otherwise traversing straight lines between two points, when each point is to be passed-through (e.g. in a motion-control system, or drawing lines on an LCD).
Along with gotoPoxn, this ramps the speed up and down, ideal for motion-control, but also kinda interesting graphically.
Interface for the HCTL-2000 series quadrature decoder chips from HP/Agilent.
While encoderDirect seems to work in most cases, this chip is *designed* to handle quadrature encoders, including filtering for noisy environments, etc.
If you can't miss a tick, use a chip like this.
used in nearly all of my AVR projects, this implements a "heartbeat" indicator. If everything's running smoothly, an LED fades in and out at a non-distracting rate (8 sec/cycle, usually). If you use "heartBlink" it indicates a hexidecimal value by blinking the number of times in each nibble. (e.g. blink=0x12 blinks once, then blinks twice, then waits and repeats).
Further, when wired correctly, the same pin can also be used as a momentary push-button input, simultaneously.
Further still, if used on the MISO pin, it has no effect on the AVR's ability to be in-system-programmed, because AVRs have 40mA load-ratings... (Thus, it's a good place to put an LED and a pushbutton)
heartbeat uses *many* other commonCode components, such as dmsTimer, hfModulation, and more, and can therefore increase code-size quite a bit. But it's usually the *first* thing I implement, in a new project. Therefore, there are quite a few options to reduce code-size.
Further Still, it handles the Watch-Dog-Timer.
similar in concept to PWM, HFM attempts to toggle a pin as quickly as possible while maintaining the proper power/maxpower ratio. It uses *very few* instruction-cycles, as there's no division or multiplication. It can also be used similar to gotoPoxn, with 8bit resolution... (See the description for "SEG_HFM" here, and see examples of it in-use in the images titled "SEG_HFM" and "SEG_RACER" here). -- heartbeat uses HFM to create the effect of an LED smoothly fading in and out.
This is my re-implementation of code and fonts originally from the program HP2XX. It's a means for drawing HPGL-vector-based text It was implemented in my drawing-machine, and my old graphic LCD project. The font itself is pretty low-resolution, but it certainly looks better than, e.g. scaling up an 8x8 character to 512x512.
This is a case where I think avrOverride can be handy, because this font is set up to load to an AVR's PROGMEM, but otherwise needn't be AVR-specific.
The HandSpring Visor series PDAs had a foldable-keyboard (made by Targus) that could fit in a (large) shirt-pocket. Cool! This interprets the scan-codes into ASCII characters, and makes use of the "special" keys.
The L298 is a dual H-Bridge chip, which can be used with holdPoxn to drive a DC motor. Another such chip is the LMD18200 (below).
The L298 requires external diodes, and when using high-frequency PWM, (basically anything inaudible) this means fast-switching diodes. It's A LOT of extra circuitry and components that aren't sitting around in most people's collections. On the other hand, the chip itself is pretty durn cheap.
The chip itself can also be used for stepper-motors, though I'm pretty sure this code is for DC motors.
A driver for text-based LCDs. I've always found these things to be particularly finnicky; one brand will work with a certain initialization-sequence, and another will just choke. I must be stupid. This *should* be pretty good at it, since I'd worked with several over the years, and this should be the culmination of that work. But I can't give you any guarantees.
This is my attempt at standardizing graphical LCD timing stuff. This is used by Drive an old Laptop Display from an AVR as well as SDRAMThing2.0. It should also be relatively easy to port to a regular TTL-input TFT, and probably even VGA. Basically anything that uses Hsync, Vsync, and/or Data-Enable. The actual interface-implementation is left to the project, so check out those two links for some examples.
More with text-based LCDs. This attempts to create a simple menu-system for e.g. setting configuration values. As I Recall... but then what's this menuUI thing, below?
Please, if you see this mentioned in a project, let me know. This is highly deprecated.
An attempt at creating a standard interface for "Home" and "Limit" switches for motion-control. I don't even know if this is still used.
No shit, I completely forgot about this. This goes through the commonCode directories and (in most cases) lists the latest versions...
The LMD18200 is an H-Bridge chip, suitable for DC motors. Use it with holdPoxn, etc. This one is *way easier* to interface than the L298 and also suited for greater loads. But it comes at a cost... *cost*. And, also it has weird pin-spacing.
Honestly don't remember...
Just what it says! Uses UART interrupts to call project-based functions to handle MIDI events, multiple inputs possible.
Sends MIDI events, multiple outputs possible.
This holds a DC motor, with a quadrature-encoder, at a specified position, regardless of a varying load. E.G. try to turn the motor's shaft by hand and it will apply the necessary power to resist movement.
Combined with gotoPoxn, which varies the position the motor tries to hold, this gives high-precision speed and position control.
Combined with gotoRamped, this gives smoothly ramping motion from one specified position to another.
With multiple-axes it assures that each motor's position is reached before continuing so e.g. a *heavily* loaded motor on one axis will not allow for a particular motion to be spacially distorted. This is, e.g., for drawing/CNC machines where loading may be somewhat unpredictable, but the shape of the motion is important.
E.G. Combined with sineTravel, a nearly perfect circle can be drawn via motors in a cartesian coordinate-system, even where the linear "gliders" are poorly aligned (causing increased loading toward one end of the axis). (I thought this was "holdPoxn", but see _About.txt.
Guess it's due for me to revisit my motion-control code. TODO.)
Oy, some sort of optimized 64-bit multiplication+division routine apparently related to goertz (drawing a complete blank)
The Alesis NanoTracker was a MIDI sequencer that had some pretty severe bugs... Alesis cancelled the product, and surplus-shoppers got 'em cheap.
This is a hardware-based interface for the NanoTracker to handle things like Play/Pause, which the actual Play/Pause footswitch input didn't handle.
This was an attempt at creating an auto-calibrator for the OSCCAL register, in order to synchronize an AVR running off its internal RC-oscillator with an input baud-rate. It sorta worked, as I recall, but not 100%. (Though I've since found some potentially big bugs in the commonCode it relies on, and it may be worth revisiting)
Osccalibrator also contains a PC-based application that eventually became my de-facto serial logger, containing time-stamps, hex/binary translation, etc. Take a look at it.
I might've signed an NDA on this one...
Basically two options, either pulse an output given an input, or hold/sustain that output, given an input. The particular input is MIDI note-on, (and note-offs). 24 refers to the number of outputs that are individually controlled.
Just what it says... connect a PS/2 device, this acts as a host (e.g. a PS/2 touch-pad). This is in no way making use of the on-chip peripherals (e.g. USI, USART, etc.) thus "polled"
These are a bit-banged Universal Asynchronous Receiver and separate Transmitter.
They make use of tcnter to determine the proper sampling times, etc. As many or few UARs and UATs can be configured as need, pins, and processing-power allows, and there's no restriction regarding their having similar baud-rates. Since these are polled, they can be a bit finicky unless the main update loop is called *quite* often. For the most-part, though, they do their job pretty well.
This configures the PWM functionality of the chip. Many different chips are handled, and it attempts to keep their interface pretty much standardized.
Should no longer be necessary. Please inform me if you find it in a project
sineTable is a table of values for a sine-wave. The table itself consists of 129 values, representing one quarter-wave, the remainder of the wave can be determined from these values. sineTable also consists of functions for retrieving these values. It has its own angle-scale; As I recall, SINE_PI is 256. It also has its own amplitude; configurable to INT8_MAX, INT16_MAX, or INT32_MAX.
It also contains "sineScaled()" which handles scaling and offsets.
sineTable is used pretty regularly in my code... definitely in gotoRamped, and sineTravel.
sineTravel creates a point-by-point travel-plan given a start-angle and end-angle in a circle, an amplitude, and an offset. It uses gotoPoxn to traverse between those points as though the "angle" varies constantly with time. A special-case is gotoRamped, which treats a single-axis motion as though it's two-axes in a sineTravel. Thus, the travel speed is determined by the speed along a single axis of a circle; ramping-up in speed, from 0 near the furthest extent along the axis, where a change in angle causes a small change along that axis, increasing in speed until it reaches the midpoint, where a the same change-in-angle corresponds to the furthest change along the axis, then ramps back down as it reaches the other extent along the axis.
use midiOut to send debug-messages via SysEx
use a timer's raw TCNT value as a timer (similar to dmsTimer, without requiring interrupts). As long as tcnter_update() is called more often than the timer overflows, this can act, essentially, as though a low-bit counter has an arbitrarily-high bit-count.
polled_uat, polled_uar, and many others use this to keep track of bit-transaction times. If, handled properly, tcnter_update() needn't be called so often (e.g. if it's *only* in use for polled_uat, then the only times it needs to be called is when polled_uat is transmitting. This requires great care, though, as other functions may be using the tcnter behind the scenes.
Should be long-since replaced by timerCommon, though may still exist in ancient code.
Attempts to create a standardized interface for all timer/counter peripherals in many devices. Used extensively, almost the exclusive means for configuring timers in my projects and commonCode. This is a bit bloated by functions which aren't often used, thus it's wise to look into the "UNUSED" configuration options, etc.
configure the PLL on the ATtiny861
OLD attempts at creating methods for changing between different types and keeping the most realistic value possible (e.g. int16_t i=768, uint8_t j=typechg(i); -> i==255 --ish)
Use the built-in UART or USART input(s)
ALSO handles "indicator detection" (e.g. ';') to handle string-input when the string is terminated.
FURTHER: can be used with any character-input device for indicator-processing (e.g. polled_uar, or usi_uart).
Use the built-in UART or USART output(s)
TODO. commonFile this! Use an ATtiny's USI device as an i2c slave.
TODO. commonfFile this! Use an ATtiny's USI device as an SPI slave.
Use an ATtiny's USI device as a half-duplex UART (Modified from Atmel's example)
Now wait just a minute... what's the difference between xyTracker and gotoPoxn??? (TODO: Revisit this!)
Code-Size Optimization, to do or not to do?
Recurring theme: Many of these commonCode packages have quite a bit more functionality than most projects require. Thus, most of these also have options to reduce code-size when certain functions are known to be unused, etc.
I, personally, find it kinda handy that the easiest way to get a project started is to ignore all those optimization options... As the project grows in size, nearing the memory limit, it's a nice surprise to find yet another bit of code that can be easily removed to regain another 200Bytes and can actually test that last code-change that was just on the verge of fitting.
Further, some of these packages offer functionality which can be *entirely* removed with no effect on the system; e.g. heartbeat has a HEART_REMOVED option, which reduces codesize dramatically, without needing to remove calls to heart_functions().... The only (intended) effect is to stop blinking an LED. (TODO: Implement simplified heart_pinInputPoll() that still works despite HEART_REMOVED) Other cases, such as HFM_REMOVED, are a bit more risky, as they may be used by other packages.
The Scheme (probably poorly written and unorganized, both the scheme itself, and this explanation of it)
There's a basic scheme, which I've termed "commonFiled" and often don't get around to doing for one-off or two-off usages (these have version numbers that end in "ncf" meaning "not commonFiled."
For each commonFiled thing, there are usually three files: thing.h, thing.c, and thing.mk.
thing.h -- in addition to being a header-file with declarations, typically gives a simple example of how to use this particular thing (after a long list of revision-info).
So look into thing.h first.
thing.c -- as usual, this is the actual source-code for thing. I've found that there are certain ways to optimize code to reduce code-size that go against "the norm..." (or at least the "good practices" taught in school)... e.g. how to include an inline function such that it won't ever be compiled separately. THUS: You may find that certain options cause thing.c to be *directly included* in your source-code, and therefore never compiled as a separate object-file. This makes things difficult in some ways... In this case, if you modify thing.c, "make" will not recognize the change. There's probably a way to fix this, but hasn't been a high priority for me. THUS IT IS WISE TO ALWAYS DO 'make clean' and then 'make' with my code. (I mean, come on... it takes less than 3 seconds to compile a 64kB AVR binary on an ancient computer.)
thing.mk -- this is thing's makefile snippet. There's a pretty standard structure to it, that makes sure thing.c is included (or not) in the SRC variable, etc. It also has a few other variables to make my life easier... (See _THING_HEADER_ below). Further, if this particular thing includes another thing, then this thing.mk makes reference to that_thing.mk in a particular way (that matches how it's done in the project's 'makefile'). In some cases, there are also special options particular to this particular "thing"... e.g. if THING_INLINE is true in your project's 'makefile', then thing.mk sets __THING_INLINE__ true as a preprocessor option, which thing.c and thing.h interpret accordingly, and it's all quite a mess when it comes to these options, because half of them are indirect like that, and half of them have to be explicitly set (via CFLAGS+=-D'WHATEVER=TRUE') in your 'makefile' WEE!
For instance, if I want to include "~/_commonCode/thing/0.20/thing.h" I just say #include _THING_HEADER_
_THING_HEADER_ is defined in thing.mk and includes the version-number set in your project's makefile.
This *also* makes it handy for cases like "heartBeat" which (typically) includes *several* other commonFiled things, such as hfModulation, and dmsTimer (and dmsTimer includes timerCommon)...
By using _WHATEVER_HEADER_ the version set by "VER_WHATEVER=" wherever it may be-so-defined is used.
Wherever has a bit of a priority-tree... the deeper in the makefile-tree VER_WHATEVER is set, the lower the priority... So, if your project's 'makefile' explicitly states that VER_TIMERCOMMON=1.20, but dmsTimer.mk says that VER_TIMERCOMMON=0.99, the *entire project* and will use 1.20. Likewise, if your makefile said VER_TIMERCOMMON=0.80, the *entire project* will use 0.80, despite the fact that dmsTimer says VER_TIMERCOMMON=0.99
Personally, I consider this a feature. It's seldom I go backwards, but there are cases (I in fact ran into one while preparing to upload the edidSpoofer code). It also helps when developing, e.g., a new version of timerCommon, in that it sorta helps to make sure that it's backwards compatible (since dmsTimer also depends on it). Though that whole theory is a bit hokey now that there are so many options.
Generally, version-numbers that are .1 away from each other (e.g. 0.50 and 0.60) aren't expected to be compatible, but 0.51 and 0.50 should definitely be.
I think I may be trying to cover too much ground, here. The jist of it is this: I keep all my _commonCode in one directory on my computer. If I make changes to anything in there I make sure, as best I can, that it's either completely compatible with the old version, or has a new version number. I *often* keep the same version number for small changes... thus in the revision notes in thing.h you will see "0.40-17" and think "but wait, my thing.h is located in 0.40/"! Typically when I make a *huge* change, I'll make a similarly huge jump in version number.
The main thing is the .mk structure, and the (potential) #inclusion of .c files. Oh, and that non-common-filed ("ncf") versions in the _commonCode directory typically haven't yet had their .mk files created, may not have a header file, probably need to be explicitly #included in main.c, and need to be explicitly handled in the project-makefile.
Also, check out _commonCode/_make/ for more info about my makefile scheme.
(And consider yourself lucky, as I only put in _commonCode-local/ the commonCode things and versions that are used by the project, otherwise you'd have a gazillion makefile snippets to look through which have nothing to do with the project ;)
Again, I'm not a genius, and I tend to reinvent the wheel repeatedly. Makefiles were extraordinarily elusive to me for quite some time, and actually remain that way. I have, in fact, written the vast-majority of what's in there (I think Eric B Weddington's gotten props for the help from his examples early early on), but it's been a long slow process, one or two tiny changes at a time, separated by months inbetween. I barely even grasp the idea of how I managed to get the compiled-code to be in _BUILD/ instead of in the _commonCode/thing/... directory. Alot of banging my head against a wall, I think (and a lot of forgetting to make-clean and not having the wherewithal to even begin wondering why my ATmega644 object file doesn't work with my ATtiny861)
uhm.... this wasn't supposed to be an explanation as much as a list... back to the top! (Third time I've read this, now... back to the top!).
TODO: anaButtons; document bithandling?, capButton(?), delayCyc, eepCharBitmap(?!), grabDecimal(?), _make...., piezoHitDetector, __std_wrappers, tinyPLL?, nkp, nlcd?