Tim Barry / mbed_blinky_offset
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers i2c_api.c Source File

i2c_api.c

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include "i2c_api.h"
00017 
00018 #if DEVICE_I2C
00019 
00020 #include "cmsis.h"
00021 #include "pinmap.h"
00022 #include "error.h"
00023 
00024 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00025 static const PinMap PinMap_I2C_SDA[] = {
00026     {P0_0 , I2C_1, 3},
00027     {P0_10, I2C_2, 2},
00028     {P0_19, I2C_1, 3},
00029     {P0_27, I2C_0, 1},
00030     {NC   , NC   , 0}
00031 };
00032 
00033 static const PinMap PinMap_I2C_SCL[] = {
00034     {P0_1 , I2C_1, 3},
00035     {P0_11, I2C_2, 2},
00036     {P0_20, I2C_1, 3},
00037     {P0_28, I2C_0, 1},
00038     {NC   , NC,    0}
00039 };
00040 
00041 #define I2C_CONSET(x)       (x->i2c->I2CONSET)
00042 #define I2C_CONCLR(x)       (x->i2c->I2CONCLR)
00043 #define I2C_STAT(x)         (x->i2c->I2STAT)
00044 #define I2C_DAT(x)          (x->i2c->I2DAT)
00045 #define I2C_SCLL(x, val)    (x->i2c->I2SCLL = val)
00046 #define I2C_SCLH(x, val)    (x->i2c->I2SCLH = val)
00047 
00048 #elif defined(TARGET_LPC11U24)
00049 static const PinMap PinMap_I2C_SDA[] = {
00050     {P0_5, I2C_0, 1},
00051     {NC  , NC   , 0}
00052 };
00053 
00054 static const PinMap PinMap_I2C_SCL[] = {
00055     {P0_4, I2C_0, 1},
00056     {NC  , NC,    0}
00057 };
00058 
00059 #define I2C_CONSET(x)       (x->i2c->CONSET)
00060 #define I2C_CONCLR(x)       (x->i2c->CONCLR)
00061 #define I2C_STAT(x)         (x->i2c->STAT)
00062 #define I2C_DAT(x)          (x->i2c->DAT)
00063 #define I2C_SCLL(x, val)    (x->i2c->SCLL = val)
00064 #define I2C_SCLH(x, val)    (x->i2c->SCLH = val)
00065 
00066 #elif defined(TARGET_LPC812)
00067 static const SWM_Map SWM_I2C_SDA[] = {
00068     {7, 24},
00069 };
00070 
00071 static const SWM_Map SWM_I2C_SCL[] = {
00072     {8, 0},
00073 };
00074 
00075 static uint8_t repeated_start = 0;
00076 
00077 #define I2C_DAT(x)          (x->i2c->MSTDAT)
00078 #define I2C_STAT(x)         ((x->i2c->STAT >> 1) & (0x07))
00079 
00080 #endif
00081 
00082 
00083 #if defined(TARGET_LPC1768) || defined(TARGET_LPC11U24) || defined(TARGET_LPC2368)
00084 static const uint32_t I2C_addr_offset[2][4] = {
00085     {0x0C, 0x20, 0x24, 0x28},
00086     {0x30, 0x34, 0x38, 0x3C}
00087 };
00088 
00089 static inline void i2c_conclr(i2c_t *obj, int start, int stop, int interrupt, int acknowledge) {
00090     I2C_CONCLR(obj) = (start << 5)
00091                     | (stop << 4)
00092                     | (interrupt << 3)
00093                     | (acknowledge << 2);
00094 }
00095 
00096 static inline void i2c_conset(i2c_t *obj, int start, int stop, int interrupt, int acknowledge) {
00097     I2C_CONSET(obj) = (start << 5)
00098                     | (stop << 4)
00099                     | (interrupt << 3)
00100                     | (acknowledge << 2);
00101 }
00102 
00103 // Clear the Serial Interrupt (SI)
00104 static inline void i2c_clear_SI(i2c_t *obj) {
00105     i2c_conclr(obj, 0, 0, 1, 0);
00106 }
00107 #endif
00108 
00109 
00110 static inline int i2c_status(i2c_t *obj) {
00111     return I2C_STAT(obj);
00112 }
00113 
00114 // Wait until the Serial Interrupt (SI) is set
00115 static int i2c_wait_SI(i2c_t *obj) {
00116     int timeout = 0;
00117 #if defined(TARGET_LPC1768) || defined(TARGET_LPC11U24) || defined(TARGET_LPC2368)
00118     while (!(I2C_CONSET(obj) & (1 << 3))) {
00119 #elif defined(TARGET_LPC812)
00120     while (!(obj->i2c->STAT & (1 << 0))) {
00121 #endif
00122         timeout++;
00123         if (timeout > 100000) return -1;
00124     }
00125     return 0;
00126 }
00127 
00128 static inline void i2c_interface_enable(i2c_t *obj) {
00129 #if defined(TARGET_LPC1768) || defined(TARGET_LPC11U24) || defined(TARGET_LPC2368)
00130     I2C_CONSET(obj) = 0x40;
00131 #elif defined(TARGET_LPC812)
00132     obj->i2c->CFG |= (1 << 0);
00133 #endif
00134 }
00135 
00136 static inline void i2c_power_enable(i2c_t *obj) {
00137 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00138     switch ((int)obj->i2c) {
00139         case I2C_0: LPC_SC->PCONP |= 1 << 7; break;
00140         case I2C_1: LPC_SC->PCONP |= 1 << 19; break;
00141         case I2C_2: LPC_SC->PCONP |= 1 << 26; break;
00142     }
00143 #elif defined(TARGET_LPC11U24)
00144     LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 5);
00145     LPC_SYSCON->PRESETCTRL |= 1 << 1;
00146 #elif defined(TARGET_LPC812)
00147     LPC_SYSCON->SYSAHBCLKCTRL |= (1<<5);    
00148     LPC_SYSCON->PRESETCTRL &= ~(0x1<<6);
00149     LPC_SYSCON->PRESETCTRL |= (0x1<<6);
00150 #endif
00151 }
00152 
00153 void i2c_init(i2c_t *obj, PinName sda, PinName scl) {
00154 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24)
00155     // determine the SPI to use
00156     I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA);
00157     I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL);
00158 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00159     obj->i2c = (LPC_I2C_TypeDef *)pinmap_merge(i2c_sda, i2c_scl);
00160 #elif defined(TARGET_LPC11U24)
00161     obj->i2c = (LPC_I2C_Type *)pinmap_merge(i2c_sda, i2c_scl);
00162 #endif
00163     
00164     if ((int)obj->i2c == NC) {
00165         error("I2C pin mapping failed");
00166     }
00167 
00168     // enable power
00169     i2c_power_enable(obj);
00170 
00171     // set default frequency at 100k
00172     i2c_frequency(obj, 100000);
00173     i2c_conclr(obj, 1, 1, 1, 1);
00174     i2c_interface_enable(obj);
00175 
00176     pinmap_pinout(sda, PinMap_I2C_SDA);
00177     pinmap_pinout(scl, PinMap_I2C_SCL);
00178     
00179 #elif defined (TARGET_LPC812)
00180     obj->i2c = (LPC_I2C_TypeDef *)LPC_I2C;
00181     
00182     const SWM_Map *swm;
00183     uint32_t regVal;
00184     
00185     swm = &SWM_I2C_SDA[0];
00186     regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
00187     LPC_SWM->PINASSIGN[swm->n] = regVal |  (sda   << swm->offset);
00188     
00189     swm = &SWM_I2C_SCL[0];
00190     regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
00191     LPC_SWM->PINASSIGN[swm->n] = regVal |  (scl   << swm->offset);
00192     
00193     // enable power
00194     i2c_power_enable(obj);
00195     // set default frequency at 100k
00196     i2c_frequency(obj, 100000);
00197     i2c_interface_enable(obj);
00198 #endif
00199 
00200 }
00201 
00202 inline int i2c_start(i2c_t *obj) {
00203     int status = 0;
00204 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24)
00205     // 8.1 Before master mode can be entered, I2CON must be initialised to:
00206     //  - I2EN STA STO SI AA - -
00207     //  -  1    0   0   0  x - -
00208     // if AA = 0, it can't enter slave mode
00209     i2c_conclr(obj, 1, 1, 1, 1);
00210 
00211     // The master mode may now be entered by setting the STA bit
00212     // this will generate a start condition when the bus becomes free
00213     i2c_conset(obj, 1, 0, 0, 1);
00214 
00215     i2c_wait_SI(obj);
00216     status = i2c_status(obj);
00217 
00218     // Clear start bit now transmitted, and interrupt bit
00219     i2c_conclr(obj, 1, 0, 0, 0);
00220 #elif defined(TARGET_LPC812)
00221     if (repeated_start) {
00222         obj->i2c->MSTCTL = (1 << 1) | (1 << 0);
00223         repeated_start = 0;
00224     } else {
00225         obj->i2c->MSTCTL = (1 << 1);
00226     }
00227 #endif
00228     return status;
00229 }
00230 
00231 inline void i2c_stop(i2c_t *obj) {
00232 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24)
00233     // write the stop bit
00234     i2c_conset(obj, 0, 1, 0, 0);
00235     i2c_clear_SI(obj);
00236 
00237     // wait for STO bit to reset
00238     while(I2C_CONSET(obj) & (1 << 4));
00239 #elif defined(TARGET_LPC812)
00240     obj->i2c->MSTCTL = (1 << 2) | (1 << 0);
00241     while ((obj->i2c->STAT & ((1 << 0) | (7 << 1))) != ((1 << 0) | (0 << 1)));
00242 #endif
00243 }
00244 
00245 
00246 static inline int i2c_do_write(i2c_t *obj, int value, uint8_t addr) {
00247     // write the data
00248     I2C_DAT(obj) = value;
00249     
00250 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24)
00251     // clear SI to init a send
00252     i2c_clear_SI(obj);
00253 #elif defined(TARGET_LPC812)
00254     if (!addr)
00255         obj->i2c->MSTCTL = (1 << 0);
00256 #endif
00257 
00258     // wait and return status
00259     i2c_wait_SI(obj);
00260     return i2c_status(obj);
00261 }
00262 
00263 static inline int i2c_do_read(i2c_t *obj, int last) {
00264 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24)
00265     // we are in state 0x40 (SLA+R tx'd) or 0x50 (data rx'd and ack)
00266     if(last) {
00267         i2c_conclr(obj, 0, 0, 0, 1); // send a NOT ACK
00268     } else {
00269         i2c_conset(obj, 0, 0, 0, 1); // send a ACK
00270     }
00271 
00272     // accept byte
00273     i2c_clear_SI(obj);
00274 #endif
00275 
00276     // wait for it to arrive
00277     i2c_wait_SI(obj);
00278 
00279 #if defined(TARGET_LPC812)
00280     if (!last)
00281         obj->i2c->MSTCTL = (1 << 0);
00282 #endif
00283 
00284     // return the data
00285     return (I2C_DAT(obj) & 0xFF);
00286 }
00287 
00288 void i2c_frequency(i2c_t *obj, int hz) {
00289 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00290     // [TODO] set pclk to /4
00291     uint32_t PCLK = SystemCoreClock  / 4;
00292 #elif defined(TARGET_LPC11U24) || defined(TARGET_LPC812)
00293     // No peripheral clock divider on the M0
00294     uint32_t PCLK = SystemCoreClock ;
00295 #endif
00296     
00297 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24)
00298     uint32_t pulse = PCLK / (hz * 2);
00299 
00300     // I2C Rate
00301     I2C_SCLL(obj, pulse);
00302     I2C_SCLH(obj, pulse);
00303 #elif defined(TARGET_LPC812)
00304     uint32_t clkdiv = PCLK / (hz * 4) - 1;
00305     
00306     obj->i2c->DIV = clkdiv;
00307     obj->i2c->MSTTIME = 0;
00308 #endif
00309 }
00310 
00311 // The I2C does a read or a write as a whole operation
00312 // There are two types of error conditions it can encounter
00313 //  1) it can not obtain the bus
00314 //  2) it gets error responses at part of the transmission
00315 //
00316 // We tackle them as follows:
00317 //  1) we retry until we get the bus. we could have a "timeout" if we can not get it
00318 //      which basically turns it in to a 2)
00319 //  2) on error, we use the standard error mechanisms to report/debug
00320 //
00321 // Therefore an I2C transaction should always complete. If it doesn't it is usually
00322 // because something is setup wrong (e.g. wiring), and we don't need to programatically
00323 // check for that
00324 
00325 int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
00326     int count, status;
00327 
00328     status = i2c_start(obj);
00329 
00330 #if defined(TARGET_LPC1768) || defined(TARGET_LPC11U24) || defined(TARGET_LPC2368)
00331     if ((status != 0x10) && (status != 0x08)) {
00332         i2c_stop(obj);
00333         return status;
00334     }
00335 #endif
00336 
00337     status = i2c_do_write(obj, (address | 0x01), 1);
00338 #if defined(TARGET_LPC1768) || defined(TARGET_LPC11U24) || defined(TARGET_LPC2368)
00339     if (status != 0x40) {
00340 #elif defined(TARGET_LPC812)
00341     if (status != 0x01) {
00342 #endif
00343         i2c_stop(obj);
00344         return status;
00345     }
00346 
00347     // Read in all except last byte
00348     for (count = 0; count < (length - 1); count++) {
00349         int value = i2c_do_read(obj, 0);
00350         status = i2c_status(obj);
00351 #if defined(TARGET_LPC1768) || defined(TARGET_LPC11U24) || defined(TARGET_LPC2368)
00352         if (status != 0x50) {
00353 #elif defined(TARGET_LPC812)
00354         if (status != 0x00) {
00355 #endif
00356             i2c_stop(obj);
00357             return status;
00358         }
00359         data[count] = (char) value;
00360     }
00361 
00362     // read in last byte
00363     int value = i2c_do_read(obj, 1);
00364     status = i2c_status(obj);
00365 #if defined(TARGET_LPC1768) || defined(TARGET_LPC11U24) || defined(TARGET_LPC2368)
00366     if (status != 0x58) {
00367 #elif defined(TARGET_LPC812)
00368     if (status != 0x01) {
00369 #endif
00370         i2c_stop(obj);
00371         return status;
00372     }
00373 
00374     data[count] = (char) value;
00375 
00376     // If not repeated start, send stop.
00377     if (stop) {
00378         i2c_stop(obj);
00379     }
00380 #if defined(TARGET_LPC812)
00381     else {
00382         repeated_start = 1;
00383     }
00384 #endif
00385 
00386     return 0;
00387 }
00388 
00389 int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
00390     int i, status;
00391 
00392     status = i2c_start(obj);
00393 
00394 #if defined(TARGET_LPC1768) || defined(TARGET_LPC11U24) || defined(TARGET_LPC2368)
00395     if ((status != 0x10) && (status != 0x08)) {
00396         i2c_stop(obj);
00397         return status;
00398     }
00399 #endif
00400 
00401     status = i2c_do_write(obj, (address & 0xFE), 1);
00402 #if defined(TARGET_LPC1768) || defined(TARGET_LPC11U24) || defined(TARGET_LPC2368)
00403     if (status != 0x18) {
00404 #elif defined(TARGET_LPC812)
00405     if (status != 0x02) {
00406 #endif
00407         i2c_stop(obj);
00408         return status;
00409     }
00410 
00411     for (i=0; i<length; i++) {
00412         status = i2c_do_write(obj, data[i], 0);
00413 #if defined(TARGET_LPC1768) || defined(TARGET_LPC11U24) || defined(TARGET_LPC2368)
00414         if(status != 0x28) {
00415 #elif defined(TARGET_LPC812)
00416         if (status != 0x02) {
00417 #endif
00418             i2c_stop(obj);
00419             return status;
00420         }
00421     }
00422 
00423 #if defined(TARGET_LPC1768) || defined(TARGET_LPC11U24) || defined(TARGET_LPC2368)
00424     i2c_clear_SI(obj);
00425 #endif
00426 
00427     // If not repeated start, send stop.
00428     if (stop) {
00429         i2c_stop(obj);
00430     }
00431 #if defined(TARGET_LPC812)
00432     else {
00433         repeated_start = 1;
00434     }
00435 #endif
00436 
00437     return 0;
00438 }
00439 
00440 void i2c_reset(i2c_t *obj) {
00441     i2c_stop(obj);
00442 }
00443 
00444 int i2c_byte_read(i2c_t *obj, int last) {
00445     return (i2c_do_read(obj, last) & 0xFF);
00446 }
00447 
00448 int i2c_byte_write(i2c_t *obj, int data) {
00449     int ack;
00450     int status = i2c_do_write(obj, (data & 0xFF), 0);
00451 
00452     switch(status) {
00453 #if defined(TARGET_LPC1768) || defined(TARGET_LPC11U24) || defined(TARGET_LPC2368)
00454         case 0x18: case 0x28:       // Master transmit ACKs
00455             ack = 1;
00456             break;
00457         case 0x40:                  // Master receive address transmitted ACK
00458             ack = 1;
00459             break;
00460         case 0xB8:                  // Slave transmit ACK
00461             ack = 1;
00462             break;
00463 #elif defined(TARGET_LPC812)
00464         case 2:
00465             ack = 1;
00466             break;
00467 #endif
00468         default:
00469             ack = 0;
00470             break;
00471     }
00472 
00473     return ack;
00474 }
00475 
00476 #if DEVICE_I2CSLAVE
00477 void i2c_slave_mode(i2c_t *obj, int enable_slave) {
00478     if (enable_slave != 0) {
00479         i2c_conclr(obj, 1, 1, 1, 0);
00480         i2c_conset(obj, 0, 0, 0, 1);
00481     } else {
00482         i2c_conclr(obj, 1, 1, 1, 1);
00483     }
00484 }
00485 
00486 int i2c_slave_receive(i2c_t *obj) {
00487     int status;
00488     int retval;
00489 
00490     status = i2c_status(obj);
00491     switch(status) {
00492         case 0x60: retval = 3; break;
00493         case 0x70: retval = 2; break;
00494         case 0xA8: retval = 1; break;
00495         default  : retval = 0; break;
00496     }
00497 
00498     return(retval);
00499 }
00500 
00501 int i2c_slave_read(i2c_t *obj, char *data, int length) {
00502     int count = 0;
00503     int status;
00504 
00505     do {
00506         i2c_clear_SI(obj);
00507         i2c_wait_SI(obj);
00508         status = i2c_status(obj);
00509         if((status == 0x80) || (status == 0x90)) {
00510             data[count] = I2C_DAT(obj) & 0xFF;
00511         }
00512         count++;
00513     } while (((status == 0x80) || (status == 0x90) ||
00514             (status == 0x060) || (status == 0x70)) && (count < length));
00515 
00516     if(status != 0xA0) {
00517         i2c_stop(obj);
00518     }
00519 
00520     i2c_clear_SI(obj);
00521 
00522     return (count - 1);
00523 }
00524 
00525 int i2c_slave_write(i2c_t *obj, const char *data, int length) {
00526     int count = 0;
00527     int status;
00528 
00529     if(length <= 0) {
00530         return(0);
00531     }
00532 
00533     do {
00534         status = i2c_do_write(obj, data[count], 0);
00535         count++;
00536     } while ((count < length) && (status == 0xB8));
00537 
00538     if((status != 0xC0) && (status != 0xC8)) {
00539         i2c_stop(obj);
00540     }
00541 
00542     i2c_clear_SI(obj);
00543 
00544     return(count);
00545 }
00546 
00547 void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) {
00548     uint32_t addr;
00549 
00550     if ((idx >= 0) && (idx <= 3)) {
00551         addr = ((uint32_t)obj->i2c) + I2C_addr_offset[0][idx];
00552         *((uint32_t *) addr) = address & 0xFF;
00553 #ifdef TARGET_LPC1768
00554         addr = ((uint32_t)obj->i2c) + I2C_addr_offset[1][idx];
00555         *((uint32_t *) addr) = mask & 0xFE;
00556 #endif
00557     }
00558 }
00559 #endif
00560 
00561 #endif