5.2.1 - Updated I2C files

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Committer:
group-onsemi
Date:
Wed Jan 25 20:34:15 2017 +0000
Revision:
0:098463de4c5d
Initial commit

Who changed what in which revision?

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