NXP's driver library for LPC17xx, ported to mbed's online compiler. Not tested! I had to fix a lot of warings and found a couple of pretty obvious bugs, so the chances are there are more. Original: http://ics.nxp.com/support/documents/microcontrollers/zip/lpc17xx.cmsis.driver.library.zip

Dependencies:   mbed

Committer:
igorsk
Date:
Wed Feb 17 16:22:39 2010 +0000
Revision:
0:1063a091a062

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
igorsk 0:1063a091a062 1 /**
igorsk 0:1063a091a062 2 * @file : lpc17xx_i2c.c
igorsk 0:1063a091a062 3 * @brief : Contains all functions support for I2C firmware library on LPC17xx
igorsk 0:1063a091a062 4 * @version : 1.0
igorsk 0:1063a091a062 5 * @date : 9. April. 2009
igorsk 0:1063a091a062 6 * @author : HieuNguyen
igorsk 0:1063a091a062 7 **************************************************************************
igorsk 0:1063a091a062 8 * Software that is described herein is for illustrative purposes only
igorsk 0:1063a091a062 9 * which provides customers with programming information regarding the
igorsk 0:1063a091a062 10 * products. This software is supplied "AS IS" without any warranties.
igorsk 0:1063a091a062 11 * NXP Semiconductors assumes no responsibility or liability for the
igorsk 0:1063a091a062 12 * use of the software, conveys no license or title under any patent,
igorsk 0:1063a091a062 13 * copyright, or mask work right to the product. NXP Semiconductors
igorsk 0:1063a091a062 14 * reserves the right to make changes in the software without
igorsk 0:1063a091a062 15 * notification. NXP Semiconductors also make no representation or
igorsk 0:1063a091a062 16 * warranty that such application will be suitable for the specified
igorsk 0:1063a091a062 17 * use without further testing or modification.
igorsk 0:1063a091a062 18 **********************************************************************/
igorsk 0:1063a091a062 19
igorsk 0:1063a091a062 20 /* Peripheral group ----------------------------------------------------------- */
igorsk 0:1063a091a062 21 /** @addtogroup I2C
igorsk 0:1063a091a062 22 * @{
igorsk 0:1063a091a062 23 */
igorsk 0:1063a091a062 24
igorsk 0:1063a091a062 25 /* Includes ------------------------------------------------------------------- */
igorsk 0:1063a091a062 26 #include "lpc17xx_i2c.h"
igorsk 0:1063a091a062 27 #include "lpc17xx_clkpwr.h"
igorsk 0:1063a091a062 28 #include "lpc17xx_pinsel.h"
igorsk 0:1063a091a062 29
igorsk 0:1063a091a062 30
igorsk 0:1063a091a062 31 /* If this source file built with example, the LPC17xx FW library configuration
igorsk 0:1063a091a062 32 * file in each example directory ("lpc17xx_libcfg.h") must be included,
igorsk 0:1063a091a062 33 * otherwise the default FW library configuration file must be included instead
igorsk 0:1063a091a062 34 */
igorsk 0:1063a091a062 35 #ifdef __BUILD_WITH_EXAMPLE__
igorsk 0:1063a091a062 36 #include "lpc17xx_libcfg.h"
igorsk 0:1063a091a062 37 #else
igorsk 0:1063a091a062 38 #include "lpc17xx_libcfg_default.h"
igorsk 0:1063a091a062 39 #endif /* __BUILD_WITH_EXAMPLE__ */
igorsk 0:1063a091a062 40
igorsk 0:1063a091a062 41
igorsk 0:1063a091a062 42 #ifdef _I2C
igorsk 0:1063a091a062 43
igorsk 0:1063a091a062 44
igorsk 0:1063a091a062 45 /* Private Types -------------------------------------------------------------- */
igorsk 0:1063a091a062 46 /** @defgroup I2C_Private_Types
igorsk 0:1063a091a062 47 * @{
igorsk 0:1063a091a062 48 */
igorsk 0:1063a091a062 49
igorsk 0:1063a091a062 50 /**
igorsk 0:1063a091a062 51 * @brief I2C device configuration structure type
igorsk 0:1063a091a062 52 */
igorsk 0:1063a091a062 53 typedef struct
igorsk 0:1063a091a062 54 {
igorsk 0:1063a091a062 55 uint32_t txrx_setup; /* Transmission setup */
igorsk 0:1063a091a062 56 int32_t dir; /* Current direction phase, 0 - write, 1 - read */
igorsk 0:1063a091a062 57 void (*inthandler)(LPC_I2C_TypeDef *I2Cx); /* Transmission interrupt handler */
igorsk 0:1063a091a062 58 } I2C_CFG_T;
igorsk 0:1063a091a062 59
igorsk 0:1063a091a062 60 /**
igorsk 0:1063a091a062 61 * @}
igorsk 0:1063a091a062 62 */
igorsk 0:1063a091a062 63
igorsk 0:1063a091a062 64 /* Private Variables ---------------------------------------------------------- */
igorsk 0:1063a091a062 65 /**
igorsk 0:1063a091a062 66 * @brief II2C driver data for I2C0, I2C1 and I2C2
igorsk 0:1063a091a062 67 */
igorsk 0:1063a091a062 68 static I2C_CFG_T i2cdat[3];
igorsk 0:1063a091a062 69
igorsk 0:1063a091a062 70
igorsk 0:1063a091a062 71
igorsk 0:1063a091a062 72 /* Private Functions ---------------------------------------------------------- */
igorsk 0:1063a091a062 73 /** @defgroup I2C_Private_Functions
igorsk 0:1063a091a062 74 * @{
igorsk 0:1063a091a062 75 */
igorsk 0:1063a091a062 76
igorsk 0:1063a091a062 77 /* Generate a start condition on I2C bus (in master mode only) */
igorsk 0:1063a091a062 78 static uint32_t I2C_Start (LPC_I2C_TypeDef *I2Cx);
igorsk 0:1063a091a062 79
igorsk 0:1063a091a062 80 /* Generate a stop condition on I2C bus (in master mode only) */
igorsk 0:1063a091a062 81 static void I2C_Stop (LPC_I2C_TypeDef *I2Cx);
igorsk 0:1063a091a062 82
igorsk 0:1063a091a062 83 /* I2C send byte subroutine */
igorsk 0:1063a091a062 84 static uint32_t I2C_SendByte (LPC_I2C_TypeDef *I2Cx, uint8_t databyte);
igorsk 0:1063a091a062 85
igorsk 0:1063a091a062 86 /* I2C get byte subroutine */
igorsk 0:1063a091a062 87 static uint32_t I2C_GetByte (LPC_I2C_TypeDef *I2Cx, uint8_t *retdat, Bool ack);
igorsk 0:1063a091a062 88
igorsk 0:1063a091a062 89 /* I2C interrupt master handler */
igorsk 0:1063a091a062 90 void I2C_MasterHandler (LPC_I2C_TypeDef *I2Cx);
igorsk 0:1063a091a062 91
igorsk 0:1063a091a062 92 /* I2C interrupt master handler */
igorsk 0:1063a091a062 93 void I2C_SlaveHandler (LPC_I2C_TypeDef *I2Cx);
igorsk 0:1063a091a062 94
igorsk 0:1063a091a062 95 /* Enable interrupt for I2C device */
igorsk 0:1063a091a062 96 void I2C_IntCmd (LPC_I2C_TypeDef *I2Cx, FunctionalState NewState);
igorsk 0:1063a091a062 97
igorsk 0:1063a091a062 98 /*--------------------------------------------------------------------------------*/
igorsk 0:1063a091a062 99
igorsk 0:1063a091a062 100 /**
igorsk 0:1063a091a062 101 * @brief Convert from I2C peripheral to number
igorsk 0:1063a091a062 102 */
igorsk 0:1063a091a062 103 static int32_t I2C_getNum(LPC_I2C_TypeDef *I2Cx){
igorsk 0:1063a091a062 104 if (I2Cx == LPC_I2C0) {
igorsk 0:1063a091a062 105 return (0);
igorsk 0:1063a091a062 106 } else if (I2Cx == LPC_I2C1) {
igorsk 0:1063a091a062 107 return (1);
igorsk 0:1063a091a062 108 } else if (I2Cx == LPC_I2C2) {
igorsk 0:1063a091a062 109 return (2);
igorsk 0:1063a091a062 110 }
igorsk 0:1063a091a062 111 return (-1);
igorsk 0:1063a091a062 112 }
igorsk 0:1063a091a062 113
igorsk 0:1063a091a062 114 /***********************************************************************
igorsk 0:1063a091a062 115 * Function: I2C_Start
igorsk 0:1063a091a062 116 * Purpose: Generate a start condition on I2C bus (in master mode only)
igorsk 0:1063a091a062 117 * Parameters:
igorsk 0:1063a091a062 118 * i2cdev: Pointer to I2C register
igorsk 0:1063a091a062 119 * blocking: blocking or none blocking mode
igorsk 0:1063a091a062 120 * Returns: value of I2C status register after generate a start condition
igorsk 0:1063a091a062 121 **********************************************************************/
igorsk 0:1063a091a062 122 static uint32_t I2C_Start (LPC_I2C_TypeDef *I2Cx)
igorsk 0:1063a091a062 123 {
igorsk 0:1063a091a062 124 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 125 I2Cx->I2CONSET = I2C_I2CONSET_STA;
igorsk 0:1063a091a062 126
igorsk 0:1063a091a062 127 // Wait for complete
igorsk 0:1063a091a062 128 while (!(I2Cx->I2CONSET & I2C_I2CONSET_SI));
igorsk 0:1063a091a062 129 I2Cx->I2CONCLR = I2C_I2CONCLR_STAC;
igorsk 0:1063a091a062 130 return (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK);
igorsk 0:1063a091a062 131 }
igorsk 0:1063a091a062 132
igorsk 0:1063a091a062 133
igorsk 0:1063a091a062 134 /***********************************************************************
igorsk 0:1063a091a062 135 * Function: I2C_Stop
igorsk 0:1063a091a062 136 * Purpose: Generate a stop condition on I2C bus (in master mode only)
igorsk 0:1063a091a062 137 * Parameters:
igorsk 0:1063a091a062 138 * I2Cx: Pointer to I2C register
igorsk 0:1063a091a062 139 * Returns: None
igorsk 0:1063a091a062 140 **********************************************************************/
igorsk 0:1063a091a062 141 static void I2C_Stop (LPC_I2C_TypeDef *I2Cx)
igorsk 0:1063a091a062 142 {
igorsk 0:1063a091a062 143
igorsk 0:1063a091a062 144 /* Make sure start bit is not active */
igorsk 0:1063a091a062 145 if (I2Cx->I2CONSET & I2C_I2CONSET_STA)
igorsk 0:1063a091a062 146 {
igorsk 0:1063a091a062 147 I2Cx->I2CONCLR = I2C_I2CONCLR_STAC;
igorsk 0:1063a091a062 148 }
igorsk 0:1063a091a062 149 I2Cx->I2CONSET = I2C_I2CONSET_STO;
igorsk 0:1063a091a062 150 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 151 }
igorsk 0:1063a091a062 152
igorsk 0:1063a091a062 153
igorsk 0:1063a091a062 154 /***********************************************************************
igorsk 0:1063a091a062 155 * Function: I2C_SendByte
igorsk 0:1063a091a062 156 * Purpose: Send a byte
igorsk 0:1063a091a062 157 * Parameters:
igorsk 0:1063a091a062 158 * I2Cx: Pointer to I2C register
igorsk 0:1063a091a062 159 * Returns: value of I2C status register after sending
igorsk 0:1063a091a062 160 **********************************************************************/
igorsk 0:1063a091a062 161 static uint32_t I2C_SendByte (LPC_I2C_TypeDef *I2Cx, uint8_t databyte)
igorsk 0:1063a091a062 162 {
igorsk 0:1063a091a062 163 /* Make sure start bit is not active */
igorsk 0:1063a091a062 164 if (I2Cx->I2CONSET & I2C_I2CONSET_STA)
igorsk 0:1063a091a062 165 {
igorsk 0:1063a091a062 166 I2Cx->I2CONCLR = I2C_I2CONCLR_STAC;
igorsk 0:1063a091a062 167 }
igorsk 0:1063a091a062 168 I2Cx->I2DAT = databyte & I2C_I2DAT_BITMASK;
igorsk 0:1063a091a062 169 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 170
igorsk 0:1063a091a062 171 while (!(I2Cx->I2CONSET & I2C_I2CONSET_SI));
igorsk 0:1063a091a062 172 return (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK);
igorsk 0:1063a091a062 173 }
igorsk 0:1063a091a062 174
igorsk 0:1063a091a062 175
igorsk 0:1063a091a062 176 /***********************************************************************
igorsk 0:1063a091a062 177 * Function: I2C_GetByte
igorsk 0:1063a091a062 178 * Purpose: Get a byte
igorsk 0:1063a091a062 179 * Parameters:
igorsk 0:1063a091a062 180 * I2Cx: Pointer to I2C register
igorsk 0:1063a091a062 181 * Returns: value of I2C status register after receiving
igorsk 0:1063a091a062 182 **********************************************************************/
igorsk 0:1063a091a062 183 static uint32_t I2C_GetByte (LPC_I2C_TypeDef *I2Cx, uint8_t *retdat, Bool ack)
igorsk 0:1063a091a062 184 {
igorsk 0:1063a091a062 185 if (ack == TRUE)
igorsk 0:1063a091a062 186 {
igorsk 0:1063a091a062 187 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 188 }
igorsk 0:1063a091a062 189 else
igorsk 0:1063a091a062 190 {
igorsk 0:1063a091a062 191 I2Cx->I2CONCLR = I2C_I2CONCLR_AAC;
igorsk 0:1063a091a062 192 }
igorsk 0:1063a091a062 193 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 194
igorsk 0:1063a091a062 195 while (!(I2Cx->I2CONSET & I2C_I2CONSET_SI));
igorsk 0:1063a091a062 196 *retdat = (uint8_t) (I2Cx->I2DAT & I2C_I2DAT_BITMASK);
igorsk 0:1063a091a062 197 return (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK);
igorsk 0:1063a091a062 198 }
igorsk 0:1063a091a062 199
igorsk 0:1063a091a062 200
igorsk 0:1063a091a062 201
igorsk 0:1063a091a062 202 /*********************************************************************//**
igorsk 0:1063a091a062 203 * @brief Enable/Disable interrupt for I2C peripheral
igorsk 0:1063a091a062 204 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
igorsk 0:1063a091a062 205 * @param[in] NewState New State of I2C peripheral interrupt in NVIC core
igorsk 0:1063a091a062 206 * should be:
igorsk 0:1063a091a062 207 * - ENABLE: enable interrupt for this I2C peripheral
igorsk 0:1063a091a062 208 * - DISABLE: disable interrupt for this I2C peripheral
igorsk 0:1063a091a062 209 * @return None
igorsk 0:1063a091a062 210 **********************************************************************/
igorsk 0:1063a091a062 211 void I2C_IntCmd (LPC_I2C_TypeDef *I2Cx, FunctionalState NewState)
igorsk 0:1063a091a062 212 {
igorsk 0:1063a091a062 213 if (NewState == ENABLE)
igorsk 0:1063a091a062 214 {
igorsk 0:1063a091a062 215 if(I2Cx == LPC_I2C0)
igorsk 0:1063a091a062 216 {
igorsk 0:1063a091a062 217 NVIC_EnableIRQ(I2C0_IRQn);
igorsk 0:1063a091a062 218 }
igorsk 0:1063a091a062 219 else if (I2Cx == LPC_I2C1)
igorsk 0:1063a091a062 220 {
igorsk 0:1063a091a062 221 NVIC_EnableIRQ(I2C1_IRQn);
igorsk 0:1063a091a062 222 }
igorsk 0:1063a091a062 223 else if (I2Cx == LPC_I2C2)
igorsk 0:1063a091a062 224 {
igorsk 0:1063a091a062 225 NVIC_EnableIRQ(I2C2_IRQn);
igorsk 0:1063a091a062 226 }
igorsk 0:1063a091a062 227 }
igorsk 0:1063a091a062 228 else
igorsk 0:1063a091a062 229 {
igorsk 0:1063a091a062 230 if(I2Cx == LPC_I2C0)
igorsk 0:1063a091a062 231 {
igorsk 0:1063a091a062 232 NVIC_DisableIRQ(I2C0_IRQn);
igorsk 0:1063a091a062 233 }
igorsk 0:1063a091a062 234 else if (I2Cx == LPC_I2C1)
igorsk 0:1063a091a062 235 {
igorsk 0:1063a091a062 236 NVIC_DisableIRQ(I2C1_IRQn);
igorsk 0:1063a091a062 237 }
igorsk 0:1063a091a062 238 else if (I2Cx == LPC_I2C2)
igorsk 0:1063a091a062 239 {
igorsk 0:1063a091a062 240 NVIC_DisableIRQ(I2C2_IRQn);
igorsk 0:1063a091a062 241 }
igorsk 0:1063a091a062 242 }
igorsk 0:1063a091a062 243 return;
igorsk 0:1063a091a062 244 }
igorsk 0:1063a091a062 245
igorsk 0:1063a091a062 246
igorsk 0:1063a091a062 247 /*********************************************************************//**
igorsk 0:1063a091a062 248 * @brief General Master Interrupt handler for I2C peripheral
igorsk 0:1063a091a062 249 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
igorsk 0:1063a091a062 250 * @return None
igorsk 0:1063a091a062 251 **********************************************************************/
igorsk 0:1063a091a062 252 void I2C_MasterHandler (LPC_I2C_TypeDef *I2Cx)
igorsk 0:1063a091a062 253 {
igorsk 0:1063a091a062 254 int32_t tmp;
igorsk 0:1063a091a062 255 uint8_t returnCode;
igorsk 0:1063a091a062 256 I2C_M_SETUP_Type *txrx_setup;
igorsk 0:1063a091a062 257
igorsk 0:1063a091a062 258 tmp = I2C_getNum(I2Cx);
igorsk 0:1063a091a062 259 txrx_setup = (I2C_M_SETUP_Type *) i2cdat[tmp].txrx_setup;
igorsk 0:1063a091a062 260
igorsk 0:1063a091a062 261 returnCode = (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK);
igorsk 0:1063a091a062 262 // Save current status
igorsk 0:1063a091a062 263 txrx_setup->status = returnCode;
igorsk 0:1063a091a062 264 // there's no relevant information
igorsk 0:1063a091a062 265 if (returnCode == I2C_I2STAT_NO_INF){
igorsk 0:1063a091a062 266 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 267 return;
igorsk 0:1063a091a062 268 }
igorsk 0:1063a091a062 269
igorsk 0:1063a091a062 270 /* ----------------------------- TRANSMIT PHASE --------------------------*/
igorsk 0:1063a091a062 271 if (i2cdat[tmp].dir == 0){
igorsk 0:1063a091a062 272 switch (returnCode)
igorsk 0:1063a091a062 273 {
igorsk 0:1063a091a062 274 /* A start/repeat start condition has been transmitted -------------------*/
igorsk 0:1063a091a062 275 case I2C_I2STAT_M_TX_START:
igorsk 0:1063a091a062 276 case I2C_I2STAT_M_TX_RESTART:
igorsk 0:1063a091a062 277 I2Cx->I2CONCLR = I2C_I2CONCLR_STAC;
igorsk 0:1063a091a062 278 /*
igorsk 0:1063a091a062 279 * If there's any transmit data, then start to
igorsk 0:1063a091a062 280 * send SLA+W right now, otherwise check whether if there's
igorsk 0:1063a091a062 281 * any receive data for next state.
igorsk 0:1063a091a062 282 */
igorsk 0:1063a091a062 283 if ((txrx_setup->tx_data != NULL) && (txrx_setup->tx_length != 0)){
igorsk 0:1063a091a062 284 I2Cx->I2DAT = (txrx_setup->sl_addr7bit << 1);
igorsk 0:1063a091a062 285 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 286 } else {
igorsk 0:1063a091a062 287 goto next_stage;
igorsk 0:1063a091a062 288 }
igorsk 0:1063a091a062 289 break;
igorsk 0:1063a091a062 290
igorsk 0:1063a091a062 291 /* SLA+W has been transmitted, ACK has been received ----------------------*/
igorsk 0:1063a091a062 292 case I2C_I2STAT_M_TX_SLAW_ACK:
igorsk 0:1063a091a062 293 /* Data has been transmitted, ACK has been received */
igorsk 0:1063a091a062 294 case I2C_I2STAT_M_TX_DAT_ACK:
igorsk 0:1063a091a062 295 /* Send more data */
igorsk 0:1063a091a062 296 if ((txrx_setup->tx_count < txrx_setup->tx_length) \
igorsk 0:1063a091a062 297 && (txrx_setup->tx_data != NULL)){
igorsk 0:1063a091a062 298 I2Cx->I2DAT = *(uint8_t *)(txrx_setup->tx_data + txrx_setup->tx_count);
igorsk 0:1063a091a062 299 txrx_setup->tx_count++;
igorsk 0:1063a091a062 300 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 301 }
igorsk 0:1063a091a062 302 // no more data, switch to next stage
igorsk 0:1063a091a062 303 else {
igorsk 0:1063a091a062 304 next_stage:
igorsk 0:1063a091a062 305 // change direction
igorsk 0:1063a091a062 306 i2cdat[tmp].dir = 1;
igorsk 0:1063a091a062 307 // Check if any data to receive
igorsk 0:1063a091a062 308 if ((txrx_setup->rx_length != 0) && (txrx_setup->rx_data != NULL)){
igorsk 0:1063a091a062 309 // check whether if we need to issue an repeat start
igorsk 0:1063a091a062 310 if ((txrx_setup->tx_length != 0) && (txrx_setup->tx_data != NULL)){
igorsk 0:1063a091a062 311 // Send out an repeat start command
igorsk 0:1063a091a062 312 I2Cx->I2CONSET = I2C_I2CONSET_STA;
igorsk 0:1063a091a062 313 I2Cx->I2CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 314 }
igorsk 0:1063a091a062 315 // Don't need issue an repeat start, just goto send SLA+R
igorsk 0:1063a091a062 316 else {
igorsk 0:1063a091a062 317 goto send_slar;
igorsk 0:1063a091a062 318 }
igorsk 0:1063a091a062 319 }
igorsk 0:1063a091a062 320 // no more data send, the go to end stage now
igorsk 0:1063a091a062 321 else {
igorsk 0:1063a091a062 322 // success, goto end stage
igorsk 0:1063a091a062 323 txrx_setup->status |= I2C_SETUP_STATUS_DONE;
igorsk 0:1063a091a062 324 goto end_stage;
igorsk 0:1063a091a062 325 }
igorsk 0:1063a091a062 326 }
igorsk 0:1063a091a062 327 break;
igorsk 0:1063a091a062 328
igorsk 0:1063a091a062 329 /* SLA+W has been transmitted, NACK has been received ----------------------*/
igorsk 0:1063a091a062 330 case I2C_I2STAT_M_TX_SLAW_NACK:
igorsk 0:1063a091a062 331 /* Data has been transmitted, NACK has been received -----------------------*/
igorsk 0:1063a091a062 332 case I2C_I2STAT_M_TX_DAT_NACK:
igorsk 0:1063a091a062 333 // update status
igorsk 0:1063a091a062 334 txrx_setup->status |= I2C_SETUP_STATUS_NOACKF;
igorsk 0:1063a091a062 335 goto retry;
igorsk 0:1063a091a062 336 /* Arbitration lost in SLA+R/W or Data bytes -------------------------------*/
igorsk 0:1063a091a062 337 case I2C_I2STAT_M_TX_ARB_LOST:
igorsk 0:1063a091a062 338 // update status
igorsk 0:1063a091a062 339 txrx_setup->status |= I2C_SETUP_STATUS_ARBF;
igorsk 0:1063a091a062 340 default:
igorsk 0:1063a091a062 341 goto retry;
igorsk 0:1063a091a062 342 }
igorsk 0:1063a091a062 343 }
igorsk 0:1063a091a062 344
igorsk 0:1063a091a062 345 /* ----------------------------- RECEIVE PHASE --------------------------*/
igorsk 0:1063a091a062 346 else if (i2cdat[tmp].dir == 1){
igorsk 0:1063a091a062 347 switch (returnCode){
igorsk 0:1063a091a062 348 /* A start/repeat start condition has been transmitted ---------------------*/
igorsk 0:1063a091a062 349 case I2C_I2STAT_M_RX_START:
igorsk 0:1063a091a062 350 case I2C_I2STAT_M_RX_RESTART:
igorsk 0:1063a091a062 351 I2Cx->I2CONCLR = I2C_I2CONCLR_STAC;
igorsk 0:1063a091a062 352 /*
igorsk 0:1063a091a062 353 * If there's any receive data, then start to
igorsk 0:1063a091a062 354 * send SLA+R right now, otherwise check whether if there's
igorsk 0:1063a091a062 355 * any receive data for end of state.
igorsk 0:1063a091a062 356 */
igorsk 0:1063a091a062 357 if ((txrx_setup->rx_data != NULL) && (txrx_setup->rx_length != 0)){
igorsk 0:1063a091a062 358 send_slar:
igorsk 0:1063a091a062 359 I2Cx->I2DAT = (txrx_setup->sl_addr7bit << 1) | 0x01;
igorsk 0:1063a091a062 360 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 361 } else {
igorsk 0:1063a091a062 362 // Success, goto end stage
igorsk 0:1063a091a062 363 txrx_setup->status |= I2C_SETUP_STATUS_DONE;
igorsk 0:1063a091a062 364 goto end_stage;
igorsk 0:1063a091a062 365 }
igorsk 0:1063a091a062 366 break;
igorsk 0:1063a091a062 367
igorsk 0:1063a091a062 368 /* SLA+R has been transmitted, ACK has been received -----------------*/
igorsk 0:1063a091a062 369 case I2C_I2STAT_M_RX_SLAR_ACK:
igorsk 0:1063a091a062 370 if (txrx_setup->rx_count < (txrx_setup->rx_length - 1)) {
igorsk 0:1063a091a062 371 /*Data will be received, ACK will be return*/
igorsk 0:1063a091a062 372 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 373 }
igorsk 0:1063a091a062 374 else {
igorsk 0:1063a091a062 375 /*Last data will be received, NACK will be return*/
igorsk 0:1063a091a062 376 I2Cx->I2CONCLR = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 377 }
igorsk 0:1063a091a062 378 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 379 break;
igorsk 0:1063a091a062 380
igorsk 0:1063a091a062 381 /* Data has been received, ACK has been returned ----------------------*/
igorsk 0:1063a091a062 382 case I2C_I2STAT_M_RX_DAT_ACK:
igorsk 0:1063a091a062 383 // Note save data and increase counter first, then check later
igorsk 0:1063a091a062 384 /* Save data */
igorsk 0:1063a091a062 385 if ((txrx_setup->rx_data != NULL) && (txrx_setup->rx_count < txrx_setup->rx_length)){
igorsk 0:1063a091a062 386 *(uint8_t *)(txrx_setup->rx_data + txrx_setup->rx_count) = (I2Cx->I2DAT & I2C_I2DAT_BITMASK);
igorsk 0:1063a091a062 387 txrx_setup->rx_count++;
igorsk 0:1063a091a062 388 }
igorsk 0:1063a091a062 389 if (txrx_setup->rx_count < (txrx_setup->rx_length - 1)) {
igorsk 0:1063a091a062 390 /*Data will be received, ACK will be return*/
igorsk 0:1063a091a062 391 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 392 }
igorsk 0:1063a091a062 393 else {
igorsk 0:1063a091a062 394 /*Last data will be received, NACK will be return*/
igorsk 0:1063a091a062 395 I2Cx->I2CONCLR = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 396 }
igorsk 0:1063a091a062 397
igorsk 0:1063a091a062 398 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 399 break;
igorsk 0:1063a091a062 400
igorsk 0:1063a091a062 401 /* Data has been received, NACK has been return -------------------------*/
igorsk 0:1063a091a062 402 case I2C_I2STAT_M_RX_DAT_NACK:
igorsk 0:1063a091a062 403 /* Save the last data */
igorsk 0:1063a091a062 404 if ((txrx_setup->rx_data != NULL) && (txrx_setup->rx_count < txrx_setup->rx_length)){
igorsk 0:1063a091a062 405 *(uint8_t *)(txrx_setup->rx_data + txrx_setup->rx_count) = (I2Cx->I2DAT & I2C_I2DAT_BITMASK);
igorsk 0:1063a091a062 406 txrx_setup->rx_count++;
igorsk 0:1063a091a062 407 }
igorsk 0:1063a091a062 408 // success, go to end stage
igorsk 0:1063a091a062 409 txrx_setup->status |= I2C_SETUP_STATUS_DONE;
igorsk 0:1063a091a062 410 goto end_stage;
igorsk 0:1063a091a062 411
igorsk 0:1063a091a062 412 /* SLA+R has been transmitted, NACK has been received ------------------*/
igorsk 0:1063a091a062 413 case I2C_I2STAT_M_RX_SLAR_NACK:
igorsk 0:1063a091a062 414 // update status
igorsk 0:1063a091a062 415 txrx_setup->status |= I2C_SETUP_STATUS_NOACKF;
igorsk 0:1063a091a062 416 goto retry;
igorsk 0:1063a091a062 417
igorsk 0:1063a091a062 418 /* Arbitration lost ----------------------------------------------------*/
igorsk 0:1063a091a062 419 case I2C_I2STAT_M_RX_ARB_LOST:
igorsk 0:1063a091a062 420 // update status
igorsk 0:1063a091a062 421 txrx_setup->status |= I2C_SETUP_STATUS_ARBF;
igorsk 0:1063a091a062 422 default:
igorsk 0:1063a091a062 423 retry:
igorsk 0:1063a091a062 424 // check if retransmission is available
igorsk 0:1063a091a062 425 if (txrx_setup->retransmissions_count < txrx_setup->retransmissions_max){
igorsk 0:1063a091a062 426 // Clear tx count
igorsk 0:1063a091a062 427 txrx_setup->tx_count = 0;
igorsk 0:1063a091a062 428 I2Cx->I2CONSET = I2C_I2CONSET_STA;
igorsk 0:1063a091a062 429 I2Cx->I2CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 430 txrx_setup->retransmissions_count++;
igorsk 0:1063a091a062 431 }
igorsk 0:1063a091a062 432 // End of stage
igorsk 0:1063a091a062 433 else {
igorsk 0:1063a091a062 434 end_stage:
igorsk 0:1063a091a062 435 // Disable interrupt
igorsk 0:1063a091a062 436 I2C_IntCmd(I2Cx, DISABLE);
igorsk 0:1063a091a062 437 // Send stop
igorsk 0:1063a091a062 438 I2C_Stop(I2Cx);
igorsk 0:1063a091a062 439 // Call callback if installed
igorsk 0:1063a091a062 440 if (txrx_setup->callback != NULL){
igorsk 0:1063a091a062 441 txrx_setup->callback();
igorsk 0:1063a091a062 442 }
igorsk 0:1063a091a062 443 }
igorsk 0:1063a091a062 444 break;
igorsk 0:1063a091a062 445 }
igorsk 0:1063a091a062 446 }
igorsk 0:1063a091a062 447 }
igorsk 0:1063a091a062 448
igorsk 0:1063a091a062 449
igorsk 0:1063a091a062 450 /*********************************************************************//**
igorsk 0:1063a091a062 451 * @brief General Slave Interrupt handler for I2C peripheral
igorsk 0:1063a091a062 452 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
igorsk 0:1063a091a062 453 * @return None
igorsk 0:1063a091a062 454 **********************************************************************/
igorsk 0:1063a091a062 455 void I2C_SlaveHandler (LPC_I2C_TypeDef *I2Cx)
igorsk 0:1063a091a062 456 {
igorsk 0:1063a091a062 457 int32_t tmp;
igorsk 0:1063a091a062 458 uint8_t returnCode;
igorsk 0:1063a091a062 459 I2C_S_SETUP_Type *txrx_setup;
igorsk 0:1063a091a062 460 uint32_t timeout;
igorsk 0:1063a091a062 461
igorsk 0:1063a091a062 462 tmp = I2C_getNum(I2Cx);
igorsk 0:1063a091a062 463 txrx_setup = (I2C_S_SETUP_Type *) i2cdat[tmp].txrx_setup;
igorsk 0:1063a091a062 464
igorsk 0:1063a091a062 465 returnCode = (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK);
igorsk 0:1063a091a062 466 // Save current status
igorsk 0:1063a091a062 467 txrx_setup->status = returnCode;
igorsk 0:1063a091a062 468 // there's no relevant information
igorsk 0:1063a091a062 469 if (returnCode == I2C_I2STAT_NO_INF){
igorsk 0:1063a091a062 470 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 471 return;
igorsk 0:1063a091a062 472 }
igorsk 0:1063a091a062 473
igorsk 0:1063a091a062 474
igorsk 0:1063a091a062 475 switch (returnCode)
igorsk 0:1063a091a062 476 {
igorsk 0:1063a091a062 477
igorsk 0:1063a091a062 478 /* No status information */
igorsk 0:1063a091a062 479 case I2C_I2STAT_NO_INF:
igorsk 0:1063a091a062 480 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 481 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 482 break;
igorsk 0:1063a091a062 483
igorsk 0:1063a091a062 484 /* Reading phase -------------------------------------------------------- */
igorsk 0:1063a091a062 485 /* Own SLA+R has been received, ACK has been returned */
igorsk 0:1063a091a062 486 case I2C_I2STAT_S_RX_SLAW_ACK:
igorsk 0:1063a091a062 487 /* General call address has been received, ACK has been returned */
igorsk 0:1063a091a062 488 case I2C_I2STAT_S_RX_GENCALL_ACK:
igorsk 0:1063a091a062 489 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 490 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 491 break;
igorsk 0:1063a091a062 492
igorsk 0:1063a091a062 493 /* Previously addressed with own SLA;
igorsk 0:1063a091a062 494 * DATA byte has been received;
igorsk 0:1063a091a062 495 * ACK has been returned */
igorsk 0:1063a091a062 496 case I2C_I2STAT_S_RX_PRE_SLA_DAT_ACK:
igorsk 0:1063a091a062 497 /* DATA has been received, ACK hasn been return */
igorsk 0:1063a091a062 498 case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_ACK:
igorsk 0:1063a091a062 499 /*
igorsk 0:1063a091a062 500 * All data bytes that over-flow the specified receive
igorsk 0:1063a091a062 501 * data length, just ignore them.
igorsk 0:1063a091a062 502 */
igorsk 0:1063a091a062 503 if ((txrx_setup->rx_count < txrx_setup->rx_length) \
igorsk 0:1063a091a062 504 && (txrx_setup->rx_data != NULL)){
igorsk 0:1063a091a062 505 *(uint8_t *)(txrx_setup->rx_data + txrx_setup->rx_count) = (uint8_t)I2Cx->I2DAT;
igorsk 0:1063a091a062 506 txrx_setup->rx_count++;
igorsk 0:1063a091a062 507 }
igorsk 0:1063a091a062 508 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 509 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 510 break;
igorsk 0:1063a091a062 511
igorsk 0:1063a091a062 512 /* Previously addressed with own SLA;
igorsk 0:1063a091a062 513 * DATA byte has been received;
igorsk 0:1063a091a062 514 * NOT ACK has been returned */
igorsk 0:1063a091a062 515 case I2C_I2STAT_S_RX_PRE_SLA_DAT_NACK:
igorsk 0:1063a091a062 516 /* DATA has been received, NOT ACK has been returned */
igorsk 0:1063a091a062 517 case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_NACK:
igorsk 0:1063a091a062 518 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 519 break;
igorsk 0:1063a091a062 520
igorsk 0:1063a091a062 521 /*
igorsk 0:1063a091a062 522 * Note that: Return code only let us know a stop condition mixed
igorsk 0:1063a091a062 523 * with a repeat start condition in the same code value.
igorsk 0:1063a091a062 524 * So we should provide a time-out. In case this is really a stop
igorsk 0:1063a091a062 525 * condition, this will return back after time out condition. Otherwise,
igorsk 0:1063a091a062 526 * next session that is slave receive data will be completed.
igorsk 0:1063a091a062 527 */
igorsk 0:1063a091a062 528
igorsk 0:1063a091a062 529 /* A Stop or a repeat start condition */
igorsk 0:1063a091a062 530 case I2C_I2STAT_S_RX_STA_STO_SLVREC_SLVTRX:
igorsk 0:1063a091a062 531 // Temporally lock the interrupt for timeout condition
igorsk 0:1063a091a062 532 I2C_IntCmd(I2Cx, DISABLE);
igorsk 0:1063a091a062 533 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 534 // enable time out
igorsk 0:1063a091a062 535 timeout = I2C_SLAVE_TIME_OUT;
igorsk 0:1063a091a062 536 while(1){
igorsk 0:1063a091a062 537 if (I2Cx->I2CONSET & I2C_I2CONSET_SI){
igorsk 0:1063a091a062 538 // re-Enable interrupt
igorsk 0:1063a091a062 539 I2C_IntCmd(I2Cx, ENABLE);
igorsk 0:1063a091a062 540 break;
igorsk 0:1063a091a062 541 } else {
igorsk 0:1063a091a062 542 timeout--;
igorsk 0:1063a091a062 543 if (timeout == 0){
igorsk 0:1063a091a062 544 // timeout occur, it's really a stop condition
igorsk 0:1063a091a062 545 txrx_setup->status |= I2C_SETUP_STATUS_DONE;
igorsk 0:1063a091a062 546 goto s_int_end;
igorsk 0:1063a091a062 547 }
igorsk 0:1063a091a062 548 }
igorsk 0:1063a091a062 549 }
igorsk 0:1063a091a062 550 break;
igorsk 0:1063a091a062 551
igorsk 0:1063a091a062 552 /* Writing phase -------------------------------------------------------- */
igorsk 0:1063a091a062 553 /* Own SLA+R has been received, ACK has been returned */
igorsk 0:1063a091a062 554 case I2C_I2STAT_S_TX_SLAR_ACK:
igorsk 0:1063a091a062 555 /* Data has been transmitted, ACK has been received */
igorsk 0:1063a091a062 556 case I2C_I2STAT_S_TX_DAT_ACK:
igorsk 0:1063a091a062 557 /*
igorsk 0:1063a091a062 558 * All data bytes that over-flow the specified receive
igorsk 0:1063a091a062 559 * data length, just ignore them.
igorsk 0:1063a091a062 560 */
igorsk 0:1063a091a062 561 if ((txrx_setup->tx_count < txrx_setup->tx_length) \
igorsk 0:1063a091a062 562 && (txrx_setup->tx_data != NULL)){
igorsk 0:1063a091a062 563 I2Cx->I2DAT = *(uint8_t *) (txrx_setup->tx_data + txrx_setup->tx_count);
igorsk 0:1063a091a062 564 txrx_setup->tx_count++;
igorsk 0:1063a091a062 565 }
igorsk 0:1063a091a062 566 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 567 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 568 break;
igorsk 0:1063a091a062 569
igorsk 0:1063a091a062 570 /* Data has been transmitted, NACK has been received,
igorsk 0:1063a091a062 571 * that means there's no more data to send, exit now */
igorsk 0:1063a091a062 572 /*
igorsk 0:1063a091a062 573 * Note: Don't wait for stop event since in slave transmit mode,
igorsk 0:1063a091a062 574 * since there no proof lets us know when a stop signal has been received
igorsk 0:1063a091a062 575 * on slave side.
igorsk 0:1063a091a062 576 */
igorsk 0:1063a091a062 577 case I2C_I2STAT_S_TX_DAT_NACK:
igorsk 0:1063a091a062 578 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 579 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 580 txrx_setup->status |= I2C_SETUP_STATUS_DONE;
igorsk 0:1063a091a062 581 goto s_int_end;
igorsk 0:1063a091a062 582
igorsk 0:1063a091a062 583 // Other status must be captured
igorsk 0:1063a091a062 584 default:
igorsk 0:1063a091a062 585 s_int_end:
igorsk 0:1063a091a062 586 // Disable interrupt
igorsk 0:1063a091a062 587 I2C_IntCmd(I2Cx, DISABLE);
igorsk 0:1063a091a062 588 I2Cx->I2CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC;
igorsk 0:1063a091a062 589 // Call callback if installed
igorsk 0:1063a091a062 590 if (txrx_setup->callback != NULL){
igorsk 0:1063a091a062 591 txrx_setup->callback();
igorsk 0:1063a091a062 592 }
igorsk 0:1063a091a062 593 break;
igorsk 0:1063a091a062 594 }
igorsk 0:1063a091a062 595 }
igorsk 0:1063a091a062 596
igorsk 0:1063a091a062 597 /**
igorsk 0:1063a091a062 598 * @}
igorsk 0:1063a091a062 599 */
igorsk 0:1063a091a062 600
igorsk 0:1063a091a062 601
igorsk 0:1063a091a062 602 /* Public Functions ----------------------------------------------------------- */
igorsk 0:1063a091a062 603 /** @addtogroup I2C_Public_Functions
igorsk 0:1063a091a062 604 * @{
igorsk 0:1063a091a062 605 */
igorsk 0:1063a091a062 606
igorsk 0:1063a091a062 607 /*********************************************************************//**
igorsk 0:1063a091a062 608 * @brief Setup clock rate for I2C peripheral
igorsk 0:1063a091a062 609 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
igorsk 0:1063a091a062 610 * @param[in] target_clock : clock of SSP (Hz)
igorsk 0:1063a091a062 611 * @return None
igorsk 0:1063a091a062 612 ***********************************************************************/
igorsk 0:1063a091a062 613 void I2C_SetClock (LPC_I2C_TypeDef *I2Cx, uint32_t target_clock)
igorsk 0:1063a091a062 614 {
igorsk 0:1063a091a062 615 uint32_t temp=0;
igorsk 0:1063a091a062 616
igorsk 0:1063a091a062 617 CHECK_PARAM(PARAM_I2Cx(I2Cx));
igorsk 0:1063a091a062 618
igorsk 0:1063a091a062 619 // Get PCLK of I2C controller
igorsk 0:1063a091a062 620 if (I2Cx == LPC_I2C0)
igorsk 0:1063a091a062 621 {
igorsk 0:1063a091a062 622 temp = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_I2C0) / target_clock;
igorsk 0:1063a091a062 623 }
igorsk 0:1063a091a062 624 else if (I2Cx == LPC_I2C1)
igorsk 0:1063a091a062 625 {
igorsk 0:1063a091a062 626 temp = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_I2C1) / target_clock;
igorsk 0:1063a091a062 627 }
igorsk 0:1063a091a062 628 else if (I2Cx == LPC_I2C2)
igorsk 0:1063a091a062 629 {
igorsk 0:1063a091a062 630 temp = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_I2C1) / target_clock;
igorsk 0:1063a091a062 631 }
igorsk 0:1063a091a062 632
igorsk 0:1063a091a062 633 /* Set the I2C clock value to register */
igorsk 0:1063a091a062 634 I2Cx->I2SCLH = (uint32_t)(temp / 2);
igorsk 0:1063a091a062 635 I2Cx->I2SCLL = (uint32_t)(temp - I2Cx->I2SCLH);
igorsk 0:1063a091a062 636 }
igorsk 0:1063a091a062 637
igorsk 0:1063a091a062 638
igorsk 0:1063a091a062 639 /*********************************************************************//**
igorsk 0:1063a091a062 640 * @brief De-initializes the I2C peripheral registers to their
igorsk 0:1063a091a062 641 * default reset values.
igorsk 0:1063a091a062 642 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
igorsk 0:1063a091a062 643 * @return None
igorsk 0:1063a091a062 644 **********************************************************************/
igorsk 0:1063a091a062 645 void I2C_DeInit(LPC_I2C_TypeDef* I2Cx)
igorsk 0:1063a091a062 646 {
igorsk 0:1063a091a062 647 CHECK_PARAM(PARAM_I2Cx(I2Cx));
igorsk 0:1063a091a062 648
igorsk 0:1063a091a062 649 /* Disable I2C control */
igorsk 0:1063a091a062 650 I2Cx->I2CONCLR = I2C_I2CONCLR_I2ENC;
igorsk 0:1063a091a062 651
igorsk 0:1063a091a062 652 if (I2Cx==LPC_I2C0)
igorsk 0:1063a091a062 653 {
igorsk 0:1063a091a062 654 /* Disable power for I2C0 module */
igorsk 0:1063a091a062 655 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCI2C0, DISABLE);
igorsk 0:1063a091a062 656 }
igorsk 0:1063a091a062 657 else if (I2Cx==LPC_I2C1)
igorsk 0:1063a091a062 658 {
igorsk 0:1063a091a062 659 /* Disable power for I2C1 module */
igorsk 0:1063a091a062 660 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCI2C1, DISABLE);
igorsk 0:1063a091a062 661 }
igorsk 0:1063a091a062 662 else if (I2Cx==LPC_I2C2)
igorsk 0:1063a091a062 663 {
igorsk 0:1063a091a062 664 /* Disable power for I2C2 module */
igorsk 0:1063a091a062 665 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCI2C2, DISABLE);
igorsk 0:1063a091a062 666 }
igorsk 0:1063a091a062 667 }
igorsk 0:1063a091a062 668
igorsk 0:1063a091a062 669
igorsk 0:1063a091a062 670 /********************************************************************//**
igorsk 0:1063a091a062 671 * @brief Initializes the I2Cx peripheral with specified parameter.
igorsk 0:1063a091a062 672 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
igorsk 0:1063a091a062 673 * @param[in] clockrate Target clock rate value to initialized I2C
igorsk 0:1063a091a062 674 * peripheral
igorsk 0:1063a091a062 675 * @return None
igorsk 0:1063a091a062 676 *********************************************************************/
igorsk 0:1063a091a062 677 void I2C_Init(LPC_I2C_TypeDef *I2Cx, uint32_t clockrate)
igorsk 0:1063a091a062 678 {
igorsk 0:1063a091a062 679 CHECK_PARAM(PARAM_I2Cx(I2Cx));
igorsk 0:1063a091a062 680
igorsk 0:1063a091a062 681 if (I2Cx==LPC_I2C0)
igorsk 0:1063a091a062 682 {
igorsk 0:1063a091a062 683 /* Set up clock and power for I2C0 module */
igorsk 0:1063a091a062 684 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCI2C0, ENABLE);
igorsk 0:1063a091a062 685 /* As default, peripheral clock for I2C0 module
igorsk 0:1063a091a062 686 * is set to FCCLK / 2 */
igorsk 0:1063a091a062 687 CLKPWR_SetPCLKDiv(CLKPWR_PCLKSEL_I2C0, CLKPWR_PCLKSEL_CCLK_DIV_2);
igorsk 0:1063a091a062 688 }
igorsk 0:1063a091a062 689 else if (I2Cx==LPC_I2C1)
igorsk 0:1063a091a062 690 {
igorsk 0:1063a091a062 691 /* Set up clock and power for I2C1 module */
igorsk 0:1063a091a062 692 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCI2C1, ENABLE);
igorsk 0:1063a091a062 693 /* As default, peripheral clock for I2C1 module
igorsk 0:1063a091a062 694 * is set to FCCLK / 2 */
igorsk 0:1063a091a062 695 CLKPWR_SetPCLKDiv(CLKPWR_PCLKSEL_I2C1, CLKPWR_PCLKSEL_CCLK_DIV_2);
igorsk 0:1063a091a062 696 }
igorsk 0:1063a091a062 697 else if (I2Cx==LPC_I2C2)
igorsk 0:1063a091a062 698 {
igorsk 0:1063a091a062 699 /* Set up clock and power for I2C2 module */
igorsk 0:1063a091a062 700 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCI2C2, ENABLE);
igorsk 0:1063a091a062 701 /* As default, peripheral clock for I2C2 module
igorsk 0:1063a091a062 702 * is set to FCCLK / 2 */
igorsk 0:1063a091a062 703 CLKPWR_SetPCLKDiv(CLKPWR_PCLKSEL_I2C2, CLKPWR_PCLKSEL_CCLK_DIV_2);
igorsk 0:1063a091a062 704 }
igorsk 0:1063a091a062 705 else {
igorsk 0:1063a091a062 706 // Up-Support this device
igorsk 0:1063a091a062 707 return;
igorsk 0:1063a091a062 708 }
igorsk 0:1063a091a062 709
igorsk 0:1063a091a062 710 /* Set clock rate */
igorsk 0:1063a091a062 711 I2C_SetClock(I2Cx, clockrate);
igorsk 0:1063a091a062 712 /* Set I2C operation to default */
igorsk 0:1063a091a062 713 I2Cx->I2CONCLR = (I2C_I2CONCLR_AAC | I2C_I2CONCLR_STAC | I2C_I2CONCLR_I2ENC);
igorsk 0:1063a091a062 714 }
igorsk 0:1063a091a062 715
igorsk 0:1063a091a062 716
igorsk 0:1063a091a062 717 /*********************************************************************//**
igorsk 0:1063a091a062 718 * @brief Enable or disable I2C peripheral's operation
igorsk 0:1063a091a062 719 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
igorsk 0:1063a091a062 720 * @param[in] NewState New State of I2Cx peripheral's operation
igorsk 0:1063a091a062 721 * @return none
igorsk 0:1063a091a062 722 **********************************************************************/
igorsk 0:1063a091a062 723 void I2C_Cmd(LPC_I2C_TypeDef* I2Cx, FunctionalState NewState)
igorsk 0:1063a091a062 724 {
igorsk 0:1063a091a062 725 CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));
igorsk 0:1063a091a062 726 CHECK_PARAM(PARAM_I2Cx(I2Cx));
igorsk 0:1063a091a062 727
igorsk 0:1063a091a062 728 if (NewState == ENABLE)
igorsk 0:1063a091a062 729 {
igorsk 0:1063a091a062 730 I2Cx->I2CONSET = I2C_I2CONSET_I2EN;
igorsk 0:1063a091a062 731 }
igorsk 0:1063a091a062 732 else
igorsk 0:1063a091a062 733 {
igorsk 0:1063a091a062 734 I2Cx->I2CONCLR = I2C_I2CONCLR_I2ENC;
igorsk 0:1063a091a062 735 }
igorsk 0:1063a091a062 736 }
igorsk 0:1063a091a062 737
igorsk 0:1063a091a062 738
igorsk 0:1063a091a062 739 /*********************************************************************//**
igorsk 0:1063a091a062 740 * @brief Transmit and Receive data in master mode
igorsk 0:1063a091a062 741 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
igorsk 0:1063a091a062 742 * @param[in] TransferCfg Pointer to a I2C_M_SETUP_Type structure that
igorsk 0:1063a091a062 743 * contains specified information about the
igorsk 0:1063a091a062 744 * configuration for master transfer.
igorsk 0:1063a091a062 745 * @param[in] Opt a I2C_TRANSFER_OPT_Type type that selected for
igorsk 0:1063a091a062 746 * interrupt or polling mode.
igorsk 0:1063a091a062 747 * @return SUCCESS or ERROR
igorsk 0:1063a091a062 748 *
igorsk 0:1063a091a062 749 * Note:
igorsk 0:1063a091a062 750 * - In case of using I2C to transmit data only, either transmit length set to 0
igorsk 0:1063a091a062 751 * or transmit data pointer set to NULL.
igorsk 0:1063a091a062 752 * - In case of using I2C to receive data only, either receive length set to 0
igorsk 0:1063a091a062 753 * or receive data pointer set to NULL.
igorsk 0:1063a091a062 754 * - In case of using I2C to transmit followed by receive data, transmit length,
igorsk 0:1063a091a062 755 * transmit data pointer, receive length and receive data pointer should be set
igorsk 0:1063a091a062 756 * corresponding.
igorsk 0:1063a091a062 757 **********************************************************************/
igorsk 0:1063a091a062 758 Status I2C_MasterTransferData(LPC_I2C_TypeDef *I2Cx, I2C_M_SETUP_Type *TransferCfg, \
igorsk 0:1063a091a062 759 I2C_TRANSFER_OPT_Type Opt)
igorsk 0:1063a091a062 760 {
igorsk 0:1063a091a062 761 uint8_t *txdat;
igorsk 0:1063a091a062 762 uint8_t *rxdat;
igorsk 0:1063a091a062 763 uint32_t CodeStatus=0;
igorsk 0:1063a091a062 764 uint8_t tmp=0;
igorsk 0:1063a091a062 765
igorsk 0:1063a091a062 766 // reset all default state
igorsk 0:1063a091a062 767 txdat = (uint8_t *) TransferCfg->tx_data;
igorsk 0:1063a091a062 768 rxdat = (uint8_t *) TransferCfg->rx_data;
igorsk 0:1063a091a062 769 // Reset I2C setup value to default state
igorsk 0:1063a091a062 770 TransferCfg->tx_count = 0;
igorsk 0:1063a091a062 771 TransferCfg->rx_count = 0;
igorsk 0:1063a091a062 772 TransferCfg->status = 0;
igorsk 0:1063a091a062 773
igorsk 0:1063a091a062 774 if (Opt == I2C_TRANSFER_POLLING){
igorsk 0:1063a091a062 775
igorsk 0:1063a091a062 776 /* First Start condition -------------------------------------------------------------- */
igorsk 0:1063a091a062 777 TransferCfg->retransmissions_count = 0;
igorsk 0:1063a091a062 778 retry:
igorsk 0:1063a091a062 779 // reset all default state
igorsk 0:1063a091a062 780 txdat = (uint8_t *) TransferCfg->tx_data;
igorsk 0:1063a091a062 781 rxdat = (uint8_t *) TransferCfg->rx_data;
igorsk 0:1063a091a062 782 // Reset I2C setup value to default state
igorsk 0:1063a091a062 783 TransferCfg->tx_count = 0;
igorsk 0:1063a091a062 784 TransferCfg->rx_count = 0;
igorsk 0:1063a091a062 785 CodeStatus = 0;
igorsk 0:1063a091a062 786
igorsk 0:1063a091a062 787 // Start command
igorsk 0:1063a091a062 788 CodeStatus = I2C_Start(I2Cx);
igorsk 0:1063a091a062 789 if ((CodeStatus != I2C_I2STAT_M_TX_START) \
igorsk 0:1063a091a062 790 && (CodeStatus != I2C_I2STAT_M_TX_RESTART)){
igorsk 0:1063a091a062 791 TransferCfg->retransmissions_count++;
igorsk 0:1063a091a062 792 if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
igorsk 0:1063a091a062 793 // save status
igorsk 0:1063a091a062 794 TransferCfg->status = CodeStatus;
igorsk 0:1063a091a062 795 goto error;
igorsk 0:1063a091a062 796 } else {
igorsk 0:1063a091a062 797 goto retry;
igorsk 0:1063a091a062 798 }
igorsk 0:1063a091a062 799 }
igorsk 0:1063a091a062 800
igorsk 0:1063a091a062 801 /* In case of sending data first --------------------------------------------------- */
igorsk 0:1063a091a062 802 if ((TransferCfg->tx_length != 0) && (TransferCfg->tx_data != NULL)){
igorsk 0:1063a091a062 803
igorsk 0:1063a091a062 804 /* Send slave address + WR direction bit = 0 ----------------------------------- */
igorsk 0:1063a091a062 805 CodeStatus = I2C_SendByte(I2Cx, (TransferCfg->sl_addr7bit << 1));
igorsk 0:1063a091a062 806 if (CodeStatus != I2C_I2STAT_M_TX_SLAW_ACK){
igorsk 0:1063a091a062 807 TransferCfg->retransmissions_count++;
igorsk 0:1063a091a062 808 if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
igorsk 0:1063a091a062 809 // save status
igorsk 0:1063a091a062 810 TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_NOACKF;
igorsk 0:1063a091a062 811 goto error;
igorsk 0:1063a091a062 812 } else {
igorsk 0:1063a091a062 813 goto retry;
igorsk 0:1063a091a062 814 }
igorsk 0:1063a091a062 815 }
igorsk 0:1063a091a062 816
igorsk 0:1063a091a062 817 /* Send a number of data bytes ---------------------------------------- */
igorsk 0:1063a091a062 818 while (TransferCfg->tx_count < TransferCfg->tx_length)
igorsk 0:1063a091a062 819 {
igorsk 0:1063a091a062 820 CodeStatus = I2C_SendByte(I2Cx, *txdat);
igorsk 0:1063a091a062 821 if (CodeStatus != I2C_I2STAT_M_TX_DAT_ACK){
igorsk 0:1063a091a062 822 TransferCfg->retransmissions_count++;
igorsk 0:1063a091a062 823 if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
igorsk 0:1063a091a062 824 // save status
igorsk 0:1063a091a062 825 TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_NOACKF;
igorsk 0:1063a091a062 826 goto error;
igorsk 0:1063a091a062 827 } else {
igorsk 0:1063a091a062 828 goto retry;
igorsk 0:1063a091a062 829 }
igorsk 0:1063a091a062 830 }
igorsk 0:1063a091a062 831
igorsk 0:1063a091a062 832 txdat++;
igorsk 0:1063a091a062 833 TransferCfg->tx_count++;
igorsk 0:1063a091a062 834 }
igorsk 0:1063a091a062 835 }
igorsk 0:1063a091a062 836
igorsk 0:1063a091a062 837 /* Second Start condition (Repeat Start) ------------------------------------------- */
igorsk 0:1063a091a062 838 if ((TransferCfg->tx_length != 0) && (TransferCfg->tx_data != NULL) \
igorsk 0:1063a091a062 839 && (TransferCfg->rx_length != 0) && (TransferCfg->rx_data != NULL)){
igorsk 0:1063a091a062 840
igorsk 0:1063a091a062 841 CodeStatus = I2C_Start(I2Cx);
igorsk 0:1063a091a062 842 if ((CodeStatus != I2C_I2STAT_M_RX_START) \
igorsk 0:1063a091a062 843 && (CodeStatus != I2C_I2STAT_M_RX_RESTART)){
igorsk 0:1063a091a062 844 TransferCfg->retransmissions_count++;
igorsk 0:1063a091a062 845 if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
igorsk 0:1063a091a062 846 // Update status
igorsk 0:1063a091a062 847 TransferCfg->status = CodeStatus;
igorsk 0:1063a091a062 848 goto error;
igorsk 0:1063a091a062 849 } else {
igorsk 0:1063a091a062 850 goto retry;
igorsk 0:1063a091a062 851 }
igorsk 0:1063a091a062 852 }
igorsk 0:1063a091a062 853 }
igorsk 0:1063a091a062 854
igorsk 0:1063a091a062 855 /* Then, start reading after sending data -------------------------------------- */
igorsk 0:1063a091a062 856 if ((TransferCfg->rx_length != 0) && (TransferCfg->rx_data != NULL)){
igorsk 0:1063a091a062 857 /* Send slave address + RD direction bit = 1 ----------------------------------- */
igorsk 0:1063a091a062 858
igorsk 0:1063a091a062 859 CodeStatus = I2C_SendByte(I2Cx, ((TransferCfg->sl_addr7bit << 1) | 0x01));
igorsk 0:1063a091a062 860 if (CodeStatus != I2C_I2STAT_M_RX_SLAR_ACK){
igorsk 0:1063a091a062 861 TransferCfg->retransmissions_count++;
igorsk 0:1063a091a062 862 if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
igorsk 0:1063a091a062 863 // update status
igorsk 0:1063a091a062 864 TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_NOACKF;
igorsk 0:1063a091a062 865 goto error;
igorsk 0:1063a091a062 866 } else {
igorsk 0:1063a091a062 867 goto retry;
igorsk 0:1063a091a062 868 }
igorsk 0:1063a091a062 869 }
igorsk 0:1063a091a062 870
igorsk 0:1063a091a062 871 /* Receive a number of data bytes ------------------------------------------------- */
igorsk 0:1063a091a062 872 while (TransferCfg->rx_count < TransferCfg->rx_length){
igorsk 0:1063a091a062 873
igorsk 0:1063a091a062 874 /*
igorsk 0:1063a091a062 875 * Note that: if data length is only one, the master should not
igorsk 0:1063a091a062 876 * issue an ACK signal on bus after reading to avoid of next data frame
igorsk 0:1063a091a062 877 * on slave side
igorsk 0:1063a091a062 878 */
igorsk 0:1063a091a062 879 if (TransferCfg->rx_count < (TransferCfg->rx_length - 1)){
igorsk 0:1063a091a062 880 // Issue an ACK signal for next data frame
igorsk 0:1063a091a062 881 CodeStatus = I2C_GetByte(I2Cx, &tmp, TRUE);
igorsk 0:1063a091a062 882 if (CodeStatus != I2C_I2STAT_M_RX_DAT_ACK){
igorsk 0:1063a091a062 883 TransferCfg->retransmissions_count++;
igorsk 0:1063a091a062 884 if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
igorsk 0:1063a091a062 885 // update status
igorsk 0:1063a091a062 886 TransferCfg->status = CodeStatus;
igorsk 0:1063a091a062 887 goto error;
igorsk 0:1063a091a062 888 } else {
igorsk 0:1063a091a062 889 goto retry;
igorsk 0:1063a091a062 890 }
igorsk 0:1063a091a062 891 }
igorsk 0:1063a091a062 892 } else {
igorsk 0:1063a091a062 893 // Do not issue an ACK signal
igorsk 0:1063a091a062 894 CodeStatus = I2C_GetByte(I2Cx, &tmp, FALSE);
igorsk 0:1063a091a062 895 if (CodeStatus != I2C_I2STAT_M_RX_DAT_NACK){
igorsk 0:1063a091a062 896 TransferCfg->retransmissions_count++;
igorsk 0:1063a091a062 897 if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){
igorsk 0:1063a091a062 898 // update status
igorsk 0:1063a091a062 899 TransferCfg->status = CodeStatus;
igorsk 0:1063a091a062 900 goto error;
igorsk 0:1063a091a062 901 } else {
igorsk 0:1063a091a062 902 goto retry;
igorsk 0:1063a091a062 903 }
igorsk 0:1063a091a062 904 }
igorsk 0:1063a091a062 905 }
igorsk 0:1063a091a062 906 *rxdat++ = tmp;
igorsk 0:1063a091a062 907 TransferCfg->rx_count++;
igorsk 0:1063a091a062 908 }
igorsk 0:1063a091a062 909 }
igorsk 0:1063a091a062 910
igorsk 0:1063a091a062 911 /* Send STOP condition ------------------------------------------------- */
igorsk 0:1063a091a062 912 I2C_Stop(I2Cx);
igorsk 0:1063a091a062 913 return SUCCESS;
igorsk 0:1063a091a062 914
igorsk 0:1063a091a062 915 error:
igorsk 0:1063a091a062 916 // Send stop condition
igorsk 0:1063a091a062 917 I2C_Stop(I2Cx);
igorsk 0:1063a091a062 918 return ERROR;
igorsk 0:1063a091a062 919 }
igorsk 0:1063a091a062 920
igorsk 0:1063a091a062 921 else if (Opt == I2C_TRANSFER_INTERRUPT){
igorsk 0:1063a091a062 922 // Setup tx_rx data, callback and interrupt handler
igorsk 0:1063a091a062 923 tmp = I2C_getNum(I2Cx);
igorsk 0:1063a091a062 924 i2cdat[tmp].txrx_setup = (uint32_t) TransferCfg;
igorsk 0:1063a091a062 925 i2cdat[tmp].inthandler = I2C_MasterHandler;
igorsk 0:1063a091a062 926 // Set direction phase, write first
igorsk 0:1063a091a062 927 i2cdat[tmp].dir = 0;
igorsk 0:1063a091a062 928
igorsk 0:1063a091a062 929 /* First Start condition -------------------------------------------------------------- */
igorsk 0:1063a091a062 930 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 931 I2Cx->I2CONSET = I2C_I2CONSET_STA;
igorsk 0:1063a091a062 932 I2C_IntCmd(I2Cx, ENABLE);
igorsk 0:1063a091a062 933
igorsk 0:1063a091a062 934 return (SUCCESS);
igorsk 0:1063a091a062 935 }
igorsk 0:1063a091a062 936
igorsk 0:1063a091a062 937 return ERROR;
igorsk 0:1063a091a062 938 }
igorsk 0:1063a091a062 939
igorsk 0:1063a091a062 940 /*********************************************************************//**
igorsk 0:1063a091a062 941 * @brief Receive and Transmit data in slave mode
igorsk 0:1063a091a062 942 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
igorsk 0:1063a091a062 943 * @param[in] TransferCfg Pointer to a I2C_S_SETUP_Type structure that
igorsk 0:1063a091a062 944 * contains specified information about the
igorsk 0:1063a091a062 945 * configuration for master transfer.
igorsk 0:1063a091a062 946 * @param[in] Opt I2C_TRANSFER_OPT_Type type that selected for
igorsk 0:1063a091a062 947 * interrupt or polling mode.
igorsk 0:1063a091a062 948 * @return SUCCESS or ERROR
igorsk 0:1063a091a062 949 *
igorsk 0:1063a091a062 950 * Note:
igorsk 0:1063a091a062 951 * The mode of slave's operation depends on the command sent from master on
igorsk 0:1063a091a062 952 * the I2C bus. If the master send a SLA+W command, this sub-routine will
igorsk 0:1063a091a062 953 * use receive data length and receive data pointer. If the master send a SLA+R
igorsk 0:1063a091a062 954 * command, this sub-routine will use transmit data length and transmit data
igorsk 0:1063a091a062 955 * pointer.
igorsk 0:1063a091a062 956 * If the master issue an repeat start command or a stop command, the slave will
igorsk 0:1063a091a062 957 * enable an time out condition, during time out condition, if there's no activity
igorsk 0:1063a091a062 958 * on I2C bus, the slave will exit, otherwise (i.e. the master send a SLA+R/W),
igorsk 0:1063a091a062 959 * the slave then switch to relevant operation mode. The time out should be used
igorsk 0:1063a091a062 960 * because the return status code can not show difference from stop and repeat
igorsk 0:1063a091a062 961 * start command in slave operation.
igorsk 0:1063a091a062 962 * In case of the expected data length from master is greater than data length
igorsk 0:1063a091a062 963 * that slave can support:
igorsk 0:1063a091a062 964 * - In case of reading operation (from master): slave will return I2C_I2DAT_IDLE_CHAR
igorsk 0:1063a091a062 965 * value.
igorsk 0:1063a091a062 966 * - In case of writing operation (from master): slave will ignore remain data from master.
igorsk 0:1063a091a062 967 **********************************************************************/
igorsk 0:1063a091a062 968 Status I2C_SlaveTransferData(LPC_I2C_TypeDef *I2Cx, I2C_S_SETUP_Type *TransferCfg, \
igorsk 0:1063a091a062 969 I2C_TRANSFER_OPT_Type Opt)
igorsk 0:1063a091a062 970 {
igorsk 0:1063a091a062 971 uint8_t *txdat;
igorsk 0:1063a091a062 972 uint8_t *rxdat;
igorsk 0:1063a091a062 973 uint32_t CodeStatus=0;
igorsk 0:1063a091a062 974 uint32_t timeout;
igorsk 0:1063a091a062 975 int32_t time_en;
igorsk 0:1063a091a062 976 int32_t tmp;
igorsk 0:1063a091a062 977
igorsk 0:1063a091a062 978 // reset all default state
igorsk 0:1063a091a062 979 txdat = (uint8_t *) TransferCfg->tx_data;
igorsk 0:1063a091a062 980 rxdat = (uint8_t *) TransferCfg->rx_data;
igorsk 0:1063a091a062 981 // Reset I2C setup value to default state
igorsk 0:1063a091a062 982 TransferCfg->tx_count = 0;
igorsk 0:1063a091a062 983 TransferCfg->rx_count = 0;
igorsk 0:1063a091a062 984 TransferCfg->status = 0;
igorsk 0:1063a091a062 985
igorsk 0:1063a091a062 986
igorsk 0:1063a091a062 987 // Polling option
igorsk 0:1063a091a062 988 if (Opt == I2C_TRANSFER_POLLING){
igorsk 0:1063a091a062 989
igorsk 0:1063a091a062 990 /* Set AA bit to ACK command on I2C bus */
igorsk 0:1063a091a062 991 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 992 /* Clear SI bit to be ready ... */
igorsk 0:1063a091a062 993 I2Cx->I2CONCLR = (I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC);
igorsk 0:1063a091a062 994
igorsk 0:1063a091a062 995 time_en = 0;
igorsk 0:1063a091a062 996 timeout = 0;
igorsk 0:1063a091a062 997
igorsk 0:1063a091a062 998 while (1)
igorsk 0:1063a091a062 999 {
igorsk 0:1063a091a062 1000 /* Check SI flag ready */
igorsk 0:1063a091a062 1001 if (I2Cx->I2CONSET & I2C_I2CONSET_SI)
igorsk 0:1063a091a062 1002 {
igorsk 0:1063a091a062 1003 time_en = 0;
igorsk 0:1063a091a062 1004
igorsk 0:1063a091a062 1005 switch (CodeStatus = (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK))
igorsk 0:1063a091a062 1006 {
igorsk 0:1063a091a062 1007
igorsk 0:1063a091a062 1008 /* No status information */
igorsk 0:1063a091a062 1009 case I2C_I2STAT_NO_INF:
igorsk 0:1063a091a062 1010 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 1011 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 1012 break;
igorsk 0:1063a091a062 1013
igorsk 0:1063a091a062 1014 /* Reading phase -------------------------------------------------------- */
igorsk 0:1063a091a062 1015 /* Own SLA+R has been received, ACK has been returned */
igorsk 0:1063a091a062 1016 case I2C_I2STAT_S_RX_SLAW_ACK:
igorsk 0:1063a091a062 1017 /* General call address has been received, ACK has been returned */
igorsk 0:1063a091a062 1018 case I2C_I2STAT_S_RX_GENCALL_ACK:
igorsk 0:1063a091a062 1019 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 1020 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 1021 break;
igorsk 0:1063a091a062 1022
igorsk 0:1063a091a062 1023 /* Previously addressed with own SLA;
igorsk 0:1063a091a062 1024 * DATA byte has been received;
igorsk 0:1063a091a062 1025 * ACK has been returned */
igorsk 0:1063a091a062 1026 case I2C_I2STAT_S_RX_PRE_SLA_DAT_ACK:
igorsk 0:1063a091a062 1027 /* DATA has been received, ACK hasn been return */
igorsk 0:1063a091a062 1028 case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_ACK:
igorsk 0:1063a091a062 1029 /*
igorsk 0:1063a091a062 1030 * All data bytes that over-flow the specified receive
igorsk 0:1063a091a062 1031 * data length, just ignore them.
igorsk 0:1063a091a062 1032 */
igorsk 0:1063a091a062 1033 if ((TransferCfg->rx_count < TransferCfg->rx_length) \
igorsk 0:1063a091a062 1034 && (TransferCfg->rx_data != NULL)){
igorsk 0:1063a091a062 1035 *rxdat++ = (uint8_t)I2Cx->I2DAT;
igorsk 0:1063a091a062 1036 TransferCfg->rx_count++;
igorsk 0:1063a091a062 1037 }
igorsk 0:1063a091a062 1038 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 1039 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 1040 break;
igorsk 0:1063a091a062 1041
igorsk 0:1063a091a062 1042 /* Previously addressed with own SLA;
igorsk 0:1063a091a062 1043 * DATA byte has been received;
igorsk 0:1063a091a062 1044 * NOT ACK has been returned */
igorsk 0:1063a091a062 1045 case I2C_I2STAT_S_RX_PRE_SLA_DAT_NACK:
igorsk 0:1063a091a062 1046 /* DATA has been received, NOT ACK has been returned */
igorsk 0:1063a091a062 1047 case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_NACK:
igorsk 0:1063a091a062 1048 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 1049 break;
igorsk 0:1063a091a062 1050
igorsk 0:1063a091a062 1051 /*
igorsk 0:1063a091a062 1052 * Note that: Return code only let us know a stop condition mixed
igorsk 0:1063a091a062 1053 * with a repeat start condition in the same code value.
igorsk 0:1063a091a062 1054 * So we should provide a time-out. In case this is really a stop
igorsk 0:1063a091a062 1055 * condition, this will return back after time out condition. Otherwise,
igorsk 0:1063a091a062 1056 * next session that is slave receive data will be completed.
igorsk 0:1063a091a062 1057 */
igorsk 0:1063a091a062 1058
igorsk 0:1063a091a062 1059 /* A Stop or a repeat start condition */
igorsk 0:1063a091a062 1060 case I2C_I2STAT_S_RX_STA_STO_SLVREC_SLVTRX:
igorsk 0:1063a091a062 1061 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 1062 // enable time out
igorsk 0:1063a091a062 1063 time_en = 1;
igorsk 0:1063a091a062 1064 timeout = 0;
igorsk 0:1063a091a062 1065 break;
igorsk 0:1063a091a062 1066
igorsk 0:1063a091a062 1067 /* Writing phase -------------------------------------------------------- */
igorsk 0:1063a091a062 1068 /* Own SLA+R has been received, ACK has been returned */
igorsk 0:1063a091a062 1069 case I2C_I2STAT_S_TX_SLAR_ACK:
igorsk 0:1063a091a062 1070 /* Data has been transmitted, ACK has been received */
igorsk 0:1063a091a062 1071 case I2C_I2STAT_S_TX_DAT_ACK:
igorsk 0:1063a091a062 1072 /*
igorsk 0:1063a091a062 1073 * All data bytes that over-flow the specified receive
igorsk 0:1063a091a062 1074 * data length, just ignore them.
igorsk 0:1063a091a062 1075 */
igorsk 0:1063a091a062 1076 if ((TransferCfg->tx_count < TransferCfg->tx_length) \
igorsk 0:1063a091a062 1077 && (TransferCfg->tx_data != NULL)){
igorsk 0:1063a091a062 1078 I2Cx->I2DAT = *txdat++;
igorsk 0:1063a091a062 1079 TransferCfg->tx_count++;
igorsk 0:1063a091a062 1080 }
igorsk 0:1063a091a062 1081 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 1082 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 1083 break;
igorsk 0:1063a091a062 1084
igorsk 0:1063a091a062 1085 /* Data has been transmitted, NACK has been received,
igorsk 0:1063a091a062 1086 * that means there's no more data to send, exit now */
igorsk 0:1063a091a062 1087 /*
igorsk 0:1063a091a062 1088 * Note: Don't wait for stop event since in slave transmit mode,
igorsk 0:1063a091a062 1089 * since there no proof lets us know when a stop signal has been received
igorsk 0:1063a091a062 1090 * on slave side.
igorsk 0:1063a091a062 1091 */
igorsk 0:1063a091a062 1092 case I2C_I2STAT_S_TX_DAT_NACK:
igorsk 0:1063a091a062 1093 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 1094 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 1095 // enable time out
igorsk 0:1063a091a062 1096 time_en = 1;
igorsk 0:1063a091a062 1097 timeout = 0;
igorsk 0:1063a091a062 1098 break;
igorsk 0:1063a091a062 1099
igorsk 0:1063a091a062 1100 // Other status must be captured
igorsk 0:1063a091a062 1101 default:
igorsk 0:1063a091a062 1102 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC;
igorsk 0:1063a091a062 1103 goto s_error;
igorsk 0:1063a091a062 1104 }
igorsk 0:1063a091a062 1105 } else if (time_en){
igorsk 0:1063a091a062 1106 if (timeout++ > I2C_SLAVE_TIME_OUT){
igorsk 0:1063a091a062 1107 // it's really a stop condition, goto end stage
igorsk 0:1063a091a062 1108 goto s_end_stage;
igorsk 0:1063a091a062 1109 }
igorsk 0:1063a091a062 1110 }
igorsk 0:1063a091a062 1111 }
igorsk 0:1063a091a062 1112
igorsk 0:1063a091a062 1113 s_end_stage:
igorsk 0:1063a091a062 1114 /* Clear AA bit to disable ACK on I2C bus */
igorsk 0:1063a091a062 1115 I2Cx->I2CONCLR = I2C_I2CONCLR_AAC;
igorsk 0:1063a091a062 1116 // Check if there's no error during operation
igorsk 0:1063a091a062 1117 // Update status
igorsk 0:1063a091a062 1118 TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_DONE;
igorsk 0:1063a091a062 1119 return SUCCESS;
igorsk 0:1063a091a062 1120
igorsk 0:1063a091a062 1121 s_error:
igorsk 0:1063a091a062 1122 /* Clear AA bit to disable ACK on I2C bus */
igorsk 0:1063a091a062 1123 I2Cx->I2CONCLR = I2C_I2CONCLR_AAC;
igorsk 0:1063a091a062 1124 // Update status
igorsk 0:1063a091a062 1125 TransferCfg->status = CodeStatus;
igorsk 0:1063a091a062 1126 return ERROR;
igorsk 0:1063a091a062 1127 }
igorsk 0:1063a091a062 1128
igorsk 0:1063a091a062 1129 else if (Opt == I2C_TRANSFER_INTERRUPT){
igorsk 0:1063a091a062 1130 // Setup tx_rx data, callback and interrupt handler
igorsk 0:1063a091a062 1131 tmp = I2C_getNum(I2Cx);
igorsk 0:1063a091a062 1132 i2cdat[tmp].txrx_setup = (uint32_t) TransferCfg;
igorsk 0:1063a091a062 1133 i2cdat[tmp].inthandler = I2C_SlaveHandler;
igorsk 0:1063a091a062 1134 // Set direction phase, read first
igorsk 0:1063a091a062 1135 i2cdat[tmp].dir = 1;
igorsk 0:1063a091a062 1136
igorsk 0:1063a091a062 1137 // Enable AA
igorsk 0:1063a091a062 1138 I2Cx->I2CONSET = I2C_I2CONSET_AA;
igorsk 0:1063a091a062 1139 I2Cx->I2CONCLR = I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC;
igorsk 0:1063a091a062 1140 I2C_IntCmd(I2Cx, ENABLE);
igorsk 0:1063a091a062 1141
igorsk 0:1063a091a062 1142 return (SUCCESS);
igorsk 0:1063a091a062 1143 }
igorsk 0:1063a091a062 1144
igorsk 0:1063a091a062 1145 return ERROR;
igorsk 0:1063a091a062 1146 }
igorsk 0:1063a091a062 1147
igorsk 0:1063a091a062 1148 /*********************************************************************//**
igorsk 0:1063a091a062 1149 * @brief Set Own slave address in I2C peripheral corresponding to
igorsk 0:1063a091a062 1150 * parameter specified in OwnSlaveAddrConfigStruct.
igorsk 0:1063a091a062 1151 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
igorsk 0:1063a091a062 1152 * @param[in] OwnSlaveAddrConfigStruct Pointer to a I2C_OWNSLAVEADDR_CFG_Type
igorsk 0:1063a091a062 1153 * structure that contains the configuration information for the
igorsk 0:1063a091a062 1154 * specified I2C slave address.
igorsk 0:1063a091a062 1155 * @return None
igorsk 0:1063a091a062 1156 **********************************************************************/
igorsk 0:1063a091a062 1157 void I2C_SetOwnSlaveAddr(LPC_I2C_TypeDef *I2Cx, I2C_OWNSLAVEADDR_CFG_Type *OwnSlaveAddrConfigStruct)
igorsk 0:1063a091a062 1158 {
igorsk 0:1063a091a062 1159 uint32_t tmp;
igorsk 0:1063a091a062 1160 CHECK_PARAM(PARAM_I2Cx(I2Cx));
igorsk 0:1063a091a062 1161 CHECK_PARAM(PARAM_I2C_SLAVEADDR_CH(OwnSlaveAddrConfigStruct->SlaveAddrChannel));
igorsk 0:1063a091a062 1162 CHECK_PARAM(PARAM_FUNCTIONALSTATE(OwnSlaveAddrConfigStruct->GeneralCallState));
igorsk 0:1063a091a062 1163
igorsk 0:1063a091a062 1164 tmp = (((uint32_t)(OwnSlaveAddrConfigStruct->SlaveAddr_7bit << 1)) \
igorsk 0:1063a091a062 1165 | ((OwnSlaveAddrConfigStruct->GeneralCallState == ENABLE) ? 0x01 : 0x00))& I2C_I2ADR_BITMASK;
igorsk 0:1063a091a062 1166 switch (OwnSlaveAddrConfigStruct->SlaveAddrChannel)
igorsk 0:1063a091a062 1167 {
igorsk 0:1063a091a062 1168 case 0:
igorsk 0:1063a091a062 1169 I2Cx->I2ADR0 = tmp;
igorsk 0:1063a091a062 1170 I2Cx->I2MASK0 = I2C_I2MASK_MASK((uint32_t) \
igorsk 0:1063a091a062 1171 (OwnSlaveAddrConfigStruct->SlaveAddrMaskValue));
igorsk 0:1063a091a062 1172 break;
igorsk 0:1063a091a062 1173 case 1:
igorsk 0:1063a091a062 1174 I2Cx->I2ADR1 = tmp;
igorsk 0:1063a091a062 1175 I2Cx->I2MASK1 = I2C_I2MASK_MASK((uint32_t) \
igorsk 0:1063a091a062 1176 (OwnSlaveAddrConfigStruct->SlaveAddrMaskValue));
igorsk 0:1063a091a062 1177 break;
igorsk 0:1063a091a062 1178 case 2:
igorsk 0:1063a091a062 1179 I2Cx->I2ADR2 = tmp;
igorsk 0:1063a091a062 1180 I2Cx->I2MASK2 = I2C_I2MASK_MASK((uint32_t) \
igorsk 0:1063a091a062 1181 (OwnSlaveAddrConfigStruct->SlaveAddrMaskValue));
igorsk 0:1063a091a062 1182 break;
igorsk 0:1063a091a062 1183 case 3:
igorsk 0:1063a091a062 1184 I2Cx->I2ADR3 = tmp;
igorsk 0:1063a091a062 1185 I2Cx->I2MASK3 = I2C_I2MASK_MASK((uint32_t) \
igorsk 0:1063a091a062 1186 (OwnSlaveAddrConfigStruct->SlaveAddrMaskValue));
igorsk 0:1063a091a062 1187 break;
igorsk 0:1063a091a062 1188 }
igorsk 0:1063a091a062 1189 }
igorsk 0:1063a091a062 1190
igorsk 0:1063a091a062 1191
igorsk 0:1063a091a062 1192 /*********************************************************************//**
igorsk 0:1063a091a062 1193 * @brief Configures functionality in I2C monitor mode
igorsk 0:1063a091a062 1194 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
igorsk 0:1063a091a062 1195 * @param[in] MonitorCfgType Monitor Configuration type, should be:
igorsk 0:1063a091a062 1196 * - I2C_MONITOR_CFG_SCL_OUTPUT: I2C module can 'stretch'
igorsk 0:1063a091a062 1197 * the clock line (hold it low) until it has had time to
igorsk 0:1063a091a062 1198 * respond to an I2C interrupt.
igorsk 0:1063a091a062 1199 * - I2C_MONITOR_CFG_MATCHALL: When this bit is set to '1'
igorsk 0:1063a091a062 1200 * and the I2C is in monitor mode, an interrupt will be
igorsk 0:1063a091a062 1201 * generated on ANY address received.
igorsk 0:1063a091a062 1202 * @param[in] NewState New State of this function, should be:
igorsk 0:1063a091a062 1203 * - ENABLE: Enable this function.
igorsk 0:1063a091a062 1204 * - DISABLE: Disable this function.
igorsk 0:1063a091a062 1205 * @return None
igorsk 0:1063a091a062 1206 **********************************************************************/
igorsk 0:1063a091a062 1207 void I2C_MonitorModeConfig(LPC_I2C_TypeDef *I2Cx, uint32_t MonitorCfgType, FunctionalState NewState)
igorsk 0:1063a091a062 1208 {
igorsk 0:1063a091a062 1209 CHECK_PARAM(PARAM_I2Cx(I2Cx));
igorsk 0:1063a091a062 1210 CHECK_PARAM(PARAM_I2C_MONITOR_CFG(MonitorCfgType));
igorsk 0:1063a091a062 1211 CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));
igorsk 0:1063a091a062 1212
igorsk 0:1063a091a062 1213 if (NewState == ENABLE)
igorsk 0:1063a091a062 1214 {
igorsk 0:1063a091a062 1215 I2Cx->MMCTRL |= MonitorCfgType;
igorsk 0:1063a091a062 1216 }
igorsk 0:1063a091a062 1217 else
igorsk 0:1063a091a062 1218 {
igorsk 0:1063a091a062 1219 I2Cx->MMCTRL &= (~MonitorCfgType) & I2C_I2MMCTRL_BITMASK;
igorsk 0:1063a091a062 1220 }
igorsk 0:1063a091a062 1221 }
igorsk 0:1063a091a062 1222
igorsk 0:1063a091a062 1223
igorsk 0:1063a091a062 1224 /*********************************************************************//**
igorsk 0:1063a091a062 1225 * @brief Enable/Disable I2C monitor mode
igorsk 0:1063a091a062 1226 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
igorsk 0:1063a091a062 1227 * @param[in] NewState New State of this function, should be:
igorsk 0:1063a091a062 1228 * - ENABLE: Enable monitor mode.
igorsk 0:1063a091a062 1229 * - DISABLE: Disable monitor mode.
igorsk 0:1063a091a062 1230 * @return None
igorsk 0:1063a091a062 1231 **********************************************************************/
igorsk 0:1063a091a062 1232 void I2C_MonitorModeCmd(LPC_I2C_TypeDef *I2Cx, FunctionalState NewState)
igorsk 0:1063a091a062 1233 {
igorsk 0:1063a091a062 1234 CHECK_PARAM(PARAM_I2Cx(I2Cx));
igorsk 0:1063a091a062 1235 CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));
igorsk 0:1063a091a062 1236
igorsk 0:1063a091a062 1237 if (NewState == ENABLE)
igorsk 0:1063a091a062 1238 {
igorsk 0:1063a091a062 1239 I2Cx->MMCTRL |= I2C_I2MMCTRL_MM_ENA;
igorsk 0:1063a091a062 1240 }
igorsk 0:1063a091a062 1241 else
igorsk 0:1063a091a062 1242 {
igorsk 0:1063a091a062 1243 I2Cx->MMCTRL &= (~I2C_I2MMCTRL_MM_ENA) & I2C_I2MMCTRL_BITMASK;
igorsk 0:1063a091a062 1244 }
igorsk 0:1063a091a062 1245 }
igorsk 0:1063a091a062 1246
igorsk 0:1063a091a062 1247
igorsk 0:1063a091a062 1248 /*********************************************************************//**
igorsk 0:1063a091a062 1249 * @brief Get data from I2C data buffer in monitor mode.
igorsk 0:1063a091a062 1250 * @param[in] I2Cx I2C peripheral selected, should be I2C0, I2C1 or I2C2
igorsk 0:1063a091a062 1251 * @return None
igorsk 0:1063a091a062 1252 * Note: In monitor mode, the I2C module may lose the ability to stretch
igorsk 0:1063a091a062 1253 * the clock (stall the bus) if the ENA_SCL bit is not set. This means that
igorsk 0:1063a091a062 1254 * the processor will have a limited amount of time to read the contents of
igorsk 0:1063a091a062 1255 * the data received on the bus. If the processor reads the I2DAT shift
igorsk 0:1063a091a062 1256 * register, as it ordinarily would, it could have only one bit-time to
igorsk 0:1063a091a062 1257 * respond to the interrupt before the received data is overwritten by
igorsk 0:1063a091a062 1258 * new data.
igorsk 0:1063a091a062 1259 **********************************************************************/
igorsk 0:1063a091a062 1260 uint8_t I2C_MonitorGetDatabuffer(LPC_I2C_TypeDef *I2Cx)
igorsk 0:1063a091a062 1261 {
igorsk 0:1063a091a062 1262 CHECK_PARAM(PARAM_I2Cx(I2Cx));
igorsk 0:1063a091a062 1263 return ((uint8_t)(I2Cx->I2DATA_BUFFER));
igorsk 0:1063a091a062 1264 }
igorsk 0:1063a091a062 1265
igorsk 0:1063a091a062 1266 /*********************************************************************//**
igorsk 0:1063a091a062 1267 * @brief Standard Interrupt handler for I2C0 peripheral
igorsk 0:1063a091a062 1268 * @param[in] None
igorsk 0:1063a091a062 1269 * @return None
igorsk 0:1063a091a062 1270 **********************************************************************/
igorsk 0:1063a091a062 1271 void I2C0_StdIntHandler(void)
igorsk 0:1063a091a062 1272 {
igorsk 0:1063a091a062 1273 i2cdat[0].inthandler(LPC_I2C0);
igorsk 0:1063a091a062 1274 }
igorsk 0:1063a091a062 1275
igorsk 0:1063a091a062 1276 /*********************************************************************//**
igorsk 0:1063a091a062 1277 * @brief Standard Interrupt handler for I2C1 peripheral
igorsk 0:1063a091a062 1278 * @param[in] None
igorsk 0:1063a091a062 1279 * @return None
igorsk 0:1063a091a062 1280 **********************************************************************/
igorsk 0:1063a091a062 1281 void I2C1_StdIntHandler(void)
igorsk 0:1063a091a062 1282 {
igorsk 0:1063a091a062 1283 i2cdat[1].inthandler(LPC_I2C1);
igorsk 0:1063a091a062 1284 }
igorsk 0:1063a091a062 1285
igorsk 0:1063a091a062 1286 /*********************************************************************//**
igorsk 0:1063a091a062 1287 * @brief Standard Interrupt handler for I2C2 peripheral
igorsk 0:1063a091a062 1288 * @param[in] None
igorsk 0:1063a091a062 1289 * @return None
igorsk 0:1063a091a062 1290 **********************************************************************/
igorsk 0:1063a091a062 1291 void I2C2_StdIntHandler(void)
igorsk 0:1063a091a062 1292 {
igorsk 0:1063a091a062 1293 i2cdat[2].inthandler(LPC_I2C2);
igorsk 0:1063a091a062 1294 }
igorsk 0:1063a091a062 1295
igorsk 0:1063a091a062 1296
igorsk 0:1063a091a062 1297 /**
igorsk 0:1063a091a062 1298 * @}
igorsk 0:1063a091a062 1299 */
igorsk 0:1063a091a062 1300
igorsk 0:1063a091a062 1301 #endif /* _I2C */
igorsk 0:1063a091a062 1302
igorsk 0:1063a091a062 1303 /**
igorsk 0:1063a091a062 1304 * @}
igorsk 0:1063a091a062 1305 */
igorsk 0:1063a091a062 1306
igorsk 0:1063a091a062 1307 /* --------------------------------- End Of File ------------------------------ */