mbed library sources, include can_api for nucleo-f091rc

Dependents:   CanNucleoF0_example

Fork of mbed-src by mbed official

Committer:
emilmont
Date:
Fri Jun 14 17:49:17 2013 +0100
Revision:
10:3bc89ef62ce7
Unify mbed library sources

Who changed what in which revision?

UserRevisionLine numberNew contents of line
emilmont 10:3bc89ef62ce7 1 /* mbed Microcontroller Library
emilmont 10:3bc89ef62ce7 2 * Copyright (c) 2006-2013 ARM Limited
emilmont 10:3bc89ef62ce7 3 *
emilmont 10:3bc89ef62ce7 4 * Licensed under the Apache License, Version 2.0 (the "License");
emilmont 10:3bc89ef62ce7 5 * you may not use this file except in compliance with the License.
emilmont 10:3bc89ef62ce7 6 * You may obtain a copy of the License at
emilmont 10:3bc89ef62ce7 7 *
emilmont 10:3bc89ef62ce7 8 * http://www.apache.org/licenses/LICENSE-2.0
emilmont 10:3bc89ef62ce7 9 *
emilmont 10:3bc89ef62ce7 10 * Unless required by applicable law or agreed to in writing, software
emilmont 10:3bc89ef62ce7 11 * distributed under the License is distributed on an "AS IS" BASIS,
emilmont 10:3bc89ef62ce7 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
emilmont 10:3bc89ef62ce7 13 * See the License for the specific language governing permissions and
emilmont 10:3bc89ef62ce7 14 * limitations under the License.
emilmont 10:3bc89ef62ce7 15 */
emilmont 10:3bc89ef62ce7 16 #include "i2c_api.h"
emilmont 10:3bc89ef62ce7 17 #include "cmsis.h"
emilmont 10:3bc89ef62ce7 18 #include "pinmap.h"
emilmont 10:3bc89ef62ce7 19 #include "error.h"
emilmont 10:3bc89ef62ce7 20
emilmont 10:3bc89ef62ce7 21 static const SWM_Map SWM_I2C_SDA[] = {
emilmont 10:3bc89ef62ce7 22 {7, 24},
emilmont 10:3bc89ef62ce7 23 };
emilmont 10:3bc89ef62ce7 24
emilmont 10:3bc89ef62ce7 25 static const SWM_Map SWM_I2C_SCL[] = {
emilmont 10:3bc89ef62ce7 26 {8, 0},
emilmont 10:3bc89ef62ce7 27 };
emilmont 10:3bc89ef62ce7 28
emilmont 10:3bc89ef62ce7 29 static uint8_t repeated_start = 0;
emilmont 10:3bc89ef62ce7 30
emilmont 10:3bc89ef62ce7 31 #define I2C_DAT(x) (x->i2c->MSTDAT)
emilmont 10:3bc89ef62ce7 32 #define I2C_STAT(x) ((x->i2c->STAT >> 1) & (0x07))
emilmont 10:3bc89ef62ce7 33
emilmont 10:3bc89ef62ce7 34 static inline int i2c_status(i2c_t *obj) {
emilmont 10:3bc89ef62ce7 35 return I2C_STAT(obj);
emilmont 10:3bc89ef62ce7 36 }
emilmont 10:3bc89ef62ce7 37
emilmont 10:3bc89ef62ce7 38 // Wait until the Serial Interrupt (SI) is set
emilmont 10:3bc89ef62ce7 39 static int i2c_wait_SI(i2c_t *obj) {
emilmont 10:3bc89ef62ce7 40 int timeout = 0;
emilmont 10:3bc89ef62ce7 41 while (!(obj->i2c->STAT & (1 << 0))) {
emilmont 10:3bc89ef62ce7 42 timeout++;
emilmont 10:3bc89ef62ce7 43 if (timeout > 100000) return -1;
emilmont 10:3bc89ef62ce7 44 }
emilmont 10:3bc89ef62ce7 45 return 0;
emilmont 10:3bc89ef62ce7 46 }
emilmont 10:3bc89ef62ce7 47
emilmont 10:3bc89ef62ce7 48 static inline void i2c_interface_enable(i2c_t *obj) {
emilmont 10:3bc89ef62ce7 49 obj->i2c->CFG |= (1 << 0);
emilmont 10:3bc89ef62ce7 50 }
emilmont 10:3bc89ef62ce7 51
emilmont 10:3bc89ef62ce7 52 static inline void i2c_power_enable(i2c_t *obj) {
emilmont 10:3bc89ef62ce7 53 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<5);
emilmont 10:3bc89ef62ce7 54 LPC_SYSCON->PRESETCTRL &= ~(0x1<<6);
emilmont 10:3bc89ef62ce7 55 LPC_SYSCON->PRESETCTRL |= (0x1<<6);
emilmont 10:3bc89ef62ce7 56 }
emilmont 10:3bc89ef62ce7 57
emilmont 10:3bc89ef62ce7 58 void i2c_init(i2c_t *obj, PinName sda, PinName scl) {
emilmont 10:3bc89ef62ce7 59 obj->i2c = (LPC_I2C_TypeDef *)LPC_I2C;
emilmont 10:3bc89ef62ce7 60
emilmont 10:3bc89ef62ce7 61 const SWM_Map *swm;
emilmont 10:3bc89ef62ce7 62 uint32_t regVal;
emilmont 10:3bc89ef62ce7 63
emilmont 10:3bc89ef62ce7 64 swm = &SWM_I2C_SDA[0];
emilmont 10:3bc89ef62ce7 65 regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
emilmont 10:3bc89ef62ce7 66 LPC_SWM->PINASSIGN[swm->n] = regVal | (sda << swm->offset);
emilmont 10:3bc89ef62ce7 67
emilmont 10:3bc89ef62ce7 68 swm = &SWM_I2C_SCL[0];
emilmont 10:3bc89ef62ce7 69 regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
emilmont 10:3bc89ef62ce7 70 LPC_SWM->PINASSIGN[swm->n] = regVal | (scl << swm->offset);
emilmont 10:3bc89ef62ce7 71
emilmont 10:3bc89ef62ce7 72 // enable power
emilmont 10:3bc89ef62ce7 73 i2c_power_enable(obj);
emilmont 10:3bc89ef62ce7 74 // set default frequency at 100k
emilmont 10:3bc89ef62ce7 75 i2c_frequency(obj, 100000);
emilmont 10:3bc89ef62ce7 76 i2c_interface_enable(obj);
emilmont 10:3bc89ef62ce7 77 }
emilmont 10:3bc89ef62ce7 78
emilmont 10:3bc89ef62ce7 79 inline int i2c_start(i2c_t *obj) {
emilmont 10:3bc89ef62ce7 80 int status = 0;
emilmont 10:3bc89ef62ce7 81 if (repeated_start) {
emilmont 10:3bc89ef62ce7 82 obj->i2c->MSTCTL = (1 << 1) | (1 << 0);
emilmont 10:3bc89ef62ce7 83 repeated_start = 0;
emilmont 10:3bc89ef62ce7 84 } else {
emilmont 10:3bc89ef62ce7 85 obj->i2c->MSTCTL = (1 << 1);
emilmont 10:3bc89ef62ce7 86 }
emilmont 10:3bc89ef62ce7 87 return status;
emilmont 10:3bc89ef62ce7 88 }
emilmont 10:3bc89ef62ce7 89
emilmont 10:3bc89ef62ce7 90 inline void i2c_stop(i2c_t *obj) {
emilmont 10:3bc89ef62ce7 91 obj->i2c->MSTCTL = (1 << 2) | (1 << 0);
emilmont 10:3bc89ef62ce7 92 while ((obj->i2c->STAT & ((1 << 0) | (7 << 1))) != ((1 << 0) | (0 << 1)));
emilmont 10:3bc89ef62ce7 93 }
emilmont 10:3bc89ef62ce7 94
emilmont 10:3bc89ef62ce7 95
emilmont 10:3bc89ef62ce7 96 static inline int i2c_do_write(i2c_t *obj, int value, uint8_t addr) {
emilmont 10:3bc89ef62ce7 97 // write the data
emilmont 10:3bc89ef62ce7 98 I2C_DAT(obj) = value;
emilmont 10:3bc89ef62ce7 99
emilmont 10:3bc89ef62ce7 100 if (!addr)
emilmont 10:3bc89ef62ce7 101 obj->i2c->MSTCTL = (1 << 0);
emilmont 10:3bc89ef62ce7 102
emilmont 10:3bc89ef62ce7 103 // wait and return status
emilmont 10:3bc89ef62ce7 104 i2c_wait_SI(obj);
emilmont 10:3bc89ef62ce7 105 return i2c_status(obj);
emilmont 10:3bc89ef62ce7 106 }
emilmont 10:3bc89ef62ce7 107
emilmont 10:3bc89ef62ce7 108 static inline int i2c_do_read(i2c_t *obj, int last) {
emilmont 10:3bc89ef62ce7 109 // wait for it to arrive
emilmont 10:3bc89ef62ce7 110 i2c_wait_SI(obj);
emilmont 10:3bc89ef62ce7 111 if (!last)
emilmont 10:3bc89ef62ce7 112 obj->i2c->MSTCTL = (1 << 0);
emilmont 10:3bc89ef62ce7 113
emilmont 10:3bc89ef62ce7 114 // return the data
emilmont 10:3bc89ef62ce7 115 return (I2C_DAT(obj) & 0xFF);
emilmont 10:3bc89ef62ce7 116 }
emilmont 10:3bc89ef62ce7 117
emilmont 10:3bc89ef62ce7 118 void i2c_frequency(i2c_t *obj, int hz) {
emilmont 10:3bc89ef62ce7 119 // No peripheral clock divider on the M0
emilmont 10:3bc89ef62ce7 120 uint32_t PCLK = SystemCoreClock;
emilmont 10:3bc89ef62ce7 121
emilmont 10:3bc89ef62ce7 122 uint32_t clkdiv = PCLK / (hz * 4) - 1;
emilmont 10:3bc89ef62ce7 123
emilmont 10:3bc89ef62ce7 124 obj->i2c->DIV = clkdiv;
emilmont 10:3bc89ef62ce7 125 obj->i2c->MSTTIME = 0;
emilmont 10:3bc89ef62ce7 126 }
emilmont 10:3bc89ef62ce7 127
emilmont 10:3bc89ef62ce7 128 // The I2C does a read or a write as a whole operation
emilmont 10:3bc89ef62ce7 129 // There are two types of error conditions it can encounter
emilmont 10:3bc89ef62ce7 130 // 1) it can not obtain the bus
emilmont 10:3bc89ef62ce7 131 // 2) it gets error responses at part of the transmission
emilmont 10:3bc89ef62ce7 132 //
emilmont 10:3bc89ef62ce7 133 // We tackle them as follows:
emilmont 10:3bc89ef62ce7 134 // 1) we retry until we get the bus. we could have a "timeout" if we can not get it
emilmont 10:3bc89ef62ce7 135 // which basically turns it in to a 2)
emilmont 10:3bc89ef62ce7 136 // 2) on error, we use the standard error mechanisms to report/debug
emilmont 10:3bc89ef62ce7 137 //
emilmont 10:3bc89ef62ce7 138 // Therefore an I2C transaction should always complete. If it doesn't it is usually
emilmont 10:3bc89ef62ce7 139 // because something is setup wrong (e.g. wiring), and we don't need to programatically
emilmont 10:3bc89ef62ce7 140 // check for that
emilmont 10:3bc89ef62ce7 141
emilmont 10:3bc89ef62ce7 142 int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
emilmont 10:3bc89ef62ce7 143 int count, status;
emilmont 10:3bc89ef62ce7 144
emilmont 10:3bc89ef62ce7 145 i2c_start(obj);
emilmont 10:3bc89ef62ce7 146
emilmont 10:3bc89ef62ce7 147 status = i2c_do_write(obj, (address | 0x01), 1);
emilmont 10:3bc89ef62ce7 148 if (status != 0x01) {
emilmont 10:3bc89ef62ce7 149 i2c_stop(obj);
emilmont 10:3bc89ef62ce7 150 return status;
emilmont 10:3bc89ef62ce7 151 }
emilmont 10:3bc89ef62ce7 152
emilmont 10:3bc89ef62ce7 153 // Read in all except last byte
emilmont 10:3bc89ef62ce7 154 for (count = 0; count < (length - 1); count++) {
emilmont 10:3bc89ef62ce7 155 int value = i2c_do_read(obj, 0);
emilmont 10:3bc89ef62ce7 156 status = i2c_status(obj);
emilmont 10:3bc89ef62ce7 157 if (status != 0x00) {
emilmont 10:3bc89ef62ce7 158 i2c_stop(obj);
emilmont 10:3bc89ef62ce7 159 return status;
emilmont 10:3bc89ef62ce7 160 }
emilmont 10:3bc89ef62ce7 161 data[count] = (char) value;
emilmont 10:3bc89ef62ce7 162 }
emilmont 10:3bc89ef62ce7 163
emilmont 10:3bc89ef62ce7 164 // read in last byte
emilmont 10:3bc89ef62ce7 165 int value = i2c_do_read(obj, 1);
emilmont 10:3bc89ef62ce7 166 status = i2c_status(obj);
emilmont 10:3bc89ef62ce7 167 if (status != 0x01) {
emilmont 10:3bc89ef62ce7 168 i2c_stop(obj);
emilmont 10:3bc89ef62ce7 169 return status;
emilmont 10:3bc89ef62ce7 170 }
emilmont 10:3bc89ef62ce7 171
emilmont 10:3bc89ef62ce7 172 data[count] = (char) value;
emilmont 10:3bc89ef62ce7 173
emilmont 10:3bc89ef62ce7 174 // If not repeated start, send stop.
emilmont 10:3bc89ef62ce7 175 if (stop) {
emilmont 10:3bc89ef62ce7 176 i2c_stop(obj);
emilmont 10:3bc89ef62ce7 177 } else {
emilmont 10:3bc89ef62ce7 178 repeated_start = 1;
emilmont 10:3bc89ef62ce7 179 }
emilmont 10:3bc89ef62ce7 180
emilmont 10:3bc89ef62ce7 181 return 0;
emilmont 10:3bc89ef62ce7 182 }
emilmont 10:3bc89ef62ce7 183
emilmont 10:3bc89ef62ce7 184 int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
emilmont 10:3bc89ef62ce7 185 int i, status;
emilmont 10:3bc89ef62ce7 186
emilmont 10:3bc89ef62ce7 187 i2c_start(obj);
emilmont 10:3bc89ef62ce7 188
emilmont 10:3bc89ef62ce7 189 status = i2c_do_write(obj, (address & 0xFE), 1);
emilmont 10:3bc89ef62ce7 190 if (status != 0x02) {
emilmont 10:3bc89ef62ce7 191 i2c_stop(obj);
emilmont 10:3bc89ef62ce7 192 return status;
emilmont 10:3bc89ef62ce7 193 }
emilmont 10:3bc89ef62ce7 194
emilmont 10:3bc89ef62ce7 195 for (i=0; i<length; i++) {
emilmont 10:3bc89ef62ce7 196 status = i2c_do_write(obj, data[i], 0);
emilmont 10:3bc89ef62ce7 197 if (status != 0x02) {
emilmont 10:3bc89ef62ce7 198 i2c_stop(obj);
emilmont 10:3bc89ef62ce7 199 return status;
emilmont 10:3bc89ef62ce7 200 }
emilmont 10:3bc89ef62ce7 201 }
emilmont 10:3bc89ef62ce7 202
emilmont 10:3bc89ef62ce7 203 // If not repeated start, send stop.
emilmont 10:3bc89ef62ce7 204 if (stop) {
emilmont 10:3bc89ef62ce7 205 i2c_stop(obj);
emilmont 10:3bc89ef62ce7 206 } else {
emilmont 10:3bc89ef62ce7 207 repeated_start = 1;
emilmont 10:3bc89ef62ce7 208 }
emilmont 10:3bc89ef62ce7 209
emilmont 10:3bc89ef62ce7 210 return 0;
emilmont 10:3bc89ef62ce7 211 }
emilmont 10:3bc89ef62ce7 212
emilmont 10:3bc89ef62ce7 213 void i2c_reset(i2c_t *obj) {
emilmont 10:3bc89ef62ce7 214 i2c_stop(obj);
emilmont 10:3bc89ef62ce7 215 }
emilmont 10:3bc89ef62ce7 216
emilmont 10:3bc89ef62ce7 217 int i2c_byte_read(i2c_t *obj, int last) {
emilmont 10:3bc89ef62ce7 218 return (i2c_do_read(obj, last) & 0xFF);
emilmont 10:3bc89ef62ce7 219 }
emilmont 10:3bc89ef62ce7 220
emilmont 10:3bc89ef62ce7 221 int i2c_byte_write(i2c_t *obj, int data) {
emilmont 10:3bc89ef62ce7 222 int ack;
emilmont 10:3bc89ef62ce7 223 int status = i2c_do_write(obj, (data & 0xFF), 0);
emilmont 10:3bc89ef62ce7 224
emilmont 10:3bc89ef62ce7 225 switch(status) {
emilmont 10:3bc89ef62ce7 226 case 2:
emilmont 10:3bc89ef62ce7 227 ack = 1;
emilmont 10:3bc89ef62ce7 228 break;
emilmont 10:3bc89ef62ce7 229 default:
emilmont 10:3bc89ef62ce7 230 ack = 0;
emilmont 10:3bc89ef62ce7 231 break;
emilmont 10:3bc89ef62ce7 232 }
emilmont 10:3bc89ef62ce7 233
emilmont 10:3bc89ef62ce7 234 return ack;
emilmont 10:3bc89ef62ce7 235 }