added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Committer:
mbed_official
Date:
Fri Jan 15 07:45:16 2016 +0000
Revision:
50:a417edff4437
Parent:
0:9b334a45a8ff
Child:
144:ef7eb2e8f9f7
Synchronized with git revision 6010f32619bfcbb01cc73747d4ff9040863482d9

Full URL: https://github.com/mbedmicro/mbed/commit/6010f32619bfcbb01cc73747d4ff9040863482d9/

Remove doubling of buffer size in realiseEndpoint()

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bogdanm 0:9b334a45a8ff 1 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 2 * @file em_i2c.c
bogdanm 0:9b334a45a8ff 3 * @brief Inter-integrated Circuit (I2C) Peripheral API
mbed_official 50:a417edff4437 4 * @version 4.2.1
bogdanm 0:9b334a45a8ff 5 *******************************************************************************
bogdanm 0:9b334a45a8ff 6 * @section License
mbed_official 50:a417edff4437 7 * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
bogdanm 0:9b334a45a8ff 8 *******************************************************************************
bogdanm 0:9b334a45a8ff 9 *
bogdanm 0:9b334a45a8ff 10 * Permission is granted to anyone to use this software for any purpose,
bogdanm 0:9b334a45a8ff 11 * including commercial applications, and to alter it and redistribute it
bogdanm 0:9b334a45a8ff 12 * freely, subject to the following restrictions:
bogdanm 0:9b334a45a8ff 13 *
bogdanm 0:9b334a45a8ff 14 * 1. The origin of this software must not be misrepresented; you must not
bogdanm 0:9b334a45a8ff 15 * claim that you wrote the original software.
bogdanm 0:9b334a45a8ff 16 * 2. Altered source versions must be plainly marked as such, and must not be
bogdanm 0:9b334a45a8ff 17 * misrepresented as being the original software.
bogdanm 0:9b334a45a8ff 18 * 3. This notice may not be removed or altered from any source distribution.
bogdanm 0:9b334a45a8ff 19 *
bogdanm 0:9b334a45a8ff 20 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
bogdanm 0:9b334a45a8ff 21 * obligation to support this Software. Silicon Labs is providing the
bogdanm 0:9b334a45a8ff 22 * Software "AS IS", with no express or implied warranties of any kind,
bogdanm 0:9b334a45a8ff 23 * including, but not limited to, any implied warranties of merchantability
bogdanm 0:9b334a45a8ff 24 * or fitness for any particular purpose or warranties against infringement
bogdanm 0:9b334a45a8ff 25 * of any proprietary rights of a third party.
bogdanm 0:9b334a45a8ff 26 *
bogdanm 0:9b334a45a8ff 27 * Silicon Labs will not be liable for any consequential, incidental, or
bogdanm 0:9b334a45a8ff 28 * special damages, or any other relief, or for any claim by any third party,
bogdanm 0:9b334a45a8ff 29 * arising from your use of this Software.
bogdanm 0:9b334a45a8ff 30 *
bogdanm 0:9b334a45a8ff 31 ******************************************************************************/
bogdanm 0:9b334a45a8ff 32
bogdanm 0:9b334a45a8ff 33 #include "em_i2c.h"
bogdanm 0:9b334a45a8ff 34 #if defined(I2C_COUNT) && (I2C_COUNT > 0)
bogdanm 0:9b334a45a8ff 35
bogdanm 0:9b334a45a8ff 36 #include "em_cmu.h"
mbed_official 50:a417edff4437 37 #include "em_bus.h"
bogdanm 0:9b334a45a8ff 38 #include "em_assert.h"
bogdanm 0:9b334a45a8ff 39
mbed_official 50:a417edff4437 40 #include <limits.h>
mbed_official 50:a417edff4437 41
bogdanm 0:9b334a45a8ff 42 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 43 * @addtogroup EM_Library
bogdanm 0:9b334a45a8ff 44 * @{
bogdanm 0:9b334a45a8ff 45 ******************************************************************************/
bogdanm 0:9b334a45a8ff 46
bogdanm 0:9b334a45a8ff 47 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 48 * @addtogroup I2C
bogdanm 0:9b334a45a8ff 49 * @brief Inter-integrated Circuit (I2C) Peripheral API
bogdanm 0:9b334a45a8ff 50 * @{
bogdanm 0:9b334a45a8ff 51 ******************************************************************************/
bogdanm 0:9b334a45a8ff 52
bogdanm 0:9b334a45a8ff 53 /*******************************************************************************
bogdanm 0:9b334a45a8ff 54 ******************************* DEFINES ***********************************
bogdanm 0:9b334a45a8ff 55 ******************************************************************************/
bogdanm 0:9b334a45a8ff 56
bogdanm 0:9b334a45a8ff 57 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
bogdanm 0:9b334a45a8ff 58
mbed_official 50:a417edff4437 59 /** Validation of I2C register block pointer reference for assert statements. */
bogdanm 0:9b334a45a8ff 60 #if (I2C_COUNT == 1)
bogdanm 0:9b334a45a8ff 61 #define I2C_REF_VALID(ref) ((ref) == I2C0)
bogdanm 0:9b334a45a8ff 62 #elif (I2C_COUNT == 2)
bogdanm 0:9b334a45a8ff 63 #define I2C_REF_VALID(ref) ((ref == I2C0) || (ref == I2C1))
mbed_official 50:a417edff4437 64 #elif (I2C_COUNT == 3)
mbed_official 50:a417edff4437 65 #define I2C_REF_VALID(ref) ((ref == I2C0) || (ref == I2C1)|| (ref == I2C2))
bogdanm 0:9b334a45a8ff 66 #endif
bogdanm 0:9b334a45a8ff 67
bogdanm 0:9b334a45a8ff 68 /** Error flags indicating I2C transfer has failed somehow. */
bogdanm 0:9b334a45a8ff 69 /* Notice that I2C_IF_TXOF (transmit overflow) is not really possible with */
bogdanm 0:9b334a45a8ff 70 /* this SW supporting master mode. Likewise for I2C_IF_RXUF (receive underflow) */
bogdanm 0:9b334a45a8ff 71 /* RXUF is only likely to occur with this SW if using a debugger peeking into */
bogdanm 0:9b334a45a8ff 72 /* RXDATA register. Thus, we ignore those types of fault. */
bogdanm 0:9b334a45a8ff 73 #define I2C_IF_ERRORS (I2C_IF_BUSERR | I2C_IF_ARBLOST)
bogdanm 0:9b334a45a8ff 74
mbed_official 50:a417edff4437 75 /* Max I2C transmission rate constant */
mbed_official 50:a417edff4437 76 #if defined( _SILICON_LABS_32B_PLATFORM_1 )
mbed_official 50:a417edff4437 77 #define I2C_CR_MAX 4
mbed_official 50:a417edff4437 78 #elif defined( _SILICON_LABS_32B_PLATFORM_2 )
mbed_official 50:a417edff4437 79 #define I2C_CR_MAX 8
mbed_official 50:a417edff4437 80 #else
mbed_official 50:a417edff4437 81 #warning "Max I2C transmission rate constant is not defined"
mbed_official 50:a417edff4437 82 #endif
mbed_official 50:a417edff4437 83
bogdanm 0:9b334a45a8ff 84 /** @endcond */
bogdanm 0:9b334a45a8ff 85
bogdanm 0:9b334a45a8ff 86 /*******************************************************************************
bogdanm 0:9b334a45a8ff 87 ******************************** ENUMS ************************************
bogdanm 0:9b334a45a8ff 88 ******************************************************************************/
bogdanm 0:9b334a45a8ff 89
bogdanm 0:9b334a45a8ff 90 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
bogdanm 0:9b334a45a8ff 91
bogdanm 0:9b334a45a8ff 92 /** Master mode transfer states. */
bogdanm 0:9b334a45a8ff 93 typedef enum
bogdanm 0:9b334a45a8ff 94 {
bogdanm 0:9b334a45a8ff 95 i2cStateStartAddrSend, /**< Send start + (first part of) address. */
bogdanm 0:9b334a45a8ff 96 i2cStateAddrWFAckNack, /**< Wait for ACK/NACK on (first part of) address. */
bogdanm 0:9b334a45a8ff 97 i2cStateAddrWF2ndAckNack, /**< Wait for ACK/NACK on second part of 10 bit address. */
bogdanm 0:9b334a45a8ff 98 i2cStateRStartAddrSend, /**< Send repeated start + (first part of) address. */
bogdanm 0:9b334a45a8ff 99 i2cStateRAddrWFAckNack, /**< Wait for ACK/NACK on address sent after repeated start. */
bogdanm 0:9b334a45a8ff 100 i2cStateDataSend, /**< Send data. */
bogdanm 0:9b334a45a8ff 101 i2cStateDataWFAckNack, /**< Wait for ACK/NACK on data sent. */
bogdanm 0:9b334a45a8ff 102 i2cStateWFData, /**< Wait for data. */
bogdanm 0:9b334a45a8ff 103 i2cStateWFStopSent, /**< Wait for STOP to have been transmitted. */
bogdanm 0:9b334a45a8ff 104 i2cStateDone /**< Transfer completed successfully. */
bogdanm 0:9b334a45a8ff 105 } I2C_TransferState_TypeDef;
bogdanm 0:9b334a45a8ff 106
bogdanm 0:9b334a45a8ff 107 /** @endcond */
bogdanm 0:9b334a45a8ff 108
bogdanm 0:9b334a45a8ff 109 /*******************************************************************************
bogdanm 0:9b334a45a8ff 110 ******************************* STRUCTS ***********************************
bogdanm 0:9b334a45a8ff 111 ******************************************************************************/
bogdanm 0:9b334a45a8ff 112
bogdanm 0:9b334a45a8ff 113 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
bogdanm 0:9b334a45a8ff 114
bogdanm 0:9b334a45a8ff 115 /** Structure used to store state information on an ongoing master mode transfer. */
bogdanm 0:9b334a45a8ff 116 typedef struct
bogdanm 0:9b334a45a8ff 117 {
bogdanm 0:9b334a45a8ff 118 /** Current state. */
bogdanm 0:9b334a45a8ff 119 I2C_TransferState_TypeDef state;
bogdanm 0:9b334a45a8ff 120
bogdanm 0:9b334a45a8ff 121 /** Result return code. */
bogdanm 0:9b334a45a8ff 122 I2C_TransferReturn_TypeDef result;
bogdanm 0:9b334a45a8ff 123
bogdanm 0:9b334a45a8ff 124 /** Offset in current sequence buffer. */
bogdanm 0:9b334a45a8ff 125 uint16_t offset;
bogdanm 0:9b334a45a8ff 126
bogdanm 0:9b334a45a8ff 127 /* Index to current sequence buffer in use. */
bogdanm 0:9b334a45a8ff 128 uint8_t bufIndx;
bogdanm 0:9b334a45a8ff 129
bogdanm 0:9b334a45a8ff 130 /** Reference to I2C transfer sequence definition provided by user. */
bogdanm 0:9b334a45a8ff 131 I2C_TransferSeq_TypeDef *seq;
bogdanm 0:9b334a45a8ff 132 } I2C_Transfer_TypeDef;
bogdanm 0:9b334a45a8ff 133
bogdanm 0:9b334a45a8ff 134 /** @endcond */
bogdanm 0:9b334a45a8ff 135
bogdanm 0:9b334a45a8ff 136 /*******************************************************************************
bogdanm 0:9b334a45a8ff 137 ***************************** LOCAL DATA *******^**************************
bogdanm 0:9b334a45a8ff 138 ******************************************************************************/
bogdanm 0:9b334a45a8ff 139
bogdanm 0:9b334a45a8ff 140 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
bogdanm 0:9b334a45a8ff 141
bogdanm 0:9b334a45a8ff 142 /**
bogdanm 0:9b334a45a8ff 143 * Lookup table for Nlow + Nhigh setting defined by CLHR. Set undefined
bogdanm 0:9b334a45a8ff 144 * index (0x3) to reflect default setting just in case.
bogdanm 0:9b334a45a8ff 145 */
bogdanm 0:9b334a45a8ff 146 static const uint8_t i2cNSum[] = { 4 + 4, 6 + 3, 11 + 6, 4 + 4 };
bogdanm 0:9b334a45a8ff 147
bogdanm 0:9b334a45a8ff 148 /** Transfer state info for ongoing master mode transfer */
bogdanm 0:9b334a45a8ff 149 static I2C_Transfer_TypeDef i2cTransfer[I2C_COUNT];
bogdanm 0:9b334a45a8ff 150
bogdanm 0:9b334a45a8ff 151 /** @endcond */
bogdanm 0:9b334a45a8ff 152
bogdanm 0:9b334a45a8ff 153 /*******************************************************************************
bogdanm 0:9b334a45a8ff 154 ************************** GLOBAL FUNCTIONS *******************************
bogdanm 0:9b334a45a8ff 155 ******************************************************************************/
bogdanm 0:9b334a45a8ff 156
bogdanm 0:9b334a45a8ff 157 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 158 * @brief
bogdanm 0:9b334a45a8ff 159 * Get current configured I2C bus frequency.
bogdanm 0:9b334a45a8ff 160 *
bogdanm 0:9b334a45a8ff 161 * @details
bogdanm 0:9b334a45a8ff 162 * This frequency is only of relevance when acting as master.
bogdanm 0:9b334a45a8ff 163 *
bogdanm 0:9b334a45a8ff 164 * @param[in] i2c
bogdanm 0:9b334a45a8ff 165 * Pointer to I2C peripheral register block.
bogdanm 0:9b334a45a8ff 166 *
bogdanm 0:9b334a45a8ff 167 * @return
bogdanm 0:9b334a45a8ff 168 * Current I2C frequency in Hz.
bogdanm 0:9b334a45a8ff 169 ******************************************************************************/
bogdanm 0:9b334a45a8ff 170 uint32_t I2C_BusFreqGet(I2C_TypeDef *i2c)
bogdanm 0:9b334a45a8ff 171 {
mbed_official 50:a417edff4437 172 uint32_t freqHfper;
bogdanm 0:9b334a45a8ff 173 uint32_t n;
bogdanm 0:9b334a45a8ff 174
mbed_official 50:a417edff4437 175 /* Max frequency is given by freqScl = freqHfper/((Nlow + Nhigh)(DIV + 1) + I2C_CR_MAX)
mbed_official 50:a417edff4437 176 * More details can be found in the reference manual,
mbed_official 50:a417edff4437 177 * I2C Clock Generation chapter. */
mbed_official 50:a417edff4437 178 freqHfper = CMU_ClockFreqGet(cmuClock_HFPER);
mbed_official 50:a417edff4437 179 /* n = Nlow + Nhigh */
bogdanm 0:9b334a45a8ff 180 n = (uint32_t)(i2cNSum[(i2c->CTRL & _I2C_CTRL_CLHR_MASK) >> _I2C_CTRL_CLHR_SHIFT]);
bogdanm 0:9b334a45a8ff 181
mbed_official 50:a417edff4437 182 return (freqHfper / ((n * (i2c->CLKDIV + 1)) + I2C_CR_MAX));
bogdanm 0:9b334a45a8ff 183 }
bogdanm 0:9b334a45a8ff 184
bogdanm 0:9b334a45a8ff 185
bogdanm 0:9b334a45a8ff 186 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 187 * @brief
bogdanm 0:9b334a45a8ff 188 * Set I2C bus frequency.
bogdanm 0:9b334a45a8ff 189 *
bogdanm 0:9b334a45a8ff 190 * @details
bogdanm 0:9b334a45a8ff 191 * The bus frequency is only of relevance when acting as a master. The bus
bogdanm 0:9b334a45a8ff 192 * frequency should not be set higher than the max frequency accepted by the
bogdanm 0:9b334a45a8ff 193 * slowest device on the bus.
bogdanm 0:9b334a45a8ff 194 *
bogdanm 0:9b334a45a8ff 195 * Notice that due to asymmetric requirements on low and high I2C clock
bogdanm 0:9b334a45a8ff 196 * cycles by the I2C specification, the actual max frequency allowed in order
bogdanm 0:9b334a45a8ff 197 * to comply with the specification may be somewhat lower than expected.
bogdanm 0:9b334a45a8ff 198 *
bogdanm 0:9b334a45a8ff 199 * Please refer to the reference manual, details on I2C clock generation,
bogdanm 0:9b334a45a8ff 200 * for max allowed theoretical frequencies for different modes.
bogdanm 0:9b334a45a8ff 201 *
bogdanm 0:9b334a45a8ff 202 * @param[in] i2c
bogdanm 0:9b334a45a8ff 203 * Pointer to I2C peripheral register block.
bogdanm 0:9b334a45a8ff 204 *
mbed_official 50:a417edff4437 205 * @param[in] freqRef
bogdanm 0:9b334a45a8ff 206 * I2C reference clock frequency in Hz that will be used. If set to 0,
mbed_official 50:a417edff4437 207 * then HFPER clock is used. Setting it to a higher than actual configured
mbed_official 50:a417edff4437 208 * value only has the consequence of reducing the real I2C frequency.
bogdanm 0:9b334a45a8ff 209 *
mbed_official 50:a417edff4437 210 * @param[in] freqScl
bogdanm 0:9b334a45a8ff 211 * Bus frequency to set (actual bus speed may be lower due to integer
bogdanm 0:9b334a45a8ff 212 * prescaling). Safe (according to I2C specification) max frequencies for
bogdanm 0:9b334a45a8ff 213 * standard, fast and fast+ modes are available using I2C_FREQ_ defines.
bogdanm 0:9b334a45a8ff 214 * (Using I2C_FREQ_ defines requires corresponding setting of @p type.)
bogdanm 0:9b334a45a8ff 215 * Slowest slave device on bus must always be considered.
bogdanm 0:9b334a45a8ff 216 *
mbed_official 50:a417edff4437 217 * @param[in] i2cMode
bogdanm 0:9b334a45a8ff 218 * Clock low to high ratio type to use. If not using i2cClockHLRStandard,
bogdanm 0:9b334a45a8ff 219 * make sure all devices on the bus support the specified mode. Using a
bogdanm 0:9b334a45a8ff 220 * non-standard ratio is useful to achieve higher bus clock in fast and
bogdanm 0:9b334a45a8ff 221 * fast+ modes.
bogdanm 0:9b334a45a8ff 222 ******************************************************************************/
bogdanm 0:9b334a45a8ff 223 void I2C_BusFreqSet(I2C_TypeDef *i2c,
mbed_official 50:a417edff4437 224 uint32_t freqRef,
mbed_official 50:a417edff4437 225 uint32_t freqScl,
mbed_official 50:a417edff4437 226 I2C_ClockHLR_TypeDef i2cMode)
bogdanm 0:9b334a45a8ff 227 {
mbed_official 50:a417edff4437 228 uint32_t n, minFreq;
mbed_official 50:a417edff4437 229 int32_t div;
bogdanm 0:9b334a45a8ff 230
bogdanm 0:9b334a45a8ff 231 /* Avoid divide by 0 */
mbed_official 50:a417edff4437 232 EFM_ASSERT(freqScl);
mbed_official 50:a417edff4437 233 if (!freqScl)
bogdanm 0:9b334a45a8ff 234 {
bogdanm 0:9b334a45a8ff 235 return;
bogdanm 0:9b334a45a8ff 236 }
bogdanm 0:9b334a45a8ff 237
bogdanm 0:9b334a45a8ff 238 /* Set the CLHR (clock low to high ratio). */
bogdanm 0:9b334a45a8ff 239 i2c->CTRL &= ~_I2C_CTRL_CLHR_MASK;
mbed_official 50:a417edff4437 240 BUS_RegMaskedWrite(&i2c->CTRL,
mbed_official 50:a417edff4437 241 _I2C_CTRL_CLHR_MASK,
mbed_official 50:a417edff4437 242 i2cMode <<_I2C_CTRL_CLHR_SHIFT);
bogdanm 0:9b334a45a8ff 243
mbed_official 50:a417edff4437 244 if (!freqRef)
mbed_official 50:a417edff4437 245 {
mbed_official 50:a417edff4437 246 freqRef = CMU_ClockFreqGet(cmuClock_HFPER);
mbed_official 50:a417edff4437 247 }
bogdanm 0:9b334a45a8ff 248
mbed_official 50:a417edff4437 249 /* Check minumum HF peripheral clock */
mbed_official 50:a417edff4437 250 minFreq = UINT_MAX;
mbed_official 50:a417edff4437 251 if (i2c->CTRL & I2C_CTRL_SLAVE)
bogdanm 0:9b334a45a8ff 252 {
mbed_official 50:a417edff4437 253 switch(i2cMode)
mbed_official 50:a417edff4437 254 {
mbed_official 50:a417edff4437 255 case i2cClockHLRStandard:
mbed_official 50:a417edff4437 256 #if defined( _SILICON_LABS_32B_PLATFORM_1 )
mbed_official 50:a417edff4437 257 minFreq = 4200000; break;
mbed_official 50:a417edff4437 258 #elif defined( _SILICON_LABS_32B_PLATFORM_2 )
mbed_official 50:a417edff4437 259 minFreq = 2000000; break;
mbed_official 50:a417edff4437 260 #endif
mbed_official 50:a417edff4437 261 case i2cClockHLRAsymetric:
mbed_official 50:a417edff4437 262 #if defined( _SILICON_LABS_32B_PLATFORM_1 )
mbed_official 50:a417edff4437 263 minFreq = 11000000; break;
mbed_official 50:a417edff4437 264 #elif defined( _SILICON_LABS_32B_PLATFORM_2 )
mbed_official 50:a417edff4437 265 minFreq = 5000000; break;
mbed_official 50:a417edff4437 266 #endif
mbed_official 50:a417edff4437 267 case i2cClockHLRFast:
mbed_official 50:a417edff4437 268 #if defined( _SILICON_LABS_32B_PLATFORM_1 )
mbed_official 50:a417edff4437 269 minFreq = 24400000; break;
mbed_official 50:a417edff4437 270 #elif defined( _SILICON_LABS_32B_PLATFORM_2 )
mbed_official 50:a417edff4437 271 minFreq = 14000000; break;
mbed_official 50:a417edff4437 272 #endif
mbed_official 50:a417edff4437 273 }
bogdanm 0:9b334a45a8ff 274 }
mbed_official 50:a417edff4437 275 else
mbed_official 50:a417edff4437 276 {
mbed_official 50:a417edff4437 277 /* For master mode, platform 1 and 2 share the same
mbed_official 50:a417edff4437 278 min frequencies */
mbed_official 50:a417edff4437 279 switch(i2cMode)
mbed_official 50:a417edff4437 280 {
mbed_official 50:a417edff4437 281 case i2cClockHLRStandard:
mbed_official 50:a417edff4437 282 minFreq = 2000000; break;
mbed_official 50:a417edff4437 283 case i2cClockHLRAsymetric:
mbed_official 50:a417edff4437 284 minFreq = 9000000; break;
mbed_official 50:a417edff4437 285 case i2cClockHLRFast:
mbed_official 50:a417edff4437 286 minFreq = 20000000; break;
mbed_official 50:a417edff4437 287 }
mbed_official 50:a417edff4437 288 }
bogdanm 0:9b334a45a8ff 289
mbed_official 50:a417edff4437 290 /* Frequency most be larger-than */
mbed_official 50:a417edff4437 291 EFM_ASSERT(freqRef > minFreq);
mbed_official 50:a417edff4437 292
mbed_official 50:a417edff4437 293 /* SCL frequency is given by
mbed_official 50:a417edff4437 294 * freqScl = freqRef/((Nlow + Nhigh) * (DIV + 1) + I2C_C_MAX)
mbed_official 50:a417edff4437 295 *
mbed_official 50:a417edff4437 296 * Thus
mbed_official 50:a417edff4437 297 * DIV = ((freqRef - (I2C_C_MAX * freqScl))/((Nlow + Nhigh) * freqScl)) - 1
mbed_official 50:a417edff4437 298 *
mbed_official 50:a417edff4437 299 * More details can be found in the reference manual,
mbed_official 50:a417edff4437 300 * I2C Clock Generation chapter. */
mbed_official 50:a417edff4437 301
mbed_official 50:a417edff4437 302 /* n = Nlow + Nhigh */
mbed_official 50:a417edff4437 303 n = (uint32_t)(i2cNSum[i2cMode]);
mbed_official 50:a417edff4437 304 div = ((freqRef - (I2C_CR_MAX * freqScl)) / (n * freqScl)) - 1;
mbed_official 50:a417edff4437 305 EFM_ASSERT(div >= 0);
mbed_official 50:a417edff4437 306 EFM_ASSERT((uint32_t)div <= _I2C_CLKDIV_DIV_MASK);
bogdanm 0:9b334a45a8ff 307
bogdanm 0:9b334a45a8ff 308 /* Clock divisor must be at least 1 in slave mode according to reference */
bogdanm 0:9b334a45a8ff 309 /* manual (in which case there is normally no need to set bus frequency). */
bogdanm 0:9b334a45a8ff 310 if ((i2c->CTRL & I2C_CTRL_SLAVE) && !div)
bogdanm 0:9b334a45a8ff 311 {
bogdanm 0:9b334a45a8ff 312 div = 1;
bogdanm 0:9b334a45a8ff 313 }
mbed_official 50:a417edff4437 314 i2c->CLKDIV = (uint32_t)div;
bogdanm 0:9b334a45a8ff 315 }
bogdanm 0:9b334a45a8ff 316
bogdanm 0:9b334a45a8ff 317
bogdanm 0:9b334a45a8ff 318 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 319 * @brief
bogdanm 0:9b334a45a8ff 320 * Enable/disable I2C.
bogdanm 0:9b334a45a8ff 321 *
bogdanm 0:9b334a45a8ff 322 * @note
bogdanm 0:9b334a45a8ff 323 * After enabling the I2C (from being disabled), the I2C is in BUSY state.
bogdanm 0:9b334a45a8ff 324 *
bogdanm 0:9b334a45a8ff 325 * @param[in] i2c
bogdanm 0:9b334a45a8ff 326 * Pointer to I2C peripheral register block.
bogdanm 0:9b334a45a8ff 327 *
bogdanm 0:9b334a45a8ff 328 * @param[in] enable
bogdanm 0:9b334a45a8ff 329 * true to enable counting, false to disable.
bogdanm 0:9b334a45a8ff 330 ******************************************************************************/
bogdanm 0:9b334a45a8ff 331 void I2C_Enable(I2C_TypeDef *i2c, bool enable)
bogdanm 0:9b334a45a8ff 332 {
bogdanm 0:9b334a45a8ff 333 EFM_ASSERT(I2C_REF_VALID(i2c));
bogdanm 0:9b334a45a8ff 334
mbed_official 50:a417edff4437 335 BUS_RegBitWrite(&(i2c->CTRL), _I2C_CTRL_EN_SHIFT, enable);
bogdanm 0:9b334a45a8ff 336 }
bogdanm 0:9b334a45a8ff 337
bogdanm 0:9b334a45a8ff 338
bogdanm 0:9b334a45a8ff 339 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 340 * @brief
bogdanm 0:9b334a45a8ff 341 * Initialize I2C.
bogdanm 0:9b334a45a8ff 342 *
bogdanm 0:9b334a45a8ff 343 * @param[in] i2c
bogdanm 0:9b334a45a8ff 344 * Pointer to I2C peripheral register block.
bogdanm 0:9b334a45a8ff 345 *
bogdanm 0:9b334a45a8ff 346 * @param[in] init
bogdanm 0:9b334a45a8ff 347 * Pointer to I2C initialization structure.
bogdanm 0:9b334a45a8ff 348 ******************************************************************************/
bogdanm 0:9b334a45a8ff 349 void I2C_Init(I2C_TypeDef *i2c, const I2C_Init_TypeDef *init)
bogdanm 0:9b334a45a8ff 350 {
bogdanm 0:9b334a45a8ff 351 EFM_ASSERT(I2C_REF_VALID(i2c));
bogdanm 0:9b334a45a8ff 352
bogdanm 0:9b334a45a8ff 353 i2c->IEN = 0;
bogdanm 0:9b334a45a8ff 354 i2c->IFC = _I2C_IFC_MASK;
bogdanm 0:9b334a45a8ff 355
bogdanm 0:9b334a45a8ff 356 /* Set SLAVE select mode */
mbed_official 50:a417edff4437 357 BUS_RegBitWrite(&(i2c->CTRL), _I2C_CTRL_SLAVE_SHIFT, init->master ? 0 : 1);
bogdanm 0:9b334a45a8ff 358
bogdanm 0:9b334a45a8ff 359 I2C_BusFreqSet(i2c, init->refFreq, init->freq, init->clhr);
bogdanm 0:9b334a45a8ff 360
mbed_official 50:a417edff4437 361 BUS_RegBitWrite(&(i2c->CTRL), _I2C_CTRL_EN_SHIFT, init->enable);
bogdanm 0:9b334a45a8ff 362 }
bogdanm 0:9b334a45a8ff 363
bogdanm 0:9b334a45a8ff 364
bogdanm 0:9b334a45a8ff 365 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 366 * @brief
bogdanm 0:9b334a45a8ff 367 * Reset I2C to same state as after a HW reset.
bogdanm 0:9b334a45a8ff 368 *
bogdanm 0:9b334a45a8ff 369 * @note
bogdanm 0:9b334a45a8ff 370 * The ROUTE register is NOT reset by this function, in order to allow for
bogdanm 0:9b334a45a8ff 371 * centralized setup of this feature.
bogdanm 0:9b334a45a8ff 372 *
bogdanm 0:9b334a45a8ff 373 * @param[in] i2c
bogdanm 0:9b334a45a8ff 374 * Pointer to I2C peripheral register block.
bogdanm 0:9b334a45a8ff 375 ******************************************************************************/
bogdanm 0:9b334a45a8ff 376 void I2C_Reset(I2C_TypeDef *i2c)
bogdanm 0:9b334a45a8ff 377 {
bogdanm 0:9b334a45a8ff 378 i2c->CTRL = _I2C_CTRL_RESETVALUE;
bogdanm 0:9b334a45a8ff 379 i2c->CLKDIV = _I2C_CLKDIV_RESETVALUE;
bogdanm 0:9b334a45a8ff 380 i2c->SADDR = _I2C_SADDR_RESETVALUE;
bogdanm 0:9b334a45a8ff 381 i2c->SADDRMASK = _I2C_SADDRMASK_RESETVALUE;
bogdanm 0:9b334a45a8ff 382 i2c->IEN = _I2C_IEN_RESETVALUE;
bogdanm 0:9b334a45a8ff 383 i2c->IFC = _I2C_IFC_MASK;
bogdanm 0:9b334a45a8ff 384 /* Do not reset route register, setting should be done independently */
bogdanm 0:9b334a45a8ff 385 }
bogdanm 0:9b334a45a8ff 386
bogdanm 0:9b334a45a8ff 387
bogdanm 0:9b334a45a8ff 388 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 389 * @brief
bogdanm 0:9b334a45a8ff 390 * Continue an initiated I2C transfer (single master mode only).
bogdanm 0:9b334a45a8ff 391 *
bogdanm 0:9b334a45a8ff 392 * @details
bogdanm 0:9b334a45a8ff 393 * This function is used repeatedly after a I2C_TransferInit() in order to
bogdanm 0:9b334a45a8ff 394 * complete a transfer. It may be used in polled mode as the below example
bogdanm 0:9b334a45a8ff 395 * shows:
bogdanm 0:9b334a45a8ff 396 * @verbatim
bogdanm 0:9b334a45a8ff 397 * I2C_TransferReturn_TypeDef ret;
bogdanm 0:9b334a45a8ff 398 *
bogdanm 0:9b334a45a8ff 399 * // Do a polled transfer
bogdanm 0:9b334a45a8ff 400 * ret = I2C_TransferInit(I2C0, seq);
bogdanm 0:9b334a45a8ff 401 * while (ret == i2cTransferInProgress)
bogdanm 0:9b334a45a8ff 402 * {
bogdanm 0:9b334a45a8ff 403 * ret = I2C_Transfer(I2C0);
bogdanm 0:9b334a45a8ff 404 * }
bogdanm 0:9b334a45a8ff 405 * @endverbatim
bogdanm 0:9b334a45a8ff 406 * It may also be used in interrupt driven mode, where this function is invoked
bogdanm 0:9b334a45a8ff 407 * from the interrupt handler. Notice that if used in interrupt mode, NVIC
bogdanm 0:9b334a45a8ff 408 * interrupts must be configured and enabled for the I2C bus used. I2C
bogdanm 0:9b334a45a8ff 409 * peripheral specific interrupts are managed by this SW.
bogdanm 0:9b334a45a8ff 410 *
bogdanm 0:9b334a45a8ff 411 * @note
bogdanm 0:9b334a45a8ff 412 * Only single master mode is supported.
bogdanm 0:9b334a45a8ff 413 *
bogdanm 0:9b334a45a8ff 414 * @param[in] i2c
bogdanm 0:9b334a45a8ff 415 * Pointer to I2C peripheral register block.
bogdanm 0:9b334a45a8ff 416 *
bogdanm 0:9b334a45a8ff 417 * @return
bogdanm 0:9b334a45a8ff 418 * Returns status for ongoing transfer.
bogdanm 0:9b334a45a8ff 419 * @li #i2cTransferInProgress - indicates that transfer not finished.
bogdanm 0:9b334a45a8ff 420 * @li #i2cTransferDone - transfer completed successfully.
bogdanm 0:9b334a45a8ff 421 * @li otherwise some sort of error has occurred.
bogdanm 0:9b334a45a8ff 422 *
bogdanm 0:9b334a45a8ff 423 ******************************************************************************/
bogdanm 0:9b334a45a8ff 424 I2C_TransferReturn_TypeDef I2C_Transfer(I2C_TypeDef *i2c)
bogdanm 0:9b334a45a8ff 425 {
bogdanm 0:9b334a45a8ff 426 uint32_t tmp;
bogdanm 0:9b334a45a8ff 427 uint32_t pending;
bogdanm 0:9b334a45a8ff 428 I2C_Transfer_TypeDef *transfer;
bogdanm 0:9b334a45a8ff 429 I2C_TransferSeq_TypeDef *seq;
bogdanm 0:9b334a45a8ff 430
bogdanm 0:9b334a45a8ff 431 EFM_ASSERT(I2C_REF_VALID(i2c));
bogdanm 0:9b334a45a8ff 432
bogdanm 0:9b334a45a8ff 433 /* Support up to 2 I2C buses */
bogdanm 0:9b334a45a8ff 434 if (i2c == I2C0)
bogdanm 0:9b334a45a8ff 435 {
bogdanm 0:9b334a45a8ff 436 transfer = i2cTransfer;
bogdanm 0:9b334a45a8ff 437 }
bogdanm 0:9b334a45a8ff 438 #if (I2C_COUNT > 1)
bogdanm 0:9b334a45a8ff 439 else if (i2c == I2C1)
bogdanm 0:9b334a45a8ff 440 {
bogdanm 0:9b334a45a8ff 441 transfer = i2cTransfer + 1;
bogdanm 0:9b334a45a8ff 442 }
bogdanm 0:9b334a45a8ff 443 #endif
bogdanm 0:9b334a45a8ff 444 else
bogdanm 0:9b334a45a8ff 445 {
mbed_official 50:a417edff4437 446 return i2cTransferUsageFault;
bogdanm 0:9b334a45a8ff 447 }
bogdanm 0:9b334a45a8ff 448
bogdanm 0:9b334a45a8ff 449 seq = transfer->seq;
bogdanm 0:9b334a45a8ff 450 for (;; )
bogdanm 0:9b334a45a8ff 451 {
bogdanm 0:9b334a45a8ff 452 pending = i2c->IF;
bogdanm 0:9b334a45a8ff 453
bogdanm 0:9b334a45a8ff 454 /* If some sort of fault, abort transfer. */
bogdanm 0:9b334a45a8ff 455 if (pending & I2C_IF_ERRORS)
bogdanm 0:9b334a45a8ff 456 {
bogdanm 0:9b334a45a8ff 457 if (pending & I2C_IF_ARBLOST)
bogdanm 0:9b334a45a8ff 458 {
bogdanm 0:9b334a45a8ff 459 /* If arbitration fault, it indicates either a slave device */
bogdanm 0:9b334a45a8ff 460 /* not responding as expected, or other master which is not */
bogdanm 0:9b334a45a8ff 461 /* supported by this SW. */
bogdanm 0:9b334a45a8ff 462 transfer->result = i2cTransferArbLost;
bogdanm 0:9b334a45a8ff 463 }
bogdanm 0:9b334a45a8ff 464 else if (pending & I2C_IF_BUSERR)
bogdanm 0:9b334a45a8ff 465 {
bogdanm 0:9b334a45a8ff 466 /* A bus error indicates a misplaced start or stop, which should */
bogdanm 0:9b334a45a8ff 467 /* not occur in master mode controlled by this SW. */
bogdanm 0:9b334a45a8ff 468 transfer->result = i2cTransferBusErr;
bogdanm 0:9b334a45a8ff 469 }
bogdanm 0:9b334a45a8ff 470
bogdanm 0:9b334a45a8ff 471 /* If error situation occurred, it is difficult to know */
bogdanm 0:9b334a45a8ff 472 /* exact cause and how to resolve. It will be up to a wrapper */
bogdanm 0:9b334a45a8ff 473 /* to determine how to handle a fault/recovery if possible. */
bogdanm 0:9b334a45a8ff 474 transfer->state = i2cStateDone;
bogdanm 0:9b334a45a8ff 475 goto done;
bogdanm 0:9b334a45a8ff 476 }
bogdanm 0:9b334a45a8ff 477
bogdanm 0:9b334a45a8ff 478 switch (transfer->state)
bogdanm 0:9b334a45a8ff 479 {
bogdanm 0:9b334a45a8ff 480 /***************************************************/
bogdanm 0:9b334a45a8ff 481 /* Send first start+address (first byte if 10 bit) */
bogdanm 0:9b334a45a8ff 482 /***************************************************/
bogdanm 0:9b334a45a8ff 483 case i2cStateStartAddrSend:
bogdanm 0:9b334a45a8ff 484 if (seq->flags & I2C_FLAG_10BIT_ADDR)
bogdanm 0:9b334a45a8ff 485 {
bogdanm 0:9b334a45a8ff 486 tmp = (((uint32_t)(seq->addr) >> 8) & 0x06) | 0xf0;
bogdanm 0:9b334a45a8ff 487
bogdanm 0:9b334a45a8ff 488 /* In 10 bit address mode, the address following the first */
bogdanm 0:9b334a45a8ff 489 /* start always indicate write. */
bogdanm 0:9b334a45a8ff 490 }
bogdanm 0:9b334a45a8ff 491 else
bogdanm 0:9b334a45a8ff 492 {
bogdanm 0:9b334a45a8ff 493 tmp = (uint32_t)(seq->addr) & 0xfe;
bogdanm 0:9b334a45a8ff 494
bogdanm 0:9b334a45a8ff 495 if (seq->flags & I2C_FLAG_READ)
bogdanm 0:9b334a45a8ff 496 {
bogdanm 0:9b334a45a8ff 497 /* Indicate read request */
bogdanm 0:9b334a45a8ff 498 tmp |= 1;
bogdanm 0:9b334a45a8ff 499 }
bogdanm 0:9b334a45a8ff 500 }
bogdanm 0:9b334a45a8ff 501
bogdanm 0:9b334a45a8ff 502 transfer->state = i2cStateAddrWFAckNack;
bogdanm 0:9b334a45a8ff 503 i2c->TXDATA = tmp; /* Data not transmitted until START sent */
bogdanm 0:9b334a45a8ff 504 i2c->CMD = I2C_CMD_START;
bogdanm 0:9b334a45a8ff 505 goto done;
bogdanm 0:9b334a45a8ff 506
bogdanm 0:9b334a45a8ff 507 /*******************************************************/
bogdanm 0:9b334a45a8ff 508 /* Wait for ACK/NACK on address (first byte if 10 bit) */
bogdanm 0:9b334a45a8ff 509 /*******************************************************/
bogdanm 0:9b334a45a8ff 510 case i2cStateAddrWFAckNack:
bogdanm 0:9b334a45a8ff 511 if (pending & I2C_IF_NACK)
bogdanm 0:9b334a45a8ff 512 {
bogdanm 0:9b334a45a8ff 513 i2c->IFC = I2C_IFC_NACK;
bogdanm 0:9b334a45a8ff 514 transfer->result = i2cTransferNack;
bogdanm 0:9b334a45a8ff 515 transfer->state = i2cStateWFStopSent;
bogdanm 0:9b334a45a8ff 516 i2c->CMD = I2C_CMD_STOP;
bogdanm 0:9b334a45a8ff 517 }
bogdanm 0:9b334a45a8ff 518 else if (pending & I2C_IF_ACK)
bogdanm 0:9b334a45a8ff 519 {
bogdanm 0:9b334a45a8ff 520 i2c->IFC = I2C_IFC_ACK;
bogdanm 0:9b334a45a8ff 521
bogdanm 0:9b334a45a8ff 522 /* If 10 bit address, send 2nd byte of address. */
bogdanm 0:9b334a45a8ff 523 if (seq->flags & I2C_FLAG_10BIT_ADDR)
bogdanm 0:9b334a45a8ff 524 {
bogdanm 0:9b334a45a8ff 525 transfer->state = i2cStateAddrWF2ndAckNack;
bogdanm 0:9b334a45a8ff 526 i2c->TXDATA = (uint32_t)(seq->addr) & 0xff;
bogdanm 0:9b334a45a8ff 527 }
bogdanm 0:9b334a45a8ff 528 else
bogdanm 0:9b334a45a8ff 529 {
bogdanm 0:9b334a45a8ff 530 /* Determine whether receiving or sending data */
bogdanm 0:9b334a45a8ff 531 if (seq->flags & I2C_FLAG_READ)
bogdanm 0:9b334a45a8ff 532 {
bogdanm 0:9b334a45a8ff 533 transfer->state = i2cStateWFData;
bogdanm 0:9b334a45a8ff 534 if(seq->buf[transfer->bufIndx].len==1)
bogdanm 0:9b334a45a8ff 535 {
bogdanm 0:9b334a45a8ff 536 i2c->CMD = I2C_CMD_NACK;
bogdanm 0:9b334a45a8ff 537 }
bogdanm 0:9b334a45a8ff 538 }
bogdanm 0:9b334a45a8ff 539 else
bogdanm 0:9b334a45a8ff 540 {
bogdanm 0:9b334a45a8ff 541 transfer->state = i2cStateDataSend;
bogdanm 0:9b334a45a8ff 542 continue;
bogdanm 0:9b334a45a8ff 543 }
bogdanm 0:9b334a45a8ff 544 }
bogdanm 0:9b334a45a8ff 545 }
bogdanm 0:9b334a45a8ff 546 goto done;
bogdanm 0:9b334a45a8ff 547
bogdanm 0:9b334a45a8ff 548 /******************************************************/
bogdanm 0:9b334a45a8ff 549 /* Wait for ACK/NACK on second byte of 10 bit address */
bogdanm 0:9b334a45a8ff 550 /******************************************************/
bogdanm 0:9b334a45a8ff 551 case i2cStateAddrWF2ndAckNack:
bogdanm 0:9b334a45a8ff 552 if (pending & I2C_IF_NACK)
bogdanm 0:9b334a45a8ff 553 {
bogdanm 0:9b334a45a8ff 554 i2c->IFC = I2C_IFC_NACK;
bogdanm 0:9b334a45a8ff 555 transfer->result = i2cTransferNack;
bogdanm 0:9b334a45a8ff 556 transfer->state = i2cStateWFStopSent;
bogdanm 0:9b334a45a8ff 557 i2c->CMD = I2C_CMD_STOP;
bogdanm 0:9b334a45a8ff 558 }
bogdanm 0:9b334a45a8ff 559 else if (pending & I2C_IF_ACK)
bogdanm 0:9b334a45a8ff 560 {
bogdanm 0:9b334a45a8ff 561 i2c->IFC = I2C_IFC_ACK;
bogdanm 0:9b334a45a8ff 562
bogdanm 0:9b334a45a8ff 563 /* If using plain read sequence with 10 bit address, switch to send */
bogdanm 0:9b334a45a8ff 564 /* repeated start. */
bogdanm 0:9b334a45a8ff 565 if (seq->flags & I2C_FLAG_READ)
bogdanm 0:9b334a45a8ff 566 {
bogdanm 0:9b334a45a8ff 567 transfer->state = i2cStateRStartAddrSend;
bogdanm 0:9b334a45a8ff 568 }
bogdanm 0:9b334a45a8ff 569 /* Otherwise expected to write 0 or more bytes */
bogdanm 0:9b334a45a8ff 570 else
bogdanm 0:9b334a45a8ff 571 {
bogdanm 0:9b334a45a8ff 572 transfer->state = i2cStateDataSend;
bogdanm 0:9b334a45a8ff 573 }
bogdanm 0:9b334a45a8ff 574 continue;
bogdanm 0:9b334a45a8ff 575 }
bogdanm 0:9b334a45a8ff 576 goto done;
bogdanm 0:9b334a45a8ff 577
bogdanm 0:9b334a45a8ff 578 /*******************************/
bogdanm 0:9b334a45a8ff 579 /* Send repeated start+address */
bogdanm 0:9b334a45a8ff 580 /*******************************/
bogdanm 0:9b334a45a8ff 581 case i2cStateRStartAddrSend:
bogdanm 0:9b334a45a8ff 582 if (seq->flags & I2C_FLAG_10BIT_ADDR)
bogdanm 0:9b334a45a8ff 583 {
bogdanm 0:9b334a45a8ff 584 tmp = ((seq->addr >> 8) & 0x06) | 0xf0;
bogdanm 0:9b334a45a8ff 585 }
bogdanm 0:9b334a45a8ff 586 else
bogdanm 0:9b334a45a8ff 587 {
bogdanm 0:9b334a45a8ff 588 tmp = seq->addr & 0xfe;
bogdanm 0:9b334a45a8ff 589 }
bogdanm 0:9b334a45a8ff 590
bogdanm 0:9b334a45a8ff 591 /* If this is a write+read combined sequence, then read is about to start */
bogdanm 0:9b334a45a8ff 592 if (seq->flags & I2C_FLAG_WRITE_READ)
bogdanm 0:9b334a45a8ff 593 {
bogdanm 0:9b334a45a8ff 594 /* Indicate read request */
bogdanm 0:9b334a45a8ff 595 tmp |= 1;
bogdanm 0:9b334a45a8ff 596 }
bogdanm 0:9b334a45a8ff 597
bogdanm 0:9b334a45a8ff 598 transfer->state = i2cStateRAddrWFAckNack;
bogdanm 0:9b334a45a8ff 599 /* We have to write START cmd first since repeated start, otherwise */
bogdanm 0:9b334a45a8ff 600 /* data would be sent first. */
bogdanm 0:9b334a45a8ff 601 i2c->CMD = I2C_CMD_START;
bogdanm 0:9b334a45a8ff 602 i2c->TXDATA = tmp;
bogdanm 0:9b334a45a8ff 603 goto done;
bogdanm 0:9b334a45a8ff 604
bogdanm 0:9b334a45a8ff 605 /**********************************************************************/
bogdanm 0:9b334a45a8ff 606 /* Wait for ACK/NACK on repeated start+address (first byte if 10 bit) */
bogdanm 0:9b334a45a8ff 607 /**********************************************************************/
bogdanm 0:9b334a45a8ff 608 case i2cStateRAddrWFAckNack:
bogdanm 0:9b334a45a8ff 609 if (pending & I2C_IF_NACK)
bogdanm 0:9b334a45a8ff 610 {
bogdanm 0:9b334a45a8ff 611 i2c->IFC = I2C_IFC_NACK;
bogdanm 0:9b334a45a8ff 612 transfer->result = i2cTransferNack;
bogdanm 0:9b334a45a8ff 613 transfer->state = i2cStateWFStopSent;
bogdanm 0:9b334a45a8ff 614 i2c->CMD = I2C_CMD_STOP;
bogdanm 0:9b334a45a8ff 615 }
bogdanm 0:9b334a45a8ff 616 else if (pending & I2C_IF_ACK)
bogdanm 0:9b334a45a8ff 617 {
bogdanm 0:9b334a45a8ff 618 i2c->IFC = I2C_IFC_ACK;
bogdanm 0:9b334a45a8ff 619
bogdanm 0:9b334a45a8ff 620 /* Determine whether receiving or sending data */
bogdanm 0:9b334a45a8ff 621 if (seq->flags & I2C_FLAG_WRITE_READ)
bogdanm 0:9b334a45a8ff 622 {
bogdanm 0:9b334a45a8ff 623 transfer->state = i2cStateWFData;
bogdanm 0:9b334a45a8ff 624 }
bogdanm 0:9b334a45a8ff 625 else
bogdanm 0:9b334a45a8ff 626 {
bogdanm 0:9b334a45a8ff 627 transfer->state = i2cStateDataSend;
bogdanm 0:9b334a45a8ff 628 continue;
bogdanm 0:9b334a45a8ff 629 }
bogdanm 0:9b334a45a8ff 630 }
bogdanm 0:9b334a45a8ff 631 goto done;
bogdanm 0:9b334a45a8ff 632
bogdanm 0:9b334a45a8ff 633 /*****************************/
bogdanm 0:9b334a45a8ff 634 /* Send a data byte to slave */
bogdanm 0:9b334a45a8ff 635 /*****************************/
bogdanm 0:9b334a45a8ff 636 case i2cStateDataSend:
bogdanm 0:9b334a45a8ff 637 /* Reached end of data buffer? */
bogdanm 0:9b334a45a8ff 638 if (transfer->offset >= seq->buf[transfer->bufIndx].len)
bogdanm 0:9b334a45a8ff 639 {
bogdanm 0:9b334a45a8ff 640 /* Move to next message part */
bogdanm 0:9b334a45a8ff 641 transfer->offset = 0;
bogdanm 0:9b334a45a8ff 642 transfer->bufIndx++;
bogdanm 0:9b334a45a8ff 643
bogdanm 0:9b334a45a8ff 644 /* Send repeated start when switching to read mode on 2nd buffer */
bogdanm 0:9b334a45a8ff 645 if (seq->flags & I2C_FLAG_WRITE_READ)
bogdanm 0:9b334a45a8ff 646 {
bogdanm 0:9b334a45a8ff 647 transfer->state = i2cStateRStartAddrSend;
bogdanm 0:9b334a45a8ff 648 continue;
bogdanm 0:9b334a45a8ff 649 }
bogdanm 0:9b334a45a8ff 650
bogdanm 0:9b334a45a8ff 651 /* Only writing from one buffer, or finished both buffers */
bogdanm 0:9b334a45a8ff 652 if ((seq->flags & I2C_FLAG_WRITE) || (transfer->bufIndx > 1))
bogdanm 0:9b334a45a8ff 653 {
bogdanm 0:9b334a45a8ff 654 transfer->state = i2cStateWFStopSent;
bogdanm 0:9b334a45a8ff 655 i2c->CMD = I2C_CMD_STOP;
bogdanm 0:9b334a45a8ff 656 goto done;
bogdanm 0:9b334a45a8ff 657 }
bogdanm 0:9b334a45a8ff 658
bogdanm 0:9b334a45a8ff 659 /* Reprocess in case next buffer is empty */
bogdanm 0:9b334a45a8ff 660 continue;
bogdanm 0:9b334a45a8ff 661 }
bogdanm 0:9b334a45a8ff 662
bogdanm 0:9b334a45a8ff 663 /* Send byte */
bogdanm 0:9b334a45a8ff 664 i2c->TXDATA = (uint32_t)(seq->buf[transfer->bufIndx].data[transfer->offset++]);
bogdanm 0:9b334a45a8ff 665 transfer->state = i2cStateDataWFAckNack;
bogdanm 0:9b334a45a8ff 666 goto done;
bogdanm 0:9b334a45a8ff 667
bogdanm 0:9b334a45a8ff 668 /*********************************************************/
bogdanm 0:9b334a45a8ff 669 /* Wait for ACK/NACK from slave after sending data to it */
bogdanm 0:9b334a45a8ff 670 /*********************************************************/
bogdanm 0:9b334a45a8ff 671 case i2cStateDataWFAckNack:
bogdanm 0:9b334a45a8ff 672 if (pending & I2C_IF_NACK)
bogdanm 0:9b334a45a8ff 673 {
bogdanm 0:9b334a45a8ff 674 i2c->IFC = I2C_IFC_NACK;
bogdanm 0:9b334a45a8ff 675 transfer->result = i2cTransferNack;
bogdanm 0:9b334a45a8ff 676 transfer->state = i2cStateWFStopSent;
bogdanm 0:9b334a45a8ff 677 i2c->CMD = I2C_CMD_STOP;
bogdanm 0:9b334a45a8ff 678 }
bogdanm 0:9b334a45a8ff 679 else if (pending & I2C_IF_ACK)
bogdanm 0:9b334a45a8ff 680 {
bogdanm 0:9b334a45a8ff 681 i2c->IFC = I2C_IFC_ACK;
bogdanm 0:9b334a45a8ff 682 transfer->state = i2cStateDataSend;
bogdanm 0:9b334a45a8ff 683 continue;
bogdanm 0:9b334a45a8ff 684 }
bogdanm 0:9b334a45a8ff 685 goto done;
bogdanm 0:9b334a45a8ff 686
bogdanm 0:9b334a45a8ff 687 /****************************/
bogdanm 0:9b334a45a8ff 688 /* Wait for data from slave */
bogdanm 0:9b334a45a8ff 689 /****************************/
bogdanm 0:9b334a45a8ff 690 case i2cStateWFData:
bogdanm 0:9b334a45a8ff 691 if (pending & I2C_IF_RXDATAV)
bogdanm 0:9b334a45a8ff 692 {
bogdanm 0:9b334a45a8ff 693 uint8_t data;
bogdanm 0:9b334a45a8ff 694 unsigned int rxLen = seq->buf[transfer->bufIndx].len;
bogdanm 0:9b334a45a8ff 695
bogdanm 0:9b334a45a8ff 696 /* Must read out data in order to not block further progress */
bogdanm 0:9b334a45a8ff 697 data = (uint8_t)(i2c->RXDATA);
bogdanm 0:9b334a45a8ff 698
bogdanm 0:9b334a45a8ff 699 /* Make sure not storing beyond end of buffer just in case */
bogdanm 0:9b334a45a8ff 700 if (transfer->offset < rxLen)
bogdanm 0:9b334a45a8ff 701 {
bogdanm 0:9b334a45a8ff 702 seq->buf[transfer->bufIndx].data[transfer->offset++] = data;
bogdanm 0:9b334a45a8ff 703 }
bogdanm 0:9b334a45a8ff 704
bogdanm 0:9b334a45a8ff 705 /* If we have read all requested data, then the sequence should end */
bogdanm 0:9b334a45a8ff 706 if (transfer->offset >= rxLen)
bogdanm 0:9b334a45a8ff 707 {
bogdanm 0:9b334a45a8ff 708 /* If there is only one byte to receive we need to transmit the
bogdanm 0:9b334a45a8ff 709 NACK now, before the stop. */
bogdanm 0:9b334a45a8ff 710 if (1 == rxLen)
bogdanm 0:9b334a45a8ff 711 {
bogdanm 0:9b334a45a8ff 712 i2c->CMD = I2C_CMD_NACK;
bogdanm 0:9b334a45a8ff 713 }
bogdanm 0:9b334a45a8ff 714
bogdanm 0:9b334a45a8ff 715 transfer->state = i2cStateWFStopSent;
bogdanm 0:9b334a45a8ff 716 i2c->CMD = I2C_CMD_STOP;
bogdanm 0:9b334a45a8ff 717 }
bogdanm 0:9b334a45a8ff 718 else
bogdanm 0:9b334a45a8ff 719 {
bogdanm 0:9b334a45a8ff 720 /* Send ACK and wait for next byte */
bogdanm 0:9b334a45a8ff 721 i2c->CMD = I2C_CMD_ACK;
bogdanm 0:9b334a45a8ff 722
bogdanm 0:9b334a45a8ff 723 if ( (1<rxLen) && (transfer->offset == (rxLen-1)) )
bogdanm 0:9b334a45a8ff 724 {
bogdanm 0:9b334a45a8ff 725 /* If there is more than one byte to receive and this is the next
bogdanm 0:9b334a45a8ff 726 to last byte we need to transmit the NACK now, before receiving
bogdanm 0:9b334a45a8ff 727 the last byte. */
bogdanm 0:9b334a45a8ff 728 i2c->CMD = I2C_CMD_NACK;
bogdanm 0:9b334a45a8ff 729 }
bogdanm 0:9b334a45a8ff 730 }
bogdanm 0:9b334a45a8ff 731 }
bogdanm 0:9b334a45a8ff 732 goto done;
bogdanm 0:9b334a45a8ff 733
bogdanm 0:9b334a45a8ff 734 /***********************************/
bogdanm 0:9b334a45a8ff 735 /* Wait for STOP to have been sent */
bogdanm 0:9b334a45a8ff 736 /***********************************/
bogdanm 0:9b334a45a8ff 737 case i2cStateWFStopSent:
bogdanm 0:9b334a45a8ff 738 if (pending & I2C_IF_MSTOP)
bogdanm 0:9b334a45a8ff 739 {
bogdanm 0:9b334a45a8ff 740 i2c->IFC = I2C_IFC_MSTOP;
bogdanm 0:9b334a45a8ff 741 transfer->state = i2cStateDone;
bogdanm 0:9b334a45a8ff 742 }
bogdanm 0:9b334a45a8ff 743 goto done;
bogdanm 0:9b334a45a8ff 744
bogdanm 0:9b334a45a8ff 745 /******************************/
bogdanm 0:9b334a45a8ff 746 /* Unexpected state, SW fault */
bogdanm 0:9b334a45a8ff 747 /******************************/
bogdanm 0:9b334a45a8ff 748 default:
bogdanm 0:9b334a45a8ff 749 transfer->result = i2cTransferSwFault;
bogdanm 0:9b334a45a8ff 750 transfer->state = i2cStateDone;
bogdanm 0:9b334a45a8ff 751 goto done;
bogdanm 0:9b334a45a8ff 752 }
bogdanm 0:9b334a45a8ff 753 }
bogdanm 0:9b334a45a8ff 754
bogdanm 0:9b334a45a8ff 755 done:
bogdanm 0:9b334a45a8ff 756
bogdanm 0:9b334a45a8ff 757 if (transfer->state == i2cStateDone)
bogdanm 0:9b334a45a8ff 758 {
bogdanm 0:9b334a45a8ff 759 /* Disable interrupt sources when done */
bogdanm 0:9b334a45a8ff 760 i2c->IEN = 0;
bogdanm 0:9b334a45a8ff 761
bogdanm 0:9b334a45a8ff 762 /* Update result unless some fault already occurred */
bogdanm 0:9b334a45a8ff 763 if (transfer->result == i2cTransferInProgress)
bogdanm 0:9b334a45a8ff 764 {
bogdanm 0:9b334a45a8ff 765 transfer->result = i2cTransferDone;
bogdanm 0:9b334a45a8ff 766 }
bogdanm 0:9b334a45a8ff 767 }
bogdanm 0:9b334a45a8ff 768 /* Until transfer is done keep returning i2cTransferInProgress */
bogdanm 0:9b334a45a8ff 769 else
bogdanm 0:9b334a45a8ff 770 {
mbed_official 50:a417edff4437 771 return i2cTransferInProgress;
bogdanm 0:9b334a45a8ff 772 }
bogdanm 0:9b334a45a8ff 773
bogdanm 0:9b334a45a8ff 774 return transfer->result;
bogdanm 0:9b334a45a8ff 775 }
bogdanm 0:9b334a45a8ff 776
bogdanm 0:9b334a45a8ff 777
bogdanm 0:9b334a45a8ff 778 /***************************************************************************//**
bogdanm 0:9b334a45a8ff 779 * @brief
bogdanm 0:9b334a45a8ff 780 * Prepare and start an I2C transfer (single master mode only).
bogdanm 0:9b334a45a8ff 781 *
bogdanm 0:9b334a45a8ff 782 * @details
bogdanm 0:9b334a45a8ff 783 * This function must be invoked in order to start an I2C transfer
bogdanm 0:9b334a45a8ff 784 * sequence. In order to actually complete the transfer, I2C_Transfer() must
bogdanm 0:9b334a45a8ff 785 * be used either in polled mode or by adding a small driver wrapper utilizing
bogdanm 0:9b334a45a8ff 786 * interrupts.
bogdanm 0:9b334a45a8ff 787 *
bogdanm 0:9b334a45a8ff 788 * @note
bogdanm 0:9b334a45a8ff 789 * Only single master mode is supported.
bogdanm 0:9b334a45a8ff 790 *
bogdanm 0:9b334a45a8ff 791 * @param[in] i2c
bogdanm 0:9b334a45a8ff 792 * Pointer to I2C peripheral register block.
bogdanm 0:9b334a45a8ff 793 *
bogdanm 0:9b334a45a8ff 794 * @param[in] seq
bogdanm 0:9b334a45a8ff 795 * Pointer to sequence structure defining the I2C transfer to take place. The
bogdanm 0:9b334a45a8ff 796 * referenced structure must exist until the transfer has fully completed.
bogdanm 0:9b334a45a8ff 797 *
bogdanm 0:9b334a45a8ff 798 * @return
bogdanm 0:9b334a45a8ff 799 * Returns status for ongoing transfer:
bogdanm 0:9b334a45a8ff 800 * @li #i2cTransferInProgress - indicates that transfer not finished.
bogdanm 0:9b334a45a8ff 801 * @li otherwise some sort of error has occurred.
bogdanm 0:9b334a45a8ff 802 ******************************************************************************/
bogdanm 0:9b334a45a8ff 803 I2C_TransferReturn_TypeDef I2C_TransferInit(I2C_TypeDef *i2c,
bogdanm 0:9b334a45a8ff 804 I2C_TransferSeq_TypeDef *seq)
bogdanm 0:9b334a45a8ff 805 {
bogdanm 0:9b334a45a8ff 806 I2C_Transfer_TypeDef *transfer;
bogdanm 0:9b334a45a8ff 807
bogdanm 0:9b334a45a8ff 808 EFM_ASSERT(I2C_REF_VALID(i2c));
bogdanm 0:9b334a45a8ff 809 EFM_ASSERT(seq);
bogdanm 0:9b334a45a8ff 810
bogdanm 0:9b334a45a8ff 811 /* Support up to 2 I2C buses */
bogdanm 0:9b334a45a8ff 812 if (i2c == I2C0)
bogdanm 0:9b334a45a8ff 813 {
bogdanm 0:9b334a45a8ff 814 transfer = i2cTransfer;
bogdanm 0:9b334a45a8ff 815 }
bogdanm 0:9b334a45a8ff 816 #if (I2C_COUNT > 1)
bogdanm 0:9b334a45a8ff 817 else if (i2c == I2C1)
bogdanm 0:9b334a45a8ff 818 {
bogdanm 0:9b334a45a8ff 819 transfer = i2cTransfer + 1;
bogdanm 0:9b334a45a8ff 820 }
bogdanm 0:9b334a45a8ff 821 #endif
bogdanm 0:9b334a45a8ff 822 else
bogdanm 0:9b334a45a8ff 823 {
mbed_official 50:a417edff4437 824 return i2cTransferUsageFault;
bogdanm 0:9b334a45a8ff 825 }
bogdanm 0:9b334a45a8ff 826
bogdanm 0:9b334a45a8ff 827 /* Check if in busy state. Since this SW assumes single master, we can */
bogdanm 0:9b334a45a8ff 828 /* just issue an abort. The BUSY state is normal after a reset. */
bogdanm 0:9b334a45a8ff 829 if (i2c->STATE & I2C_STATE_BUSY)
bogdanm 0:9b334a45a8ff 830 {
bogdanm 0:9b334a45a8ff 831 i2c->CMD = I2C_CMD_ABORT;
bogdanm 0:9b334a45a8ff 832 }
bogdanm 0:9b334a45a8ff 833
bogdanm 0:9b334a45a8ff 834 /* Make sure user is not trying to read 0 bytes, it is not */
bogdanm 0:9b334a45a8ff 835 /* possible according to I2C spec, since slave will always start */
bogdanm 0:9b334a45a8ff 836 /* sending first byte ACK on address. The read operation can */
bogdanm 0:9b334a45a8ff 837 /* only be stopped by NACKing a received byte, ie minimum 1 byte. */
bogdanm 0:9b334a45a8ff 838 if (((seq->flags & I2C_FLAG_READ) && !(seq->buf[0].len)) ||
bogdanm 0:9b334a45a8ff 839 ((seq->flags & I2C_FLAG_WRITE_READ) && !(seq->buf[1].len))
bogdanm 0:9b334a45a8ff 840 )
bogdanm 0:9b334a45a8ff 841 {
mbed_official 50:a417edff4437 842 return i2cTransferUsageFault;
bogdanm 0:9b334a45a8ff 843 }
bogdanm 0:9b334a45a8ff 844
bogdanm 0:9b334a45a8ff 845 /* Prepare for a transfer */
bogdanm 0:9b334a45a8ff 846 transfer->state = i2cStateStartAddrSend;
bogdanm 0:9b334a45a8ff 847 transfer->result = i2cTransferInProgress;
bogdanm 0:9b334a45a8ff 848 transfer->offset = 0;
bogdanm 0:9b334a45a8ff 849 transfer->bufIndx = 0;
bogdanm 0:9b334a45a8ff 850 transfer->seq = seq;
bogdanm 0:9b334a45a8ff 851
bogdanm 0:9b334a45a8ff 852 /* Ensure buffers are empty */
bogdanm 0:9b334a45a8ff 853 i2c->CMD = I2C_CMD_CLEARPC | I2C_CMD_CLEARTX;
bogdanm 0:9b334a45a8ff 854 if (i2c->IF & I2C_IF_RXDATAV)
bogdanm 0:9b334a45a8ff 855 {
bogdanm 0:9b334a45a8ff 856 (void)i2c->RXDATA;
bogdanm 0:9b334a45a8ff 857 }
bogdanm 0:9b334a45a8ff 858
bogdanm 0:9b334a45a8ff 859 /* Clear all pending interrupts prior to starting transfer. */
bogdanm 0:9b334a45a8ff 860 i2c->IFC = _I2C_IFC_MASK;
bogdanm 0:9b334a45a8ff 861
bogdanm 0:9b334a45a8ff 862 /* Enable those interrupts we are interested in throughout transfer. */
bogdanm 0:9b334a45a8ff 863 /* Notice that the I2C interrupt must also be enabled in the NVIC, but */
bogdanm 0:9b334a45a8ff 864 /* that is left for an additional driver wrapper. */
bogdanm 0:9b334a45a8ff 865 i2c->IEN = I2C_IF_NACK | I2C_IF_ACK | I2C_IF_MSTOP |
bogdanm 0:9b334a45a8ff 866 I2C_IF_RXDATAV | I2C_IF_ERRORS;
bogdanm 0:9b334a45a8ff 867
bogdanm 0:9b334a45a8ff 868 /* Start transfer */
mbed_official 50:a417edff4437 869 return I2C_Transfer(i2c);
bogdanm 0:9b334a45a8ff 870 }
bogdanm 0:9b334a45a8ff 871
bogdanm 0:9b334a45a8ff 872 /** @} (end addtogroup I2C) */
bogdanm 0:9b334a45a8ff 873 /** @} (end addtogroup EM_Library) */
bogdanm 0:9b334a45a8ff 874 #endif /* defined(I2C_COUNT) && (I2C_COUNT > 0) */