mbed-os

Fork of mbed-os by erkin yucel

Committer:
elessair
Date:
Sun Oct 23 15:10:02 2016 +0000
Revision:
0:f269e3021894
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
elessair 0:f269e3021894 1 /* mbed Microcontroller Library
elessair 0:f269e3021894 2 * Copyright (c) 2006-2013 ARM Limited
elessair 0:f269e3021894 3 *
elessair 0:f269e3021894 4 * Licensed under the Apache License, Version 2.0 (the "License");
elessair 0:f269e3021894 5 * you may not use this file except in compliance with the License.
elessair 0:f269e3021894 6 * You may obtain a copy of the License at
elessair 0:f269e3021894 7 *
elessair 0:f269e3021894 8 * http://www.apache.org/licenses/LICENSE-2.0
elessair 0:f269e3021894 9 *
elessair 0:f269e3021894 10 * Unless required by applicable law or agreed to in writing, software
elessair 0:f269e3021894 11 * distributed under the License is distributed on an "AS IS" BASIS,
elessair 0:f269e3021894 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
elessair 0:f269e3021894 13 * See the License for the specific language governing permissions and
elessair 0:f269e3021894 14 * limitations under the License.
elessair 0:f269e3021894 15 */
elessair 0:f269e3021894 16 #include <stdlib.h>
elessair 0:f269e3021894 17 #include <string.h>
elessair 0:f269e3021894 18
elessair 0:f269e3021894 19 #include "i2c_api.h"
elessair 0:f269e3021894 20 #include "cmsis.h"
elessair 0:f269e3021894 21 #include "pinmap.h"
elessair 0:f269e3021894 22
elessair 0:f269e3021894 23 #define LPC824_I2C0_FMPLUS 1
elessair 0:f269e3021894 24
elessair 0:f269e3021894 25 #if DEVICE_I2C
elessair 0:f269e3021894 26
elessair 0:f269e3021894 27 static const SWM_Map SWM_I2C_SDA[] = {
elessair 0:f269e3021894 28 //PINASSIGN Register ID, Pinselect bitfield position
elessair 0:f269e3021894 29 { 9, 8},
elessair 0:f269e3021894 30 { 9, 24},
elessair 0:f269e3021894 31 {10, 8},
elessair 0:f269e3021894 32 };
elessair 0:f269e3021894 33
elessair 0:f269e3021894 34 static const SWM_Map SWM_I2C_SCL[] = {
elessair 0:f269e3021894 35 //PINASSIGN Register ID, Pinselect bitfield position
elessair 0:f269e3021894 36 { 9, 16},
elessair 0:f269e3021894 37 {10, 0},
elessair 0:f269e3021894 38 {10, 16},
elessair 0:f269e3021894 39 };
elessair 0:f269e3021894 40
elessair 0:f269e3021894 41
elessair 0:f269e3021894 42 static int i2c_used = 0;
elessair 0:f269e3021894 43 static uint8_t repeated_start = 0;
elessair 0:f269e3021894 44
elessair 0:f269e3021894 45 #define I2C_DAT(x) (x->i2c->MSTDAT)
elessair 0:f269e3021894 46 #define I2C_STAT(x) ((x->i2c->STAT >> 1) & (0x07))
elessair 0:f269e3021894 47
elessair 0:f269e3021894 48 static inline void i2c_power_enable(int ch)
elessair 0:f269e3021894 49 {
elessair 0:f269e3021894 50 switch(ch) {
elessair 0:f269e3021894 51 case 0:
elessair 0:f269e3021894 52 // I2C0, Same as for LPC812
elessair 0:f269e3021894 53 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 5);
elessair 0:f269e3021894 54 LPC_SYSCON->PRESETCTRL &= ~(1 << 6);
elessair 0:f269e3021894 55 LPC_SYSCON->PRESETCTRL |= (1 << 6);
elessair 0:f269e3021894 56 break;
elessair 0:f269e3021894 57 case 1:
elessair 0:f269e3021894 58 case 2:
elessair 0:f269e3021894 59 case 3:
elessair 0:f269e3021894 60 // I2C1,I2C2 or I2C3. Not available for LPC812
elessair 0:f269e3021894 61 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << (20 + ch));
elessair 0:f269e3021894 62 LPC_SYSCON->PRESETCTRL &= ~(1 << (13 + ch));
elessair 0:f269e3021894 63 LPC_SYSCON->PRESETCTRL |= (1 << (13 + ch));
elessair 0:f269e3021894 64 break;
elessair 0:f269e3021894 65 default:
elessair 0:f269e3021894 66 break;
elessair 0:f269e3021894 67 }
elessair 0:f269e3021894 68 }
elessair 0:f269e3021894 69
elessair 0:f269e3021894 70
elessair 0:f269e3021894 71 static inline void i2c_interface_enable(i2c_t *obj) {
elessair 0:f269e3021894 72 obj->i2c->CFG |= (1 << 0); // Enable Master mode
elessair 0:f269e3021894 73 // obj->i2c->CFG &= ~(1 << 1); // Disable Slave mode
elessair 0:f269e3021894 74 }
elessair 0:f269e3021894 75
elessair 0:f269e3021894 76
elessair 0:f269e3021894 77 static int get_available_i2c(void) {
elessair 0:f269e3021894 78 int i;
elessair 0:f269e3021894 79 for (i=0; i<3; i++) {
elessair 0:f269e3021894 80 if ((i2c_used & (1 << i)) == 0)
elessair 0:f269e3021894 81 return i+1;
elessair 0:f269e3021894 82 }
elessair 0:f269e3021894 83 return -1;
elessair 0:f269e3021894 84 }
elessair 0:f269e3021894 85
elessair 0:f269e3021894 86 void i2c_init(i2c_t *obj, PinName sda, PinName scl)
elessair 0:f269e3021894 87 {
elessair 0:f269e3021894 88 const SWM_Map *swm;
elessair 0:f269e3021894 89 uint32_t regVal;
elessair 0:f269e3021894 90 int i2c_ch = 0;
elessair 0:f269e3021894 91
elessair 0:f269e3021894 92 //LPC824
elessair 0:f269e3021894 93 //I2C0 can support FM+ but only on P0_11 and P0_10
elessair 0:f269e3021894 94 if (sda == I2C_SDA && scl == I2C_SCL) {
elessair 0:f269e3021894 95 //Select I2C mode for P0_11 and P0_10
elessair 0:f269e3021894 96 LPC_SWM->PINENABLE0 &= ~(0x3 << 11);
elessair 0:f269e3021894 97
elessair 0:f269e3021894 98 #if(LPC824_I2C0_FMPLUS == 1)
elessair 0:f269e3021894 99 // Enable FM+ mode on P0_11, P0_10
elessair 0:f269e3021894 100 LPC_IOCON->PIO0_10 &= ~(0x3 << 8);
elessair 0:f269e3021894 101 LPC_IOCON->PIO0_10 |= (0x2 << 8); //FM+ mode
elessair 0:f269e3021894 102 LPC_IOCON->PIO0_11 &= ~(0x3 << 8);
elessair 0:f269e3021894 103 LPC_IOCON->PIO0_11 |= (0x2 << 8); //FM+ mode
elessair 0:f269e3021894 104 #endif
elessair 0:f269e3021894 105 }
elessair 0:f269e3021894 106 else {
elessair 0:f269e3021894 107 //Select any other pin for I2C1, I2C2 or I2C3
elessair 0:f269e3021894 108 i2c_ch = get_available_i2c();
elessair 0:f269e3021894 109 if (i2c_ch == -1)
elessair 0:f269e3021894 110 return;
elessair 0:f269e3021894 111 i2c_used |= (1 << (i2c_ch - 1));
elessair 0:f269e3021894 112
elessair 0:f269e3021894 113 swm = &SWM_I2C_SDA[i2c_ch - 1];
elessair 0:f269e3021894 114 regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
elessair 0:f269e3021894 115 LPC_SWM->PINASSIGN[swm->n] = regVal | ((sda >> PIN_SHIFT) << swm->offset);
elessair 0:f269e3021894 116
elessair 0:f269e3021894 117 swm = &SWM_I2C_SCL[i2c_ch - 1];
elessair 0:f269e3021894 118 regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
elessair 0:f269e3021894 119 LPC_SWM->PINASSIGN[swm->n] = regVal | ((scl >> PIN_SHIFT) << swm->offset);
elessair 0:f269e3021894 120 }
elessair 0:f269e3021894 121
elessair 0:f269e3021894 122 switch(i2c_ch) {
elessair 0:f269e3021894 123 case 0:
elessair 0:f269e3021894 124 obj->i2c = (LPC_I2C0_Type *)LPC_I2C0;
elessair 0:f269e3021894 125 break;
elessair 0:f269e3021894 126 case 1:
elessair 0:f269e3021894 127 obj->i2c = (LPC_I2C0_Type *)LPC_I2C1;
elessair 0:f269e3021894 128 break;
elessair 0:f269e3021894 129 case 2:
elessair 0:f269e3021894 130 obj->i2c = (LPC_I2C0_Type *)LPC_I2C2;
elessair 0:f269e3021894 131 break;
elessair 0:f269e3021894 132 case 3:
elessair 0:f269e3021894 133 obj->i2c = (LPC_I2C0_Type *)LPC_I2C3;
elessair 0:f269e3021894 134 break;
elessair 0:f269e3021894 135 default:
elessair 0:f269e3021894 136 break;
elessair 0:f269e3021894 137 }
elessair 0:f269e3021894 138
elessair 0:f269e3021894 139 // enable power
elessair 0:f269e3021894 140 i2c_power_enable(i2c_ch);
elessair 0:f269e3021894 141 // set default frequency at 100k
elessair 0:f269e3021894 142 i2c_frequency(obj, 100000);
elessair 0:f269e3021894 143 i2c_interface_enable(obj);
elessair 0:f269e3021894 144 }
elessair 0:f269e3021894 145
elessair 0:f269e3021894 146
elessair 0:f269e3021894 147 static inline int i2c_status(i2c_t *obj) {
elessair 0:f269e3021894 148 return I2C_STAT(obj);
elessair 0:f269e3021894 149 }
elessair 0:f269e3021894 150
elessair 0:f269e3021894 151 // Wait until the Master Serial Interrupt (SI) is set
elessair 0:f269e3021894 152 // Timeout when it takes too long.
elessair 0:f269e3021894 153 static int i2c_wait_SI(i2c_t *obj) {
elessair 0:f269e3021894 154 int timeout = 0;
elessair 0:f269e3021894 155 while (!(obj->i2c->STAT & (1 << 0))) {
elessair 0:f269e3021894 156 timeout++;
elessair 0:f269e3021894 157 if (timeout > 100000) return -1;
elessair 0:f269e3021894 158 }
elessair 0:f269e3021894 159 return 0;
elessair 0:f269e3021894 160 }
elessair 0:f269e3021894 161
elessair 0:f269e3021894 162
elessair 0:f269e3021894 163 //Attention. Spec says: First store Address in DAT before setting STA !
elessair 0:f269e3021894 164 //Undefined state when using single byte I2C operations and too much delay
elessair 0:f269e3021894 165 //between i2c_start and do_i2c_write(Address).
elessair 0:f269e3021894 166 //Also note that lpc812/824 will immediately continue reading a byte when Address b0 == 1
elessair 0:f269e3021894 167 inline int i2c_start(i2c_t *obj) {
elessair 0:f269e3021894 168 int status = 0;
elessair 0:f269e3021894 169 if (repeated_start) {
elessair 0:f269e3021894 170 obj->i2c->MSTCTL = (1 << 1) | (1 << 0); // STA bit and Continue bit to complete previous RD or WR
elessair 0:f269e3021894 171 repeated_start = 0;
elessair 0:f269e3021894 172 } else {
elessair 0:f269e3021894 173 obj->i2c->MSTCTL = (1 << 1); // STA bit
elessair 0:f269e3021894 174 }
elessair 0:f269e3021894 175 return status;
elessair 0:f269e3021894 176 }
elessair 0:f269e3021894 177
elessair 0:f269e3021894 178 //Generate Stop condition and wait until bus is Idle
elessair 0:f269e3021894 179 //Will also send NAK for previous RD
elessair 0:f269e3021894 180 inline int i2c_stop(i2c_t *obj) {
elessair 0:f269e3021894 181 int timeout = 0;
elessair 0:f269e3021894 182
elessair 0:f269e3021894 183 // STP bit and Continue bit. Sends NAK to complete previous RD
elessair 0:f269e3021894 184 obj->i2c->MSTCTL = (1 << 2) | (1 << 0);
elessair 0:f269e3021894 185
elessair 0:f269e3021894 186 //Spin until Ready (b0 == 1)and Status is Idle (b3..b1 == 000)
elessair 0:f269e3021894 187 while ((obj->i2c->STAT & ((7 << 1) | (1 << 0))) != ((0 << 1) | (1 << 0))) {
elessair 0:f269e3021894 188 timeout ++;
elessair 0:f269e3021894 189 if (timeout > 100000) return 1;
elessair 0:f269e3021894 190 }
elessair 0:f269e3021894 191
elessair 0:f269e3021894 192 // repeated_start = 0; // bus free
elessair 0:f269e3021894 193 return 0;
elessair 0:f269e3021894 194 }
elessair 0:f269e3021894 195
elessair 0:f269e3021894 196 //Spec says: first check Idle and status is Ok
elessair 0:f269e3021894 197 static inline int i2c_do_write(i2c_t *obj, int value, uint8_t addr) {
elessair 0:f269e3021894 198 // write the data
elessair 0:f269e3021894 199 I2C_DAT(obj) = value;
elessair 0:f269e3021894 200
elessair 0:f269e3021894 201 if (!addr)
elessair 0:f269e3021894 202 obj->i2c->MSTCTL = (1 << 0); //Set continue for data. Should not be set for addr since that uses STA
elessair 0:f269e3021894 203
elessair 0:f269e3021894 204 // wait and return status
elessair 0:f269e3021894 205 i2c_wait_SI(obj);
elessair 0:f269e3021894 206 return i2c_status(obj);
elessair 0:f269e3021894 207 }
elessair 0:f269e3021894 208
elessair 0:f269e3021894 209
elessair 0:f269e3021894 210 //Attention, correct Order: wait for data ready, read data, read status, continue, return
elessair 0:f269e3021894 211 //Dont read DAT or STAT when not ready, so dont read after setting continue.
elessair 0:f269e3021894 212 //Results may be invalid when next read is underway.
elessair 0:f269e3021894 213 static inline int i2c_do_read(i2c_t *obj, int last) {
elessair 0:f269e3021894 214 // wait for it to arrive
elessair 0:f269e3021894 215 i2c_wait_SI(obj);
elessair 0:f269e3021894 216 if (!last)
elessair 0:f269e3021894 217 obj->i2c->MSTCTL = (1 << 0); //ACK and Continue
elessair 0:f269e3021894 218
elessair 0:f269e3021894 219 // return the data
elessair 0:f269e3021894 220 return (I2C_DAT(obj) & 0xFF);
elessair 0:f269e3021894 221 }
elessair 0:f269e3021894 222
elessair 0:f269e3021894 223
elessair 0:f269e3021894 224 void i2c_frequency(i2c_t *obj, int hz) {
elessair 0:f269e3021894 225 // No peripheral clock divider on the M0
elessair 0:f269e3021894 226 uint32_t PCLK = SystemCoreClock;
elessair 0:f269e3021894 227
elessair 0:f269e3021894 228 uint32_t clkdiv = PCLK / (hz * 4) - 1;
elessair 0:f269e3021894 229
elessair 0:f269e3021894 230 obj->i2c->CLKDIV = clkdiv;
elessair 0:f269e3021894 231 obj->i2c->MSTTIME = 0;
elessair 0:f269e3021894 232 }
elessair 0:f269e3021894 233
elessair 0:f269e3021894 234 // The I2C does a read or a write as a whole operation
elessair 0:f269e3021894 235 // There are two types of error conditions it can encounter
elessair 0:f269e3021894 236 // 1) it can not obtain the bus
elessair 0:f269e3021894 237 // 2) it gets error responses at part of the transmission
elessair 0:f269e3021894 238 //
elessair 0:f269e3021894 239 // We tackle them as follows:
elessair 0:f269e3021894 240 // 1) we retry until we get the bus. we could have a "timeout" if we can not get it
elessair 0:f269e3021894 241 // which basically turns it in to a 2)
elessair 0:f269e3021894 242 // 2) on error, we use the standard error mechanisms to report/debug
elessair 0:f269e3021894 243 //
elessair 0:f269e3021894 244 // Therefore an I2C transaction should always complete. If it doesn't it is usually
elessair 0:f269e3021894 245 // because something is setup wrong (e.g. wiring), and we don't need to programatically
elessair 0:f269e3021894 246 // check for that
elessair 0:f269e3021894 247 int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
elessair 0:f269e3021894 248 int count, status;
elessair 0:f269e3021894 249
elessair 0:f269e3021894 250 //Store the address+RD and then generate STA
elessair 0:f269e3021894 251 I2C_DAT(obj) = address | 0x01;
elessair 0:f269e3021894 252 i2c_start(obj);
elessair 0:f269e3021894 253
elessair 0:f269e3021894 254 // Wait for completion of STA and Sending of SlaveAddress+RD and first Read byte
elessair 0:f269e3021894 255 i2c_wait_SI(obj);
elessair 0:f269e3021894 256 status = i2c_status(obj);
elessair 0:f269e3021894 257 if (status == 0x03) { // NAK on SlaveAddress
elessair 0:f269e3021894 258 i2c_stop(obj);
elessair 0:f269e3021894 259 return I2C_ERROR_NO_SLAVE;
elessair 0:f269e3021894 260 }
elessair 0:f269e3021894 261
elessair 0:f269e3021894 262 // Read in all except last byte
elessair 0:f269e3021894 263 for (count = 0; count < (length-1); count++) {
elessair 0:f269e3021894 264
elessair 0:f269e3021894 265 // Wait for it to arrive, note that first byte read after address+RD is already waiting
elessair 0:f269e3021894 266 i2c_wait_SI(obj);
elessair 0:f269e3021894 267 status = i2c_status(obj);
elessair 0:f269e3021894 268 if (status != 0x01) { // RX RDY
elessair 0:f269e3021894 269 i2c_stop(obj);
elessair 0:f269e3021894 270 return count;
elessair 0:f269e3021894 271 }
elessair 0:f269e3021894 272 data[count] = I2C_DAT(obj) & 0xFF; // Store read byte
elessair 0:f269e3021894 273
elessair 0:f269e3021894 274 obj->i2c->MSTCTL = (1 << 0); // Send ACK and Continue to read
elessair 0:f269e3021894 275 }
elessair 0:f269e3021894 276
elessair 0:f269e3021894 277 // Read final byte
elessair 0:f269e3021894 278 // Wait for it to arrive
elessair 0:f269e3021894 279 i2c_wait_SI(obj);
elessair 0:f269e3021894 280
elessair 0:f269e3021894 281 status = i2c_status(obj);
elessair 0:f269e3021894 282 if (status != 0x01) { // RX RDY
elessair 0:f269e3021894 283 i2c_stop(obj);
elessair 0:f269e3021894 284 return count;
elessair 0:f269e3021894 285 }
elessair 0:f269e3021894 286 data[count] = I2C_DAT(obj) & 0xFF; // Store final read byte
elessair 0:f269e3021894 287
elessair 0:f269e3021894 288 // If not repeated start, send stop.
elessair 0:f269e3021894 289 if (stop) {
elessair 0:f269e3021894 290 i2c_stop(obj); // Also sends NAK for last read byte
elessair 0:f269e3021894 291 } else {
elessair 0:f269e3021894 292 repeated_start = 1;
elessair 0:f269e3021894 293 }
elessair 0:f269e3021894 294
elessair 0:f269e3021894 295 return length;
elessair 0:f269e3021894 296 }
elessair 0:f269e3021894 297
elessair 0:f269e3021894 298
elessair 0:f269e3021894 299 int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
elessair 0:f269e3021894 300 int i, status;
elessair 0:f269e3021894 301
elessair 0:f269e3021894 302 //Store the address+/WR and then generate STA
elessair 0:f269e3021894 303 I2C_DAT(obj) = address & 0xFE;
elessair 0:f269e3021894 304 i2c_start(obj);
elessair 0:f269e3021894 305
elessair 0:f269e3021894 306 // Wait for completion of STA and Sending of SlaveAddress+/WR
elessair 0:f269e3021894 307 i2c_wait_SI(obj);
elessair 0:f269e3021894 308 status = i2c_status(obj);
elessair 0:f269e3021894 309 if (status == 0x03) { // NAK SlaveAddress
elessair 0:f269e3021894 310 i2c_stop(obj);
elessair 0:f269e3021894 311 return I2C_ERROR_NO_SLAVE;
elessair 0:f269e3021894 312 }
elessair 0:f269e3021894 313
elessair 0:f269e3021894 314 //Write all bytes
elessair 0:f269e3021894 315 for (i=0; i<length; i++) {
elessair 0:f269e3021894 316 status = i2c_do_write(obj, data[i], 0);
elessair 0:f269e3021894 317 if (status != 0x02) { // TX RDY. Handles a Slave NAK on datawrite
elessair 0:f269e3021894 318 i2c_stop(obj);
elessair 0:f269e3021894 319 return i;
elessair 0:f269e3021894 320 }
elessair 0:f269e3021894 321 }
elessair 0:f269e3021894 322
elessair 0:f269e3021894 323 // If not repeated start, send stop.
elessair 0:f269e3021894 324 if (stop) {
elessair 0:f269e3021894 325 i2c_stop(obj);
elessair 0:f269e3021894 326 } else {
elessair 0:f269e3021894 327 repeated_start = 1;
elessair 0:f269e3021894 328 }
elessair 0:f269e3021894 329
elessair 0:f269e3021894 330 return length;
elessair 0:f269e3021894 331 }
elessair 0:f269e3021894 332
elessair 0:f269e3021894 333 void i2c_reset(i2c_t *obj) {
elessair 0:f269e3021894 334 i2c_stop(obj);
elessair 0:f269e3021894 335 }
elessair 0:f269e3021894 336
elessair 0:f269e3021894 337 int i2c_byte_read(i2c_t *obj, int last) {
elessair 0:f269e3021894 338 return (i2c_do_read(obj, last) & 0xFF);
elessair 0:f269e3021894 339 // return (i2c_do_read(obj, last, 0) & 0xFF);
elessair 0:f269e3021894 340 }
elessair 0:f269e3021894 341
elessair 0:f269e3021894 342 int i2c_byte_write(i2c_t *obj, int data) {
elessair 0:f269e3021894 343 int ack;
elessair 0:f269e3021894 344 int status = i2c_do_write(obj, (data & 0xFF), 0);
elessair 0:f269e3021894 345
elessair 0:f269e3021894 346 switch(status) {
elessair 0:f269e3021894 347 case 2: // TX RDY. Handles a Slave NAK on datawrite
elessair 0:f269e3021894 348 ack = 1;
elessair 0:f269e3021894 349 break;
elessair 0:f269e3021894 350 default:
elessair 0:f269e3021894 351 ack = 0;
elessair 0:f269e3021894 352 break;
elessair 0:f269e3021894 353 }
elessair 0:f269e3021894 354
elessair 0:f269e3021894 355 return ack;
elessair 0:f269e3021894 356 }
elessair 0:f269e3021894 357
elessair 0:f269e3021894 358
elessair 0:f269e3021894 359 #if DEVICE_I2CSLAVE
elessair 0:f269e3021894 360
elessair 0:f269e3021894 361 #define I2C_SLVDAT(x) (x->i2c->SLVDAT)
elessair 0:f269e3021894 362 #define I2C_SLVSTAT(x) ((x->i2c->STAT >> 9) & (0x03))
elessair 0:f269e3021894 363 #define I2C_SLVSI(x) ((x->i2c->STAT >> 8) & (0x01))
elessair 0:f269e3021894 364 //#define I2C_SLVCNT(x) (x->i2c->SLVCTL = (1 << 0))
elessair 0:f269e3021894 365 //#define I2C_SLVNAK(x) (x->i2c->SLVCTL = (1 << 1))
elessair 0:f269e3021894 366
elessair 0:f269e3021894 367 #if(0)
elessair 0:f269e3021894 368 // Wait until the Slave Serial Interrupt (SI) is set
elessair 0:f269e3021894 369 // Timeout when it takes too long.
elessair 0:f269e3021894 370 static int i2c_wait_slave_SI(i2c_t *obj) {
elessair 0:f269e3021894 371 int timeout = 0;
elessair 0:f269e3021894 372 while (!(obj->i2c->STAT & (1 << 8))) {
elessair 0:f269e3021894 373 timeout++;
elessair 0:f269e3021894 374 if (timeout > 100000) return -1;
elessair 0:f269e3021894 375 }
elessair 0:f269e3021894 376 return 0;
elessair 0:f269e3021894 377 }
elessair 0:f269e3021894 378 #endif
elessair 0:f269e3021894 379
elessair 0:f269e3021894 380 void i2c_slave_mode(i2c_t *obj, int enable_slave) {
elessair 0:f269e3021894 381
elessair 0:f269e3021894 382 if (enable_slave) {
elessair 0:f269e3021894 383 // obj->i2c->CFG &= ~(1 << 0); //Disable Master mode
elessair 0:f269e3021894 384 obj->i2c->CFG |= (1 << 1); //Enable Slave mode
elessair 0:f269e3021894 385 }
elessair 0:f269e3021894 386 else {
elessair 0:f269e3021894 387 // obj->i2c->CFG |= (1 << 0); //Enable Master mode
elessair 0:f269e3021894 388 obj->i2c->CFG &= ~(1 << 1); //Disable Slave mode
elessair 0:f269e3021894 389 }
elessair 0:f269e3021894 390 }
elessair 0:f269e3021894 391
elessair 0:f269e3021894 392 // Wait for next I2C event and find out what is going on
elessair 0:f269e3021894 393 //
elessair 0:f269e3021894 394 int i2c_slave_receive(i2c_t *obj) {
elessair 0:f269e3021894 395 int addr;
elessair 0:f269e3021894 396
elessair 0:f269e3021894 397 // Check if there is any data pending
elessair 0:f269e3021894 398 if (! I2C_SLVSI(obj)) {
elessair 0:f269e3021894 399 return 0; //NoData
elessair 0:f269e3021894 400 };
elessair 0:f269e3021894 401
elessair 0:f269e3021894 402 // Check State
elessair 0:f269e3021894 403 switch(I2C_SLVSTAT(obj)) {
elessair 0:f269e3021894 404 case 0x0: // Slave address plus R/W received
elessair 0:f269e3021894 405 // At least one of the four slave addresses has been matched by hardware.
elessair 0:f269e3021894 406 // You can figure out which address by checking Slave address match Index in STAT register.
elessair 0:f269e3021894 407
elessair 0:f269e3021894 408 // Get the received address
elessair 0:f269e3021894 409 addr = I2C_SLVDAT(obj) & 0xFF;
elessair 0:f269e3021894 410 // Send ACK on address and Continue
elessair 0:f269e3021894 411 obj->i2c->SLVCTL = (1 << 0);
elessair 0:f269e3021894 412
elessair 0:f269e3021894 413 if (addr == 0x00) {
elessair 0:f269e3021894 414 return 2; //WriteGeneral
elessair 0:f269e3021894 415 }
elessair 0:f269e3021894 416 //check the RW bit
elessair 0:f269e3021894 417 if ((addr & 0x01) == 0x01) {
elessair 0:f269e3021894 418 return 1; //ReadAddressed
elessair 0:f269e3021894 419 }
elessair 0:f269e3021894 420 else {
elessair 0:f269e3021894 421 return 3; //WriteAddressed
elessair 0:f269e3021894 422 }
elessair 0:f269e3021894 423 //break;
elessair 0:f269e3021894 424
elessair 0:f269e3021894 425 case 0x1: // Slave receive. Received data is available (Slave Receiver mode).
elessair 0:f269e3021894 426 // Oops, should never get here...
elessair 0:f269e3021894 427 obj->i2c->SLVCTL = (1 << 1); // Send NACK on received data, try to recover...
elessair 0:f269e3021894 428 return 0; //NoData
elessair 0:f269e3021894 429
elessair 0:f269e3021894 430 case 0x2: // Slave transmit. Data can be transmitted (Slave Transmitter mode).
elessair 0:f269e3021894 431 // Oops, should never get here...
elessair 0:f269e3021894 432 I2C_SLVDAT(obj) = 0xFF; // Send dummy data for transmission
elessair 0:f269e3021894 433 obj->i2c->SLVCTL = (1 << 0); // Continue and try to recover...
elessair 0:f269e3021894 434 return 0; //NoData
elessair 0:f269e3021894 435
elessair 0:f269e3021894 436 case 0x3: // Reserved.
elessair 0:f269e3021894 437 default: // Oops, should never get here...
elessair 0:f269e3021894 438 obj->i2c->SLVCTL = (1 << 0); // Continue and try to recover...
elessair 0:f269e3021894 439 return 0; //NoData
elessair 0:f269e3021894 440 //break;
elessair 0:f269e3021894 441 } //switch status
elessair 0:f269e3021894 442 }
elessair 0:f269e3021894 443
elessair 0:f269e3021894 444 // The dedicated I2C Slave byte read and byte write functions need to be called
elessair 0:f269e3021894 445 // from 'common' mbed I2CSlave API for devices that have separate Master and
elessair 0:f269e3021894 446 // Slave engines such as the lpc812 and lpc1549.
elessair 0:f269e3021894 447
elessair 0:f269e3021894 448 //Called when Slave is addressed for Write, Slave will receive Data in polling mode
elessair 0:f269e3021894 449 //Parameter last=1 means received byte will be NACKed.
elessair 0:f269e3021894 450 int i2c_slave_byte_read(i2c_t *obj, int last) {
elessair 0:f269e3021894 451 int data;
elessair 0:f269e3021894 452
elessair 0:f269e3021894 453 // Wait for data
elessair 0:f269e3021894 454 while (!I2C_SLVSI(obj)); // Wait forever
elessair 0:f269e3021894 455 //if (i2c_wait_slave_SI(obj) != 0) {return -2;} // Wait with timeout
elessair 0:f269e3021894 456
elessair 0:f269e3021894 457 // Dont bother to check State, were not returning it anyhow..
elessair 0:f269e3021894 458 //if (I2C_SLVSTAT(obj)) == 0x01) {
elessair 0:f269e3021894 459 // Slave receive. Received data is available (Slave Receiver mode).
elessair 0:f269e3021894 460 //};
elessair 0:f269e3021894 461
elessair 0:f269e3021894 462 data = I2C_SLVDAT(obj) & 0xFF; // Get and store the received data
elessair 0:f269e3021894 463 if (last) {
elessair 0:f269e3021894 464 obj->i2c->SLVCTL = (1 << 1); // Send NACK on received data and Continue
elessair 0:f269e3021894 465 }
elessair 0:f269e3021894 466 else {
elessair 0:f269e3021894 467 obj->i2c->SLVCTL = (1 << 0); // Send ACK on data and Continue to read
elessair 0:f269e3021894 468 }
elessair 0:f269e3021894 469
elessair 0:f269e3021894 470 return data;
elessair 0:f269e3021894 471 }
elessair 0:f269e3021894 472
elessair 0:f269e3021894 473
elessair 0:f269e3021894 474 //Called when Slave is addressed for Read, Slave will send Data in polling mode
elessair 0:f269e3021894 475 //
elessair 0:f269e3021894 476 int i2c_slave_byte_write(i2c_t *obj, int data) {
elessair 0:f269e3021894 477
elessair 0:f269e3021894 478 // Wait until Ready
elessair 0:f269e3021894 479 while (!I2C_SLVSI(obj)); // Wait forever
elessair 0:f269e3021894 480 // if (i2c_wait_slave_SI(obj) != 0) {return -2;} // Wait with timeout
elessair 0:f269e3021894 481
elessair 0:f269e3021894 482 // Check State
elessair 0:f269e3021894 483 switch(I2C_SLVSTAT(obj)) {
elessair 0:f269e3021894 484 case 0x0: // Slave address plus R/W received
elessair 0:f269e3021894 485 // At least one of the four slave addresses has been matched by hardware.
elessair 0:f269e3021894 486 // You can figure out which address by checking Slave address match Index in STAT register.
elessair 0:f269e3021894 487 // I2C Restart occurred
elessair 0:f269e3021894 488 return -1;
elessair 0:f269e3021894 489 //break;
elessair 0:f269e3021894 490 case 0x1: // Slave receive. Received data is available (Slave Receiver mode).
elessair 0:f269e3021894 491 // Should not get here...
elessair 0:f269e3021894 492 return -2;
elessair 0:f269e3021894 493 //break;
elessair 0:f269e3021894 494 case 0x2: // Slave transmit. Data can be transmitted (Slave Transmitter mode).
elessair 0:f269e3021894 495 I2C_SLVDAT(obj) = data & 0xFF; // Store the data for transmission
elessair 0:f269e3021894 496 obj->i2c->SLVCTL = (1 << 0); // Continue to send
elessair 0:f269e3021894 497
elessair 0:f269e3021894 498 return 1;
elessair 0:f269e3021894 499 //break;
elessair 0:f269e3021894 500 case 0x3: // Reserved.
elessair 0:f269e3021894 501 default:
elessair 0:f269e3021894 502 // Should not get here...
elessair 0:f269e3021894 503 return -3;
elessair 0:f269e3021894 504 //break;
elessair 0:f269e3021894 505 } // switch status
elessair 0:f269e3021894 506 }
elessair 0:f269e3021894 507
elessair 0:f269e3021894 508
elessair 0:f269e3021894 509 //Called when Slave is addressed for Write, Slave will receive Data in polling mode
elessair 0:f269e3021894 510 //Parameter length (>=1) is the maximum allowable number of bytes. All bytes will be ACKed.
elessair 0:f269e3021894 511 int i2c_slave_read(i2c_t *obj, char *data, int length) {
elessair 0:f269e3021894 512 int count=0;
elessair 0:f269e3021894 513
elessair 0:f269e3021894 514 // Read and ACK all expected bytes
elessair 0:f269e3021894 515 while (count < length) {
elessair 0:f269e3021894 516 // Wait for data
elessair 0:f269e3021894 517 while (!I2C_SLVSI(obj)); // Wait forever
elessair 0:f269e3021894 518 // if (i2c_wait_slave_SI(obj) != 0) {return -2;} // Wait with timeout
elessair 0:f269e3021894 519
elessair 0:f269e3021894 520 // Check State
elessair 0:f269e3021894 521 switch(I2C_SLVSTAT(obj)) {
elessair 0:f269e3021894 522 case 0x0: // Slave address plus R/W received
elessair 0:f269e3021894 523 // At least one of the four slave addresses has been matched by hardware.
elessair 0:f269e3021894 524 // You can figure out which address by checking Slave address match Index in STAT register.
elessair 0:f269e3021894 525 // I2C Restart occurred
elessair 0:f269e3021894 526 return -1;
elessair 0:f269e3021894 527 //break;
elessair 0:f269e3021894 528
elessair 0:f269e3021894 529 case 0x1: // Slave receive. Received data is available (Slave Receiver mode).
elessair 0:f269e3021894 530 data[count] = I2C_SLVDAT(obj) & 0xFF; // Get and store the received data
elessair 0:f269e3021894 531 obj->i2c->SLVCTL = (1 << 0); // Send ACK on data and Continue to read
elessair 0:f269e3021894 532 break;
elessair 0:f269e3021894 533
elessair 0:f269e3021894 534 case 0x2: // Slave transmit. Data can be transmitted (Slave Transmitter mode).
elessair 0:f269e3021894 535 case 0x3: // Reserved.
elessair 0:f269e3021894 536 default: // Should never get here...
elessair 0:f269e3021894 537 return -2;
elessair 0:f269e3021894 538 //break;
elessair 0:f269e3021894 539 } // switch status
elessair 0:f269e3021894 540
elessair 0:f269e3021894 541 count++;
elessair 0:f269e3021894 542 } // for all bytes
elessair 0:f269e3021894 543
elessair 0:f269e3021894 544 return count; // Received the expected number of bytes
elessair 0:f269e3021894 545 }
elessair 0:f269e3021894 546
elessair 0:f269e3021894 547
elessair 0:f269e3021894 548 //Called when Slave is addressed for Read, Slave will send Data in polling mode
elessair 0:f269e3021894 549 //Parameter length (>=1) is the maximum number of bytes. Exit when Slave byte is NACKed.
elessair 0:f269e3021894 550 int i2c_slave_write(i2c_t *obj, const char *data, int length) {
elessair 0:f269e3021894 551 int count;
elessair 0:f269e3021894 552
elessair 0:f269e3021894 553 // Send and all bytes or Exit on NAK
elessair 0:f269e3021894 554 for (count=0; count < length; count++) {
elessair 0:f269e3021894 555 // Wait until Ready for data
elessair 0:f269e3021894 556 while (!I2C_SLVSI(obj)); // Wait forever
elessair 0:f269e3021894 557 // if (i2c_wait_slave_SI(obj) != 0) {return -2;} // Wait with timeout
elessair 0:f269e3021894 558
elessair 0:f269e3021894 559 // Check State
elessair 0:f269e3021894 560 switch(I2C_SLVSTAT(obj)) {
elessair 0:f269e3021894 561 case 0x0: // Slave address plus R/W received
elessair 0:f269e3021894 562 // At least one of the four slave addresses has been matched by hardware.
elessair 0:f269e3021894 563 // You can figure out which address by checking Slave address match Index in STAT register.
elessair 0:f269e3021894 564 // I2C Restart occurred
elessair 0:f269e3021894 565 return -1;
elessair 0:f269e3021894 566 //break;
elessair 0:f269e3021894 567 case 0x1: // Slave receive. Received data is available (Slave Receiver mode).
elessair 0:f269e3021894 568 // Should not get here...
elessair 0:f269e3021894 569 return -2;
elessair 0:f269e3021894 570 //break;
elessair 0:f269e3021894 571 case 0x2: // Slave transmit. Data can be transmitted (Slave Transmitter mode).
elessair 0:f269e3021894 572 I2C_SLVDAT(obj) = data[count] & 0xFF; // Store the data for transmission
elessair 0:f269e3021894 573 obj->i2c->SLVCTL = (1 << 0); // Continue to send
elessair 0:f269e3021894 574 break;
elessair 0:f269e3021894 575 case 0x3: // Reserved.
elessair 0:f269e3021894 576 default:
elessair 0:f269e3021894 577 // Should not get here...
elessair 0:f269e3021894 578 return -3;
elessair 0:f269e3021894 579 //break;
elessair 0:f269e3021894 580 } // switch status
elessair 0:f269e3021894 581 } // for all bytes
elessair 0:f269e3021894 582
elessair 0:f269e3021894 583 return length; // Transmitted the max number of bytes
elessair 0:f269e3021894 584 }
elessair 0:f269e3021894 585
elessair 0:f269e3021894 586
elessair 0:f269e3021894 587 // Set the four slave addresses.
elessair 0:f269e3021894 588 void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) {
elessair 0:f269e3021894 589 obj->i2c->SLVADR0 = (address & 0xFE); // Store address in address 0 register
elessair 0:f269e3021894 590 obj->i2c->SLVADR1 = (0x00 & 0xFE); // Store general call write address in address 1 register
elessair 0:f269e3021894 591 obj->i2c->SLVADR2 = (0x01); // Disable address 2 register
elessair 0:f269e3021894 592 obj->i2c->SLVADR3 = (0x01); // Disable address 3 register
elessair 0:f269e3021894 593 obj->i2c->SLVQUAL0 = (mask & 0xFE); // Qualifier mask for address 0 register. Any maskbit that is 1 will always be a match
elessair 0:f269e3021894 594 }
elessair 0:f269e3021894 595
elessair 0:f269e3021894 596 #endif
elessair 0:f269e3021894 597
elessair 0:f269e3021894 598 #endif