Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

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

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mjr 86:e30a1f60f783 1 // Bit-bang I2C for KL25Z
mjr 86:e30a1f60f783 2 //
mjr 86:e30a1f60f783 3 // This implements an I2C interface that can operate on any KL25Z GPIO
mjr 86:e30a1f60f783 4 // ports, whether or not they're connected to I2C hardware on the MCU.
mjr 86:e30a1f60f783 5 // We simply send and receive bits using direct port manipulation (often
mjr 86:e30a1f60f783 6 // called "bit banging") instead of using the MCU I2C hardware. This
mjr 86:e30a1f60f783 7 // is more flexible than the mbed I2C class, since that only works with
mjr 86:e30a1f60f783 8 // a small number of pins, and there are only two I2C modules in the
mjr 86:e30a1f60f783 9 // system. This GPIO version can be to gain additional I2C ports if
mjr 86:e30a1f60f783 10 // the hardware I2C modules are committed to other purposes, or all of
mjr 86:e30a1f60f783 11 // the I2C-capable pins are being used for other purposes.
mjr 86:e30a1f60f783 12 //
mjr 86:e30a1f60f783 13 // The tradeoff for the added flexibility is that the hardware I2C is
mjr 86:e30a1f60f783 14 // faster. This implementation can take advantage of bus speeds up to
mjr 86:e30a1f60f783 15 // about 500kHz, which produces data rates of about 272 kbps. Higher
mjr 86:e30a1f60f783 16 // clock speeds are allowed, but the actual bit rate will plateau at
mjr 86:e30a1f60f783 17 // this level due to the performance constraints of the CPU (and of
mjr 86:e30a1f60f783 18 // this code itself; some additional performance could probably be
mjr 86:e30a1f60f783 19 // gained by optimizing it further). The KL25Z I2C hardware can double
mjr 86:e30a1f60f783 20 // our speed: it can achieve bus speeds of 1MHz and data rates of about
mjr 86:e30a1f60f783 21 // 540kbps. Of course, such high speeds can only be used with compatible
mjr 86:e30a1f60f783 22 // devices; many devices are limited to the "standard mode" at 100kHz or
mjr 86:e30a1f60f783 23 // "fast mode" at 400kHz, both of which we can fully saturate. However,
mjr 86:e30a1f60f783 24 // even at the slower bus speeds, the hardware I2C has another advantage:
mjr 86:e30a1f60f783 25 // it's capable of DMA operation. That's vastly superior for large
mjr 86:e30a1f60f783 26 // transactions since it lets the CPU do other work in parallel with
mjr 86:e30a1f60f783 27 // I2C bit movement.
mjr 82:4f6209cb5c33 28 //
mjr 86:e30a1f60f783 29 // This class isn't meant to be directly compatible with the mbed I2C
mjr 86:e30a1f60f783 30 // class, but we try to adhere to the mbed conventions and method names
mjr 86:e30a1f60f783 31 // to make it a mostly drop-in replacement. In particular, we use the
mjr 86:e30a1f60f783 32 // mbed library's "2X" device address convention. Most device data sheets
mjr 86:e30a1f60f783 33 // list the device I2C address in 7-bit format, so you'll have to shift
mjr 86:e30a1f60f783 34 // the nominal address from the data sheet left one bit in each call
mjr 86:e30a1f60f783 35 // to a routine here.
mjr 86:e30a1f60f783 36 //
mjr 87:8d35c74403af 37 // Electrically, the I2C bus consists of two lines, SDA (data) and SCL
mjr 87:8d35c74403af 38 // (clock). Multiple devices can connect to the bus by connecting to
mjr 87:8d35c74403af 39 // these two lines; the lines are shared among all of the devices. Each
mjr 87:8d35c74403af 40 // line has a pull-up resistor that pulls it to logic '1' voltage. Each
mjr 87:8d35c74403af 41 // device connects with an open-collector circuit that can short the line
mjr 87:8d35c74403af 42 // to ground (logic '0'). This means that any device can assert a 'low'
mjr 87:8d35c74403af 43 // but no one can actually assert a 'high'; the pull-up makes it so that
mjr 87:8d35c74403af 44 // a 'high' occurs when no one is asserting a 'low'. On an MCU, we release
mjr 87:8d35c74403af 45 // a line by putting the GPIO pin in high-Z state, which we can do on the
mjr 87:8d35c74403af 46 // KL25Z by setting its direction to INPUT mode. So our GPIO write strategy
mjr 87:8d35c74403af 47 // is like this:
mjr 86:e30a1f60f783 48 //
mjr 86:e30a1f60f783 49 // - take a pin low (0):
mjr 86:e30a1f60f783 50 // pin.input();
mjr 86:e30a1f60f783 51 // pin.write(0);
mjr 86:e30a1f60f783 52 //
mjr 86:e30a1f60f783 53 // - take a pin high (1):
mjr 86:e30a1f60f783 54 // pin.output();
mjr 86:e30a1f60f783 55 //
mjr 86:e30a1f60f783 56 // Note that we don't actually have to write the '0' on each pull low,
mjr 86:e30a1f60f783 57 // since we just leave the port output register set with '0'. Changing
mjr 86:e30a1f60f783 58 // the direction to output is enough to assert the low level, since the
mjr 86:e30a1f60f783 59 // hardware asserts the level that was previously stored in the output
mjr 86:e30a1f60f783 60 // register whenever the direction is changed from input to output.
mjr 87:8d35c74403af 61 //
mjr 87:8d35c74403af 62 // The KL25Z by default provides a built-in pull-up resistor on each GPIO
mjr 87:8d35c74403af 63 // set to input mode. This can optionally be used as the bus-wide pull-up
mjr 87:8d35c74403af 64 // for each line. Standard practice is to use external pull-up resistors
mjr 87:8d35c74403af 65 // rather than MCU pull-ups, but the internal pull-ups are fine for ad hoc
mjr 87:8d35c74403af 66 // setups where there's only one external device connected to a GPIO pair.
mjr 86:e30a1f60f783 67
mjr 82:4f6209cb5c33 68
mjr 82:4f6209cb5c33 69 #ifndef _BITBANGI2C_H_
mjr 82:4f6209cb5c33 70 #define _BITBANGI2C_H_
mjr 82:4f6209cb5c33 71
mjr 82:4f6209cb5c33 72 #include "mbed.h"
mjr 86:e30a1f60f783 73 #include "gpio_api.h"
mjr 86:e30a1f60f783 74 #include "pinmap.h"
mjr 86:e30a1f60f783 75
mjr 86:e30a1f60f783 76
mjr 87:8d35c74403af 77 // For testing purposes: a cover class for the mbed library I2C bridging
mjr 87:8d35c74403af 78 // the minor differences in our interface. This allows switching between
mjr 87:8d35c74403af 79 // BitBangI2C and the mbed library I2C via a macro of the like.
mjr 87:8d35c74403af 80 class MbedI2C: public I2C
mjr 87:8d35c74403af 81 {
mjr 87:8d35c74403af 82 public:
mjr 87:8d35c74403af 83 MbedI2C(PinName sda, PinName scl, bool internalPullups) : I2C(sda, scl) { }
mjr 87:8d35c74403af 84
mjr 87:8d35c74403af 85 int write(int addr, const uint8_t *data, size_t len, bool repeated = false)
mjr 87:8d35c74403af 86 {
mjr 87:8d35c74403af 87 return I2C::write(addr, (const char *)data, len, repeated);
mjr 87:8d35c74403af 88 }
mjr 87:8d35c74403af 89 int read(int addr, uint8_t *data, size_t len, bool repeated = false)
mjr 87:8d35c74403af 90 {
mjr 87:8d35c74403af 91 return I2C::read(addr, (char *)data, len, repeated);
mjr 87:8d35c74403af 92 }
mjr 87:8d35c74403af 93
mjr 87:8d35c74403af 94 void reset() { }
mjr 87:8d35c74403af 95 };
mjr 87:8d35c74403af 96
mjr 87:8d35c74403af 97
mjr 86:e30a1f60f783 98 // DigitalInOut replacmement class for I2C use. I2C uses pins a little
mjr 86:e30a1f60f783 99 // differently from other use cases. I2C is a bus, where many devices can
mjr 86:e30a1f60f783 100 // be attached to each line. To allow this shared access, devices can
mjr 86:e30a1f60f783 101 // only drive the line low. No device can drive the line high; instead,
mjr 86:e30a1f60f783 102 // the line is *pulled* high, by the attached pull-up resistors, when no
mjr 86:e30a1f60f783 103 // one is driving it low. As a result, we can't use the normal DigitalOut
mjr 86:e30a1f60f783 104 // write(), since that would try to actively drive the pin high on write(1).
mjr 86:e30a1f60f783 105 // Instead, write(1) needs to change the pin to high-impedance (high-Z)
mjr 86:e30a1f60f783 106 // state instead of driving it, which on the KL25Z is accomplished by
mjr 86:e30a1f60f783 107 // changing the port direction mode to INPUT. So:
mjr 86:e30a1f60f783 108 //
mjr 86:e30a1f60f783 109 // write(0) = direction->OUTPUT (pin->0)
mjr 86:e30a1f60f783 110 // write(1) = direction->INPUT
mjr 86:e30a1f60f783 111 //
mjr 86:e30a1f60f783 112 class I2CInOut
mjr 86:e30a1f60f783 113 {
mjr 86:e30a1f60f783 114 public:
mjr 87:8d35c74403af 115 I2CInOut(PinName pin, bool internalPullup)
mjr 86:e30a1f60f783 116 {
mjr 86:e30a1f60f783 117 // initialize the pin
mjr 86:e30a1f60f783 118 gpio_t g;
mjr 86:e30a1f60f783 119 gpio_init(&g, pin);
mjr 86:e30a1f60f783 120
mjr 86:e30a1f60f783 121 // get the registers
mjr 87:8d35c74403af 122 unsigned int portno = (unsigned int)pin >> PORT_SHIFT;
mjr 87:8d35c74403af 123 uint32_t pinno = (uint32_t)(pin & 0x7C) >> 2;
mjr 87:8d35c74403af 124 FGPIO_Type *r = (FGPIO_Type *)(FPTA_BASE + portno*0x40);
mjr 87:8d35c74403af 125 __IO uint32_t *pin_pcr = &(((PORT_Type *)(PORTA_BASE + 0x1000*portno)))->PCR[pinno];
mjr 86:e30a1f60f783 126
mjr 87:8d35c74403af 127 // set the desired internal pull-up mode
mjr 87:8d35c74403af 128 if (internalPullup)
mjr 87:8d35c74403af 129 *pin_pcr |= 0x02;
mjr 87:8d35c74403af 130 else
mjr 87:8d35c74403af 131 *pin_pcr &= ~0x02;
mjr 86:e30a1f60f783 132
mjr 86:e30a1f60f783 133 // save the register information we'll need later
mjr 86:e30a1f60f783 134 this->mask = g.mask;
mjr 86:e30a1f60f783 135 this->PDDR = &r->PDDR;
mjr 86:e30a1f60f783 136 this->PDIR = &r->PDIR;
mjr 86:e30a1f60f783 137
mjr 86:e30a1f60f783 138 // initially set as input to release the line
mjr 86:e30a1f60f783 139 r->PDDR &= ~mask;
mjr 86:e30a1f60f783 140
mjr 86:e30a1f60f783 141 // Set the output value to 0. It will always be zero, since
mjr 86:e30a1f60f783 142 // this is the only value we ever drive. When we want the port
mjr 86:e30a1f60f783 143 // to go high, we release it by changing the direction to input.
mjr 86:e30a1f60f783 144 r->PCOR = mask;
mjr 86:e30a1f60f783 145 }
mjr 86:e30a1f60f783 146
mjr 86:e30a1f60f783 147 // write a 1 (high) or 0 (low) value to the pin
mjr 86:e30a1f60f783 148 inline void write(int b) { if (b) hi(); else lo(); }
mjr 86:e30a1f60f783 149
mjr 86:e30a1f60f783 150 // Take the line high: set as input to put it in high-Z state so that
mjr 86:e30a1f60f783 151 // the pull-up resistor takes over.
mjr 86:e30a1f60f783 152 inline void hi() { *PDDR &= ~mask; }
mjr 86:e30a1f60f783 153
mjr 86:e30a1f60f783 154 // Take the line low: set as output to assert our '0' on the line and
mjr 86:e30a1f60f783 155 // pull it low. Note that we don't have to explicitly write the port
mjr 86:e30a1f60f783 156 // output register, since we initialized it with a '0' on our port and
mjr 86:e30a1f60f783 157 // never change it. The hardware will assert the level stored in the
mjr 86:e30a1f60f783 158 // register each time we change the direction to output, so there's no
mjr 86:e30a1f60f783 159 // need to write the port output register again each time.
mjr 86:e30a1f60f783 160 inline void lo() { *PDDR |= mask; }
mjr 86:e30a1f60f783 161
mjr 86:e30a1f60f783 162 // read the line
mjr 86:e30a1f60f783 163 inline int read()
mjr 86:e30a1f60f783 164 {
mjr 86:e30a1f60f783 165 *PDDR &= ~mask; // set as input
mjr 86:e30a1f60f783 166 return *PDIR & mask; // read the port
mjr 86:e30a1f60f783 167 }
mjr 86:e30a1f60f783 168
mjr 86:e30a1f60f783 169 // direction register
mjr 86:e30a1f60f783 170 volatile uint32_t *PDDR;
mjr 86:e30a1f60f783 171
mjr 86:e30a1f60f783 172 // input register
mjr 86:e30a1f60f783 173 volatile uint32_t *PDIR;
mjr 86:e30a1f60f783 174
mjr 86:e30a1f60f783 175 // pin mask
mjr 86:e30a1f60f783 176 uint32_t mask;
mjr 86:e30a1f60f783 177 };
mjr 86:e30a1f60f783 178
mjr 86:e30a1f60f783 179
mjr 86:e30a1f60f783 180
mjr 86:e30a1f60f783 181 // bit-bang I2C
mjr 82:4f6209cb5c33 182 class BitBangI2C
mjr 82:4f6209cb5c33 183 {
mjr 82:4f6209cb5c33 184 public:
mjr 82:4f6209cb5c33 185 // create the interface
mjr 87:8d35c74403af 186 BitBangI2C(PinName sda, PinName scl, bool internalPullups);
mjr 82:4f6209cb5c33 187
mjr 82:4f6209cb5c33 188 // set the bus frequency in Hz
mjr 86:e30a1f60f783 189 void frequency(uint32_t freq);
mjr 82:4f6209cb5c33 190
mjr 82:4f6209cb5c33 191 // set START condition on the bus
mjr 82:4f6209cb5c33 192 void start();
mjr 82:4f6209cb5c33 193
mjr 82:4f6209cb5c33 194 // set STOP condition on the bus
mjr 82:4f6209cb5c33 195 void stop();
mjr 82:4f6209cb5c33 196
mjr 82:4f6209cb5c33 197 // Write a series of bytes. Returns 0 on success, non-zero on failure.
mjr 82:4f6209cb5c33 198 // Important: 'addr' is 2X the nominal address - shift left by one bit.
mjr 82:4f6209cb5c33 199 int write(uint8_t addr, const uint8_t *data, size_t len, bool repeated = false);
mjr 82:4f6209cb5c33 200
mjr 82:4f6209cb5c33 201 // write a byte; returns true if ACK was received
mjr 82:4f6209cb5c33 202 int write(uint8_t data);
mjr 82:4f6209cb5c33 203
mjr 82:4f6209cb5c33 204 // Read a series of bytes. Returns 0 on success, non-zero on failure.
mjr 82:4f6209cb5c33 205 // Important: 'addr' is 2X the nominal address - shift left by one bit.
mjr 82:4f6209cb5c33 206 int read(uint8_t addr, uint8_t *data, size_t len, bool repeated = false);
mjr 82:4f6209cb5c33 207
mjr 82:4f6209cb5c33 208 // read a byte, optionally sending an ACK on receipt
mjr 82:4f6209cb5c33 209 int read(bool ack);
mjr 82:4f6209cb5c33 210
mjr 82:4f6209cb5c33 211 // wait for ACK; returns true if ACK was received
mjr 82:4f6209cb5c33 212 bool wait(uint32_t timeout_us);
mjr 82:4f6209cb5c33 213
mjr 82:4f6209cb5c33 214 // reset the bus
mjr 82:4f6209cb5c33 215 void reset();
mjr 82:4f6209cb5c33 216
mjr 82:4f6209cb5c33 217 protected:
mjr 82:4f6209cb5c33 218 // read/write a bit
mjr 82:4f6209cb5c33 219 int readBit();
mjr 86:e30a1f60f783 220
mjr 86:e30a1f60f783 221 // write a bit
mjr 86:e30a1f60f783 222 inline void writeBit(int bit)
mjr 86:e30a1f60f783 223 {
mjr 86:e30a1f60f783 224 // put the bit on the SDA line
mjr 86:e30a1f60f783 225 sdaPin.write(bit);
mjr 86:e30a1f60f783 226 hiResWait(tSuDat);
mjr 86:e30a1f60f783 227
mjr 86:e30a1f60f783 228 // clock it
mjr 86:e30a1f60f783 229 sclPin.hi();
mjr 87:8d35c74403af 230 hiResWait(tHigh);
mjr 86:e30a1f60f783 231
mjr 86:e30a1f60f783 232 // drop the clock
mjr 86:e30a1f60f783 233 sclPin.lo();
mjr 86:e30a1f60f783 234 hiResWait(tLow);
mjr 86:e30a1f60f783 235 }
mjr 82:4f6209cb5c33 236
mjr 82:4f6209cb5c33 237 // set SCL/SDA lines to high (1) or low(0)
mjr 86:e30a1f60f783 238 inline void scl(int level) { sclPin.write(level); }
mjr 86:e30a1f60f783 239 inline void sda(int level) { sdaPin.write(level); }
mjr 86:e30a1f60f783 240
mjr 86:e30a1f60f783 241 inline void sclHi() { sclPin.hi(); }
mjr 86:e30a1f60f783 242 inline void sclLo() { sclPin.lo(); }
mjr 86:e30a1f60f783 243 inline void sdaHi() { sdaPin.hi(); }
mjr 86:e30a1f60f783 244 inline void sdaLo() { sdaPin.lo(); }
mjr 82:4f6209cb5c33 245
mjr 87:8d35c74403af 246 // SDA and SCL pins
mjr 87:8d35c74403af 247 I2CInOut sdaPin;
mjr 86:e30a1f60f783 248 I2CInOut sclPin;
mjr 82:4f6209cb5c33 249
mjr 82:4f6209cb5c33 250 // inverse of frequency = clock period in microseconds
mjr 82:4f6209cb5c33 251 uint32_t clkPeriod_us;
mjr 86:e30a1f60f783 252
mjr 86:e30a1f60f783 253 // High-resolution wait. This provides sub-microsecond wait
mjr 86:e30a1f60f783 254 // times, to get minimum times for I2C events. With the ARM
mjr 86:e30a1f60f783 255 // compiler, this produces measured wait times as follows:
mjr 86:e30a1f60f783 256 //
mjr 86:e30a1f60f783 257 // n=0 104ns
mjr 86:e30a1f60f783 258 // n=1 167ns
mjr 86:e30a1f60f783 259 // n=2 271ns
mjr 86:e30a1f60f783 260 // n=3 375ns
mjr 86:e30a1f60f783 261 // n=4 479ns
mjr 86:e30a1f60f783 262 //
mjr 86:e30a1f60f783 263 // For n > 1, the wait time is 167ns + (n-1)*104ns.
mjr 86:e30a1f60f783 264 // These times take into account caller overhead to load the
mjr 86:e30a1f60f783 265 // wait time from a member variable. Callers getting the wait
mjr 86:e30a1f60f783 266 // time from a constant or stack variable will have different
mjr 86:e30a1f60f783 267 // results.
mjr 86:e30a1f60f783 268 inline void hiResWait(volatile int n)
mjr 86:e30a1f60f783 269 {
mjr 86:e30a1f60f783 270 while (n != 0)
mjr 86:e30a1f60f783 271 --n;
mjr 86:e30a1f60f783 272 }
mjr 86:e30a1f60f783 273
mjr 86:e30a1f60f783 274 // Figure the hiResWait() time for a given nanosecond time.
mjr 86:e30a1f60f783 275 // We use this during setup to precompute the wait times required
mjr 86:e30a1f60f783 276 // for various events at a given clock speed.
mjr 86:e30a1f60f783 277 int calcHiResWaitTime(int nanoseconds)
mjr 86:e30a1f60f783 278 {
mjr 86:e30a1f60f783 279 // the shortest wait time is 104ns
mjr 86:e30a1f60f783 280 if (nanoseconds <= 104)
mjr 86:e30a1f60f783 281 return 0;
mjr 86:e30a1f60f783 282
mjr 86:e30a1f60f783 283 // Above that, we work in 104ns increments with a base
mjr 86:e30a1f60f783 284 // of 167ns. We round at the halfway point, because we
mjr 86:e30a1f60f783 285 // assume there's always a little extra overhead in the
mjr 86:e30a1f60f783 286 // caller itself that will pad by at least one instruction
mjr 86:e30a1f60f783 287 // of 60ns, which is more than half our interval.
mjr 86:e30a1f60f783 288 return (nanoseconds - 167 + 52)/104 + 1;
mjr 86:e30a1f60f783 289 }
mjr 86:e30a1f60f783 290
mjr 86:e30a1f60f783 291 // Time delays for I2C events. I2C has minimum timing requirements
mjr 86:e30a1f60f783 292 // based on the clock speed. Some of these are as short as 50ns.
mjr 86:e30a1f60f783 293 // The mbed wait timer has microsecond resolution, which is much
mjr 86:e30a1f60f783 294 // too coarse for fast I2C clock speeds, so we implement our own
mjr 86:e30a1f60f783 295 // finer-grained wait.
mjr 86:e30a1f60f783 296 //
mjr 86:e30a1f60f783 297 // These are in hiResWait() units - see above.
mjr 86:e30a1f60f783 298 //
mjr 86:e30a1f60f783 299 int tLow; // SCL low period
mjr 86:e30a1f60f783 300 int tHigh; // SCL high period
mjr 86:e30a1f60f783 301 int tHdSta; // hold time for start condition
mjr 86:e30a1f60f783 302 int tSuSta; // setup time for repeated start condition
mjr 86:e30a1f60f783 303 int tSuSto; // setup time for stop condition
mjr 86:e30a1f60f783 304 int tSuDat; // data setup time
mjr 86:e30a1f60f783 305 int tAck; // ACK time
mjr 87:8d35c74403af 306 int tBuf; // bus free time between start and stop conditions
mjr 87:8d35c74403af 307
mjr 87:8d35c74403af 308 // are we in a Stop condition?
mjr 87:8d35c74403af 309 bool inStop;
mjr 82:4f6209cb5c33 310 };
mjr 82:4f6209cb5c33 311
mjr 82:4f6209cb5c33 312 #endif /* _BITBANGI2C_H_ */