示例#1
0
文件: efm32_i2c.c 项目: spqr/EFMoo
/***************************************************************************//**
 * @brief
 *   Initialize I2C.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @param[in] init
 *   Pointer to I2C initialization structure.
 ******************************************************************************/
void I2C_Init(I2C_TypeDef *i2c, const I2C_Init_TypeDef *init)
{
  EFM_ASSERT(I2C_REF_VALID(i2c));

  i2c->IEN = 0;
  i2c->IFC = _I2C_IFC_MASK;

  I2C_BusFreqSet(i2c, init->refFreq, init->freq, init->clhr);

  BITBAND_Peripheral(&(i2c->CTRL),
                     _I2C_CTRL_SLAVE_SHIFT,
                     ~((unsigned int)(init->master)));

  BITBAND_Peripheral(&(i2c->CTRL),
                     _I2C_CTRL_EN_SHIFT,
                     (unsigned int)(init->enable));
}
示例#2
0
/***************************************************************************//**
 * @brief
 *   Continue an initiated I2C transfer (single master mode only).
 *
 * @details
 *   This function is used repeatedly after a I2C_TransferInit() in order to
 *   complete a transfer. It may be used in polled mode as the below example
 *   shows:
 * @verbatim
 * I2C_TransferReturn_TypeDef ret;
 *
 * // Do a polled transfer
 * ret = I2C_TransferInit(I2C0, seq);
 * while (ret == i2cTransferInProgress)
 * {
 *   ret = I2C_Transfer(I2C0);
 * }
 * @endverbatim
 *  It may also be used in interrupt driven mode, where this function is invoked
 *  from the interrupt handler. Notice that if used in interrupt mode, NVIC
 *  interrupts must be configured and enabled for the I2C bus used. I2C
 *  peripheral specific interrupts are managed by this SW.
 *
 * @note
 *   Only single master mode is supported.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @return
 *   Returns status for ongoing transfer.
 *   @li #i2cTransferInProgress - indicates that transfer not finished.
 *   @li #i2cTransferDone - transfer completed successfully.
 *   @li otherwise some sort of error has occurred.
 *
 ******************************************************************************/
I2C_TransferReturn_TypeDef I2C_Transfer(I2C_TypeDef *i2c)
{
  uint32_t                tmp;
  uint32_t                pending;
  I2C_Transfer_TypeDef    *transfer;
  I2C_TransferSeq_TypeDef *seq;

  EFM_ASSERT(I2C_REF_VALID(i2c));

  /* Support up to 2 I2C buses */
  if (i2c == I2C0)
  {
    transfer = i2cTransfer;
  }
#if (I2C_COUNT > 1)
  else if (i2c == I2C1)
  {
    transfer = i2cTransfer + 1;
  }
#endif
  else
  {
    return(i2cTransferUsageFault);
  }

  seq = transfer->seq;
  for (;; )
  {
    pending = i2c->IF;

    /* If some sort of fault, abort transfer. */
    if (pending & I2C_IF_ERRORS)
    {
      if (pending & I2C_IF_ARBLOST)
      {
        /* If arbitration fault, it indicates either a slave device */
        /* not responding as expected, or other master which is not */
        /* supported by this SW. */
        transfer->result = i2cTransferArbLost;
      }
      else if (pending & I2C_IF_BUSERR)
      {
        /* A bus error indicates a misplaced start or stop, which should */
        /* not occur in master mode controlled by this SW. */
        transfer->result = i2cTransferBusErr;
      }

      /* If error situation occurred, it is difficult to know */
      /* exact cause and how to resolve. It will be up to a wrapper */
      /* to determine how to handle a fault/recovery if possible. */
      transfer->state = i2cStateDone;
      goto done;
    }

    switch (transfer->state)
    {
    /***************************************************/
    /* Send first start+address (first byte if 10 bit) */
    /***************************************************/
    case i2cStateStartAddrSend:
      if (seq->flags & I2C_FLAG_10BIT_ADDR)
      {
        tmp = (((uint32_t)(seq->addr) >> 8) & 0x06) | 0xf0;

        /* In 10 bit address mode, the address following the first */
        /* start always indicate write. */
      }
      else
      {
        tmp = (uint32_t)(seq->addr) & 0xfe;

        if (seq->flags & I2C_FLAG_READ)
        {
          /* Indicate read request */
          tmp |= 1;
        }
      }

      transfer->state = i2cStateAddrWFAckNack;
      i2c->TXDATA     = tmp; /* Data not transmitted until START sent */
      i2c->CMD        = I2C_CMD_START;
      goto done;

    /*******************************************************/
    /* Wait for ACK/NACK on address (first byte if 10 bit) */
    /*******************************************************/
    case i2cStateAddrWFAckNack:
      if (pending & I2C_IF_NACK)
      {
        i2c->IFC         = I2C_IFC_NACK;
        transfer->result = i2cTransferNack;
        transfer->state  = i2cStateWFStopSent;
        i2c->CMD         = I2C_CMD_STOP;
      }
      else if (pending & I2C_IF_ACK)
      {
        i2c->IFC = I2C_IFC_ACK;

        /* If 10 bit address, send 2nd byte of address. */
        if (seq->flags & I2C_FLAG_10BIT_ADDR)
        {
          transfer->state = i2cStateAddrWF2ndAckNack;
          i2c->TXDATA     = (uint32_t)(seq->addr) & 0xff;
        }
        else
        {
          /* Determine whether receiving or sending data */
          if (seq->flags & I2C_FLAG_READ)
          {
            transfer->state = i2cStateWFData;
            if(seq->buf[transfer->bufIndx].len==1)
            {
              i2c->CMD  = I2C_CMD_NACK;
            }
          }
          else
          {
            transfer->state = i2cStateDataSend;
            continue;
          }
        }
      }
      goto done;

    /******************************************************/
    /* Wait for ACK/NACK on second byte of 10 bit address */
    /******************************************************/
    case i2cStateAddrWF2ndAckNack:
      if (pending & I2C_IF_NACK)
      {
        i2c->IFC         = I2C_IFC_NACK;
        transfer->result = i2cTransferNack;
        transfer->state  = i2cStateWFStopSent;
        i2c->CMD         = I2C_CMD_STOP;
      }
      else if (pending & I2C_IF_ACK)
      {
        i2c->IFC = I2C_IFC_ACK;

        /* If using plain read sequence with 10 bit address, switch to send */
        /* repeated start. */
        if (seq->flags & I2C_FLAG_READ)
        {
          transfer->state = i2cStateRStartAddrSend;
        }
        /* Otherwise expected to write 0 or more bytes */
        else
        {
          transfer->state = i2cStateDataSend;
        }
        continue;
      }
      goto done;

    /*******************************/
    /* Send repeated start+address */
    /*******************************/
    case i2cStateRStartAddrSend:
      if (seq->flags & I2C_FLAG_10BIT_ADDR)
      {
        tmp = ((seq->addr >> 8) & 0x06) | 0xf0;
      }
示例#3
0
/***************************************************************************//**
 * @brief
 *   Enable/disable I2C.
 *
 * @note
 *   After enabling the I2C (from being disabled), the I2C is in BUSY state.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @param[in] enable
 *   true to enable counting, false to disable.
 ******************************************************************************/
void I2C_Enable(I2C_TypeDef *i2c, bool enable)
{
  EFM_ASSERT(I2C_REF_VALID(i2c));

  BITBAND_Peripheral(&(i2c->CTRL), _I2C_CTRL_EN_SHIFT, (unsigned int)enable);
}
示例#4
0
/***************************************************************************//**
 * @brief
 *   Enable/disable I2C.
 *
 * @note
 *   After enabling the I2C (from being disabled), the I2C is in BUSY state.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @param[in] enable
 *   true to enable counting, false to disable.
 ******************************************************************************/
void I2C_Enable(I2C_TypeDef *i2c, bool enable)
{
  EFM_ASSERT(I2C_REF_VALID(i2c));

  BUS_RegBitWrite(&(i2c->CTRL), _I2C_CTRL_EN_SHIFT, enable);
}