added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Committer:
JojoS
Date:
Sat Sep 10 15:32:04 2016 +0000
Revision:
147:ba84b7dc41a7
Parent:
144:ef7eb2e8f9f7
added prescaler for 16 bit timers (solution as in LPC11xx), default prescaler 31 for max 28 ms period time

Who changed what in which revision?

UserRevisionLine numberNew contents of line
<> 144:ef7eb2e8f9f7 1 /***************************************************************************//**
<> 144:ef7eb2e8f9f7 2 * @file i2c_api.c
<> 144:ef7eb2e8f9f7 3 *******************************************************************************
<> 144:ef7eb2e8f9f7 4 * @section License
<> 144:ef7eb2e8f9f7 5 * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
<> 144:ef7eb2e8f9f7 6 *******************************************************************************
<> 144:ef7eb2e8f9f7 7 *
<> 144:ef7eb2e8f9f7 8 * SPDX-License-Identifier: Apache-2.0
<> 144:ef7eb2e8f9f7 9 *
<> 144:ef7eb2e8f9f7 10 * Licensed under the Apache License, Version 2.0 (the "License"); you may
<> 144:ef7eb2e8f9f7 11 * not use this file except in compliance with the License.
<> 144:ef7eb2e8f9f7 12 * You may obtain a copy of the License at
<> 144:ef7eb2e8f9f7 13 *
<> 144:ef7eb2e8f9f7 14 * http://www.apache.org/licenses/LICENSE-2.0
<> 144:ef7eb2e8f9f7 15 *
<> 144:ef7eb2e8f9f7 16 * Unless required by applicable law or agreed to in writing, software
<> 144:ef7eb2e8f9f7 17 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
<> 144:ef7eb2e8f9f7 18 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<> 144:ef7eb2e8f9f7 19 * See the License for the specific language governing permissions and
<> 144:ef7eb2e8f9f7 20 * limitations under the License.
<> 144:ef7eb2e8f9f7 21 *
<> 144:ef7eb2e8f9f7 22 ******************************************************************************/
<> 144:ef7eb2e8f9f7 23
<> 144:ef7eb2e8f9f7 24 #include "device.h"
<> 144:ef7eb2e8f9f7 25 #include "clocking.h"
<> 144:ef7eb2e8f9f7 26 #include <stdio.h>
<> 144:ef7eb2e8f9f7 27
<> 144:ef7eb2e8f9f7 28 #if DEVICE_I2C
<> 144:ef7eb2e8f9f7 29
<> 144:ef7eb2e8f9f7 30 #include "mbed_assert.h"
<> 144:ef7eb2e8f9f7 31 #include "i2c_api.h"
<> 144:ef7eb2e8f9f7 32 #include "PeripheralPins.h"
<> 144:ef7eb2e8f9f7 33 #include "pinmap_function.h"
<> 144:ef7eb2e8f9f7 34 #include "sleepmodes.h"
<> 144:ef7eb2e8f9f7 35
<> 144:ef7eb2e8f9f7 36 #include "em_i2c.h"
<> 144:ef7eb2e8f9f7 37 #include "em_cmu.h"
<> 144:ef7eb2e8f9f7 38
<> 144:ef7eb2e8f9f7 39 /** Error flags indicating I2C transfer has failed somehow. */
<> 144:ef7eb2e8f9f7 40 /* Notice that I2C_IF_TXOF (transmit overflow) is not really possible with */
<> 144:ef7eb2e8f9f7 41 /* this SW supporting master mode. Likewise for I2C_IF_RXUF (receive underflow) */
<> 144:ef7eb2e8f9f7 42 /* RXUF is only likely to occur with this SW if using a debugger peeking into */
<> 144:ef7eb2e8f9f7 43 /* RXDATA register. Thus, we ignore those types of fault. */
<> 144:ef7eb2e8f9f7 44 #define I2C_IF_ERRORS (I2C_IF_BUSERR | I2C_IF_ARBLOST)
<> 144:ef7eb2e8f9f7 45 #define I2C_TIMEOUT 100000
<> 144:ef7eb2e8f9f7 46
<> 144:ef7eb2e8f9f7 47 /* Prototypes */
<> 144:ef7eb2e8f9f7 48 int block_and_wait_for_ack(I2C_TypeDef *i2c);
<> 144:ef7eb2e8f9f7 49 void i2c_enable(i2c_t *obj, uint8_t enable);
<> 144:ef7eb2e8f9f7 50 void i2c_enable_pins(i2c_t *obj, uint8_t enable);
<> 144:ef7eb2e8f9f7 51 void i2c_enable_interrupt(i2c_t *obj, uint32_t address, uint8_t enable);
<> 144:ef7eb2e8f9f7 52
<> 144:ef7eb2e8f9f7 53 static uint8_t i2c_get_index(i2c_t *obj)
<> 144:ef7eb2e8f9f7 54 {
<> 144:ef7eb2e8f9f7 55 uint8_t index = 0;
<> 144:ef7eb2e8f9f7 56 switch ((int)obj->i2c.i2c) {
<> 144:ef7eb2e8f9f7 57 #ifdef I2C0
<> 144:ef7eb2e8f9f7 58 case I2C_0:
<> 144:ef7eb2e8f9f7 59 index = 0;
<> 144:ef7eb2e8f9f7 60 break;
<> 144:ef7eb2e8f9f7 61 #endif
<> 144:ef7eb2e8f9f7 62 #ifdef I2C1
<> 144:ef7eb2e8f9f7 63 case I2C_1:
<> 144:ef7eb2e8f9f7 64 index = 1;
<> 144:ef7eb2e8f9f7 65 break;
<> 144:ef7eb2e8f9f7 66 #endif
<> 144:ef7eb2e8f9f7 67 default:
<> 144:ef7eb2e8f9f7 68 printf("I2C module not available.. Out of bound access.");
<> 144:ef7eb2e8f9f7 69 break;
<> 144:ef7eb2e8f9f7 70 }
<> 144:ef7eb2e8f9f7 71 return index;
<> 144:ef7eb2e8f9f7 72 }
<> 144:ef7eb2e8f9f7 73
<> 144:ef7eb2e8f9f7 74 static CMU_Clock_TypeDef i2c_get_clock(i2c_t *obj)
<> 144:ef7eb2e8f9f7 75 {
<> 144:ef7eb2e8f9f7 76 CMU_Clock_TypeDef clock;
<> 144:ef7eb2e8f9f7 77 switch ((int)obj->i2c.i2c) {
<> 144:ef7eb2e8f9f7 78 #ifdef I2C0
<> 144:ef7eb2e8f9f7 79 case I2C_0:
<> 144:ef7eb2e8f9f7 80 clock = cmuClock_I2C0;
<> 144:ef7eb2e8f9f7 81 break;
<> 144:ef7eb2e8f9f7 82 #endif
<> 144:ef7eb2e8f9f7 83 #ifdef I2C1
<> 144:ef7eb2e8f9f7 84 case I2C_1:
<> 144:ef7eb2e8f9f7 85 clock = cmuClock_I2C1;
<> 144:ef7eb2e8f9f7 86 break;
<> 144:ef7eb2e8f9f7 87 #endif
<> 144:ef7eb2e8f9f7 88 default:
<> 144:ef7eb2e8f9f7 89 printf("I2C module not available.. Out of bound access. (clock)");
<> 144:ef7eb2e8f9f7 90 clock = cmuClock_HFPER;
<> 144:ef7eb2e8f9f7 91 break;
<> 144:ef7eb2e8f9f7 92 }
<> 144:ef7eb2e8f9f7 93 return clock;
<> 144:ef7eb2e8f9f7 94 }
<> 144:ef7eb2e8f9f7 95
<> 144:ef7eb2e8f9f7 96 void i2c_init(i2c_t *obj, PinName sda, PinName scl)
<> 144:ef7eb2e8f9f7 97 {
<> 144:ef7eb2e8f9f7 98 /* Find out which I2C peripheral we're asked to use */
<> 144:ef7eb2e8f9f7 99 I2CName i2c_sda = (I2CName) pinmap_peripheral(sda, PinMap_I2C_SDA);
<> 144:ef7eb2e8f9f7 100 I2CName i2c_scl = (I2CName) pinmap_peripheral(scl, PinMap_I2C_SCL);
<> 144:ef7eb2e8f9f7 101 obj->i2c.i2c = (I2C_TypeDef*) pinmap_merge(i2c_sda, i2c_scl);
<> 144:ef7eb2e8f9f7 102 MBED_ASSERT(((int) obj->i2c.i2c) != NC);
<> 144:ef7eb2e8f9f7 103
<> 144:ef7eb2e8f9f7 104 /* You need both SDA and SCL for I2C, so configuring one of them to NC is illegal */
<> 144:ef7eb2e8f9f7 105 MBED_ASSERT((uint32_t)sda != (uint32_t)NC);
<> 144:ef7eb2e8f9f7 106 MBED_ASSERT((uint32_t)scl != (uint32_t)NC);
<> 144:ef7eb2e8f9f7 107
<> 144:ef7eb2e8f9f7 108 /* Enable clock for the peripheral */
<> 144:ef7eb2e8f9f7 109 CMU_ClockEnable(i2c_get_clock(obj), true);
<> 144:ef7eb2e8f9f7 110
<> 144:ef7eb2e8f9f7 111 /* Initializing the I2C */
<> 144:ef7eb2e8f9f7 112 /* Using default settings */
<> 144:ef7eb2e8f9f7 113 I2C_Init_TypeDef i2cInit = I2C_INIT_DEFAULT;
<> 144:ef7eb2e8f9f7 114 I2C_Init(obj->i2c.i2c, &i2cInit);
<> 144:ef7eb2e8f9f7 115
<> 144:ef7eb2e8f9f7 116 /* Enable pins at correct location */
<> 144:ef7eb2e8f9f7 117 #ifdef I2C_ROUTE_SDAPEN
<> 144:ef7eb2e8f9f7 118 /* Find common location in pinmap */
<> 144:ef7eb2e8f9f7 119 int loc_sda = pin_location(sda, PinMap_I2C_SDA);
<> 144:ef7eb2e8f9f7 120 int loc_scl = pin_location(scl, PinMap_I2C_SCL);
<> 144:ef7eb2e8f9f7 121 int loc = pinmap_merge(loc_sda, loc_scl);
<> 144:ef7eb2e8f9f7 122 MBED_ASSERT(loc != NC);
<> 144:ef7eb2e8f9f7 123 /* Set location */
<> 144:ef7eb2e8f9f7 124 obj->i2c.i2c->ROUTE = I2C_ROUTE_SDAPEN | I2C_ROUTE_SCLPEN | (loc << _I2C_ROUTE_LOCATION_SHIFT);
<> 144:ef7eb2e8f9f7 125 #else
<> 144:ef7eb2e8f9f7 126 obj->i2c.i2c->ROUTEPEN = I2C_ROUTEPEN_SDAPEN | I2C_ROUTEPEN_SCLPEN;
<> 144:ef7eb2e8f9f7 127 obj->i2c.i2c->ROUTELOC0 = (pin_location(sda, PinMap_I2C_SDA) << _I2C_ROUTELOC0_SDALOC_SHIFT) |
<> 144:ef7eb2e8f9f7 128 (pin_location(scl, PinMap_I2C_SCL) << _I2C_ROUTELOC0_SCLLOC_SHIFT);
<> 144:ef7eb2e8f9f7 129 #endif
<> 144:ef7eb2e8f9f7 130
<> 144:ef7eb2e8f9f7 131 /* Set up the pins for I2C use */
<> 144:ef7eb2e8f9f7 132 /* Note: Set up pins in higher drive strength to reduce slew rate */
<> 144:ef7eb2e8f9f7 133 /* Though this requires user knowledge, since drive strength is controlled per port, not pin */
<> 144:ef7eb2e8f9f7 134 pin_mode(scl, WiredAndPullUp);
<> 144:ef7eb2e8f9f7 135 pin_mode(sda, WiredAndPullUp);
<> 144:ef7eb2e8f9f7 136
<> 144:ef7eb2e8f9f7 137 /* Enable General Call Address Mode. That is; we respond to the general address (0x0) */
<> 144:ef7eb2e8f9f7 138 obj->i2c.i2c->CTRL |= _I2C_CTRL_GCAMEN_MASK;
<> 144:ef7eb2e8f9f7 139
<> 144:ef7eb2e8f9f7 140 /* We are assuming that there is only one master. So disable automatic arbitration */
<> 144:ef7eb2e8f9f7 141 obj->i2c.i2c->CTRL |= _I2C_CTRL_ARBDIS_MASK;
<> 144:ef7eb2e8f9f7 142
<> 144:ef7eb2e8f9f7 143 /* Set to master (needed if this I2C block was used previously as slave) */
<> 144:ef7eb2e8f9f7 144 i2c_slave_mode(obj, false);
<> 144:ef7eb2e8f9f7 145
<> 144:ef7eb2e8f9f7 146 /* Enable i2c */
<> 144:ef7eb2e8f9f7 147 i2c_enable(obj, true);
<> 144:ef7eb2e8f9f7 148 }
<> 144:ef7eb2e8f9f7 149
<> 144:ef7eb2e8f9f7 150 void i2c_enable(i2c_t *obj, uint8_t enable)
<> 144:ef7eb2e8f9f7 151 {
<> 144:ef7eb2e8f9f7 152 I2C_Enable(obj->i2c.i2c, enable);
<> 144:ef7eb2e8f9f7 153 if (!enable) {
<> 144:ef7eb2e8f9f7 154 /* After a reset BUSY is usually set. We assume that we are the only master and call abort,
<> 144:ef7eb2e8f9f7 155 * which sends nothing on the bus, it just allows us to assume that the bus is idle */
<> 144:ef7eb2e8f9f7 156 if (obj->i2c.i2c->STATE & I2C_STATE_BUSY) {
<> 144:ef7eb2e8f9f7 157 obj->i2c.i2c->CMD = I2C_CMD_ABORT;
<> 144:ef7eb2e8f9f7 158 }
<> 144:ef7eb2e8f9f7 159 }
<> 144:ef7eb2e8f9f7 160 }
<> 144:ef7eb2e8f9f7 161
<> 144:ef7eb2e8f9f7 162 void i2c_enable_interrupt(i2c_t *obj, uint32_t address, uint8_t enable)
<> 144:ef7eb2e8f9f7 163 {
<> 144:ef7eb2e8f9f7 164 IRQn_Type irq_number;
<> 144:ef7eb2e8f9f7 165
<> 144:ef7eb2e8f9f7 166 switch (i2c_get_index(obj)) {
<> 144:ef7eb2e8f9f7 167 #ifdef I2C0
<> 144:ef7eb2e8f9f7 168 case 0:
<> 144:ef7eb2e8f9f7 169 irq_number = I2C0_IRQn;
<> 144:ef7eb2e8f9f7 170 break;
<> 144:ef7eb2e8f9f7 171 #endif
<> 144:ef7eb2e8f9f7 172 #ifdef I2C1
<> 144:ef7eb2e8f9f7 173 case 1:
<> 144:ef7eb2e8f9f7 174 irq_number = I2C1_IRQn;
<> 144:ef7eb2e8f9f7 175 break;
<> 144:ef7eb2e8f9f7 176 #endif
<> 144:ef7eb2e8f9f7 177 }
<> 144:ef7eb2e8f9f7 178
<> 144:ef7eb2e8f9f7 179 NVIC_SetVector(irq_number, address);
<> 144:ef7eb2e8f9f7 180 /* Lower IRQ priority to avoid messing with asynch RX on UART */
<> 144:ef7eb2e8f9f7 181 NVIC_SetPriority(irq_number, 1);
<> 144:ef7eb2e8f9f7 182 if (enable) {
<> 144:ef7eb2e8f9f7 183 NVIC_EnableIRQ(irq_number);
<> 144:ef7eb2e8f9f7 184 } else {
<> 144:ef7eb2e8f9f7 185 NVIC_DisableIRQ(irq_number);
<> 144:ef7eb2e8f9f7 186 }
<> 144:ef7eb2e8f9f7 187 }
<> 144:ef7eb2e8f9f7 188
<> 144:ef7eb2e8f9f7 189 /* Set the frequency of the I2C interface */
<> 144:ef7eb2e8f9f7 190 void i2c_frequency(i2c_t *obj, int hz)
<> 144:ef7eb2e8f9f7 191 {
<> 144:ef7eb2e8f9f7 192 /* Set frequency. As the second argument is 0,
<> 144:ef7eb2e8f9f7 193 * HFPER clock frequency is used as reference freq */
<> 144:ef7eb2e8f9f7 194 if (hz <= 0) return;
<> 144:ef7eb2e8f9f7 195 /* In I2C Normal mode (50% duty), we can go up to 100kHz */
<> 144:ef7eb2e8f9f7 196 if (hz <= 100000) {
<> 144:ef7eb2e8f9f7 197 I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, hz, i2cClockHLRStandard);
<> 144:ef7eb2e8f9f7 198 }
<> 144:ef7eb2e8f9f7 199 /* In I2C Fast mode (6:3 ratio), we can go up to 400kHz */
<> 144:ef7eb2e8f9f7 200 else if (hz <= 400000) {
<> 144:ef7eb2e8f9f7 201 I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, hz, i2cClockHLRAsymetric);
<> 144:ef7eb2e8f9f7 202 }
<> 144:ef7eb2e8f9f7 203 /* In I2C Fast+ mode (11:6 ratio), we can go up to 1 MHz */
<> 144:ef7eb2e8f9f7 204 else if (hz <= 1000000) {
<> 144:ef7eb2e8f9f7 205 I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, hz, i2cClockHLRFast);
<> 144:ef7eb2e8f9f7 206 }
<> 144:ef7eb2e8f9f7 207 /* Cap requested frequency at 1MHz */
<> 144:ef7eb2e8f9f7 208 else {
<> 144:ef7eb2e8f9f7 209 I2C_BusFreqSet(obj->i2c.i2c, REFERENCE_FREQUENCY, 1000000, i2cClockHLRFast);
<> 144:ef7eb2e8f9f7 210 }
<> 144:ef7eb2e8f9f7 211 }
<> 144:ef7eb2e8f9f7 212
<> 144:ef7eb2e8f9f7 213 /* Creates a start condition on the I2C bus */
<> 144:ef7eb2e8f9f7 214 int i2c_start(i2c_t *obj)
<> 144:ef7eb2e8f9f7 215 {
<> 144:ef7eb2e8f9f7 216 I2C_TypeDef *i2c = obj->i2c.i2c;
<> 144:ef7eb2e8f9f7 217
<> 144:ef7eb2e8f9f7 218 /* Ensure buffers are empty */
<> 144:ef7eb2e8f9f7 219 i2c->CMD = I2C_CMD_CLEARPC | I2C_CMD_CLEARTX;
<> 144:ef7eb2e8f9f7 220 if (i2c->IF & I2C_IF_RXDATAV) {
<> 144:ef7eb2e8f9f7 221 (void) i2c->RXDATA;
<> 144:ef7eb2e8f9f7 222 }
<> 144:ef7eb2e8f9f7 223
<> 144:ef7eb2e8f9f7 224 /* Clear all pending interrupts prior to starting transfer. */
<> 144:ef7eb2e8f9f7 225 i2c->IFC = _I2C_IFC_MASK;
<> 144:ef7eb2e8f9f7 226
<> 144:ef7eb2e8f9f7 227 /* Send start */
<> 144:ef7eb2e8f9f7 228 obj->i2c.i2c->CMD = I2C_CMD_START;
<> 144:ef7eb2e8f9f7 229 return 0;
<> 144:ef7eb2e8f9f7 230 }
<> 144:ef7eb2e8f9f7 231
<> 144:ef7eb2e8f9f7 232 /* Creates a stop condition on the I2C bus */
<> 144:ef7eb2e8f9f7 233 int i2c_stop(i2c_t *obj)
<> 144:ef7eb2e8f9f7 234 {
<> 144:ef7eb2e8f9f7 235 obj->i2c.i2c->CMD = I2C_CMD_STOP;
<> 144:ef7eb2e8f9f7 236
<> 144:ef7eb2e8f9f7 237 /* Wait for the stop to be sent */
<> 144:ef7eb2e8f9f7 238 int timeout = I2C_TIMEOUT;
<> 144:ef7eb2e8f9f7 239 while (!(obj->i2c.i2c->IF & I2C_IF_MSTOP) && !timeout--);
<> 144:ef7eb2e8f9f7 240
<> 144:ef7eb2e8f9f7 241 return 0;
<> 144:ef7eb2e8f9f7 242 }
<> 144:ef7eb2e8f9f7 243
<> 144:ef7eb2e8f9f7 244 /* Returns number of bytes read */
<> 144:ef7eb2e8f9f7 245 int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
<> 144:ef7eb2e8f9f7 246 {
<> 144:ef7eb2e8f9f7 247 int retval;
<> 144:ef7eb2e8f9f7 248
<> 144:ef7eb2e8f9f7 249 i2c_start(obj);
<> 144:ef7eb2e8f9f7 250
<> 144:ef7eb2e8f9f7 251 retval = i2c_byte_write(obj, (address | 1));
<> 144:ef7eb2e8f9f7 252 if ((!retval) || (length == 0)) { //Write address with W flag (last bit 1)
<> 144:ef7eb2e8f9f7 253 obj->i2c.i2c->CMD = I2C_CMD_STOP | I2C_CMD_ABORT;
<> 144:ef7eb2e8f9f7 254 while(obj->i2c.i2c->STATE & I2C_STATE_BUSY); // Wait until the bus is done
<> 144:ef7eb2e8f9f7 255 return (retval == 0 ? I2C_ERROR_NO_SLAVE : 0); //NACK or error when writing adress. Return 0 as 0 bytes were read
<> 144:ef7eb2e8f9f7 256 }
<> 144:ef7eb2e8f9f7 257 int i = 0;
<> 144:ef7eb2e8f9f7 258 while (i < length) {
<> 144:ef7eb2e8f9f7 259 uint8_t last = (i == length - 1);
<> 144:ef7eb2e8f9f7 260 data[i++] = i2c_byte_read(obj, last);
<> 144:ef7eb2e8f9f7 261 }
<> 144:ef7eb2e8f9f7 262
<> 144:ef7eb2e8f9f7 263 if (stop) {
<> 144:ef7eb2e8f9f7 264 i2c_stop(obj);
<> 144:ef7eb2e8f9f7 265 }
<> 144:ef7eb2e8f9f7 266
<> 144:ef7eb2e8f9f7 267 return length;
<> 144:ef7eb2e8f9f7 268 }
<> 144:ef7eb2e8f9f7 269
<> 144:ef7eb2e8f9f7 270 int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
<> 144:ef7eb2e8f9f7 271 {
<> 144:ef7eb2e8f9f7 272 i2c_start(obj);
<> 144:ef7eb2e8f9f7 273
<> 144:ef7eb2e8f9f7 274 if (!i2c_byte_write(obj, (address & 0xFE))) {
<> 144:ef7eb2e8f9f7 275 i2c_stop(obj);
<> 144:ef7eb2e8f9f7 276 return I2C_ERROR_NO_SLAVE; //NACK or error when writing adress. Return 0 as 0 bytes were written
<> 144:ef7eb2e8f9f7 277 }
<> 144:ef7eb2e8f9f7 278 int i;
<> 144:ef7eb2e8f9f7 279 for (i = 0; i < length; i++) {
<> 144:ef7eb2e8f9f7 280 if (!i2c_byte_write(obj, data[i])) {
<> 144:ef7eb2e8f9f7 281 i2c_stop(obj);
<> 144:ef7eb2e8f9f7 282 return i;
<> 144:ef7eb2e8f9f7 283 }
<> 144:ef7eb2e8f9f7 284 }
<> 144:ef7eb2e8f9f7 285
<> 144:ef7eb2e8f9f7 286 if (stop) {
<> 144:ef7eb2e8f9f7 287 i2c_stop(obj);
<> 144:ef7eb2e8f9f7 288 }
<> 144:ef7eb2e8f9f7 289
<> 144:ef7eb2e8f9f7 290 return length;
<> 144:ef7eb2e8f9f7 291 }
<> 144:ef7eb2e8f9f7 292
<> 144:ef7eb2e8f9f7 293 void i2c_reset(i2c_t *obj)
<> 144:ef7eb2e8f9f7 294 {
<> 144:ef7eb2e8f9f7 295 /* EMLib function */
<> 144:ef7eb2e8f9f7 296 I2C_Reset(obj->i2c.i2c);
<> 144:ef7eb2e8f9f7 297 }
<> 144:ef7eb2e8f9f7 298
<> 144:ef7eb2e8f9f7 299 int i2c_byte_read(i2c_t *obj, int last)
<> 144:ef7eb2e8f9f7 300 {
<> 144:ef7eb2e8f9f7 301 int timeout = I2C_TIMEOUT;
<> 144:ef7eb2e8f9f7 302 /* Wait for data */
<> 144:ef7eb2e8f9f7 303 while (!(obj->i2c.i2c->STATUS & I2C_STATUS_RXDATAV) && timeout--);
<> 144:ef7eb2e8f9f7 304
<> 144:ef7eb2e8f9f7 305 if (timeout <= 0) {
<> 144:ef7eb2e8f9f7 306 return 0; //TODO Is this the correct way to handle this?
<> 144:ef7eb2e8f9f7 307 }
<> 144:ef7eb2e8f9f7 308 char data = obj->i2c.i2c->RXDATA;
<> 144:ef7eb2e8f9f7 309
<> 144:ef7eb2e8f9f7 310 if (last) {
<> 144:ef7eb2e8f9f7 311 obj->i2c.i2c->CMD = I2C_CMD_NACK;
<> 144:ef7eb2e8f9f7 312 } else {
<> 144:ef7eb2e8f9f7 313 obj->i2c.i2c->CMD = I2C_CMD_ACK;
<> 144:ef7eb2e8f9f7 314 }
<> 144:ef7eb2e8f9f7 315 return data;
<> 144:ef7eb2e8f9f7 316 }
<> 144:ef7eb2e8f9f7 317
<> 144:ef7eb2e8f9f7 318 int i2c_byte_write(i2c_t *obj, int data)
<> 144:ef7eb2e8f9f7 319 {
<> 144:ef7eb2e8f9f7 320 obj->i2c.i2c->TXDATA = data;
<> 144:ef7eb2e8f9f7 321 return block_and_wait_for_ack(obj->i2c.i2c);
<> 144:ef7eb2e8f9f7 322 }
<> 144:ef7eb2e8f9f7 323
<> 144:ef7eb2e8f9f7 324 /*
<> 144:ef7eb2e8f9f7 325 * Returns 1 for ACK. 0 for NACK, timeout or error.
<> 144:ef7eb2e8f9f7 326 */
<> 144:ef7eb2e8f9f7 327 int block_and_wait_for_ack(I2C_TypeDef *i2c)
<> 144:ef7eb2e8f9f7 328 {
<> 144:ef7eb2e8f9f7 329 uint32_t pending;
<> 144:ef7eb2e8f9f7 330 uint32_t timeout = I2C_TIMEOUT;
<> 144:ef7eb2e8f9f7 331 while (timeout > 0) {
<> 144:ef7eb2e8f9f7 332 timeout -= 1;
<> 144:ef7eb2e8f9f7 333 pending = i2c->IF;
<> 144:ef7eb2e8f9f7 334 /* If some sort of fault, abort transfer. */
<> 144:ef7eb2e8f9f7 335 if (pending & I2C_IF_ERRORS) {
<> 144:ef7eb2e8f9f7 336 if (pending & I2C_IF_ARBLOST) {
<> 144:ef7eb2e8f9f7 337 /* If arbitration fault, it indicates either a slave device */
<> 144:ef7eb2e8f9f7 338 /* not responding as expected, or other master which is not */
<> 144:ef7eb2e8f9f7 339 /* supported by this SW. */
<> 144:ef7eb2e8f9f7 340 return 0;
<> 144:ef7eb2e8f9f7 341 } else if (pending & I2C_IF_BUSERR) {
<> 144:ef7eb2e8f9f7 342 /* A bus error indicates a misplaced start or stop, which should */
<> 144:ef7eb2e8f9f7 343 /* not occur in master mode controlled by this SW. */
<> 144:ef7eb2e8f9f7 344 return 0;
<> 144:ef7eb2e8f9f7 345 }
<> 144:ef7eb2e8f9f7 346 }
<> 144:ef7eb2e8f9f7 347
<> 144:ef7eb2e8f9f7 348 if (pending & I2C_IF_NACK) {
<> 144:ef7eb2e8f9f7 349 i2c->IFC = I2C_IFC_NACK;
<> 144:ef7eb2e8f9f7 350 return 0; //Received NACK
<> 144:ef7eb2e8f9f7 351 } else if (pending & I2C_IF_ACK) {
<> 144:ef7eb2e8f9f7 352 i2c->IFC = I2C_IFC_ACK;
<> 144:ef7eb2e8f9f7 353 return 1; //Got ACK
<> 144:ef7eb2e8f9f7 354 }
<> 144:ef7eb2e8f9f7 355 }
<> 144:ef7eb2e8f9f7 356 return 0; //Timeout
<> 144:ef7eb2e8f9f7 357 }
<> 144:ef7eb2e8f9f7 358
<> 144:ef7eb2e8f9f7 359 #if DEVICE_I2CSLAVE
<> 144:ef7eb2e8f9f7 360
<> 144:ef7eb2e8f9f7 361 #define NoData 0
<> 144:ef7eb2e8f9f7 362 #define ReadAddressed 1
<> 144:ef7eb2e8f9f7 363 #define WriteGeneral 2
<> 144:ef7eb2e8f9f7 364 #define WriteAddressed 3
<> 144:ef7eb2e8f9f7 365
<> 144:ef7eb2e8f9f7 366
<> 144:ef7eb2e8f9f7 367 void i2c_slave_mode(i2c_t *obj, int enable_slave)
<> 144:ef7eb2e8f9f7 368 {
<> 144:ef7eb2e8f9f7 369 if(enable_slave) {
<> 144:ef7eb2e8f9f7 370 /* Reference manual note: DIV must be set to 1 during slave operation */
<> 144:ef7eb2e8f9f7 371 obj->i2c.i2c->CLKDIV = 1;
<> 144:ef7eb2e8f9f7 372 obj->i2c.i2c->CTRL |= _I2C_CTRL_SLAVE_MASK;
<> 144:ef7eb2e8f9f7 373 obj->i2c.i2c->CTRL |= _I2C_CTRL_AUTOACK_MASK; //Slave implementation assumes auto acking
<> 144:ef7eb2e8f9f7 374 } else {
<> 144:ef7eb2e8f9f7 375 obj->i2c.i2c->CTRL &= ~_I2C_CTRL_SLAVE_MASK;
<> 144:ef7eb2e8f9f7 376 obj->i2c.i2c->CTRL &= ~_I2C_CTRL_AUTOACK_MASK; //Master implementation ACKs manually
<> 144:ef7eb2e8f9f7 377 /* function is only called with enable_slave = false through i2c_init(..), so frequency is
<> 144:ef7eb2e8f9f7 378 already guaranteed to be set */
<> 144:ef7eb2e8f9f7 379 }
<> 144:ef7eb2e8f9f7 380 }
<> 144:ef7eb2e8f9f7 381
<> 144:ef7eb2e8f9f7 382 int i2c_slave_receive(i2c_t *obj)
<> 144:ef7eb2e8f9f7 383 {
<> 144:ef7eb2e8f9f7 384
<> 144:ef7eb2e8f9f7 385 if(obj->i2c.i2c->IF & I2C_IF_ADDR) {
<> 144:ef7eb2e8f9f7 386 obj->i2c.i2c->IFC = I2C_IF_ADDR; //Clear interrupt
<> 144:ef7eb2e8f9f7 387 /*0x00 is the address for general write.
<> 144:ef7eb2e8f9f7 388 The address the master wrote is in RXDATA now
<> 144:ef7eb2e8f9f7 389 and reading it also frees the buffer for the next
<> 144:ef7eb2e8f9f7 390 write which can then be acked. */
<> 144:ef7eb2e8f9f7 391 if(obj->i2c.i2c->RXDATA == 0x00) {
<> 144:ef7eb2e8f9f7 392 return WriteGeneral; //Read the address;
<> 144:ef7eb2e8f9f7 393 }
<> 144:ef7eb2e8f9f7 394
<> 144:ef7eb2e8f9f7 395 if(obj->i2c.i2c->STATE & I2C_STATE_TRANSMITTER) {
<> 144:ef7eb2e8f9f7 396 return ReadAddressed;
<> 144:ef7eb2e8f9f7 397 } else {
<> 144:ef7eb2e8f9f7 398 return WriteAddressed;
<> 144:ef7eb2e8f9f7 399 }
<> 144:ef7eb2e8f9f7 400 }
<> 144:ef7eb2e8f9f7 401
<> 144:ef7eb2e8f9f7 402 return NoData;
<> 144:ef7eb2e8f9f7 403
<> 144:ef7eb2e8f9f7 404 }
<> 144:ef7eb2e8f9f7 405
<> 144:ef7eb2e8f9f7 406 int i2c_slave_read(i2c_t *obj, char *data, int length)
<> 144:ef7eb2e8f9f7 407 {
<> 144:ef7eb2e8f9f7 408 int count;
<> 144:ef7eb2e8f9f7 409 for (count = 0; count < length; count++) {
<> 144:ef7eb2e8f9f7 410 data[count] = i2c_byte_read(obj, 0);
<> 144:ef7eb2e8f9f7 411 }
<> 144:ef7eb2e8f9f7 412
<> 144:ef7eb2e8f9f7 413
<> 144:ef7eb2e8f9f7 414 return count;
<> 144:ef7eb2e8f9f7 415
<> 144:ef7eb2e8f9f7 416 }
<> 144:ef7eb2e8f9f7 417
<> 144:ef7eb2e8f9f7 418 int i2c_slave_write(i2c_t *obj, const char *data, int length)
<> 144:ef7eb2e8f9f7 419 {
<> 144:ef7eb2e8f9f7 420 int count;
<> 144:ef7eb2e8f9f7 421 for (count = 0; count < length; count++) {
<> 144:ef7eb2e8f9f7 422 i2c_byte_write(obj, data[count]);
<> 144:ef7eb2e8f9f7 423 }
<> 144:ef7eb2e8f9f7 424
<> 144:ef7eb2e8f9f7 425 return count;
<> 144:ef7eb2e8f9f7 426 }
<> 144:ef7eb2e8f9f7 427
<> 144:ef7eb2e8f9f7 428 void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask)
<> 144:ef7eb2e8f9f7 429 {
<> 144:ef7eb2e8f9f7 430 obj->i2c.i2c->SADDR = address;
<> 144:ef7eb2e8f9f7 431 obj->i2c.i2c->SADDRMASK = 0xFE;//mask;
<> 144:ef7eb2e8f9f7 432 }
<> 144:ef7eb2e8f9f7 433
<> 144:ef7eb2e8f9f7 434 #endif //DEVICE_I2CSLAVE
<> 144:ef7eb2e8f9f7 435
<> 144:ef7eb2e8f9f7 436 #ifdef DEVICE_I2C_ASYNCH
<> 144:ef7eb2e8f9f7 437
<> 144:ef7eb2e8f9f7 438 #include "em_dma.h"
<> 144:ef7eb2e8f9f7 439 #include "dma_api_HAL.h"
<> 144:ef7eb2e8f9f7 440 #include "dma_api.h"
<> 144:ef7eb2e8f9f7 441 #include "sleep_api.h"
<> 144:ef7eb2e8f9f7 442 #include "buffer.h"
<> 144:ef7eb2e8f9f7 443
<> 144:ef7eb2e8f9f7 444 /** Start i2c asynchronous transfer.
<> 144:ef7eb2e8f9f7 445 * @param obj The I2C object
<> 144:ef7eb2e8f9f7 446 * @param tx The buffer to send
<> 144:ef7eb2e8f9f7 447 * @param tx_length The number of words to transmit
<> 144:ef7eb2e8f9f7 448 * @param rx The buffer to receive
<> 144:ef7eb2e8f9f7 449 * @param rx_length The number of words to receive
<> 144:ef7eb2e8f9f7 450 * @param address The address to be set - 7bit or 9 bit
<> 144:ef7eb2e8f9f7 451 * @param stop If true, stop will be generated after the transfer is done
<> 144:ef7eb2e8f9f7 452 * @param handler The I2C IRQ handler to be set
<> 144:ef7eb2e8f9f7 453 * @param hint DMA hint usage
<> 144:ef7eb2e8f9f7 454 */
<> 144:ef7eb2e8f9f7 455 void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint32_t address, uint32_t stop, uint32_t handler, uint32_t event, DMAUsage hint)
<> 144:ef7eb2e8f9f7 456 {
<> 144:ef7eb2e8f9f7 457 I2C_TransferReturn_TypeDef retval;
<> 144:ef7eb2e8f9f7 458 if(i2c_active(obj)) return;
<> 144:ef7eb2e8f9f7 459 if((tx_length == 0) && (rx_length == 0)) return;
<> 144:ef7eb2e8f9f7 460 // For now, we are assuming a solely interrupt-driven implementation.
<> 144:ef7eb2e8f9f7 461
<> 144:ef7eb2e8f9f7 462 // Store transfer config
<> 144:ef7eb2e8f9f7 463 obj->i2c.xfer.addr = address;
<> 144:ef7eb2e8f9f7 464
<> 144:ef7eb2e8f9f7 465 // Some combination of tx_length and rx_length will tell us what to do
<> 144:ef7eb2e8f9f7 466 if((tx_length > 0) && (rx_length == 0)) {
<> 144:ef7eb2e8f9f7 467 obj->i2c.xfer.flags = I2C_FLAG_WRITE;
<> 144:ef7eb2e8f9f7 468 //Store buffer info
<> 144:ef7eb2e8f9f7 469 obj->i2c.xfer.buf[0].data = (void *)tx;
<> 144:ef7eb2e8f9f7 470 obj->i2c.xfer.buf[0].len = (uint16_t) tx_length;
<> 144:ef7eb2e8f9f7 471 } else if ((tx_length == 0) && (rx_length > 0)) {
<> 144:ef7eb2e8f9f7 472 obj->i2c.xfer.flags = I2C_FLAG_READ;
<> 144:ef7eb2e8f9f7 473 //Store buffer info
<> 144:ef7eb2e8f9f7 474 obj->i2c.xfer.buf[0].data = rx;
<> 144:ef7eb2e8f9f7 475 obj->i2c.xfer.buf[0].len = (uint16_t) rx_length;
<> 144:ef7eb2e8f9f7 476 } else if ((tx_length > 0) && (rx_length > 0)) {
<> 144:ef7eb2e8f9f7 477 obj->i2c.xfer.flags = I2C_FLAG_WRITE_READ;
<> 144:ef7eb2e8f9f7 478 //Store buffer info
<> 144:ef7eb2e8f9f7 479 obj->i2c.xfer.buf[0].data = (void *)tx;
<> 144:ef7eb2e8f9f7 480 obj->i2c.xfer.buf[0].len = (uint16_t) tx_length;
<> 144:ef7eb2e8f9f7 481 obj->i2c.xfer.buf[1].data = rx;
<> 144:ef7eb2e8f9f7 482 obj->i2c.xfer.buf[1].len = (uint16_t) rx_length;
<> 144:ef7eb2e8f9f7 483 }
<> 144:ef7eb2e8f9f7 484
<> 144:ef7eb2e8f9f7 485 if(address > 255) obj->i2c.xfer.flags |= I2C_FLAG_10BIT_ADDR;
<> 144:ef7eb2e8f9f7 486
<> 144:ef7eb2e8f9f7 487 // Store event flags
<> 144:ef7eb2e8f9f7 488 obj->i2c.events = event;
<> 144:ef7eb2e8f9f7 489
<> 144:ef7eb2e8f9f7 490 // Enable interrupt
<> 144:ef7eb2e8f9f7 491 i2c_enable_interrupt(obj, handler, true);
<> 144:ef7eb2e8f9f7 492
<> 144:ef7eb2e8f9f7 493 // Kick off the transfer
<> 144:ef7eb2e8f9f7 494 retval = I2C_TransferInit(obj->i2c.i2c, &(obj->i2c.xfer));
<> 144:ef7eb2e8f9f7 495
<> 144:ef7eb2e8f9f7 496 if(retval == i2cTransferInProgress) {
<> 144:ef7eb2e8f9f7 497 blockSleepMode(EM1);
<> 144:ef7eb2e8f9f7 498 } else {
<> 144:ef7eb2e8f9f7 499 // something happened, and the transfer did not go through
<> 144:ef7eb2e8f9f7 500 // So, we need to clean up
<> 144:ef7eb2e8f9f7 501
<> 144:ef7eb2e8f9f7 502 // Disable interrupt
<> 144:ef7eb2e8f9f7 503 i2c_enable_interrupt(obj, 0, false);
<> 144:ef7eb2e8f9f7 504
<> 144:ef7eb2e8f9f7 505 // Block until free
<> 144:ef7eb2e8f9f7 506 while(i2c_active(obj));
<> 144:ef7eb2e8f9f7 507 }
<> 144:ef7eb2e8f9f7 508 }
<> 144:ef7eb2e8f9f7 509
<> 144:ef7eb2e8f9f7 510 /** The asynchronous IRQ handler
<> 144:ef7eb2e8f9f7 511 * @param obj The I2C object which holds the transfer information
<> 144:ef7eb2e8f9f7 512 * @return Returns event flags if a transfer termination condition was met or 0 otherwise.
<> 144:ef7eb2e8f9f7 513 */
<> 144:ef7eb2e8f9f7 514 uint32_t i2c_irq_handler_asynch(i2c_t *obj)
<> 144:ef7eb2e8f9f7 515 {
<> 144:ef7eb2e8f9f7 516
<> 144:ef7eb2e8f9f7 517 // For now, we are assuming a solely interrupt-driven implementation.
<> 144:ef7eb2e8f9f7 518
<> 144:ef7eb2e8f9f7 519 I2C_TransferReturn_TypeDef status = I2C_Transfer(obj->i2c.i2c);
<> 144:ef7eb2e8f9f7 520 switch(status) {
<> 144:ef7eb2e8f9f7 521 case i2cTransferInProgress:
<> 144:ef7eb2e8f9f7 522 // Still busy transferring, so let it.
<> 144:ef7eb2e8f9f7 523 return 0;
<> 144:ef7eb2e8f9f7 524 case i2cTransferDone:
<> 144:ef7eb2e8f9f7 525 // Transfer has completed
<> 144:ef7eb2e8f9f7 526
<> 144:ef7eb2e8f9f7 527 // Disable interrupt
<> 144:ef7eb2e8f9f7 528 i2c_enable_interrupt(obj, 0, false);
<> 144:ef7eb2e8f9f7 529
<> 144:ef7eb2e8f9f7 530 unblockSleepMode(EM1);
<> 144:ef7eb2e8f9f7 531
<> 144:ef7eb2e8f9f7 532 return I2C_EVENT_TRANSFER_COMPLETE & obj->i2c.events;
<> 144:ef7eb2e8f9f7 533 case i2cTransferNack:
<> 144:ef7eb2e8f9f7 534 // A NACK has been received while an ACK was expected. This is usually because the slave did not respond to the address.
<> 144:ef7eb2e8f9f7 535 // Disable interrupt
<> 144:ef7eb2e8f9f7 536 i2c_enable_interrupt(obj, 0, false);
<> 144:ef7eb2e8f9f7 537
<> 144:ef7eb2e8f9f7 538 unblockSleepMode(EM1);
<> 144:ef7eb2e8f9f7 539
<> 144:ef7eb2e8f9f7 540 return I2C_EVENT_ERROR_NO_SLAVE & obj->i2c.events;
<> 144:ef7eb2e8f9f7 541 default:
<> 144:ef7eb2e8f9f7 542 // An error situation has arisen.
<> 144:ef7eb2e8f9f7 543 // Disable interrupt
<> 144:ef7eb2e8f9f7 544 i2c_enable_interrupt(obj, 0, false);
<> 144:ef7eb2e8f9f7 545
<> 144:ef7eb2e8f9f7 546 unblockSleepMode(EM1);
<> 144:ef7eb2e8f9f7 547
<> 144:ef7eb2e8f9f7 548 // return error
<> 144:ef7eb2e8f9f7 549 return I2C_EVENT_ERROR & obj->i2c.events;
<> 144:ef7eb2e8f9f7 550 }
<> 144:ef7eb2e8f9f7 551 }
<> 144:ef7eb2e8f9f7 552
<> 144:ef7eb2e8f9f7 553 /** Attempts to determine if I2C peripheral is already in use.
<> 144:ef7eb2e8f9f7 554 * @param obj The I2C object
<> 144:ef7eb2e8f9f7 555 * @return non-zero if the I2C module is active or zero if it is not
<> 144:ef7eb2e8f9f7 556 */
<> 144:ef7eb2e8f9f7 557 uint8_t i2c_active(i2c_t *obj)
<> 144:ef7eb2e8f9f7 558 {
<> 144:ef7eb2e8f9f7 559 return (obj->i2c.i2c->STATE & I2C_STATE_BUSY);
<> 144:ef7eb2e8f9f7 560 }
<> 144:ef7eb2e8f9f7 561
<> 144:ef7eb2e8f9f7 562 /** Abort ongoing asynchronous transaction.
<> 144:ef7eb2e8f9f7 563 * @param obj The I2C object
<> 144:ef7eb2e8f9f7 564 */
<> 144:ef7eb2e8f9f7 565 void i2c_abort_asynch(i2c_t *obj)
<> 144:ef7eb2e8f9f7 566 {
<> 144:ef7eb2e8f9f7 567 // Do not deactivate I2C twice
<> 144:ef7eb2e8f9f7 568 if (!i2c_active(obj)) return;
<> 144:ef7eb2e8f9f7 569
<> 144:ef7eb2e8f9f7 570 // Disable interrupt
<> 144:ef7eb2e8f9f7 571 i2c_enable_interrupt(obj, 0, false);
<> 144:ef7eb2e8f9f7 572
<> 144:ef7eb2e8f9f7 573 // Abort
<> 144:ef7eb2e8f9f7 574 obj->i2c.i2c->CMD = I2C_CMD_STOP | I2C_CMD_ABORT;
<> 144:ef7eb2e8f9f7 575
<> 144:ef7eb2e8f9f7 576 // Block until free
<> 144:ef7eb2e8f9f7 577 while(i2c_active(obj));
<> 144:ef7eb2e8f9f7 578
<> 144:ef7eb2e8f9f7 579 unblockSleepMode(EM1);
<> 144:ef7eb2e8f9f7 580 }
<> 144:ef7eb2e8f9f7 581
<> 144:ef7eb2e8f9f7 582 #endif //DEVICE_I2C ASYNCH
<> 144:ef7eb2e8f9f7 583 #endif //DEVICE_I2C