ON Semiconductor / mbed-os

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