Esempio n. 1
0
/**
 * @brief   I2C error handler.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] isr       content of the ISR register to be decoded
 *
 * @notapi
 */
static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint32_t isr) {

#if STM32_I2C_USE_DMA == TRUE
  /* Clears DMA interrupt flags just to be safe.*/
  dmaStreamDisable(i2cp->dmatx);
  dmaStreamDisable(i2cp->dmarx);
#else
  /* Disabling RX and TX interrupts.*/
  i2cp->i2c->CR1 &= ~(I2C_CR1_TXIE | I2C_CR1_RXIE);
#endif

  if (isr & I2C_ISR_BERR)
    i2cp->errors |= I2C_BUS_ERROR;

  if (isr & I2C_ISR_ARLO)
    i2cp->errors |= I2C_ARBITRATION_LOST;

  if (isr & I2C_ISR_OVR)
    i2cp->errors |= I2C_OVERRUN;

  if (isr & I2C_ISR_TIMEOUT)
    i2cp->errors |= I2C_TIMEOUT;

  /* If some error has been identified then sends wakes the waiting thread.*/
  if (i2cp->errors != I2C_NO_ERROR)
    _i2c_wakeup_error_isr(i2cp);
}
Esempio n. 2
0
/**
 * @brief   Common IRQ handler.
 * @note    Tries hard to clear all the pending interrupt sources, we don't
 *          want to go through the whole ISR and have another interrupt soon
 *          after.
 *
 * @param[in] i2cp         pointer to an I2CDriver
 */
static void i2c_serve_interrupt(I2CDriver *i2cp) {
  NRF_TWIM_Type *i2c = i2cp->i2c;

  if (i2c->EVENTS_ERROR) {
    uint32_t err = i2c->ERRORSRC;
    i2c->EVENTS_ERROR = 0;
    (void)i2c->EVENTS_ERROR;

    if (err & 0x01)	// nRF52832 Product Specification v1.3 p.314 TWIM_ERRORSRC OVERRUN bit = 0x01
      i2cp->errors |= I2C_OVERRUN;
    if (err & (TWIM_ERRORSRC_ANACK_Msk | TWIM_ERRORSRC_DNACK_Msk))
      i2cp->errors |= I2C_ACK_FAILURE;

    i2c->TASKS_STOP = 1;

    _i2c_wakeup_error_isr(i2cp);
  } else if(i2c->EVENTS_STOPPED) {

    i2c->EVENTS_STOPPED = 0;
    (void)i2c->EVENTS_STOPPED;

    _i2c_wakeup_isr(i2cp);
  }
}
Esempio n. 3
0
/**
 * @brief   I2C shared ISR code.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] isr       content of the ISR register to be decoded
 *
 * @notapi
 */
static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t isr) {
  I2C_TypeDef *dp = i2cp->i2c;

  /* Special case of a received NACK, the transfer is aborted.*/
  if ((isr & I2C_ISR_NACKF) != 0U) {
#if STM32_I2C_USE_DMA == TRUE
    /* Stops the associated DMA streams.*/
    dmaStreamDisable(i2cp->dmatx);
    dmaStreamDisable(i2cp->dmarx);
#endif

    /* Error flag.*/
    i2cp->errors |= I2C_ACK_FAILURE;

    /* Transaction finished sending the STOP.*/
    dp->CR2 |= I2C_CR2_STOP;

    /* Make sure no more interrupts.*/
    dp->CR1 &= ~(I2C_CR1_TCIE | I2C_CR1_TXIE | I2C_CR1_RXIE);

    /* Errors are signaled to the upper layer.*/
    _i2c_wakeup_error_isr(i2cp);

    return;
  }

#if STM32_I2C_USE_DMA == FALSE
  /* Handling of data transfer if the DMA mode is disabled.*/
  {
    uint32_t cr1 = dp->CR1;

    if (i2cp->state == I2C_ACTIVE_TX) {
      /* Transmission phase.*/
      if (((cr1 &I2C_CR1_TXIE) != 0U) && ((isr & I2C_ISR_TXIS) != 0U)) {
        dp->TXDR = (uint32_t)*i2cp->txptr;
        i2cp->txptr++;
        i2cp->txbytes--;
        if (i2cp->txbytes == 0U) {
          dp->CR1 &= ~I2C_CR1_TXIE;
        }
      }
    }
    else {
      /* Receive phase.*/
      if (((cr1 & I2C_CR1_RXIE) != 0U) && ((isr & I2C_ISR_RXNE) != 0U)) {
        *i2cp->rxptr = (uint8_t)dp->RXDR;
        i2cp->rxptr++;
        i2cp->rxbytes--;
        if (i2cp->rxbytes == 0U) {
          dp->CR1 &= ~I2C_CR1_RXIE;
        }
      }
    }
  }
#endif

  /* Partial transfer handling, restarting the transfer and returning.*/
  if ((isr & I2C_ISR_TCR) != 0U) {
    if (i2cp->state == I2C_ACTIVE_TX) {
      i2c_lld_setup_tx_transfer(i2cp);
    }
    else {
      i2c_lld_setup_rx_transfer(i2cp);
    }
    return;
  }

  /* The following condition is true if a transfer phase has been completed.*/
  if ((isr & I2C_ISR_TC) != 0U) {
    if (i2cp->state == I2C_ACTIVE_TX) {
      /* End of the transmit phase.*/

#if STM32_I2C_USE_DMA == TRUE
      /* Disabling TX DMA channel.*/
      dmaStreamDisable(i2cp->dmatx);
#endif

      /* Starting receive phase if necessary.*/
      if (i2c_lld_get_rxbytes(i2cp) > 0U) {
        /* Setting up the peripheral.*/
        i2c_lld_setup_rx_transfer(i2cp);

#if STM32_I2C_USE_DMA == TRUE
        /* Enabling RX DMA.*/
        dmaStreamEnable(i2cp->dmarx);
#else
        /* RX interrupt enabled.*/
        dp->CR1 |= I2C_CR1_RXIE;
#endif

        /* Starts the read operation.*/
        dp->CR2 |= I2C_CR2_START;

        /* State change.*/
        i2cp->state = I2C_ACTIVE_RX;

        /* Note, returning because the transaction is not over yet.*/
        return;
      }
    }
    else {
      /* End of the receive phase.*/
#if STM32_I2C_USE_DMA == TRUE
      /* Disabling RX DMA channel.*/
      dmaStreamDisable(i2cp->dmarx);
#endif
    }

    /* Transaction finished sending the STOP.*/
    dp->CR2 |= I2C_CR2_STOP;

    /* Make sure no more 'Transfer Complete' interrupts.*/
    dp->CR1 &= ~I2C_CR1_TCIE;

    /* Normal transaction end.*/
    _i2c_wakeup_isr(i2cp);
  }
}
Esempio n. 4
0
/**
 * @brief   Common IRQ handler.
 * @note    Tries hard to clear all the pending interrupt sources, we don't
 *          want to go through the whole ISR and have another interrupt soon
 *          after.
 *
 * @param[in] i2cp         pointer to an I2CDriver
 */
static void serve_interrupt(I2CDriver *i2cp) {

  I2C_TypeDef *i2c = i2cp->i2c;
  intstate_t state = i2cp->intstate;

  if (i2c->S & I2Cx_S_ARBL) {

    i2cp->errors |= I2C_ARBITRATION_LOST;
    i2c->S |= I2Cx_S_ARBL;

  } else if (state == STATE_SEND) {

    if (i2c->S & I2Cx_S_RXAK)
      i2cp->errors |= I2C_ACK_FAILURE;
    else if (i2cp->txbuf != NULL && i2cp->txidx < i2cp->txbytes)
      i2c->D = i2cp->txbuf[i2cp->txidx++];
    else
      i2cp->intstate = STATE_STOP;

  } else if (state == STATE_DUMMY) {

    if (i2c->S & I2Cx_S_RXAK)
      i2cp->errors |= I2C_ACK_FAILURE;
    else {
      i2c->C1 &= ~I2Cx_C1_TX;

      if (i2cp->rxbytes > 1)
        i2c->C1 &= ~I2Cx_C1_TXAK;
      else
        i2c->C1 |= I2Cx_C1_TXAK;
      (void) i2c->D;
      i2cp->intstate = STATE_RECV;
    }

  } else if (state == STATE_RECV) {

    if (i2cp->rxbytes > 1) {
      if (i2cp->rxidx == (i2cp->rxbytes - 2))
        i2c->C1 |= I2Cx_C1_TXAK;
      else
        i2c->C1 &= ~I2Cx_C1_TXAK;
    }

    if (i2cp->rxidx == i2cp->rxbytes - 1)
      i2c->C1 &= ~(I2Cx_C1_TX | I2Cx_C1_MST);

    i2cp->rxbuf[i2cp->rxidx++] = i2c->D;

    if (i2cp->rxidx == i2cp->rxbytes)
      i2cp->intstate = STATE_STOP;
  }

  /* Reset interrupt flag */
  i2c->S |= I2Cx_S_IICIF;

  if (i2cp->errors != I2C_NO_ERROR)
    _i2c_wakeup_error_isr(i2cp);

  if (i2cp->intstate == STATE_STOP)
    _i2c_wakeup_isr(i2cp);
}
Esempio n. 5
0
/**
 * @brief   Common IRQ handler.
 * @note    Tries hard to clear all the pending interrupt sources, we don't
 *          want to go through the whole ISR and have another interrupt soon
 *          after.
 *
 * @param[in] i2cp         pointer to an I2CDriver
 */
static void serve_interrupt(I2CDriver *i2cp) {

  I2C_TypeDef *i2c = i2cp->i2c;
  intstate_t state = i2cp->intstate;

  /* check if we're master or slave */
  if (i2c->C1 & I2Cx_C1_MST) {
    /* master */

    if (i2c->S & I2Cx_S_ARBL) {
      /* check if we lost arbitration */
      i2cp->errors |= I2C_ARBITRATION_LOST;
      i2c->S |= I2Cx_S_ARBL;
      /* TODO: may need to do more here, reset bus? */
      /* Perhaps clear MST? */
    }

#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
    else if ((i2cp->rsta_workaround == RSTA_WORKAROUND_ON) && (i2cp->i2c->FLT & I2Cx_FLT_STARTF)) {
      i2cp->rsta_workaround = RSTA_WORKAROUND_OFF;
      /* clear+disable STARTF/STOPF interrupts and wake up the thread */
      i2cp->i2c->FLT |= I2Cx_FLT_STOPF|I2Cx_FLT_STARTF;
      i2cp->i2c->FLT &= ~I2Cx_FLT_SSIE;
      i2c->S |= I2Cx_S_IICIF;
      _i2c_wakeup_isr(i2cp);
    }
#endif /* KL27Z RST workaround */

    else if (i2c->S & I2Cx_S_TCF) {
      /* just completed byte transfer */
      if (i2c->C1 & I2Cx_C1_TX) {
        /* the byte was transmitted */

        if (state == STATE_SEND) {
          /* currently sending stuff */

          if (i2c->S & I2Cx_S_RXAK) {
            /* slave did not ACK */
            i2cp->errors |= I2C_ACK_FAILURE;
            /* the thread will be woken up at the end of ISR and release the bus */

          } else if (i2cp->txbuf != NULL && i2cp->txidx < i2cp->txbytes) {
            /* slave ACK'd and we want to send more */
            i2c->D = i2cp->txbuf[i2cp->txidx++];
          } else {
            /* slave ACK'd and we are done sending */
            i2cp->intstate = STATE_STOP;
            /* this wakes up the waiting thread at the end of ISR */
          }

        } else if (state == STATE_RECV) {
          /* should be receiving stuff, so we've just sent the address */

          if (i2c->S & I2Cx_S_RXAK) {
            /* slave did not ACK */
            i2cp->errors |= I2C_ACK_FAILURE;
            /* the thread will be woken up and release the bus */

          } else {
            /* slave ACK'd, we should be receiving next */
            i2c->C1 &= ~I2Cx_C1_TX;

            if (i2cp->rxbytes > 1) {
              /* multi-byte read, send ACK after next transfer */
              i2c->C1 &= ~I2Cx_C1_TXAK;
            } else {
              /* only 1 byte remaining, send NAK */
              i2c->C1 |= I2Cx_C1_TXAK;
            }

            (void) i2c->D; /* dummy read; triggers next receive */
          }

        } /* possibly check other states here - should not happen! */

      } else {
        /* the byte was received */

        if (state == STATE_RECV) {
          /* currently receiving stuff */
          /* the received byte is now in D */

          if (i2cp->rxbytes > 1) {
            /* expecting at least one byte after this one */
            if (i2cp->rxidx == (i2cp->rxbytes - 2)) {
              /* expecting exactly one byte after this one, NAK that one */
              i2c->C1 |= I2Cx_C1_TXAK;
            } else {
              /* expecting more than one after this one, respond with ACK */
              i2c->C1 &= ~I2Cx_C1_TXAK;
            }
          }

          if (i2cp->rxidx == i2cp->rxbytes - 1) {
            /* D is the last byte we're expecting */
            /* release bus: switch to RX mode, send STOP */
            /* need to do it now otherwise the I2C module will wait for another byte */
            // delayMicroseconds(1);
            i2c->C1 &= ~(I2Cx_C1_TX | I2Cx_C1_MST);
            i2cp->intstate = STATE_STOP;
            /* this wakes up the waiting thread at the end of ISR */
          }

          /* get the data from D; this triggers the next receive */
          i2cp->rxbuf[i2cp->rxidx++] = i2c->D;

          // if (i2cp->rxidx == i2cp->rxbytes) {
            /* done receiving */
          // }
        } /* possibly check other states here - should not happen! */
      }

    } /* possibly check other interrupt flags here */
  } else {
    /* slave */

    /* Not implemented yet */
  }

  /* Reset other interrupt sources */
#if defined(I2Cx_FLT_STOPF) /* extra flags on KL26Z and KL27Z */
  i2cp->i2c->FLT |= I2Cx_FLT_STOPF;
#endif
#if defined(I2Cx_FLT_STARTF) /* extra flags on KL27Z */
  i2cp->i2c->FLT |= I2Cx_FLT_STARTF;
#endif
  /* Reset interrupt flag */
  i2c->S |= I2Cx_S_IICIF;

  if (i2cp->errors != I2C_NO_ERROR)
    _i2c_wakeup_error_isr(i2cp);

  if (i2cp->intstate == STATE_STOP)
    _i2c_wakeup_isr(i2cp);
}
Esempio n. 6
0
/**
 * @brief   I2C shared ISR code.
 *
 * @param[in] i2cp  pointer to the @p I2CDriver object
 *
 * @notapi
 */
static void i2c_lld_serve_interrupt(I2CDriver *i2cp)
{
  I2C_TypeDef *dp = i2cp->i2c;
  uint32_t status;

  // clear MIS bit in MICR by writing 1
  dp->MICR = 1;

  // read interrupt status
  status = dp->MCS;

  if (status & TIVA_MCS_ERROR) {
    i2cp->errors |= I2C_BUS_ERROR;
  }
  if (status & TIVA_MCS_ARBLST) {
    i2cp->errors |= I2C_ARBITRATION_LOST;
  }

  if (i2cp->errors == I2C_NO_ERROR) {
    // no error detected
    switch(i2cp->intstate) {
      case STATE_IDLE: {
        _i2c_wakeup_isr(i2cp);
        break;
      }
      case STATE_WRITE_NEXT: {
        if (i2cp->txbytes == 1) {
          i2cp->intstate = STATE_WRITE_FINAL;
        }
        dp->MDR = *(i2cp->txbuf);
        i2cp->txbuf++;
        i2cp->txbytes--;
        // start transmission
        dp->MCS = TIVA_I2C_BURST_SEND_CONTINUE;
        break;
      }
      case STATE_WRITE_FINAL: {
        if (i2cp->rxbytes == 0) {
          i2cp->intstate = STATE_IDLE;
        }
        else if (i2cp->rxbytes == 1) {
          i2cp->intstate = STATE_READ_ONE;
        }
        else {
          i2cp->intstate = STATE_READ_FIRST;
        }
        dp->MDR = *(i2cp->txbuf);
        i2cp->txbuf++;
        // txbytes - 1
        i2cp->txbytes--;
        // start transmission
        dp->MCS = TIVA_I2C_BURST_SEND_FINISH;
        break;
      }
      case STATE_WAIT_ACK: {
        break;
      }
      case STATE_SEND_ACK: {
        break;
      }
      case STATE_READ_ONE: {
        i2cp->intstate = STATE_READ_WAIT;
        // Initializes driver fields, LSB = 1 -> read.
         i2cp->addr |= 1;

         // set slave address
         dp->MSA = i2cp->addr;
          i2cp->rxbytes--;
         //start receiving
         dp->MCS = TIVA_I2C_SINGLE_RECEIVE;

        break;
      }
      case STATE_READ_FIRST: {
        if (i2cp->rxbytes == 2) {
          i2cp->intstate = STATE_READ_FINAL;
        }
        else {
          i2cp->intstate = STATE_READ_NEXT;
        }

        // Initializes driver fields, LSB = 1 -> read.
         i2cp->addr |= 1;

         // set slave address
         dp->MSA = i2cp->addr;
          i2cp->rxbytes--;
         //start receiving
         dp->MCS = TIVA_I2C_BURST_RECEIVE_START;

        break;
      }
      case STATE_READ_NEXT: {
        if(i2cp->rxbytes == 2) {
          i2cp->intstate = STATE_READ_FINAL;
        }
        *(i2cp->rxbuf) = dp->MDR;
        i2cp->rxbuf++;
        i2cp->rxbytes--;
        //start receiving
        dp->MCS = TIVA_I2C_BURST_RECEIVE_CONTINUE;

        break;
      }
      case STATE_READ_FINAL: {
        i2cp->intstate = STATE_READ_WAIT;
        *(i2cp->rxbuf) = dp->MDR;
        i2cp->rxbuf++;
          i2cp->rxbytes--;
        //start receiving
        dp->MCS = TIVA_I2C_BURST_RECEIVE_FINISH;

        break;
      }
      case STATE_READ_WAIT: {
        i2cp->intstate = STATE_IDLE;
        *(i2cp->rxbuf) = dp->MDR;
        i2cp->rxbuf++;
        _i2c_wakeup_isr(i2cp);
        break;
      }
    }
  }
  else {
    // error detected
    _i2c_wakeup_error_isr(i2cp);
  }
}