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
source/lpc17xx_i2c.c@0:1063a091a062, 2010-02-17 (annotated)
- Committer:
- igorsk
- Date:
- Wed Feb 17 16:22:39 2010 +0000
- Revision:
- 0:1063a091a062
Who changed what in which revision?
User | Revision | Line number | New 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 ------------------------------ */ |