mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Committer:
bogdanm
Date:
Thu Oct 01 15:25:22 2015 +0300
Revision:
0:9b334a45a8ff
Child:
144:ef7eb2e8f9f7
Initial commit on mbed-dev

Replaces mbed-src (now inactive)

Who changed what in which revision?

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