/**************************************************************************//** * * @brief Starts the I2C monitor * * @retval CMD_STATUS_OK If successfully started * @retval CMD_STATUS_ERR_* If the I2C monitor could not be started * *****************************************************************************/ cmd_status_t monitor_i2c_Start(void) { if (!validConfiguration) { // no point in arming if the configuration is invalid return CMD_STATUS_ERR_MON_I2C_NOT_CONFIGURED; } CLR_MEAS_PIN_1(); TIM_Init(LPC_TIMER3, TIM_TIMER_MODE, &timerCfg); TIM_Cmd(LPC_TIMER3, ENABLE); circbuff_Reset(pSampleBuffer); bytesToCapture = pSampleBuffer->size / SAMPLE_SIZE; pSampleData = (uint32_t*)pSampleBuffer->data; done = FALSE; I2C_IntCmd(LPC_I2C0, TRUE); I2C_MonitorModeCmd(LPC_I2C0, ENABLE); while (!done) { TIM_Waitms(10); } return CMD_STATUS_OK; }
int _I2C_IntCmd(uint8_t * args) { uint8_t * arg_ptr; LPC_I2C_TypeDef* I2Cx; Bool NewState; if ((arg_ptr = (uint8_t *) strtok(NULL, " ")) == NULL) return 1; I2Cx = (LPC_I2C_TypeDef*) strtoul((char *) arg_ptr, NULL, 16); if ((arg_ptr = (uint8_t *) strtok(NULL, " ")) == NULL) return 1; NewState = (Bool) strtoul((char *) arg_ptr, NULL, 16); I2C_IntCmd(I2Cx, NewState); return 0; }
/**************************************************************************//** * * @brief I2C Interrupt handler, saves all I2C samples * @ingroup RES_IRQ * *****************************************************************************/ void I2C0_IRQHandler(void) { SET_MEAS_PIN_1(); *pSampleData++ = LPC_TIMER3->TC; *pSampleData++ = LPC_I2C0->STAT; *pSampleData++ = LPC_I2C0->DATA_BUFFER; /* As (soon to be) explained in LPC43xx User Manual Errata: Introduction: The I2C monitor allows the device to monitor the I2C traffic on the I2C bus in a non-intrusive way. Problem: In the slave-transmitter mode, the device set in the monitor mode must write a dummy value of 0xFF into the DAT register. If this is not done, the received data from the slave device will be corrupted. To allow the monitor mode to have sufficient time to process the data on the I2C bus, the device may need to have the ability to stretch the I2C clock. Under this condition, the I2C monitor mode is not 100% non-intrusive. */ switch (LPC_I2C0->STAT) { case 0xA8: // Own SLA + R has been received, ACK returned case 0xB0: case 0xB8: // data byte in DAT transmitted, ACK received case 0xC0: // (last) data byte transmitted, NACK received case 0xC8: // last data byte in DAT transmitted, ACK received LPC_I2C0->DAT = 0xFF; // Pretend to shift out 0xFF break; } LPC_I2C0->CONCLR = I2C_I2CONCLR_SIC; if (--bytesToCapture == 0) { I2C_MonitorModeCmd(LPC_I2C0, DISABLE); I2C_IntCmd(LPC_I2C0, FALSE); done = TRUE; } CLR_MEAS_PIN_1(); }
/*********************************************************************//** * @brief Receive and Transmit data in slave mode * @param[in] I2Cx I2C peripheral selected, should be * - LPC_I2C0 * - LPC_I2C1 * - LPC_I2C2 * @param[in] TransferCfg Pointer to a I2C_S_SETUP_Type structure that * contains specified information about the * configuration for master transfer. * @param[in] Opt I2C_TRANSFER_OPT_Type type that selected for * interrupt or polling mode. * @return SUCCESS or ERROR * * Note: * The mode of slave's operation depends on the command sent from master on * the I2C bus. If the master send a SLA+W command, this sub-routine will * use receive data length and receive data pointer. If the master send a SLA+R * command, this sub-routine will use transmit data length and transmit data * pointer. * If the master issue an repeat start command or a stop command, the slave will * enable an time out condition, during time out condition, if there's no activity * on I2C bus, the slave will exit, otherwise (i.e. the master send a SLA+R/W), * the slave then switch to relevant operation mode. The time out should be used * because the return status code can not show difference from stop and repeat * start command in slave operation. * In case of the expected data length from master is greater than data length * that slave can support: * - In case of reading operation (from master): slave will return I2C_I2DAT_IDLE_CHAR * value. * - In case of writing operation (from master): slave will ignore remain data from master. **********************************************************************/ Status I2C_SlaveTransferData(LPC_I2C_TypeDef *I2Cx, I2C_S_SETUP_Type *TransferCfg, \ I2C_TRANSFER_OPT_Type Opt) { uint8_t *txdat; uint8_t *rxdat; uint32_t CodeStatus; uint32_t timeout; int32_t time_en; int32_t tmp; // reset all default state txdat = (uint8_t *) TransferCfg->tx_data; rxdat = (uint8_t *) TransferCfg->rx_data; // Reset I2C setup value to default state TransferCfg->tx_count = 0; TransferCfg->rx_count = 0; TransferCfg->status = 0; // Polling option if (Opt == I2C_TRANSFER_POLLING){ /* Set AA bit to ACK command on I2C bus */ I2Cx->I2CONSET = I2C_I2CONSET_AA; /* Clear SI bit to be ready ... */ I2Cx->I2CONCLR = (I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC); time_en = 0; timeout = 0; while (1) { /* Check SI flag ready */ if (I2Cx->I2CONSET & I2C_I2CONSET_SI) { time_en = 0; switch (CodeStatus = (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK)) { /* No status information */ case I2C_I2STAT_NO_INF: I2Cx->I2CONSET = I2C_I2CONSET_AA; I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; break; /* Reading phase -------------------------------------------------------- */ /* Own SLA+R has been received, ACK has been returned */ case I2C_I2STAT_S_RX_SLAW_ACK: /* General call address has been received, ACK has been returned */ case I2C_I2STAT_S_RX_GENCALL_ACK: I2Cx->I2CONSET = I2C_I2CONSET_AA; I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; break; /* Previously addressed with own SLA; * DATA byte has been received; * ACK has been returned */ case I2C_I2STAT_S_RX_PRE_SLA_DAT_ACK: /* DATA has been received, ACK hasn been return */ case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_ACK: /* * All data bytes that over-flow the specified receive * data length, just ignore them. */ if ((TransferCfg->rx_count < TransferCfg->rx_length) \ && (TransferCfg->rx_data != NULL)){ *rxdat++ = (uint8_t)I2Cx->I2DAT; TransferCfg->rx_count++; } I2Cx->I2CONSET = I2C_I2CONSET_AA; I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; break; /* Previously addressed with own SLA; * DATA byte has been received; * NOT ACK has been returned */ case I2C_I2STAT_S_RX_PRE_SLA_DAT_NACK: /* DATA has been received, NOT ACK has been returned */ case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_NACK: I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; break; /* * Note that: Return code only let us know a stop condition mixed * with a repeat start condition in the same code value. * So we should provide a time-out. In case this is really a stop * condition, this will return back after time out condition. Otherwise, * next session that is slave receive data will be completed. */ /* A Stop or a repeat start condition */ case I2C_I2STAT_S_RX_STA_STO_SLVREC_SLVTRX: I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; // enable time out time_en = 1; timeout = 0; break; /* Writing phase -------------------------------------------------------- */ /* Own SLA+R has been received, ACK has been returned */ case I2C_I2STAT_S_TX_SLAR_ACK: /* Data has been transmitted, ACK has been received */ case I2C_I2STAT_S_TX_DAT_ACK: /* * All data bytes that over-flow the specified receive * data length, just ignore them. */ if ((TransferCfg->tx_count < TransferCfg->tx_length) \ && (TransferCfg->tx_data != NULL)){ I2Cx->I2DAT = *txdat++; TransferCfg->tx_count++; } I2Cx->I2CONSET = I2C_I2CONSET_AA; I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; break; /* Data has been transmitted, NACK has been received, * that means there's no more data to send, exit now */ /* * Note: Don't wait for stop event since in slave transmit mode, * since there no proof lets us know when a stop signal has been received * on slave side. */ case I2C_I2STAT_S_TX_DAT_NACK: I2Cx->I2CONSET = I2C_I2CONSET_AA; I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; // enable time out time_en = 1; timeout = 0; break; // Other status must be captured default: I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; goto s_error; } } else if (time_en){ if (timeout++ > I2C_SLAVE_TIME_OUT){ // it's really a stop condition, goto end stage goto s_end_stage; } } } s_end_stage: /* Clear AA bit to disable ACK on I2C bus */ I2Cx->I2CONCLR = I2C_I2CONCLR_AAC; // Check if there's no error during operation // Update status TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_DONE; return SUCCESS; s_error: /* Clear AA bit to disable ACK on I2C bus */ I2Cx->I2CONCLR = I2C_I2CONCLR_AAC; // Update status TransferCfg->status = CodeStatus; return ERROR; } else if (Opt == I2C_TRANSFER_INTERRUPT){ // Setup tx_rx data, callback and interrupt handler tmp = I2C_getNum(I2Cx); i2cdat[tmp].txrx_setup = (uint32_t) TransferCfg; // Set direction phase, read first i2cdat[tmp].dir = 1; // Enable AA I2Cx->I2CONSET = I2C_I2CONSET_AA; I2Cx->I2CONCLR = I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC; I2C_IntCmd(I2Cx, TRUE); return (SUCCESS); } return ERROR; }
/*********************************************************************//** * @brief Transmit and Receive data in master mode * @param[in] I2Cx I2C peripheral selected, should be: * - LPC_I2C0 * - LPC_I2C1 * - LPC_I2C2 * @param[in] TransferCfg Pointer to a I2C_M_SETUP_Type structure that * contains specified information about the * configuration for master transfer. * @param[in] Opt a I2C_TRANSFER_OPT_Type type that selected for * interrupt or polling mode. * @return SUCCESS or ERROR * * Note: * - In case of using I2C to transmit data only, either transmit length set to 0 * or transmit data pointer set to NULL. * - In case of using I2C to receive data only, either receive length set to 0 * or receive data pointer set to NULL. * - In case of using I2C to transmit followed by receive data, transmit length, * transmit data pointer, receive length and receive data pointer should be set * corresponding. **********************************************************************/ Status I2C_MasterTransferData(LPC_I2C_TypeDef *I2Cx, I2C_M_SETUP_Type *TransferCfg, \ I2C_TRANSFER_OPT_Type Opt) { uint8_t *txdat; uint8_t *rxdat; uint32_t CodeStatus; uint8_t tmp; // reset all default state txdat = (uint8_t *) TransferCfg->tx_data; rxdat = (uint8_t *) TransferCfg->rx_data; // Reset I2C setup value to default state TransferCfg->tx_count = 0; TransferCfg->rx_count = 0; TransferCfg->status = 0; if (Opt == I2C_TRANSFER_POLLING){ /* First Start condition -------------------------------------------------------------- */ TransferCfg->retransmissions_count = 0; retry: // reset all default state txdat = (uint8_t *) TransferCfg->tx_data; rxdat = (uint8_t *) TransferCfg->rx_data; // Reset I2C setup value to default state TransferCfg->tx_count = 0; TransferCfg->rx_count = 0; CodeStatus = 0; // Start command CodeStatus = I2C_Start(I2Cx); if ((CodeStatus != I2C_I2STAT_M_TX_START) \ && (CodeStatus != I2C_I2STAT_M_TX_RESTART)){ TransferCfg->retransmissions_count++; if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ // save status TransferCfg->status = CodeStatus; goto error; } else { goto retry; } } /* In case of sending data first --------------------------------------------------- */ if ((TransferCfg->tx_length != 0) && (TransferCfg->tx_data != NULL)){ /* Send slave address + WR direction bit = 0 ----------------------------------- */ CodeStatus = I2C_SendByte(I2Cx, (TransferCfg->sl_addr7bit << 1)); if (CodeStatus != I2C_I2STAT_M_TX_SLAW_ACK){ TransferCfg->retransmissions_count++; if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ // save status TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_NOACKF; goto error; } else { goto retry; } } /* Send a number of data bytes ---------------------------------------- */ while (TransferCfg->tx_count < TransferCfg->tx_length) { CodeStatus = I2C_SendByte(I2Cx, *txdat); if (CodeStatus != I2C_I2STAT_M_TX_DAT_ACK){ TransferCfg->retransmissions_count++; if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ // save status TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_NOACKF; goto error; } else { goto retry; } } txdat++; TransferCfg->tx_count++; } } /* Second Start condition (Repeat Start) ------------------------------------------- */ if ((TransferCfg->tx_length != 0) && (TransferCfg->tx_data != NULL) \ && (TransferCfg->rx_length != 0) && (TransferCfg->rx_data != NULL)){ CodeStatus = I2C_Start(I2Cx); if ((CodeStatus != I2C_I2STAT_M_RX_START) \ && (CodeStatus != I2C_I2STAT_M_RX_RESTART)){ TransferCfg->retransmissions_count++; if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ // Update status TransferCfg->status = CodeStatus; goto error; } else { goto retry; } } } /* Then, start reading after sending data -------------------------------------- */ if ((TransferCfg->rx_length != 0) && (TransferCfg->rx_data != NULL)){ /* Send slave address + RD direction bit = 1 ----------------------------------- */ CodeStatus = I2C_SendByte(I2Cx, ((TransferCfg->sl_addr7bit << 1) | 0x01)); if (CodeStatus != I2C_I2STAT_M_RX_SLAR_ACK){ TransferCfg->retransmissions_count++; if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ // update status TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_NOACKF; goto error; } else { goto retry; } } /* Receive a number of data bytes ------------------------------------------------- */ while (TransferCfg->rx_count < TransferCfg->rx_length){ /* * Note that: if data length is only one, the master should not * issue an ACK signal on bus after reading to avoid of next data frame * on slave side */ if (TransferCfg->rx_count < (TransferCfg->rx_length - 1)){ // Issue an ACK signal for next data frame CodeStatus = I2C_GetByte(I2Cx, &tmp, TRUE); if (CodeStatus != I2C_I2STAT_M_RX_DAT_ACK){ TransferCfg->retransmissions_count++; if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ // update status TransferCfg->status = CodeStatus; goto error; } else { goto retry; } } } else { // Do not issue an ACK signal CodeStatus = I2C_GetByte(I2Cx, &tmp, FALSE); if (CodeStatus != I2C_I2STAT_M_RX_DAT_NACK){ TransferCfg->retransmissions_count++; if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ // update status TransferCfg->status = CodeStatus; goto error; } else { goto retry; } } } *rxdat++ = tmp; TransferCfg->rx_count++; } } /* Send STOP condition ------------------------------------------------- */ I2C_Stop(I2Cx); return SUCCESS; error: // Send stop condition I2C_Stop(I2Cx); return ERROR; } else if (Opt == I2C_TRANSFER_INTERRUPT){ // Setup tx_rx data, callback and interrupt handler tmp = I2C_getNum(I2Cx); i2cdat[tmp].txrx_setup = (uint32_t) TransferCfg; // Set direction phase, write first i2cdat[tmp].dir = 0; /* First Start condition -------------------------------------------------------------- */ I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; I2Cx->I2CONSET = I2C_I2CONSET_STA; I2C_IntCmd(I2Cx, TRUE); return (SUCCESS); } return ERROR; }
/*********************************************************************//** * @brief General Slave Interrupt handler for I2C peripheral * @param[in] I2Cx I2C peripheral selected, should be: * - LPC_I2C0 * - LPC_I2C1 * - LPC_I2C2 * @return None **********************************************************************/ void I2C_SlaveHandler (LPC_I2C_TypeDef *I2Cx) { int32_t tmp; uint8_t returnCode; I2C_S_SETUP_Type *txrx_setup; uint32_t timeout; tmp = I2C_getNum(I2Cx); txrx_setup = (I2C_S_SETUP_Type *) i2cdat[tmp].txrx_setup; returnCode = (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK); // Save current status txrx_setup->status = returnCode; // there's no relevant information if (returnCode == I2C_I2STAT_NO_INF){ I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; return; } switch (returnCode) { /* No status information */ case I2C_I2STAT_NO_INF: I2Cx->I2CONSET = I2C_I2CONSET_AA; I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; break; /* Reading phase -------------------------------------------------------- */ /* Own SLA+R has been received, ACK has been returned */ case I2C_I2STAT_S_RX_SLAW_ACK: /* General call address has been received, ACK has been returned */ case I2C_I2STAT_S_RX_GENCALL_ACK: I2Cx->I2CONSET = I2C_I2CONSET_AA; I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; break; /* Previously addressed with own SLA; * DATA byte has been received; * ACK has been returned */ case I2C_I2STAT_S_RX_PRE_SLA_DAT_ACK: /* DATA has been received, ACK hasn been return */ case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_ACK: /* * All data bytes that over-flow the specified receive * data length, just ignore them. */ if ((txrx_setup->rx_count < txrx_setup->rx_length) \ && (txrx_setup->rx_data != NULL)){ *(uint8_t *)(txrx_setup->rx_data + txrx_setup->rx_count) = (uint8_t)I2Cx->I2DAT; txrx_setup->rx_count++; } I2Cx->I2CONSET = I2C_I2CONSET_AA; I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; break; /* Previously addressed with own SLA; * DATA byte has been received; * NOT ACK has been returned */ case I2C_I2STAT_S_RX_PRE_SLA_DAT_NACK: /* DATA has been received, NOT ACK has been returned */ case I2C_I2STAT_S_RX_PRE_GENCALL_DAT_NACK: I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; break; /* * Note that: Return code only let us know a stop condition mixed * with a repeat start condition in the same code value. * So we should provide a time-out. In case this is really a stop * condition, this will return back after time out condition. Otherwise, * next session that is slave receive data will be completed. */ /* A Stop or a repeat start condition */ case I2C_I2STAT_S_RX_STA_STO_SLVREC_SLVTRX: // Temporally lock the interrupt for timeout condition I2C_IntCmd(I2Cx, FALSE); I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; // enable time out timeout = I2C_SLAVE_TIME_OUT; while(1){ if (I2Cx->I2CONSET & I2C_I2CONSET_SI){ // re-Enable interrupt I2C_IntCmd(I2Cx, TRUE); break; } else { timeout--; if (timeout == 0){ // timeout occur, it's really a stop condition txrx_setup->status |= I2C_SETUP_STATUS_DONE; goto s_int_end; } } } break; /* Writing phase -------------------------------------------------------- */ /* Own SLA+R has been received, ACK has been returned */ case I2C_I2STAT_S_TX_SLAR_ACK: /* Data has been transmitted, ACK has been received */ case I2C_I2STAT_S_TX_DAT_ACK: /* * All data bytes that over-flow the specified receive * data length, just ignore them. */ if ((txrx_setup->tx_count < txrx_setup->tx_length) \ && (txrx_setup->tx_data != NULL)){ I2Cx->I2DAT = *(uint8_t *) (txrx_setup->tx_data + txrx_setup->tx_count); txrx_setup->tx_count++; } I2Cx->I2CONSET = I2C_I2CONSET_AA; I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; break; /* Data has been transmitted, NACK has been received, * that means there's no more data to send, exit now */ /* * Note: Don't wait for stop event since in slave transmit mode, * since there no proof lets us know when a stop signal has been received * on slave side. */ case I2C_I2STAT_S_TX_DAT_NACK: I2Cx->I2CONSET = I2C_I2CONSET_AA; I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; txrx_setup->status |= I2C_SETUP_STATUS_DONE; goto s_int_end; // Other status must be captured default: s_int_end: // Disable interrupt I2C_IntCmd(I2Cx, FALSE); I2Cx->I2CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC; I2C_SlaveComplete[tmp] = TRUE; break; } }
/*********************************************************************//** * @brief General Master Interrupt handler for I2C peripheral * @param[in] I2Cx I2C peripheral selected, should be: * - LPC_I2C * - LPC_I2C1 * - LPC_I2C2 * @return None **********************************************************************/ void I2C_MasterHandler (LPC_I2C_TypeDef *I2Cx) { int32_t tmp; uint8_t returnCode; I2C_M_SETUP_Type *txrx_setup; tmp = I2C_getNum(I2Cx); txrx_setup = (I2C_M_SETUP_Type *) i2cdat[tmp].txrx_setup; returnCode = (I2Cx->I2STAT & I2C_STAT_CODE_BITMASK); // Save current status txrx_setup->status = returnCode; // there's no relevant information if (returnCode == I2C_I2STAT_NO_INF){ I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; return; } /* ----------------------------- TRANSMIT PHASE --------------------------*/ if (i2cdat[tmp].dir == 0){ switch (returnCode) { /* A start/repeat start condition has been transmitted -------------------*/ case I2C_I2STAT_M_TX_START: case I2C_I2STAT_M_TX_RESTART: I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; /* * If there's any transmit data, then start to * send SLA+W right now, otherwise check whether if there's * any receive data for next state. */ if ((txrx_setup->tx_data != NULL) && (txrx_setup->tx_length != 0)){ I2Cx->I2DAT = (txrx_setup->sl_addr7bit << 1); I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; } else { goto next_stage; } break; /* SLA+W has been transmitted, ACK has been received ----------------------*/ case I2C_I2STAT_M_TX_SLAW_ACK: /* Data has been transmitted, ACK has been received */ case I2C_I2STAT_M_TX_DAT_ACK: /* Send more data */ if ((txrx_setup->tx_count < txrx_setup->tx_length) \ && (txrx_setup->tx_data != NULL)){ I2Cx->I2DAT = *(uint8_t *)(txrx_setup->tx_data + txrx_setup->tx_count); txrx_setup->tx_count++; I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; } // no more data, switch to next stage else { next_stage: // change direction i2cdat[tmp].dir = 1; // Check if any data to receive if ((txrx_setup->rx_length != 0) && (txrx_setup->rx_data != NULL)){ // check whether if we need to issue an repeat start if ((txrx_setup->tx_length != 0) && (txrx_setup->tx_data != NULL)){ // Send out an repeat start command I2Cx->I2CONSET = I2C_I2CONSET_STA; I2Cx->I2CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC; } // Don't need issue an repeat start, just goto send SLA+R else { goto send_slar; } } // no more data send, the go to end stage now else { // success, goto end stage txrx_setup->status |= I2C_SETUP_STATUS_DONE; goto end_stage; } } break; /* SLA+W has been transmitted, NACK has been received ----------------------*/ case I2C_I2STAT_M_TX_SLAW_NACK: /* Data has been transmitted, NACK has been received -----------------------*/ case I2C_I2STAT_M_TX_DAT_NACK: // update status txrx_setup->status |= I2C_SETUP_STATUS_NOACKF; goto retry; /* Arbitration lost in SLA+R/W or Data bytes -------------------------------*/ case I2C_I2STAT_M_TX_ARB_LOST: // update status txrx_setup->status |= I2C_SETUP_STATUS_ARBF; default: goto retry; } } /* ----------------------------- RECEIVE PHASE --------------------------*/ else if (i2cdat[tmp].dir == 1){ switch (returnCode){ /* A start/repeat start condition has been transmitted ---------------------*/ case I2C_I2STAT_M_RX_START: case I2C_I2STAT_M_RX_RESTART: I2Cx->I2CONCLR = I2C_I2CONCLR_STAC; /* * If there's any receive data, then start to * send SLA+R right now, otherwise check whether if there's * any receive data for end of state. */ if ((txrx_setup->rx_data != NULL) && (txrx_setup->rx_length != 0)){ send_slar: I2Cx->I2DAT = (txrx_setup->sl_addr7bit << 1) | 0x01; I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; } else { // Success, goto end stage txrx_setup->status |= I2C_SETUP_STATUS_DONE; goto end_stage; } break; /* SLA+R has been transmitted, ACK has been received -----------------*/ case I2C_I2STAT_M_RX_SLAR_ACK: if (txrx_setup->rx_count < (txrx_setup->rx_length - 1)) { /*Data will be received, ACK will be return*/ I2Cx->I2CONSET = I2C_I2CONSET_AA; } else { /*Last data will be received, NACK will be return*/ I2Cx->I2CONCLR = I2C_I2CONSET_AA; } I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; break; /* Data has been received, ACK has been returned ----------------------*/ case I2C_I2STAT_M_RX_DAT_ACK: // Note save data and increase counter first, then check later /* Save data */ if ((txrx_setup->rx_data != NULL) && (txrx_setup->rx_count < txrx_setup->rx_length)){ *(uint8_t *)(txrx_setup->rx_data + txrx_setup->rx_count) = (I2Cx->I2DAT & I2C_I2DAT_BITMASK); txrx_setup->rx_count++; } if (txrx_setup->rx_count < (txrx_setup->rx_length - 1)) { /*Data will be received, ACK will be return*/ I2Cx->I2CONSET = I2C_I2CONSET_AA; } else { /*Last data will be received, NACK will be return*/ I2Cx->I2CONCLR = I2C_I2CONSET_AA; } I2Cx->I2CONCLR = I2C_I2CONCLR_SIC; break; /* Data has been received, NACK has been return -------------------------*/ case I2C_I2STAT_M_RX_DAT_NACK: /* Save the last data */ if ((txrx_setup->rx_data != NULL) && (txrx_setup->rx_count < txrx_setup->rx_length)){ *(uint8_t *)(txrx_setup->rx_data + txrx_setup->rx_count) = (I2Cx->I2DAT & I2C_I2DAT_BITMASK); txrx_setup->rx_count++; } // success, go to end stage txrx_setup->status |= I2C_SETUP_STATUS_DONE; goto end_stage; /* SLA+R has been transmitted, NACK has been received ------------------*/ case I2C_I2STAT_M_RX_SLAR_NACK: // update status txrx_setup->status |= I2C_SETUP_STATUS_NOACKF; goto retry; /* Arbitration lost ----------------------------------------------------*/ case I2C_I2STAT_M_RX_ARB_LOST: // update status txrx_setup->status |= I2C_SETUP_STATUS_ARBF; default: retry: // check if retransmission is available if (txrx_setup->retransmissions_count < txrx_setup->retransmissions_max){ // Clear tx count txrx_setup->tx_count = 0; I2Cx->I2CONSET = I2C_I2CONSET_STA; I2Cx->I2CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC; txrx_setup->retransmissions_count++; } // End of stage else { end_stage: // Disable interrupt I2C_IntCmd(I2Cx, FALSE); // Send stop I2C_Stop(I2Cx); I2C_MasterComplete[tmp] = TRUE; } break; } } }
/*********************************************************************//** * @brief Transmit and Receive data in master mode * @param[in] I2Cx I2C peripheral selected, should be: * - LPC_I2C0 * - LPC_I2C1 * - LPC_I2C2 * @param[in] TransferCfg Pointer to a I2C_M_SETUP_Type structure that * contains specified information about the * configuration for master transfer. * @param[in] Opt a I2C_TRANSFER_OPT_Type type that selected for * interrupt or polling mode. * @return SUCCESS or ERROR * * Note: * - In case of using I2C to transmit data only, either transmit length set to 0 * or transmit data pointer set to NULL. * - In case of using I2C to receive data only, either receive length set to 0 * or receive data pointer set to NULL. * - In case of using I2C to transmit followed by receive data, transmit length, * transmit data pointer, receive length and receive data pointer should be set * corresponding. **********************************************************************/ Status I2C_MasterTransferData(en_I2C_unitId i2cId, I2C_M_SETUP_Type *TransferCfg, I2C_TRANSFER_OPT_Type Opt) { LPC_I2C_TypeDef* I2Cx = I2C_GetPointer(i2cId); uint32_t CodeStatus; int32_t Ret = I2C_OK; // Reset I2C setup value to default state TransferCfg->tx_count = 0; TransferCfg->rx_count = 0; TransferCfg->status = 0; if (Opt == I2C_TRANSFER_POLLING) { /* First Start condition -------------------------------------------------------------- */ TransferCfg->retransmissions_count = 0; retry: // Reset I2C setup value to default state TransferCfg->tx_count = 0; TransferCfg->rx_count = 0; // Start command CodeStatus = I2C_Start(I2Cx, I2C_TRANSFER_POLLING); while(1) // send data first and then receive data from Slave. { Ret = I2C_MasterHanleStates(i2cId, CodeStatus, TransferCfg, I2C_TRANSFER_POLLING); if(I2C_CheckError(Ret)) { TransferCfg->retransmissions_count++; if (TransferCfg->retransmissions_count > TransferCfg->retransmissions_max){ // save status TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_NOACKF; goto error; } else { goto retry; } } else if( (Ret & I2C_BYTE_SENT) || (Ret & I2C_BYTE_RECV)) { // Wait for sending ends/ Wait for next byte while (!(I2Cx->CONSET & I2C_I2CONSET_SI)); } else if (Ret & I2C_SEND_END) // already send all data { // If no need to wait for data from Slave if(TransferCfg->rx_count >= (TransferCfg->rx_length)) { break; } else { I2C_Start(I2Cx, I2C_TRANSFER_POLLING); } } else if (Ret & I2C_RECV_END) // already receive all data { break; } CodeStatus = I2Cx->STAT & I2C_STAT_CODE_BITMASK; } return SUCCESS; error: return ERROR; } else if (Opt == I2C_TRANSFER_INTERRUPT) { // Setup tx_rx data, callback and interrupt handler i2cdat[i2cId].txrx_setup = (uint32_t) TransferCfg; // Set direction phase, write first i2cdat[i2cId].dir = 0; /* First Start condition -------------------------------------------------------------- */ // Reset STA, STO, SI I2C_Start(I2Cx, I2C_TRANSFER_INTERRUPT); I2C_IntCmd(i2cId, TRUE); return (SUCCESS); } return ERROR; }
/*********************************************************************//** * @brief General Slave Interrupt handler for I2C peripheral * @param[in] I2Cx I2C peripheral selected, should be: * - LPC_I2C0 * - LPC_I2C1 * - LPC_I2C2 * @return None **********************************************************************/ void I2C_SlaveHandler (en_I2C_unitId i2cId) { LPC_I2C_TypeDef* I2Cx = I2C_GetPointer(i2cId); uint8_t returnCode; I2C_S_SETUP_Type *txrx_setup; uint32_t timeout; int32_t Ret = I2C_OK; txrx_setup = (I2C_S_SETUP_Type *) i2cdat[i2cId].txrx_setup; handle_state: returnCode = (I2Cx->STAT & I2C_STAT_CODE_BITMASK); // Save current status txrx_setup->status = returnCode; Ret = I2C_SlaveHanleStates(i2cId, returnCode, txrx_setup); if(I2C_CheckError(Ret)) { goto s_int_end; } else if (Ret & I2C_STA_STO_RECV) { // Temporally lock the interrupt for timeout condition I2C_IntCmd(i2cId, FALSE); // enable time out timeout = I2C_SLAVE_TIME_OUT; while(1) { if (I2Cx->CONSET & I2C_I2CONSET_SI) { // re-Enable interrupt I2C_IntCmd(i2cId, TRUE); goto handle_state; } else { timeout--; if (timeout == 0) { // timeout occur, it's really a stop condition txrx_setup->status |= I2C_SETUP_STATUS_DONE; goto s_int_end; } } } } else if(Ret &I2C_SEND_END) { goto s_int_end; } else { return; } s_int_end: // Disable interrupt I2C_IntCmd(i2cId, FALSE); I2Cx->CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC; I2C_SlaveComplete[i2cId] = TRUE; }
/*********************************************************************//** * @brief General Master Interrupt handler for I2C peripheral * @param[in] I2Cx I2C peripheral selected, should be: * - LPC_I2C * - LPC_I2C1 * - LPC_I2C2 * @return None **********************************************************************/ void I2C_MasterHandler(en_I2C_unitId i2cId) { LPC_I2C_TypeDef* I2Cx = I2C_GetPointer(i2cId); uint8_t returnCode; I2C_M_SETUP_Type *txrx_setup; int32_t Ret = I2C_OK; txrx_setup = (I2C_M_SETUP_Type *) i2cdat[i2cId].txrx_setup; returnCode = (I2Cx->STAT & I2C_STAT_CODE_BITMASK); // Save current status txrx_setup->status = returnCode; Ret = I2C_MasterHanleStates(i2cId, returnCode, txrx_setup, I2C_TRANSFER_INTERRUPT); if(I2C_CheckError(Ret)) { if(txrx_setup->retransmissions_count < txrx_setup->retransmissions_max) { // Retry txrx_setup->retransmissions_count ++; txrx_setup->tx_count = 0; txrx_setup->rx_count = 0; // Reset STA, STO, SI I2C_Start(I2Cx, I2C_TRANSFER_INTERRUPT); return; } else { goto s_int_end; } } else if (Ret & I2C_SEND_END) { // If no need to wait for data from Slave if(txrx_setup->rx_count >= (txrx_setup->rx_length)) { goto s_int_end; } else // Start to wait for data from Slave { // Reset STA, STO, SI I2C_Start(I2Cx, I2C_TRANSFER_INTERRUPT); return; } } else if (Ret & I2C_RECV_END) { goto s_int_end; } else { return; } s_int_end: // Disable interrupt I2C_IntCmd(i2cId, FALSE); I2Cx->CONCLR = I2C_I2CONCLR_AAC | I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC; I2C_MasterComplete[i2cId] = TRUE; }
/*********************************************************************//** * @brief Receive and Transmit data in slave mode * @param[in] I2Cx I2C peripheral selected, should be * - LPC_I2C0 * - LPC_I2C1 * - LPC_I2C2 * @param[in] TransferCfg Pointer to a I2C_S_SETUP_Type structure that * contains specified information about the * configuration for master transfer. * @param[in] Opt I2C_TRANSFER_OPT_Type type that selected for * interrupt or polling mode. * @return SUCCESS or ERROR * * Note: * The mode of slave's operation depends on the command sent from master on * the I2C bus. If the master send a SLA+W command, this sub-routine will * use receive data length and receive data pointer. If the master send a SLA+R * command, this sub-routine will use transmit data length and transmit data * pointer. * If the master issue an repeat start command or a stop command, the slave will * enable an time out condition, during time out condition, if there's no activity * on I2C bus, the slave will exit, otherwise (i.e. the master send a SLA+R/W), * the slave then switch to relevant operation mode. The time out should be used * because the return status code can not show difference from stop and repeat * start command in slave operation. * In case of the expected data length from master is greater than data length * that slave can support: * - In case of reading operation (from master): slave will return I2C_I2DAT_IDLE_CHAR * value. * - In case of writing operation (from master): slave will ignore remain data from master. **********************************************************************/ Status I2C_SlaveTransferData(en_I2C_unitId i2cId, I2C_S_SETUP_Type *TransferCfg, I2C_TRANSFER_OPT_Type Opt) { LPC_I2C_TypeDef* I2Cx = I2C_GetPointer(i2cId); int32_t Ret = I2C_OK; uint32_t CodeStatus; uint32_t timeout; int32_t time_en; // Reset I2C setup value to default state TransferCfg->tx_count = 0; TransferCfg->rx_count = 0; TransferCfg->status = 0; // Polling option if (Opt == I2C_TRANSFER_POLLING) { /* Set AA bit to ACK command on I2C bus */ I2Cx->CONSET = I2C_I2CONSET_AA; /* Clear SI bit to be ready ... */ I2Cx->CONCLR = (I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC|I2C_I2CONCLR_STOC); time_en = 0; timeout = 0; while (1) { /* Check SI flag ready */ if (I2Cx->CONSET & I2C_I2CONSET_SI) { time_en = 0; CodeStatus = (I2Cx->STAT & I2C_STAT_CODE_BITMASK); Ret = I2C_SlaveHanleStates(i2cId, CodeStatus, TransferCfg); if(I2C_CheckError(Ret)) { goto s_error; } else if(Ret & I2C_STA_STO_RECV) { time_en = 1; timeout = 0; } else if (Ret & I2C_SEND_END) { goto s_end_stage; } } else if (time_en) { if (timeout++ > I2C_SLAVE_TIME_OUT) { // it's really a stop condition, goto end stage goto s_end_stage; } } } s_end_stage: /* Clear AA bit to disable ACK on I2C bus */ I2Cx->CONCLR = I2C_I2CONCLR_AAC; // Check if there's no error during operation // Update status TransferCfg->status = CodeStatus | I2C_SETUP_STATUS_DONE; return SUCCESS; s_error: /* Clear AA bit to disable ACK on I2C bus */ I2Cx->CONCLR = I2C_I2CONCLR_AAC; // Update status TransferCfg->status = CodeStatus; return ERROR; } else if (Opt == I2C_TRANSFER_INTERRUPT) { // Setup tx_rx data, callback and interrupt handler i2cdat[i2cId].txrx_setup = (uint32_t) TransferCfg; // Set direction phase, read first i2cdat[i2cId].dir = 1; // Enable AA I2Cx->CONSET = I2C_I2CONSET_AA; I2Cx->CONCLR = I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC; I2C_IntCmd(i2cId, TRUE); return (SUCCESS); } return ERROR; }
void I2C2_IRQHandler( void ) { uint32_t ulI2CStatus, ulChar, ulReceived = 0UL; portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; const unsigned portBASE_TYPE uxI2CNumber = 2UL; Transfer_Control_t *pxTransferStruct; /* Determine the event that caused the interrupt. */ ulI2CStatus = ( LPC_I2C2->I2STAT & I2C_STAT_CODE_BITMASK ); /* States that are valid for both Rx and Tx, or are not dependent on either of the Rx or Tx state transfer structures being populated. */ switch( ulI2CStatus ) { case I2C_I2STAT_NO_INF : /* There is no I2C status information to act upon. Clear the interrupt. */ LPC_I2C2->I2CONCLR = I2C_I2CONCLR_SIC; break; case I2C_I2STAT_M_RX_START : case I2C_I2STAT_M_RX_RESTART : /* A start or restart. Send the slave address and 'W'rite bits. This could be during an Rx or a Tx, hence it is outside of the Rx and Tx state machines. */ LPC_I2C2->I2DAT = ( ucSlaveAddresses[ uxI2CNumber ] << 1U ) | ( uint8_t ) xDataDirection[ uxI2CNumber ]; /* Clear the interrupt and the start bit. */ LPC_I2C2->I2CONCLR = I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC; break; case I2C_I2STAT_M_TX_SLAW_NACK: /* SLA+W has been transmitted, and a NACK was received. */ case I2C_I2STAT_M_TX_DAT_NACK: /* Data has been transmitted, and a NACK was received. */ case I2C_I2STAT_M_TX_ARB_LOST: /* Arbitration lost. Could be Rx or Tx. */ case I2C_I2STAT_M_RX_SLAR_NACK: /* SLA+W has been transmitted, and a NACK was received. */ /* Clear the interrupt. */ LPC_I2C2->I2CONCLR = I2C_I2CONCLR_SIC; /* force an assert. */ configASSERT( xHigherPriorityTaskWoken ); break; } /* Transmit state machine. */ pxTransferStruct = pxTxTransferControlStructs[ uxI2CNumber ]; if( pxTransferStruct != NULL ) { switch( ulI2CStatus ) { case I2C_I2STAT_M_TX_SLAW_ACK: case I2C_I2STAT_M_TX_DAT_ACK: /* An Ack has been received after either the slave address or data was transmitted. Is there more data to send? */ iouitlsTX_SINGLE_CHAR_FROM_ZERO_COPY_BUFFER_FROM_ISR( pxTransferStruct, ( LPC_I2C2->I2DAT = ucChar ), ulChar ); if( ulChar == pdFALSE ) { /* There was no more data to send, so send the stop bit and disable interrupts. */ I2C_IntCmd( LPC_I2C2, DISABLE ); I2C_Stop( LPC_I2C2 ); pxTxTransferControlStructs[ uxI2CNumber ] = NULL; xDataDirection[ uxI2CNumber ] = i2cIdle; ioutilsGIVE_ZERO_COPY_MUTEX( pxTransferStruct, xHigherPriorityTaskWoken ); } else { /* Clear the interrupt. */ LPC_I2C2->I2CONCLR = I2C_I2CONCLR_SIC; } break; default: /* Error and naks can be implemented by extending this switch statement. */ break; } } /* Receive state machine. */ pxTransferStruct = pxRxTransferControlStructs[ uxI2CNumber ]; if( pxTransferStruct != NULL ) { switch( ulI2CStatus ) { case I2C_I2STAT_M_RX_SLAR_ACK: /* The slave address has been acknowledged. */ if( xBytesOutstanding[ uxI2CNumber ] > 1U ) { /* Expecting more than one more byte, keep ACKing. */ LPC_I2C2->I2CONSET = I2C_I2CONSET_AA; } else { /* End the reception after the next byte. */ LPC_I2C2->I2CONCLR = I2C_I2CONSET_AA; } LPC_I2C2->I2CONCLR = I2C_I2CONCLR_SIC; break; case I2C_I2STAT_M_RX_DAT_ACK: case I2C_I2STAT_M_RX_DAT_NACK: /* Data was received. The strange ( ulChar++ == 0UL ) parameter is used to ensure only a single character is received. */ ulChar = 0UL; ioutilsRX_CHARS_INTO_CIRCULAR_BUFFER_FROM_ISR( pxTransferStruct, /* The structure that contains the reference to the circular buffer. */ ( ulChar++ == 0UL ), /* While loop condition. */ LPC_I2C2->I2DAT, /* Register holding the received character. */ ulReceived, xHigherPriorityTaskWoken ); configASSERT( xBytesOutstanding[ uxI2CNumber ] ); ( xBytesOutstanding[ uxI2CNumber ] )--; if( ulI2CStatus == I2C_I2STAT_M_RX_DAT_ACK ) { if( xBytesOutstanding[ uxI2CNumber ] > 1U ) { /* Expecting more than one more byte, keep ACKing. */ LPC_I2C2->I2CONSET = I2C_I2CONSET_AA; } else { /* End the reception after the next byte. */ LPC_I2C2->I2CONCLR = I2C_I2CONSET_AA; } LPC_I2C2->I2CONCLR = I2C_I2CONCLR_SIC; } else { /* This is the last data item. */ configASSERT( xBytesOutstanding[ uxI2CNumber ] == 0U ); I2C_IntCmd( LPC_I2C2, DISABLE ); I2C_Stop( LPC_I2C2 ); xDataDirection[ uxI2CNumber ] = i2cIdle; } break; default: /* Error and naks can be implemented by extending this switch statement. */ break; } } /* If lHigherPriorityTaskWoken is now equal to pdTRUE, then a context switch should be performed before the interrupt exists. That ensures the unblocked (higher priority) task is returned to immediately. */ portEND_SWITCHING_ISR( xHigherPriorityTaskWoken ); }
portBASE_TYPE FreeRTOS_I2C_ioctl( Peripheral_Descriptor_t const pxPeripheral, uint32_t ulRequest, void *pvValue ) { Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral; uint32_t ulValue = ( uint32_t ) pvValue; const int8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( ( ( Peripheral_Control_t * const ) pxPeripheral ) ); portBASE_TYPE xReturn = pdPASS; LPC_I2C_TypeDef * pxI2C = ( LPC_I2C_TypeDef * ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) ); /* Sanity check the array index. */ configASSERT( cPeripheralNumber < ( int8_t ) ( sizeof( xIRQ ) / sizeof( IRQn_Type ) ) ); taskENTER_CRITICAL(); { switch( ulRequest ) { case ioctlSET_I2C_SLAVE_ADDRESS : ucSlaveAddresses[ cPeripheralNumber ] = ( uint8_t ) ulValue; break; case ioctlUSE_INTERRUPTS : if( ulValue == pdFALSE ) { NVIC_DisableIRQ( xIRQ[ cPeripheralNumber ] ); } else { /* Ensure the interrupt is not already enabled. */ I2C_IntCmd( pxI2C, DISABLE ); /* Clear any pending interrupts in the peripheral and NVIC. */ pxI2C->I2CONCLR = I2C_I2CONCLR_SIC; NVIC_ClearPendingIRQ( xIRQ[ cPeripheralNumber ] ); /* Set the priority of the interrupt to the minimum interrupt priority. A separate command can be issued to raise the priority if desired. The interrupt is only enabled when a transfer is started. */ NVIC_SetPriority( xIRQ[ cPeripheralNumber ], configMIN_LIBRARY_INTERRUPT_PRIORITY ); /* Remember the transfer control structure that should be used for Rx. A reference to the Tx transfer control structure is taken when a write() operation is actually performed. */ pxRxTransferControlStructs[ cPeripheralNumber ] = pxPeripheralControl->pxRxControl; } break; case ioctlSET_SPEED : /* Set up the default I2C configuration. */ I2C_SetClock( pxI2C, ulValue ); break; case ioctlSET_INTERRUPT_PRIORITY : /* The ISR uses ISR safe FreeRTOS API functions, so the priority being set must be lower than or equal to (ie numerically larger than or equal to) configMAX_LIBRARY_INTERRUPT_PRIORITY. */ configASSERT( ulValue >= configMAX_LIBRARY_INTERRUPT_PRIORITY ); NVIC_SetPriority( xIRQ[ cPeripheralNumber ], ulValue ); break; default : xReturn = pdFAIL; break; } } taskEXIT_CRITICAL(); return xReturn; }
size_t FreeRTOS_I2C_read( Peripheral_Descriptor_t const pxPeripheral, void * const pvBuffer, const size_t xBytes ) { Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral; size_t xReturn = 0U; LPC_I2C_TypeDef * const pxI2C = ( LPC_I2C_TypeDef * const ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) ); I2C_M_SETUP_Type *pxI2CTransferDefinition; const int8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( ( ( Peripheral_Control_t * const ) pxPeripheral ) ); /* Sanity check the array index. */ configASSERT( cPeripheralNumber < ( int8_t ) ( sizeof( xIRQ ) / sizeof( IRQn_Type ) ) ); configASSERT( xBytes > 0U ); /* Remove compiler warnings when configASSERT() is not defined. */ ( void ) xBytes; switch( diGET_RX_TRANSFER_TYPE( pxPeripheralControl ) ) { case ioctlUSE_POLLED_RX : #if ioconfigUSE_I2C_POLLED_RX == 1 { /* Configure the transfer data. No semaphore or queue is used here, so the application must ensure only one task attempts to make a polling write at a time. */ pxI2CTransferDefinition = ( I2C_M_SETUP_Type * ) diGET_RX_TRANSFER_STATE( pxPeripheralControl ); configASSERT( pxI2CTransferDefinition ); pxI2CTransferDefinition->sl_addr7bit = ucSlaveAddresses[ cPeripheralNumber ]; pxI2CTransferDefinition->tx_data = NULL; pxI2CTransferDefinition->tx_length = 0; pxI2CTransferDefinition->rx_data = ( uint8_t * ) pvBuffer;; pxI2CTransferDefinition->rx_length = xBytes; pxI2CTransferDefinition->retransmissions_max = boardI2C_MAX_RETRANSMISSIONS; if( I2C_MasterTransferData( pxI2C, pxI2CTransferDefinition, I2C_TRANSFER_POLLING ) == SUCCESS ) { xReturn = xBytes; } } #endif /* ioconfigUSE_I2C_POLLED_RX */ break; case ioctlUSE_CIRCULAR_BUFFER_RX : #if ioconfigUSE_I2C_CIRCULAR_BUFFER_RX == 1 { /* There is nothing to prevent multiple tasks attempting to read the circular buffer at any one time. The implementation of the circular buffer uses a semaphore to indicate when new data is available, and the semaphore will ensure that only the highest priority task that is attempting a read will actually receive bytes. */ if( xDataDirection[ cPeripheralNumber ] == i2cIdle ) { /* This is the first time read() has been called for this transfer. Start the transfer by setting the start bit, then mark the read transfer as in progress. */ pxI2C->I2CONSET = I2C_I2CONSET_STA; xDataDirection[ cPeripheralNumber ] = i2cReading; xBytesOutstanding[ cPeripheralNumber ] = xBytes; I2C_IntCmd( pxI2C, ENABLE ); } ioutilsRECEIVE_CHARS_FROM_CIRCULAR_BUFFER ( pxPeripheralControl, I2C_IntCmd( pxI2C, DISABLE ), /* Disable peripheral. */ I2C_IntCmd( pxI2C, ENABLE ), /* Enable peripheral. */ ( ( uint8_t * ) pvBuffer ), /* Data destination. */ xBytes, /* Bytes to read. */ xReturn /* Number of bytes read. */ ); } #endif /* ioconfigUSE_I2C_CIRCULAR_BUFFER_RX */ break; case ioctlUSE_CHARACTER_QUEUE_RX : /* Not (yet?) implemented for I2C. */ configASSERT( xReturn ); break; default : /* Other methods can be implemented here. */ configASSERT( xReturn ); /* Prevent compiler warnings when the configuration is set such that the following parameters are not used. */ ( void ) pvBuffer; ( void ) pxI2C; ( void ) pxI2CTransferDefinition; ( void ) cPeripheralNumber; break; } return xReturn; }
size_t FreeRTOS_I2C_write( Peripheral_Descriptor_t const pxPeripheral, const void *pvBuffer, const size_t xBytes ) { Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral; size_t xReturn = 0U; LPC_I2C_TypeDef * const pxI2C = ( LPC_I2C_TypeDef * const ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) ); I2C_M_SETUP_Type *pxI2CTransferDefinition; const int8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( ( ( Peripheral_Control_t * const ) pxPeripheral ) ); /* Remember which transfer control structure is being used, so if an interrupt is being used, it can continue the same transfer until all data has been transmitted. */ pxTxTransferControlStructs[ cPeripheralNumber ] = diGET_TX_TRANSFER_STRUCT( pxPeripheralControl ); xDataDirection[ cPeripheralNumber ] = i2cWriting; switch( diGET_TX_TRANSFER_TYPE( pxPeripheralControl ) ) { case ioctlUSE_POLLED_TX : #if ioconfigUSE_I2C_POLLED_TX == 1 { /* Configure the transfer data. No semaphore or queue is used here, so the application must ensure only one task attempts to make a polling write at a time. */ pxI2CTransferDefinition = ( I2C_M_SETUP_Type * ) diGET_TX_TRANSFER_STATE( pxPeripheralControl ); configASSERT( pxI2CTransferDefinition ); pxI2CTransferDefinition->sl_addr7bit = ucSlaveAddresses[ cPeripheralNumber ]; pxI2CTransferDefinition->tx_data = ( uint8_t * ) pvBuffer; pxI2CTransferDefinition->tx_length = xBytes; pxI2CTransferDefinition->rx_data = NULL; pxI2CTransferDefinition->rx_length = 0; pxI2CTransferDefinition->retransmissions_max = boardI2C_MAX_RETRANSMISSIONS; if( I2C_MasterTransferData( pxI2C, pxI2CTransferDefinition, I2C_TRANSFER_POLLING ) == SUCCESS ) { xReturn = xBytes; } } #endif /* ioconfigUSE_I2C_POLLED_TX_RX */ /* The transfer struct is set back to NULL as the Tx is complete before the above call to I2C_ReadWrite() completes. */ pxTxTransferControlStructs[ cPeripheralNumber ] = NULL; break; case ioctlUSE_ZERO_COPY_TX : #if ioconfigUSE_I2C_ZERO_COPY_TX == 1 { /* The implementation of the zero copy write uses a semaphore to indicate whether a write is complete (and so the buffer being written free again) or not. The semantics of using a zero copy write dictate that a zero copy write can only be attempted by a task, once the semaphore has been successfully obtained by that task. This ensure that only one task can perform a zero copy write at any one time. Ensure the semaphore is not currently available, if this function has been called without it being obtained first then it is an error. */ configASSERT( xIOUtilsGetZeroCopyWriteMutex( pxPeripheralControl, ioctlOBTAIN_WRITE_MUTEX, 0U ) == 0 ); xReturn = xBytes; ioutilsINITIATE_ZERO_COPY_TX ( pxPeripheralControl, I2C_IntCmd( pxI2C, DISABLE ), /* Disable interrupt. Not really necessary in this case as it should not be enabled anyway. */ ( void ) 0, /* As the start condition has not been sent, the interrupt is not enabled yet. */ 0, /* In this case no write is attempted and all that should happen is the buffer gets set up ready. */ pvBuffer, /* Data source. */ xReturn /* Number of bytes to be written. This will get set to zero if the write mutex is not held. */ ); /* Ensure there are not already interrupt pending. */ pxI2C->I2CONCLR = ( I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC | I2C_I2CONCLR_AAC | I2C_I2CONCLR_STAC ); /* Set start flag. */ pxI2C->I2CONSET = I2C_I2CONSET_STA; /* Now enable interrupts. */ I2C_IntCmd( pxI2C, ENABLE ); } #endif /* ioconfigUSE_I2C_ZERO_COPY_TX */ break; case ioctlUSE_CHARACTER_QUEUE_TX : /* Not (yet?) implemented for I2C. */ configASSERT( xReturn ); break; default : /* Other methods can be implemented here. For now, set the stored Tx structure back to NULL as nothing is being sent. */ pxTxTransferControlStructs[ cPeripheralNumber ] = NULL; configASSERT( xReturn ); /* Prevent compiler warnings when the configuration is set such that the following parameters are not used. */ ( void ) pvBuffer; ( void ) xBytes; ( void ) pxI2C; ( void ) pxI2CTransferDefinition; break; } return xReturn; }
/*********************************************************************//** * @brief c_entry: Main program body * @param[in] None * @return int **********************************************************************/ int c_entry(void) { PINSEL_CFG_Type PinCfg; uint8_t idx,i; /* Initialize debug via UART0 * – 115200bps * – 8 data bit * – No parity * – 1 stop bit * – No flow control */ debug_frmwrk_init(); //print menu screen print_menu(); /* I2C block ------------------------------------------------------------------- */ /* * Init I2C pin connect */ PinCfg.OpenDrain = 0; PinCfg.Pinmode = 0; PinCfg.Funcnum = 1; PinCfg.Pinnum = 27; PinCfg.Portnum = 0; PINSEL_ConfigPin(&PinCfg);//SDA0 PinCfg.Pinnum = 28; PINSEL_ConfigPin(&PinCfg);//SCL0 // Initialize I2C peripheral I2C_Init(I2CDEV, 100000); /* Configure interrupt for I2C in NVIC of ARM core */ /* Disable I2C0 interrupt */ NVIC_DisableIRQ(I2C0_IRQn); /* preemption = 1, sub-priority = 0 */ NVIC_SetPriority(I2C0_IRQn, ((0x01<<3)|0x01)); //enable I2C interrupt I2C_IntCmd(LPC_I2C0, ENABLE); /* Enable I2C operation */ I2C_Cmd(I2CDEV, ENABLE); while(1) { idx=0;count=0; while(idx<2) { if(idx==0) { _DBG_("\n\rEnter monitor buffer size: "); } idx++; switch(_DG) { case '0': count=(count<<4)|0x00;break; case '1': count=(count<<4)|0x01;break; case '2': count=(count<<4)|0x02;break; case '3': count=(count<<4)|0x03;break; case '4': count=(count<<4)|0x04;break; case '5': count=(count<<4)|0x05;break; case '6': count=(count<<4)|0x06;break; case '7': count=(count<<4)|0x07;break; case '8': count=(count<<4)|0x08;break; case '9': count=(count<<4)|0x09;break; case 'a': count=(count<<4)|0x0A;break; case 'A': count=(count<<4)|0x0A;break; case 'b': count=(count<<4)|0x0B;break; case 'B': count=(count<<4)|0x0B;break; case 'c': count=(count<<4)|0x0C;break; case 'C': count=(count<<4)|0x0C;break; case 'd': count=(count<<4)|0x0D;break; case 'D': count=(count<<4)|0x0D;break; case 'e': count=(count<<4)|0x0E;break; case 'E': count=(count<<4)|0x0E;break; case 'f': count=(count<<4)|0x0F;break; case 'F': count=(count<<4)|0x0F;break; default: idx=0;count=0;break; } if(idx==2) { if(count>BUFFER_SIZE) { _DBG_("invalid! The size is bigger than ");_DBH(BUFFER_SIZE); idx=0;count=0; } else _DBH(count); } } //Configure I2C in monitor mode I2C_MonitorModeConfig(I2CDEV,(uint32_t)I2C_MONITOR_CFG_MATCHALL, ENABLE); I2C_MonitorModeCmd(I2CDEV, ENABLE); _DBG_("\n\rStart monitoring I2C bus..."); while(done==FALSE); done=FALSE; _DBG_("done!"); for(i=0;i<count;i++) { if((i%16)==0) _DBG_(""); _DBH(buffer[i]);_DBC(0x20); buffer[i]=0; } } return 1; }