Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
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_ */
Generated on Thu Jul 14 2022 12:20:36 by 1.7.2