summaryrefslogtreecommitdiff
path: root/bsp/efm32/Libraries/emlib/inc/em_i2c.h
blob: abedc3be1ecfea1b7a552014828425684f1875d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
/***************************************************************************//**
 * @file
 * @brief Inter-intergrated circuit (I2C) peripheral API
 * @author Energy Micro AS
 * @version 3.0.0
 *******************************************************************************
 * @section License
 * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
 *******************************************************************************
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 *
 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
 * obligation to support this Software. Energy Micro AS is providing the
 * Software "AS IS", with no express or implied warranties of any kind,
 * including, but not limited to, any implied warranties of merchantability
 * or fitness for any particular purpose or warranties against infringement
 * of any proprietary rights of a third party.
 *
 * Energy Micro AS will not be liable for any consequential, incidental, or
 * special damages, or any other relief, or for any claim by any third party,
 * arising from your use of this Software.
 *
 ******************************************************************************/
#ifndef __EM_I2C_H
#define __EM_I2C_H

#include <stdbool.h>
#include "em_part.h"

#ifdef __cplusplus
extern "C" {
#endif

/***************************************************************************//**
 * @addtogroup EM_Library
 * @{
 ******************************************************************************/

/***************************************************************************//**
 * @addtogroup I2C
 * @{
 ******************************************************************************/

/*******************************************************************************
 *******************************   DEFINES   ***********************************
 ******************************************************************************/

/**
 * @brief
 *   Standard mode max frequency assuming using 4:4 ratio for Nlow:Nhigh.
 * @details
 *   From I2C specification: Min Tlow = 4.7us, min Thigh = 4.0us,
 *   max Trise=1.0us, max Tfall=0.3us. Since ratio is 4:4, have to use
 *   worst case value of Tlow or Thigh as base.
 *
 *   1/(Tlow + Thigh + 1us + 0.3us) = 1/(4.7 + 4.7 + 1.3)us = 93458Hz
 */
#define I2C_FREQ_STANDARD_MAX    93500

/**
 * @brief
 *   Fast mode max frequency assuming using 6:3 ratio for Nlow:Nhigh.
 * @details
 *   From I2C specification: Min Tlow = 1.3us, min Thigh = 0.6us,
 *   max Trise=0.3us, max Tfall=0.3us. Since ratio is 6:3, have to use
 *   worst case value of Tlow or 2xThigh as base.
 *
 *   1/(Tlow + Thigh + 0.3us + 0.3us) = 1/(1.3 + 0.65 + 0.6)us = 392157Hz
 */
#define I2C_FREQ_FAST_MAX        392500


/**
 * @brief
 *   Fast mode+ max frequency assuming using 11:6 ratio for Nlow:Nhigh.
 * @details
 *   From I2C specification: Min Tlow = 0.5us, min Thigh = 0.26us,
 *   max Trise=0.012us, max Tfall=0.12us. Since ratio is 11:6, have to use
 *   worst case value of Tlow or (11/6)xThigh as base.
 *
 *   1/(Tlow + Thigh + 0.12us + 0.12us) = 1/(0.5 + 0.273 + 0.24)us = 987167Hz
 */
#define I2C_FREQ_FASTPLUS_MAX    987500


/**
 * @brief
 *   Indicate plain write sequence: S+ADDR(W)+DATA0+P.
 * @details
 *   @li S - Start
 *   @li ADDR(W) - address with W/R bit cleared
 *   @li DATA0 - Data taken from buffer with index 0
 *   @li P - Stop
 */
#define I2C_FLAG_WRITE          0x0001

/**
 * @brief
 *   Indicate plain read sequence: S+ADDR(R)+DATA0+P.
 * @details
 *   @li S - Start
 *   @li ADDR(R) - address with W/R bit set
 *   @li DATA0 - Data read into buffer with index 0
 *   @li P - Stop
 */
#define I2C_FLAG_READ           0x0002

/**
 * @brief
 *   Indicate combined write/read sequence: S+ADDR(W)+DATA0+Sr+ADDR(R)+DATA1+P.
 * @details
 *   @li S - Start
 *   @li Sr - Repeated start
 *   @li ADDR(W) - address with W/R bit cleared
 *   @li ADDR(R) - address with W/R bit set
 *   @li DATAn - Data written from/read into buffer with index n
 *   @li P - Stop
 */
#define I2C_FLAG_WRITE_READ     0x0004

/**
 * @brief
 *   Indicate write sequence using two buffers: S+ADDR(W)+DATA0+DATA1+P.
 * @details
 *   @li S - Start
 *   @li ADDR(W) - address with W/R bit cleared
 *   @li DATAn - Data written from buffer with index n
 *   @li P - Stop
 */
#define I2C_FLAG_WRITE_WRITE    0x0008

/** Use 10 bit address. */
#define I2C_FLAG_10BIT_ADDR     0x0010


/*******************************************************************************
 ********************************   ENUMS   ************************************
 ******************************************************************************/

/** Clock low to high ratio settings. */
typedef enum
{
  i2cClockHLRStandard  = _I2C_CTRL_CLHR_STANDARD,      /**< Ratio is 4:4 */
  i2cClockHLRAsymetric = _I2C_CTRL_CLHR_ASYMMETRIC,    /**< Ratio is 6:3 */
  i2cClockHLRFast      = _I2C_CTRL_CLHR_FAST           /**< Ratio is 11:3 */
} I2C_ClockHLR_TypeDef;


/** Return codes for single master mode transfer function. */
typedef enum
{
  /* In progress code (>0) */
  i2cTransferInProgress = 1,    /**< Transfer in progress. */

  /* Complete code (=0) */
  i2cTransferDone       = 0,    /**< Transfer completed successfully. */

  /* Transfer error codes (<0) */
  i2cTransferNack       = -1,   /**< NACK received during transfer. */
  i2cTransferBusErr     = -2,   /**< Bus error during transfer (misplaced START/STOP). */
  i2cTransferArbLost    = -3,   /**< Arbitration lost during transfer. */
  i2cTransferUsageFault = -4,   /**< Usage fault. */
  i2cTransferSwFault    = -5    /**< SW fault. */
} I2C_TransferReturn_TypeDef;


/*******************************************************************************
 *******************************   STRUCTS   ***********************************
 ******************************************************************************/

/** I2C initialization structure. */
typedef struct
{
  /** Enable I2C peripheral when init completed. */
  bool                 enable;

  /** Set to master (true) or slave (false) mode */
  bool                 master;

  /**
   * I2C reference clock assumed when configuring bus frequency setup.
   * Set it to 0 if currently configurated reference clock shall be used
   * This parameter is only applicable if operating in master mode.
   */
  uint32_t             refFreq;

  /**
   * (Max) I2C bus frequency to use. This parameter is only applicable
   * if operating in master mode.
   */
  uint32_t             freq;

  /** Clock low/high ratio control. */
  I2C_ClockHLR_TypeDef clhr;
} I2C_Init_TypeDef;

/** Suggested default config for I2C init structure. */
#define I2C_INIT_DEFAULT                                                    \
  { true,                    /* Enable when init done */                    \
    true,                    /* Set to master mode */                       \
    0,                       /* Use currently configured reference clock */ \
    I2C_FREQ_STANDARD_MAX,   /* Set to standard rate assuring being */      \
                             /* within I2C spec */                          \
    i2cClockHLRStandard      /* Set to use 4:4 low/high duty cycle */       \
  }


/**
 * @brief
 *   Master mode transfer message structure used to define a complete
 *   I2C transfer sequence (from start to stop).
 * @details
 *   The structure allows for defining the following types of sequences,
 *   please refer to defines for sequence details.
 *   @li #I2C_FLAG_READ - data read into buf[0].data
 *   @li #I2C_FLAG_WRITE - data written from buf[0].data
 *   @li #I2C_FLAG_WRITE_READ - data written from buf[0].data and read
 *     into buf[1].data
 *   @li #I2C_FLAG_WRITE_WRITE - data written from buf[0].data and
 *     buf[1].data
 */
typedef struct
{
  /**
   * @brief
   *   Address to use after (repeated) start.
   * @details
   *   Layout details, A = address bit, X = don't care bit (set to 0):
   *   @li 7 bit address - use format AAAA AAAX.
   *   @li 10 bit address - use format XXXX XAAX AAAA AAAA
   */
  uint16_t addr;

  /** Flags defining sequence type and details, see I2C_FLAG_... defines. */
  uint16_t flags;

  /**
   * Buffers used to hold data to send from or receive into depending
   * on sequence type.
   */
  struct
  {
    /** Buffer used for data to transmit/receive, must be @p len long. */
    uint8_t  *data;

    /**
     * Number of bytes in @p data to send or receive. Notice that when
     * receiving data to this buffer, at least 1 byte must be received.
     * Setting @p len to 0 in the receive case is considered a usage fault.
     * Transmitting 0 bytes is legal, in which case only the address
     * is transmitted after the start condition.
     */
    uint16_t len;
  } buf[2];
} I2C_TransferSeq_TypeDef;


/*******************************************************************************
 *****************************   PROTOTYPES   **********************************
 ******************************************************************************/

uint32_t I2C_BusFreqGet(I2C_TypeDef *i2c);
void I2C_BusFreqSet(I2C_TypeDef *i2c,
                    uint32_t refFreq,
                    uint32_t freq,
                    I2C_ClockHLR_TypeDef type);
void I2C_Enable(I2C_TypeDef *i2c, bool enable);
void I2C_Init(I2C_TypeDef *i2c, const I2C_Init_TypeDef *init);

/***************************************************************************//**
 * @brief
 *   Clear one or more pending I2C interrupts.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @param[in] flags
 *   Pending I2C interrupt source to clear. Use a bitwse logic OR combination of
 *   valid interrupt flags for the I2C module (I2C_IF_nnn).
 ******************************************************************************/
__STATIC_INLINE void I2C_IntClear(I2C_TypeDef *i2c, uint32_t flags)
{
  i2c->IFC = flags;
}


/***************************************************************************//**
 * @brief
 *   Disable one or more I2C interrupts.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @param[in] flags
 *   I2C interrupt sources to disable. Use a bitwise logic OR combination of
 *   valid interrupt flags for the I2C module (I2C_IF_nnn).
 ******************************************************************************/
__STATIC_INLINE void I2C_IntDisable(I2C_TypeDef *i2c, uint32_t flags)
{
  i2c->IEN &= ~(flags);
}


/***************************************************************************//**
 * @brief
 *   Enable one or more I2C interrupts.
 *
 * @note
 *   Depending on the use, a pending interrupt may already be set prior to
 *   enabling the interrupt. Consider using I2C_IntClear() prior to enabling
 *   if such a pending interrupt should be ignored.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @param[in] flags
 *   I2C interrupt sources to enable. Use a bitwise logic OR combination of
 *   valid interrupt flags for the I2C module (I2C_IF_nnn).
 ******************************************************************************/
__STATIC_INLINE void I2C_IntEnable(I2C_TypeDef *i2c, uint32_t flags)
{
  i2c->IEN |= flags;
}


/***************************************************************************//**
 * @brief
 *   Get pending I2C interrupt flags.
 *
 * @note
 *   The event bits are not cleared by the use of this function.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @return
 *   I2C interrupt sources pending. A bitwise logic OR combination of valid
 *   interrupt flags for the I2C module (I2C_IF_nnn).
 ******************************************************************************/
__STATIC_INLINE uint32_t I2C_IntGet(I2C_TypeDef *i2c)
{
  return(i2c->IF);
}


/***************************************************************************//**
 * @brief
 *   Set one or more pending I2C interrupts from SW.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @param[in] flags
 *   I2C interrupt sources to set to pending. Use a bitwise logic OR combination
 *   of valid interrupt flags for the I2C module (I2C_IF_nnn).
 ******************************************************************************/
__STATIC_INLINE void I2C_IntSet(I2C_TypeDef *i2c, uint32_t flags)
{
  i2c->IFS = flags;
}

void I2C_Reset(I2C_TypeDef *i2c);

/***************************************************************************//**
 * @brief
 *   Get slave address used for I2C peripheral (when operating in slave mode).
 *
 * @details
 *   For 10 bit addressing mode, the address is split in two bytes, and only
 *   the first byte setting is fetched, effectively only controlling the 2 most
 *   significant bits of the 10 bit address. Full handling of 10 bit addressing
 *   in slave mode requires additional SW handling.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @return
 *   I2C slave address in use. The 7 most significant bits define the actual
 *   address, the least significant bit is reserved and always returned as 0.
 ******************************************************************************/
__STATIC_INLINE uint8_t I2C_SlaveAddressGet(I2C_TypeDef *i2c)
{
  return((uint8_t)(i2c->SADDR));
}


/***************************************************************************//**
 * @brief
 *   Set slave address to use for I2C peripheral (when operating in slave mode).
 *
 * @details
 *   For 10 bit addressing mode, the address is split in two bytes, and only
 *   the first byte is set, effectively only controlling the 2 most significant
 *   bits of the 10 bit address. Full handling of 10 bit addressing in slave
 *   mode requires additional SW handling.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @param[in] addr
 *   I2C slave address to use. The 7 most significant bits define the actual
 *   address, the least significant bit is reserved and always set to 0.
 ******************************************************************************/
__STATIC_INLINE void I2C_SlaveAddressSet(I2C_TypeDef *i2c, uint8_t addr)
{
  i2c->SADDR = (uint32_t)addr & 0xfe;
}


/***************************************************************************//**
 * @brief
 *   Get slave address mask used for I2C peripheral (when operating in slave
 *   mode).
 *
 * @details
 *   The address mask defines how the comparator works. A bit position with
 *   value 0 means that the corresponding slave address bit is ignored during
 *   comparison (don't care). A bit position with value 1 means that the
 *   corresponding slave address bit must match.
 *
 *   For 10 bit addressing mode, the address is split in two bytes, and only
 *   the mask for the first address byte is fetched, effectively only
 *   controlling the 2 most significant bits of the 10 bit address.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @return
 *   I2C slave address mask in use. The 7 most significant bits define the
 *   actual address mask, the least significant bit is reserved and always
 *   returned as 0.
 ******************************************************************************/
__STATIC_INLINE uint8_t I2C_SlaveAddressMaskGet(I2C_TypeDef *i2c)
{
  return((uint8_t)(i2c->SADDRMASK));
}


/***************************************************************************//**
 * @brief
 *   Set slave address mask used for I2C peripheral (when operating in slave
 *   mode).
 *
 * @details
 *   The address mask defines how the comparator works. A bit position with
 *   value 0 means that the corresponding slave address bit is ignored during
 *   comparison (don't care). A bit position with value 1 means that the
 *   corresponding slave address bit must match.
 *
 *   For 10 bit addressing mode, the address is split in two bytes, and only
 *   the mask for the first address byte is set, effectively only controlling
 *   the 2 most significant bits of the 10 bit address.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @param[in] mask
 *   I2C slave address mask to use. The 7 most significant bits define the
 *   actual address mask, the least significant bit is reserved and should
 *   be 0.
 ******************************************************************************/
__STATIC_INLINE void I2C_SlaveAddressMaskSet(I2C_TypeDef *i2c, uint8_t mask)
{
  i2c->SADDRMASK = (uint32_t)mask & 0xfe;
}


I2C_TransferReturn_TypeDef I2C_Transfer(I2C_TypeDef *i2c);
I2C_TransferReturn_TypeDef I2C_TransferInit(I2C_TypeDef *i2c,
                                            I2C_TransferSeq_TypeDef *seq);

/** @} (end addtogroup I2C) */
/** @} (end addtogroup EM_Library) */

#ifdef __cplusplus
}
#endif

#endif /* __EM_I2C_H */