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