Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

Committer:
arnoz
Date:
Fri Oct 01 08:19:46 2021 +0000
Revision:
116:7a67265d7c19
Parent:
40:cc0d9814522b
- Correct information regarding your last merge

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mjr 34:6b981a2afab7 1 /* Copyright 2014 M J Roberts, MIT License
mjr 34:6b981a2afab7 2 *
mjr 34:6b981a2afab7 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
mjr 34:6b981a2afab7 4 * and associated documentation files (the "Software"), to deal in the Software without
mjr 34:6b981a2afab7 5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
mjr 34:6b981a2afab7 6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
mjr 34:6b981a2afab7 7 * Software is furnished to do so, subject to the following conditions:
mjr 34:6b981a2afab7 8 *
mjr 34:6b981a2afab7 9 * The above copyright notice and this permission notice shall be included in all copies or
mjr 34:6b981a2afab7 10 * substantial portions of the Software.
mjr 34:6b981a2afab7 11 *
mjr 34:6b981a2afab7 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
mjr 34:6b981a2afab7 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
mjr 34:6b981a2afab7 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
mjr 34:6b981a2afab7 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
mjr 34:6b981a2afab7 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
mjr 34:6b981a2afab7 17 */
mjr 34:6b981a2afab7 18
mjr 34:6b981a2afab7 19 #ifndef HC595_INCLUDED
mjr 34:6b981a2afab7 20 #define HC595_INCLUDED
mjr 34:6b981a2afab7 21
mjr 34:6b981a2afab7 22 #include "mbed.h"
mjr 34:6b981a2afab7 23
mjr 34:6b981a2afab7 24 // 74HC595 Interface
mjr 34:6b981a2afab7 25 //
mjr 34:6b981a2afab7 26 // We require four GPIO pins:
mjr 34:6b981a2afab7 27 //
mjr 34:6b981a2afab7 28 // sin - serial data
mjr 34:6b981a2afab7 29 // sclk - serial clock
mjr 34:6b981a2afab7 30 // latch - the LATCH signal, which transfers the internal shift register
mjr 34:6b981a2afab7 31 // bits to the physical output pin states
mjr 34:6b981a2afab7 32 // ena - the Enable signal
mjr 34:6b981a2afab7 33 //
mjr 34:6b981a2afab7 34 // Note that the physical !OE (output enable) pin on the 74HC595 is active-low.
mjr 34:6b981a2afab7 35 // To allow for orderly startup that guarantees that outputs won't be pulsed
mjr 34:6b981a2afab7 36 // (even briefly) during power-on, we require the !OE pin to be wired with a
mjr 34:6b981a2afab7 37 // pull-up resistor to Vcc, and connected to our ENA GPIO pin via an inverter.
mjr 34:6b981a2afab7 38 //
mjr 34:6b981a2afab7 39 // Recommended wiring: connect the GPIO pin to the base of an NPN transistor
mjr 34:6b981a2afab7 40 // through a 2.2K resistor, connect the collector the !OE pin on the 74HC595,
mjr 34:6b981a2afab7 41 // and connect the emitter to ground. This will pull !OE to ground when we
mjr 34:6b981a2afab7 42 // write a digital 1 to the ENA GPIO, enabling the outputs.
mjr 34:6b981a2afab7 43 //
mjr 34:6b981a2afab7 44 // We use simple bit-banging through plain DigitalOut pins to send serial
mjr 34:6b981a2afab7 45 // data to the chips. This is fast enough for our purposes, since we send
mjr 34:6b981a2afab7 46 // only 8 bits per chip on each update (about 4us per chip per update), and
mjr 34:6b981a2afab7 47 // we only update when we get a command from the PC host that changes an
mjr 34:6b981a2afab7 48 // output state. These updates are at USB speed, so the update interval is
mjr 34:6b981a2afab7 49 // extremely long compared to the bit-banging time. If we wanted to use
mjr 34:6b981a2afab7 50 // these chips to implement PWM controlled by the microcontroller, or we
mjr 34:6b981a2afab7 51 // simply wanted to use a very long daisy-chain, we'd probably have to use
mjr 34:6b981a2afab7 52 // a faster transfer mechanism, such as the SPIO controller.
mjr 34:6b981a2afab7 53
mjr 34:6b981a2afab7 54 class HC595
mjr 34:6b981a2afab7 55 {
mjr 34:6b981a2afab7 56 public:
mjr 34:6b981a2afab7 57 HC595(int nchips, PinName sin, PinName sclk, PinName latch, PinName ena) :
mjr 34:6b981a2afab7 58 nchips(nchips), sin(sin), sclk(sclk), latch(latch), ena(ena)
mjr 34:6b981a2afab7 59 {
mjr 34:6b981a2afab7 60 // turn off all pins initially
mjr 34:6b981a2afab7 61 this->sin = 0;
mjr 34:6b981a2afab7 62 this->sclk = 0;
mjr 34:6b981a2afab7 63 this->latch = 0;
mjr 34:6b981a2afab7 64 this->ena = 0;
mjr 34:6b981a2afab7 65
mjr 34:6b981a2afab7 66 // allocate the state array
mjr 34:6b981a2afab7 67 state = new char[nchips*8];
mjr 34:6b981a2afab7 68 memset(state, 0, nchips*8);
mjr 34:6b981a2afab7 69 dirty = false;
mjr 34:6b981a2afab7 70 }
mjr 34:6b981a2afab7 71
mjr 34:6b981a2afab7 72 // Initialize. This must be called once at startup to clear the chips'
mjr 40:cc0d9814522b 73 // shift registers. We clock a 0 bit (OFF state) to each shift register
mjr 40:cc0d9814522b 74 // position and latch the OFF states on the outputs. Note that this
mjr 40:cc0d9814522b 75 // doesn't enable the chips - that must be done with a separate call
mjr 40:cc0d9814522b 76 // to enable(true).
mjr 34:6b981a2afab7 77 void init()
mjr 34:6b981a2afab7 78 {
mjr 34:6b981a2afab7 79 // set the internal state of all inputs
mjr 34:6b981a2afab7 80 memset(state, 0, nchips*8);
mjr 34:6b981a2afab7 81 dirty = false;
mjr 34:6b981a2afab7 82
mjr 34:6b981a2afab7 83 // clock a 0 to each shift register bit (8 per chip)
mjr 34:6b981a2afab7 84 sin = 0;
mjr 34:6b981a2afab7 85 for (int i = 0 ; i < nchips*8 ; ++i)
mjr 34:6b981a2afab7 86 {
mjr 34:6b981a2afab7 87 sclk = 1;
mjr 34:6b981a2afab7 88 sclk = 0;
mjr 34:6b981a2afab7 89 }
mjr 34:6b981a2afab7 90
mjr 34:6b981a2afab7 91 // latch the output data (this transfers the serial data register
mjr 34:6b981a2afab7 92 // bit for each pin to the actual output pin)
mjr 34:6b981a2afab7 93 latch = 1;
mjr 34:6b981a2afab7 94 latch = 0;
mjr 34:6b981a2afab7 95 }
mjr 34:6b981a2afab7 96
mjr 34:6b981a2afab7 97 // Set an output state. This only sets the state internally; call
mjr 34:6b981a2afab7 98 // update() to apply changes to the physical outputs.
mjr 34:6b981a2afab7 99 void set(int idx, int val)
mjr 34:6b981a2afab7 100 {
mjr 34:6b981a2afab7 101 if (state[idx] != val)
mjr 34:6b981a2afab7 102 {
mjr 34:6b981a2afab7 103 state[idx] = val;
mjr 34:6b981a2afab7 104 dirty = true;
mjr 34:6b981a2afab7 105 }
mjr 34:6b981a2afab7 106 }
mjr 34:6b981a2afab7 107
mjr 40:cc0d9814522b 108 // Global enable/disable the outputs. We use this for cleaner startup,
mjr 40:cc0d9814522b 109 // by disabling all outputs after power-on and when coming out of sleep
mjr 40:cc0d9814522b 110 // mode until we've had a chance to initialize the chip registers. The
mjr 40:cc0d9814522b 111 // chips have random values in their shift registers when first powered
mjr 40:cc0d9814522b 112 // on, so we have to send an initial update after power-on. The snag
mjr 40:cc0d9814522b 113 // is that the chips might have a separate power supply from the KL25Z,
mjr 40:cc0d9814522b 114 // so we can't assume that the chips are powered just because the program
mjr 40:cc0d9814522b 115 // is running. Instead, we can use the USB connection status as a proxy
mjr 40:cc0d9814522b 116 // for chip power, on the assumption that (a) the chips are running off
mjr 40:cc0d9814522b 117 // of the PC power supply, and (b) the USB connection can only be running
mjr 40:cc0d9814522b 118 // when the PC is running (hence the PC power supply is on).
mjr 40:cc0d9814522b 119 void enable(bool f)
mjr 40:cc0d9814522b 120 {
mjr 40:cc0d9814522b 121 // set the new enable state
mjr 40:cc0d9814522b 122 ena = (f ? 1 : 0);
mjr 40:cc0d9814522b 123 }
mjr 40:cc0d9814522b 124
mjr 34:6b981a2afab7 125 // Apply updates. This sends the current state of each pin to the
mjr 40:cc0d9814522b 126 // chips and latches the new settings. If 'force' is true, we flush
mjr 40:cc0d9814522b 127 // our internal state to the chips even if we haven't made any changes
mjr 40:cc0d9814522b 128 // since the last update.
mjr 40:cc0d9814522b 129 void update(bool force = false)
mjr 34:6b981a2afab7 130 {
mjr 40:cc0d9814522b 131 // if we have changes to apply, or the caller wants the update to
mjr 40:cc0d9814522b 132 // happen regardless of pending changes, refresh the chips
mjr 40:cc0d9814522b 133 if (dirty || force)
mjr 34:6b981a2afab7 134 {
mjr 34:6b981a2afab7 135 // Clock out the new states. Since the outputs are arranged
mjr 34:6b981a2afab7 136 // as shift registers, we have to clock out the bits in reverse
mjr 34:6b981a2afab7 137 // order of port numbers - the first bit we output will end up
mjr 34:6b981a2afab7 138 // in the last register after we clock out all of the other bits.
mjr 34:6b981a2afab7 139 // So clock out the last bit first and the first bit last.
mjr 34:6b981a2afab7 140 for (int i = nchips*8-1 ; i >= 0 ; --i)
mjr 34:6b981a2afab7 141 {
mjr 34:6b981a2afab7 142 sclk = 0;
mjr 34:6b981a2afab7 143 sin = state[i];
mjr 34:6b981a2afab7 144 sclk = 1;
mjr 34:6b981a2afab7 145 }
mjr 34:6b981a2afab7 146
mjr 34:6b981a2afab7 147 // latch the new states
mjr 34:6b981a2afab7 148 latch = 1;
mjr 34:6b981a2afab7 149 sclk = 0;
mjr 34:6b981a2afab7 150 latch = 0;
mjr 34:6b981a2afab7 151
mjr 34:6b981a2afab7 152 // outputs now reflect internal state
mjr 34:6b981a2afab7 153 dirty = false;
mjr 34:6b981a2afab7 154 }
mjr 34:6b981a2afab7 155 }
mjr 34:6b981a2afab7 156
mjr 34:6b981a2afab7 157
mjr 34:6b981a2afab7 158 private:
mjr 34:6b981a2afab7 159 int nchips; // number of chips in daisy chain
mjr 34:6b981a2afab7 160 bool dirty; // do we have changes to send to the chips?
mjr 34:6b981a2afab7 161 DigitalOut sin; // serial data pin
mjr 34:6b981a2afab7 162 DigitalOut sclk; // serial clock pin
mjr 34:6b981a2afab7 163 DigitalOut latch; // latch pin
mjr 34:6b981a2afab7 164 DigitalOut ena; // enable pin
mjr 34:6b981a2afab7 165 char *state; // array of current output states (0=off, 1=on)
mjr 34:6b981a2afab7 166 };
mjr 34:6b981a2afab7 167
mjr 34:6b981a2afab7 168 #endif // HC595_INCLUDED