An input/output controller for virtual pinball machines, with plunger position tracking, accelerometer-based nudge sensing, button input encoding, and feedback device control.

Dependencies:   USBDevice mbed FastAnalogIn FastIO FastPWM SimpleDMA

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers 74HC595.h Source File

74HC595.h

00001 /* Copyright 2014 M J Roberts, MIT License
00002 *
00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004 * and associated documentation files (the "Software"), to deal in the Software without
00005 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
00006 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
00007 * Software is furnished to do so, subject to the following conditions:
00008 *
00009 * The above copyright notice and this permission notice shall be included in all copies or
00010 * substantial portions of the Software.
00011 *
00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017 */
00018 
00019 #ifndef HC595_INCLUDED
00020 #define HC595_INCLUDED
00021 
00022 #include "mbed.h"
00023 
00024 // 74HC595 Interface
00025 //
00026 // We require four GPIO pins: 
00027 //
00028 //    sin - serial data
00029 //    sclk - serial clock
00030 //    latch - the LATCH signal, which transfers the internal shift register
00031 //            bits to the physical output pin states
00032 //    ena - the Enable signal
00033 //
00034 // Note that the physical !OE (output enable) pin on the 74HC595 is active-low.
00035 // To allow for orderly startup that guarantees that outputs won't be pulsed
00036 // (even briefly) during power-on, we require the !OE pin to be wired with a
00037 // pull-up resistor to Vcc, and connected to our ENA GPIO pin via an inverter.
00038 //
00039 // Recommended wiring: connect the GPIO pin to the base of an NPN transistor
00040 // through a 2.2K resistor, connect the collector the !OE pin on the 74HC595, 
00041 // and connect the emitter to ground.  This will pull !OE to ground when we
00042 // write a digital 1 to the ENA GPIO, enabling the outputs.
00043 //
00044 // We use simple bit-banging through plain DigitalOut pins to send serial
00045 // data to the chips.  This is fast enough for our purposes, since we send
00046 // only 8 bits per chip on each update (about 4us per chip per update), and
00047 // we only update when we get a command from the PC host that changes an
00048 // output state.  These updates are at USB speed, so the update interval is
00049 // extremely long compared to the bit-banging time.  If we wanted to use
00050 // these chips to implement PWM controlled by the microcontroller, or we
00051 // simply wanted to use a very long daisy-chain, we'd probably have to use 
00052 // a faster transfer mechanism, such as the SPIO controller.
00053 
00054 class HC595
00055 {
00056 public:
00057     HC595(int nchips, PinName sin, PinName sclk, PinName latch, PinName ena) :
00058         nchips(nchips), sin(sin), sclk(sclk), latch(latch), ena(ena)
00059     {
00060         // turn off all pins initially
00061         this->sin = 0;
00062         this->sclk = 0;
00063         this->latch = 0;
00064         this->ena = 0;
00065         
00066         // allocate the state array
00067         state = new char[nchips*8];
00068         memset(state, 0, nchips*8);
00069         dirty = false;
00070     }
00071     
00072     // Initialize.  This must be called once at startup to clear the chips' 
00073     // shift registers and enable the physical outputs.  We clock a 0 bit (OFF
00074     // state) to each shift register position, latch the OFF states on the
00075     // outputs, and enable the chips.
00076     void init()
00077     {
00078         // set the internal state of all inputs
00079         memset(state, 0, nchips*8);
00080         dirty = false;
00081         
00082         // clock a 0 to each shift register bit (8 per chip)
00083         sin = 0;
00084         for (int i = 0 ; i < nchips*8 ; ++i)
00085         {
00086             sclk = 1;
00087             sclk = 0;
00088         }
00089         
00090         // latch the output data (this transfers the serial data register
00091         // bit for each pin to the actual output pin)
00092         latch = 1;
00093         latch = 0;
00094         
00095         // enable the outputs
00096         ena = 1;
00097     }
00098     
00099     // Set an output state.  This only sets the state internally; call
00100     // update() to apply changes to the physical outputs.
00101     void set(int idx, int val)
00102     {
00103         if (state[idx] != val)
00104         {
00105             state[idx] = val;
00106             dirty = true;
00107         }
00108     }
00109     
00110     // Apply updates.  This sends the current state of each pin to the
00111     // chips and latches the new settings.
00112     void update()
00113     {
00114         // if we have changes to apply, send the changes
00115         if (dirty)
00116         {
00117             // Clock out the new states.  Since the outputs are arranged
00118             // as shift registers, we have to clock out the bits in reverse
00119             // order of port numbers - the first bit we output will end up
00120             // in the last register after we clock out all of the other bits.
00121             // So clock out the last bit first and the first bit last.
00122             for (int i = nchips*8-1 ; i >= 0 ; --i)
00123             {
00124                 sclk = 0;
00125                 sin = state[i];
00126                 sclk = 1;
00127             }
00128             
00129             // latch the new states
00130             latch = 1;
00131             sclk = 0;
00132             latch = 0;
00133             
00134             // outputs now reflect internal state
00135             dirty = false;
00136         }
00137     }
00138     
00139     
00140 private:
00141     int nchips;         // number of chips in daisy chain
00142     bool dirty;         // do we have changes to send to the chips?
00143     DigitalOut sin;     // serial data pin
00144     DigitalOut sclk;    // serial clock pin
00145     DigitalOut latch;   // latch pin
00146     DigitalOut ena;     // enable pin
00147     char *state;        // array of current output states (0=off, 1=on)
00148 };
00149         
00150 #endif // HC595_INCLUDED