An I/O controller for virtual pinball machines: accelerometer nudge sensing, analog plunger input, button input encoding, LedWiz compatible output controls, and more.

Dependencies:   mbed FastIO FastPWM USBDevice

Fork of Pinscape_Controller by Mike R

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BitBangI2C.h Source File

BitBangI2C.h

00001 // Bit-bang I2C for KL25Z
00002 //
00003 // This implements an I2C interface that can operate on any KL25Z GPIO
00004 // ports, whether or not they're connected to I2C hardware on the MCU.  
00005 // We simply send and receive bits using direct port manipulation (often
00006 // called "bit banging") instead of using the MCU I2C hardware.  This
00007 // is more flexible than the mbed I2C class, since that only works with
00008 // a small number of pins, and there are only two I2C modules in the
00009 // system.  This GPIO version can be to gain additional I2C ports if
00010 // the hardware I2C modules are committed to other purposes, or all of
00011 // the I2C-capable pins are being used for other purposes.
00012 //
00013 // The tradeoff for the added flexibility is that the hardware I2C is
00014 // faster.  This implementation can take advantage of bus speeds up to 
00015 // about 500kHz, which produces data rates of about 272 kbps.  Higher 
00016 // clock speeds are allowed, but the actual bit rate will plateau at 
00017 // this level due to the performance constraints of the CPU (and of
00018 // this code itself; some additional performance could probably be 
00019 // gained by optimizing it further).  The KL25Z I2C hardware can double 
00020 // our speed: it can achieve bus speeds of 1MHz and data rates of about
00021 // 540kbps.  Of course, such high speeds can only be used with compatible 
00022 // devices; many devices are limited to the "standard mode" at 100kHz or 
00023 // "fast mode" at 400kHz, both of which we can fully saturate.  However, 
00024 // even at the slower bus speeds, the hardware I2C has another advantage:
00025 // it's capable of DMA operation.  That's vastly superior for large 
00026 // transactions since it lets the CPU do other work in parallel with 
00027 // I2C bit movement.
00028 //
00029 // This class isn't meant to be directly compatible with the mbed I2C 
00030 // class, but we try to adhere to the mbed conventions and method names 
00031 // to make it a mostly drop-in replacement.  In particular, we use the 
00032 // mbed library's "2X" device address convention.  Most device data sheets
00033 // list the device I2C address in 7-bit format, so you'll have to shift
00034 // the nominal address from the data sheet left one bit in each call
00035 // to a routine here.
00036 //
00037 // Electrically, the I2C bus consists of two lines, SDA (data) and SCL
00038 // (clock).  Multiple devices can connect to the bus by connecting to
00039 // these two lines; the lines are shared among all of the devices.  Each
00040 // line has a pull-up resistor that pulls it to logic '1' voltage.  Each
00041 // device connects with an open-collector circuit that can short the line
00042 // to ground (logic '0').  This means that any device can assert a 'low'
00043 // but no one can actually assert a 'high'; the pull-up makes it so that
00044 // a 'high' occurs when no one is asserting a 'low'.  On an MCU, we release
00045 // a line by putting the GPIO pin in high-Z state, which we can do on the
00046 // KL25Z by setting its direction to INPUT mode.  So our GPIO write strategy 
00047 // is like this:
00048 //
00049 //   - take a pin low (0):   
00050 //        pin.input(); 
00051 //        pin.write(0);
00052 //
00053 //   - take a pin high (1):
00054 //        pin.output();
00055 //
00056 // Note that we don't actually have to write the '0' on each pull low,
00057 // since we just leave the port output register set with '0'.  Changing
00058 // the direction to output is enough to assert the low level, since the
00059 // hardware asserts the level that was previously stored in the output
00060 // register whenever the direction is changed from input to output.
00061 //
00062 // The KL25Z by default provides a built-in pull-up resistor on each GPIO
00063 // set to input mode.  This can optionally be used as the bus-wide pull-up
00064 // for each line.  Standard practice is to use external pull-up resistors
00065 // rather than MCU pull-ups, but the internal pull-ups are fine for ad hoc
00066 // setups where there's only one external device connected to a GPIO pair.
00067 
00068 
00069 #ifndef _BITBANGI2C_H_
00070 #define _BITBANGI2C_H_
00071  
00072 #include "mbed.h"
00073 #include "gpio_api.h"
00074 #include "pinmap.h"
00075 
00076 
00077 // For testing purposes: a cover class for the mbed library I2C bridging
00078 // the minor differences in our interface.  This allows switching between
00079 // BitBangI2C and the mbed library I2C via a macro of the like.
00080 class MbedI2C: public I2C
00081 {
00082 public:
00083     MbedI2C(PinName sda, PinName scl, bool internalPullups) : I2C(sda, scl) { }
00084     
00085     int write(int addr, const uint8_t *data, size_t len, bool repeated = false)
00086     {
00087         return I2C::write(addr, (const char *)data, len, repeated);
00088     }
00089     int read(int addr, uint8_t *data, size_t len, bool repeated = false)
00090     {
00091         return I2C::read(addr, (char *)data, len, repeated);
00092     }
00093     
00094     void reset() { }
00095 };
00096 
00097 
00098 // DigitalInOut replacmement class for I2C use.  I2C uses pins a little
00099 // differently from other use cases.  I2C is a bus, where many devices can
00100 // be attached to each line.  To allow this shared access, devices can 
00101 // only drive the line low.  No device can drive the line high; instead,
00102 // the line is *pulled* high, by the attached pull-up resistors, when no 
00103 // one is driving it low.  As a result, we can't use the normal DigitalOut
00104 // write(), since that would try to actively drive the pin high on write(1).
00105 // Instead, write(1) needs to change the pin to high-impedance (high-Z) 
00106 // state instead of driving it, which on the KL25Z is accomplished by 
00107 // changing the port direction mode to INPUT.  So:  
00108 //
00109 //   write(0) = direction->OUTPUT (pin->0)
00110 //   write(1) = direction->INPUT
00111 //
00112 class I2CInOut
00113 {
00114 public:
00115     I2CInOut(PinName pin, bool internalPullup)
00116     {
00117         // initialize the pin
00118         gpio_t g;
00119         gpio_init(&g, pin);
00120         
00121         // get the registers
00122         unsigned int portno = (unsigned int)pin >> PORT_SHIFT;
00123         uint32_t pinno = (uint32_t)(pin & 0x7C) >> 2;
00124         FGPIO_Type *r = (FGPIO_Type *)(FPTA_BASE + portno*0x40);
00125         __IO uint32_t *pin_pcr = &(((PORT_Type *)(PORTA_BASE + 0x1000*portno)))->PCR[pinno];
00126         
00127         // set the desired internal pull-up mode
00128         if (internalPullup)
00129             *pin_pcr |= 0x02;
00130         else
00131             *pin_pcr &= ~0x02;
00132            
00133         // save the register information we'll need later
00134         this->mask = g.mask;
00135         this->PDDR = &r->PDDR;          
00136         this->PDIR = &r->PDIR;
00137         
00138         // initially set as input to release the line
00139         r->PDDR &= ~mask;
00140         
00141         // Set the output value to 0.  It will always be zero, since
00142         // this is the only value we ever drive.  When we want the port
00143         // to go high, we release it by changing the direction to input.
00144         r->PCOR = mask;
00145     }
00146     
00147     // write a 1 (high) or 0 (low) value to the pin
00148     inline void write(int b) { if (b) hi(); else lo(); }
00149     
00150     // Take the line high: set as input to put it in high-Z state so that
00151     // the pull-up resistor takes over.
00152     inline void hi() { *PDDR &= ~mask; }
00153     
00154     // Take the line low: set as output to assert our '0' on the line and
00155     // pull it low.  Note that we don't have to explicitly write the port
00156     // output register, since we initialized it with a '0' on our port and
00157     // never change it.  The hardware will assert the level stored in the
00158     // register each time we change the direction to output, so there's no
00159     // need to write the port output register again each time.
00160     inline void lo() { *PDDR |= mask; }
00161     
00162     // read the line
00163     inline int read()
00164     {
00165         *PDDR &= ~mask;         // set as input
00166         return *PDIR & mask;    // read the port
00167     }
00168     
00169     // direction register
00170     volatile uint32_t *PDDR;
00171     
00172     // input register
00173     volatile uint32_t *PDIR;
00174     
00175     // pin mask 
00176     uint32_t mask;
00177 };
00178 
00179 
00180 
00181 // bit-bang I2C
00182 class BitBangI2C 
00183 {
00184 public:    
00185     // create the interface
00186     BitBangI2C(PinName sda, PinName scl, bool internalPullups);
00187 
00188     // set the bus frequency in Hz
00189     void frequency(uint32_t freq);
00190 
00191     // set START condition on the bus
00192     void start();
00193 
00194     // set STOP condition on the bus
00195     void stop();
00196     
00197     // Write a series of bytes.  Returns 0 on success, non-zero on failure.
00198     // Important: 'addr' is 2X the nominal address - shift left by one bit.
00199     int write(uint8_t addr, const uint8_t *data, size_t len, bool repeated = false);
00200     
00201     // write a byte; returns true if ACK was received
00202     int write(uint8_t data);
00203     
00204     // Read a series of bytes.  Returns 0 on success, non-zero on failure.
00205     // Important: 'addr' is 2X the nominal address - shift left by one bit.
00206     int read(uint8_t addr, uint8_t *data, size_t len, bool repeated = false);
00207 
00208     // read a byte, optionally sending an ACK on receipt
00209     int read(bool ack);
00210 
00211     // wait for ACK; returns true if ACK was received
00212     bool wait(uint32_t timeout_us);
00213 
00214     // reset the bus
00215     void reset();
00216 
00217 protected:
00218     // read/write a bit
00219     int readBit();
00220     
00221     // write a bit
00222     inline void writeBit(int bit)
00223     {
00224         // put the bit on the SDA line
00225         sdaPin.write(bit);
00226         hiResWait(tSuDat);
00227         
00228         // clock it
00229         sclPin.hi();
00230         hiResWait(tHigh);
00231         
00232         // drop the clock
00233         sclPin.lo();
00234         hiResWait(tLow);
00235     }
00236     
00237     // set SCL/SDA lines to high (1) or low(0)
00238     inline void scl(int level) { sclPin.write(level); }
00239     inline void sda(int level) { sdaPin.write(level); }
00240     
00241     inline void sclHi() { sclPin.hi(); }
00242     inline void sclLo() { sclPin.lo(); }
00243     inline void sdaHi() { sdaPin.hi(); }
00244     inline void sdaLo() { sdaPin.lo(); }
00245 
00246     // SDA and SCL pins
00247     I2CInOut sdaPin;
00248     I2CInOut sclPin;
00249 
00250     // inverse of frequency = clock period in microseconds
00251     uint32_t clkPeriod_us;
00252     
00253     // High-resolution wait.  This provides sub-microsecond wait
00254     // times, to get minimum times for I2C events.  With the ARM
00255     // compiler, this produces measured wait times as follows:
00256     //
00257     //    n=0    104ns
00258     //    n=1    167ns
00259     //    n=2    271ns
00260     //    n=3    375ns
00261     //    n=4    479ns
00262     //
00263     // For n > 1, the wait time is 167ns + (n-1)*104ns.
00264     // These times take into account caller overhead to load the
00265     // wait time from a member variable.  Callers getting the wait
00266     // time from a constant or stack variable will have different 
00267     // results.
00268     inline void hiResWait(volatile int n)
00269     {
00270         while (n != 0)
00271             --n;
00272     }
00273     
00274     // Figure the hiResWait() time for a given nanosecond time.
00275     // We use this during setup to precompute the wait times required
00276     // for various events at a given clock speed.
00277     int calcHiResWaitTime(int nanoseconds)
00278     {
00279         // the shortest wait time is 104ns
00280         if (nanoseconds <= 104)
00281             return 0;
00282             
00283         // Above that, we work in 104ns increments with a base 
00284         // of 167ns.  We round at the halfway point, because we
00285         // assume there's always a little extra overhead in the
00286         // caller itself that will pad by at least one instruction
00287         // of 60ns, which is more than half our interval.
00288         return (nanoseconds - 167 + 52)/104 + 1;
00289     }
00290     
00291     // Time delays for I2C events.  I2C has minimum timing requirements
00292     // based on the clock speed.  Some of these are as short as 50ns.
00293     // The mbed wait timer has microsecond resolution, which is much
00294     // too coarse for fast I2C clock speeds, so we implement our own
00295     // finer-grained wait.
00296     //
00297     // These are in hiResWait() units - see above.
00298     //
00299     int tLow;       // SCL low period
00300     int tHigh;      // SCL high period
00301     int tHdSta;     // hold time for start condition
00302     int tSuSta;     // setup time for repeated start condition
00303     int tSuSto;     // setup time for stop condition
00304     int tSuDat;     // data setup time
00305     int tAck;       // ACK time
00306     int tBuf;       // bus free time between start and stop conditions
00307     
00308     // are we in a Stop condition?
00309     bool inStop;
00310 };
00311  
00312 #endif /* _BITBANGI2C_H_ */