Ejemplo n.º 1
0
/**************************************************************************//**
 *
 * @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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
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;
		}
	}
}
Ejemplo n.º 8
0
/*********************************************************************//**
 * @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;
}
Ejemplo n.º 9
0
/*********************************************************************//**
 * @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;
}
Ejemplo n.º 10
0
/*********************************************************************//**
 * @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;
		
}
Ejemplo n.º 11
0
/*********************************************************************//**
 * @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;
}
Ejemplo n.º 16
0
/*********************************************************************//**
 * @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;
}