Dual channel El Cheapo pulse generator
So, what is this all about?
For some thing at work it was useful/necessary to generate a not-too-tast, not-too-perfect yet arbitrary long and complex 2-channel digital signal. The thing described here is not that interesting, but can be built in a jiffy (2.5 hours by yours truly, starting from scratch :-) and is really cheap.
The device itself acts as a dumb interpreter/timer of an incoming headerless bitstream (2 bits per sample, ad inifinitum), and outputs samples on each of 2 output-channels (A and B) at fixed intervals.
Apart from a fairly uninteresting LM317 regulator and an equally boring Maxim MAX232 level-converter, there is...
Workhorse (although it's burning cycles most of the time) is the faithful ATtiny2313 (although the schematic show an AT90s2313 there). Input-bitstream comes from a RS232 connection from a host-PC, although a 'self-test' jumper can be closed to have it feed a nice bitstream to itself - mainly useful to test output-levels and -timing. Samples are output as 0V (low) or 5V (high) on 2 pins 'A' and 'B'.
This is the 3rd or even 4th unit I had the honour of soldering together; the other ones blew up, quite literally. Looking at the schematic, a diode after the 24VDC-terminal can be seen, as well as 2 clamp-diodes for each channel. In addition, a 4k7 resistor is placed after the clamp-diodes. This prevents damage in case of short-circuit or connecting an output to the gnd- or 24V-rail.
This is the less-boring part, perhaps. Software consists of a real-time part (inside the MCU) and a piece of software on PC that basically feeds the device with a bitstream. The latter can be your average TeraTerm.EXE, or it can be a custom interpreter/generator - I chose the latter.
The bitstream from the PC arrives in an 10-bit frame (startbit + 8N1) @ 115k2. Only 8 useful bits are present in each frame. Since a sample-(pair) consists of 2 bits (1 for each channel, to be output simultaneously), this gives us a sample-rate of ( 115200 / 10 ) * 4 ) ~ 46 kHz = freq_sample. This is not just a Good Idea, it's a fact of life, and follows directly from sample-size (2 bits), frame-layout (10 bits) and serial bit-time ( 1 / 115200 ). We can only output samples at freq_sample Hz using this simple 'bitstream' method, period.
Therefore, 1 sample-period = ( 1 / freq_sample ) ~ 21.7 usec. Bytes will be arriving (assuming there is no delay between serial frames, i.o.w. each stop-bit is immediately followed by the start-bit for the next frame) at ( (1 / 115200 ) * 10 ) ~ 86.8 usec = ( 1 / freq_frame ). This makes sense, since freq_sample = ( 4 * freq_frame ), since there are 4 samples in a frame. Lovely.
The software will basically do the following: wait for a byte, then, 4 times in a row, snoop the next 2 sample-bits from the byte at freq_sample. After that, the cycle repeats when a new byte comes in.
To do this, 2 interrupt-handlers ('Rx-complete'-interrupt and a timer-interrupt) are used in the following way:
- on arrival of a byte/frame over the serial link, 'Rx-complete' ('RXC') handler is entered
- in RXC-handler,