work in progress
Dependencies: FastAnalogIn FastIO USBDevice mbed FastPWM SimpleDMA
Fork of Pinscape_Controller by
Diff: 74HC595/74HC595.h
- Revision:
- 36:6b981a2afab7
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/74HC595/74HC595.h Thu Dec 03 07:34:57 2015 +0000 @@ -0,0 +1,150 @@ +/* Copyright 2014 M J Roberts, MIT License +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software +* and associated documentation files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef HC595_INCLUDED +#define HC595_INCLUDED + +#include "mbed.h" + +// 74HC595 Interface +// +// We require four GPIO pins: +// +// sin - serial data +// sclk - serial clock +// latch - the LATCH signal, which transfers the internal shift register +// bits to the physical output pin states +// ena - the Enable signal +// +// Note that the physical !OE (output enable) pin on the 74HC595 is active-low. +// To allow for orderly startup that guarantees that outputs won't be pulsed +// (even briefly) during power-on, we require the !OE pin to be wired with a +// pull-up resistor to Vcc, and connected to our ENA GPIO pin via an inverter. +// +// Recommended wiring: connect the GPIO pin to the base of an NPN transistor +// through a 2.2K resistor, connect the collector the !OE pin on the 74HC595, +// and connect the emitter to ground. This will pull !OE to ground when we +// write a digital 1 to the ENA GPIO, enabling the outputs. +// +// We use simple bit-banging through plain DigitalOut pins to send serial +// data to the chips. This is fast enough for our purposes, since we send +// only 8 bits per chip on each update (about 4us per chip per update), and +// we only update when we get a command from the PC host that changes an +// output state. These updates are at USB speed, so the update interval is +// extremely long compared to the bit-banging time. If we wanted to use +// these chips to implement PWM controlled by the microcontroller, or we +// simply wanted to use a very long daisy-chain, we'd probably have to use +// a faster transfer mechanism, such as the SPIO controller. + +class HC595 +{ +public: + HC595(int nchips, PinName sin, PinName sclk, PinName latch, PinName ena) : + nchips(nchips), sin(sin), sclk(sclk), latch(latch), ena(ena) + { + // turn off all pins initially + this->sin = 0; + this->sclk = 0; + this->latch = 0; + this->ena = 0; + + // allocate the state array + state = new char[nchips*8]; + memset(state, 0, nchips*8); + dirty = false; + } + + // Initialize. This must be called once at startup to clear the chips' + // shift registers and enable the physical outputs. We clock a 0 bit (OFF + // state) to each shift register position, latch the OFF states on the + // outputs, and enable the chips. + void init() + { + // set the internal state of all inputs + memset(state, 0, nchips*8); + dirty = false; + + // clock a 0 to each shift register bit (8 per chip) + sin = 0; + for (int i = 0 ; i < nchips*8 ; ++i) + { + sclk = 1; + sclk = 0; + } + + // latch the output data (this transfers the serial data register + // bit for each pin to the actual output pin) + latch = 1; + latch = 0; + + // enable the outputs + ena = 1; + } + + // Set an output state. This only sets the state internally; call + // update() to apply changes to the physical outputs. + void set(int idx, int val) + { + if (state[idx] != val) + { + state[idx] = val; + dirty = true; + } + } + + // Apply updates. This sends the current state of each pin to the + // chips and latches the new settings. + void update() + { + // if we have changes to apply, send the changes + if (dirty) + { + // Clock out the new states. Since the outputs are arranged + // as shift registers, we have to clock out the bits in reverse + // order of port numbers - the first bit we output will end up + // in the last register after we clock out all of the other bits. + // So clock out the last bit first and the first bit last. + for (int i = nchips*8-1 ; i >= 0 ; --i) + { + sclk = 0; + sin = state[i]; + sclk = 1; + } + + // latch the new states + latch = 1; + sclk = 0; + latch = 0; + + // outputs now reflect internal state + dirty = false; + } + } + + +private: + int nchips; // number of chips in daisy chain + bool dirty; // do we have changes to send to the chips? + DigitalOut sin; // serial data pin + DigitalOut sclk; // serial clock pin + DigitalOut latch; // latch pin + DigitalOut ena; // enable pin + char *state; // array of current output states (0=off, 1=on) +}; + +#endif // HC595_INCLUDED