Ejemplo n.º 1
0
static inline msg_t _i2c_txrx_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                      const uint8_t *txbuf, size_t txbytes,
                                      uint8_t *rxbuf, size_t rxbytes,
                                      systime_t timeout) {

  (void)timeout;
  msg_t msg;

  uint8_t op = (i2cp->intstate == STATE_SEND) ? 0 : 1;

  i2cp->errors = I2C_NO_ERROR;
  i2cp->addr = addr;

  i2cp->txbuf = txbuf;
  i2cp->txbytes = txbytes;
  i2cp->txidx = 0;

  i2cp->rxbuf = rxbuf;
  i2cp->rxbytes = rxbytes;
  i2cp->rxidx = 0;

  /* send START */
  i2cp->i2c->C1 |= I2Cx_C1_MST;
  i2cp->i2c->C1 |= I2Cx_C1_TX;

  /* FIXME: should not use busy waiting! */
  while (!(i2cp->i2c->S & I2Cx_S_BUSY));

  i2cp->i2c->D = addr << 1 | op;

  msg = osalThreadSuspendTimeoutS(&i2cp->thread, TIME_INFINITE);

  /* FIXME */
  //if (i2cp->i2c->S & I2Cx_S_RXAK)
  //  i2cp->errors |= I2C_ACK_FAILURE;

  if (msg == MSG_OK && txbuf != NULL && rxbuf != NULL) {
    i2cp->i2c->C1 |= I2Cx_C1_RSTA;
    /* FIXME */
    while (!(i2cp->i2c->S & I2Cx_S_BUSY));

    i2cp->intstate = STATE_DUMMY;
    i2cp->i2c->D = i2cp->addr << 1 | 1;

    msg = osalThreadSuspendTimeoutS(&i2cp->thread, TIME_INFINITE);
  }

  i2cp->i2c->C1 &= ~(I2Cx_C1_TX | I2Cx_C1_MST);
  /* FIXME */
  while (i2cp->i2c->S & I2Cx_S_BUSY);

  return msg;
}
Ejemplo n.º 2
0
/**
 * @brief   Receives data via the I2C bus as master.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] addr      slave device address
 * @param[out] rxbuf    pointer to the receive buffer
 * @param[in] rxbytes   number of bytes to be received
 * @param[in] timeout   the number of ticks before the operation timeouts,
 *                      the following special values are allowed:
 *                      - @a TIME_INFINITE no timeout.
 *                      .
 * @return              The operation status.
 * @retval RDY_OK       if the function succeeded.
 * @retval RDY_RESET    if one or more I2C errors occurred, the errors can
 *                      be retrieved using @p i2cGetErrors().
 * @retval RDY_TIMEOUT  if a timeout occurred before operation end. <b>After a
 *                      timeout the driver must be stopped and restarted
 *                      because the bus is in an uncertain state</b>.
 *
 * @notapi
 */
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                     uint8_t *rxbuf, size_t rxbytes,
                                     systime_t timeout)
{
  I2C_TypeDef *dp = i2cp->i2c;
  systime_t start, end;

  i2cp->rxbuf = rxbuf;
  i2cp->rxbytes = rxbytes;

  /* Resetting error flags for this transfer.*/
  i2cp->errors = I2C_NO_ERROR;

  /* Initializes driver fields, LSB = 1 -> receive.*/
  i2cp->addr = (addr << 1) | 0x01;

  /* Releases the lock from high level driver.*/
  osalSysUnlock();

  /* Calculating the time window for the timeout on the busy bus condition.*/
  start = osalOsGetSystemTimeX();
  end = start + OSAL_MS2ST(TIVA_I2C_BUSY_TIMEOUT);

  /* Waits until BUSY flag is reset or, alternatively, for a timeout
     condition.*/
  while (true) {
    osalSysLock();

    /* If the bus is not busy then the operation can continue, note, the
       loop is exited in the locked state.*/
    if ((dp->MCS & TIVA_MCS_BUSY) == 0)
      break;

    /* If the system time went outside the allowed window then a timeout
       condition is returned.*/
    if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), start, end))
      return MSG_TIMEOUT;

    osalSysUnlock();
  }

  /* set slave address */
  dp->MSA = addr;

  /* Starts the operation.*/
  dp->MCS = TIVA_I2C_SINGLE_RECEIVE;

  /* Waits for the operation completion or a timeout.*/
  return osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
}
Ejemplo n.º 3
0
static inline msg_t _i2c_txrx_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                      const uint8_t *txbuf, size_t txbytes,
                                      uint8_t *rxbuf, size_t rxbytes,
                                      systime_t timeout) {

  NRF_TWIM_Type *i2c = i2cp->i2c;
  msg_t msg;

  i2cp->errors = I2C_NO_ERROR;
  i2cp->addr = addr;

  uint8_t tx_bytes = txbytes;
  uint8_t rx_bytes = rxbytes;

  i2cp->i2c->SHORTS = 0;
  i2c->ADDRESS = addr;

  if (tx_bytes && rx_bytes) {
	i2c->TXD.PTR = (uint32_t)txbuf;
	i2c->TXD.MAXCNT = tx_bytes;
	i2c->TXD.LIST = TWIM_TXD_LIST_LIST_ArrayList << TWIM_TXD_LIST_LIST_Pos;
	i2c->RXD.PTR = (uint32_t)rxbuf;
	i2c->RXD.MAXCNT = rx_bytes;
	i2c->RXD.LIST = TWIM_RXD_LIST_LIST_ArrayList << TWIM_RXD_LIST_LIST_Pos;
    i2cp->i2c->SHORTS = TWIM_SHORTS_LASTTX_STARTRX_Enabled << TWIM_SHORTS_LASTTX_STARTRX_Pos |
    					TWIM_SHORTS_LASTRX_STOP_Enabled << TWIM_SHORTS_LASTRX_STOP_Pos;
    i2c->TASKS_STARTTX = 1;
  } else if (tx_bytes && !rx_bytes) {
	i2c->TXD.PTR = (uint32_t)txbuf;
	i2c->TXD.MAXCNT = tx_bytes;
	i2c->TXD.LIST = TWIM_TXD_LIST_LIST_ArrayList << TWIM_TXD_LIST_LIST_Pos;
    i2cp->i2c->SHORTS = TWIM_SHORTS_LASTTX_STOP_Enabled << TWIM_SHORTS_LASTTX_STOP_Pos;
    i2c->TASKS_STARTTX = 1;
  } else if (!tx_bytes && rx_bytes) {
	i2c->RXD.PTR = (uint32_t)rxbuf;
	i2c->RXD.MAXCNT = rx_bytes;
	i2c->RXD.LIST = TWIM_RXD_LIST_LIST_ArrayList << TWIM_RXD_LIST_LIST_Pos;
    i2cp->i2c->SHORTS = TWIM_SHORTS_LASTRX_STOP_Enabled << TWIM_SHORTS_LASTRX_STOP_Pos;
    i2c->TASKS_STARTRX = 1;
  } else {
    osalDbgAssert(0, "no bytes to transfer");
  }

  msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);

  if (msg == MSG_TIMEOUT)
    i2c->TASKS_STOP = 1;

  return msg;
}
Ejemplo n.º 4
0
/**
 * @brief   Transmits data via the I2C bus as master.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] addr      slave device address
 * @param[in] txbuf     pointer to the transmit buffer
 * @param[in] txbytes   number of bytes to be transmitted
 * @param[out] rxbuf    pointer to the receive buffer
 * @param[in] rxbytes   number of bytes to be received
 * @param[in] timeout   the number of ticks before the operation timeouts,
 *                      the following special values are allowed:
 *                      - @a TIME_INFINITE no timeout.
 *                      .
 * @return              The operation status.
 * @retval MSG_OK       if the function succeeded.
 * @retval MSG_RESET    if one or more I2C errors occurred, the errors can
 *                      be retrieved using @p i2cGetErrors().
 * @retval MSG_TIMEOUT  if a timeout occurred before operation end. <b>After a
 *                      timeout the driver must be stopped and restarted
 *                      because the bus is in an uncertain state</b>.
 *
 * @notapi
 */
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                      const uint8_t *txbuf, size_t txbytes,
                                      uint8_t *rxbuf, size_t rxbytes,
                                      systime_t timeout) {
  i2cp->errors = I2C_NO_ERROR;
  i2cp->addr = addr;
  i2cp->txbuf = txbuf;
  i2cp->txbytes = txbytes;
  i2cp->txidx = 0;
  i2cp->rxbuf = rxbuf;
  i2cp->rxbytes = rxbytes;
  i2cp->rxidx = 0;

  TWCR = ((1 << TWSTA) | (1 << TWINT) | (1 << TWEN) | (1 << TWIE));

  return osalThreadSuspendTimeoutS(&i2cp->thread, TIME_INFINITE);
}
Ejemplo n.º 5
0
void send_mouse(report_mouse_t *report) {
  osalSysLock();
  if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
    osalSysUnlock();
    return;
  }

  if(usbGetTransmitStatusI(&USB_DRIVER, MOUSE_IN_EPNUM)) {
    /* Need to either suspend, or loop and call unlock/lock during
     * every iteration - otherwise the system will remain locked,
     * no interrupts served, so USB not going through as well.
     * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
    if (osalThreadSuspendTimeoutS(&(&USB_DRIVER)->epc[MOUSE_IN_EPNUM]->in_state->thread, MS2ST(10)==MSG_TIMEOUT)) {
      osalSysUnlock();
      return;
    }
  }
  usbStartTransmitI(&USB_DRIVER, MOUSE_IN_EPNUM, (uint8_t *)report, sizeof(report_mouse_t));
  osalSysUnlock();
}
Ejemplo n.º 6
0
/**
 * @brief   Performs a receive operation on the UART peripheral.
 * @note    The function returns when the specified number of frames have been
 *          received or on error/timeout.
 * @note    The buffers are organized as uint8_t arrays for data sizes below
 *          or equal to 8 bits else it is organized as uint16_t arrays.
 *
 * @param[in] uartp     pointer to the @p UARTDriver object
 * @param[in,out] np    number of data frames to receive, on exit the number
 *                      of frames actually received
 * @param[in] rxbuf     the pointer to the receive buffer
 * @param[in] timeout   operation timeout
 *
 * @return              The operation status.
 * @retval MSG_OK       if the operation completed successfully.
 * @retval MSG_TIMEOUT  if the operation timed out.
 * @retval MSG_RESET    in case of a receive error.
 *
 * @api
 */
msg_t uartReceiveTimeout(UARTDriver *uartp, size_t *np,
                         void *rxbuf, systime_t timeout) {
  msg_t msg;

  osalDbgCheck((uartp != NULL) && (*np > 0U) && (rxbuf != NULL));

  osalSysLock();
  osalDbgAssert(uartp->state == UART_READY, "is active");
  osalDbgAssert(uartp->rxstate != UART_RX_ACTIVE, "rx active");

  /* Receive start.*/
  uart_lld_start_receive(uartp, *np, rxbuf);
  uartp->rxstate = UART_RX_ACTIVE;

  /* Waiting for result.*/
  msg = osalThreadSuspendTimeoutS(&uartp->threadrx, timeout);
  if (msg != MSG_OK) {
    *np = uartStopReceiveI(uartp);
  }
  osalSysUnlock();

  return msg;
}
Ejemplo n.º 7
0
/**
 * @brief   Performs a transmission on the UART peripheral.
 * @note    The function returns when the specified number of frames have been
 *          physically transmitted or on timeout.
 * @note    The buffers are organized as uint8_t arrays for data sizes below
 *          or equal to 8 bits else it is organized as uint16_t arrays.
 *
 * @param[in] uartp     pointer to the @p UARTDriver object
 * @param[in,out] np    number of data frames to transmit, on exit the number
 *                      of frames actually transmitted
 * @param[in] txbuf     the pointer to the transmit buffer
 * @param[in] timeout   operation timeout
 * @return              The operation status.
 * @retval MSG_OK       if the operation completed successfully.
 * @retval MSG_TIMEOUT  if the operation timed out.
 *
 * @api
 */
msg_t uartSendFullTimeout(UARTDriver *uartp, size_t *np,
                          const void *txbuf, systime_t timeout) {
  msg_t msg;

  osalDbgCheck((uartp != NULL) && (*np > 0U) && (txbuf != NULL));

  osalSysLock();
  osalDbgAssert(uartp->state == UART_READY, "is active");
  osalDbgAssert(uartp->txstate != UART_TX_ACTIVE, "tx active");

  /* Transmission start.*/
  uartp->early = false;
  uart_lld_start_send(uartp, *np, txbuf);
  uartp->txstate = UART_TX_ACTIVE;

  /* Waiting for result.*/
  msg = osalThreadSuspendTimeoutS(&uartp->threadtx, timeout);
  if (msg != MSG_OK) {
    *np = uartStopSendI(uartp);
  }
  osalSysUnlock();

  return msg;
}
Ejemplo n.º 8
0
/**
 * @brief   Receives data via the I2C bus as master.
 * @details Number of receiving bytes must be more than 1 on STM32F1x. This is
 *          hardware restriction.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] addr      slave device address
 * @param[out] rxbuf    pointer to the receive buffer
 * @param[in] rxbytes   number of bytes to be received
 * @param[in] timeout   the number of ticks before the operation timeouts,
 *                      the following special values are allowed:
 *                      - @a TIME_INFINITE no timeout.
 *                      .
 * @return              The operation status.
 * @retval MSG_OK       if the function succeeded.
 * @retval MSG_RESET    if one or more I2C errors occurred, the errors can
 *                      be retrieved using @p i2cGetErrors().
 * @retval MSG_TIMEOUT  if a timeout occurred before operation end. <b>After a
 *                      timeout the driver must be stopped and restarted
 *                      because the bus is in an uncertain state</b>.
 *
 * @notapi
 */
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                     uint8_t *rxbuf, size_t rxbytes,
                                     systime_t timeout) {
  msg_t msg;
  I2C_TypeDef *dp = i2cp->i2c;
  systime_t start, end;

  /* Resetting error flags for this transfer.*/
  i2cp->errors = I2C_NO_ERROR;

  /* Releases the lock from high level driver.*/
  osalSysUnlock();

#if STM32_I2C_USE_DMA == TRUE
  /* RX DMA setup.*/
  dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
  dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
  dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
#else
  i2cp->rxptr   = rxbuf;
  i2cp->rxbytes = rxbytes;
#endif

  /* Calculating the time window for the timeout on the busy bus condition.*/
  start = osalOsGetSystemTimeX();
  end = start + OSAL_MS2ST(STM32_I2C_BUSY_TIMEOUT);

  /* Waits until BUSY flag is reset or, alternatively, for a timeout
     condition.*/
  while (true) {
    osalSysLock();

    /* If the bus is not busy then the operation can continue, note, the
       loop is exited in the locked state.*/
    if ((dp->ISR & I2C_ISR_BUSY) == 0)
      break;

    /* If the system time went outside the allowed window then a timeout
       condition is returned.*/
    if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), start, end)) {
      return MSG_TIMEOUT;
    }

    osalSysUnlock();
  }

  /* Setting up the slave address.*/
  i2c_lld_set_address(i2cp, addr);

  /* Setting up the peripheral.*/
  i2c_lld_setup_rx_transfer(i2cp);

#if STM32_I2C_USE_DMA == TRUE
  /* Enabling RX DMA.*/
  dmaStreamEnable(i2cp->dmarx);

  /* Transfer complete interrupt enabled.*/
  dp->CR1 |= I2C_CR1_TCIE;
#else

  /* Transfer complete and RX interrupts enabled.*/
  dp->CR1 |= I2C_CR1_TCIE | I2C_CR1_RXIE;
#endif

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

  /* Waits for the operation completion or a timeout.*/
  msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);

  /* In case of a software timeout a STOP is sent as an extreme attempt
     to release the bus.*/
  if (msg == MSG_TIMEOUT) {
    dp->CR2 |= I2C_CR2_STOP;
  }

  return msg;
}
Ejemplo n.º 9
0
static inline msg_t _i2c_txrx_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                      const uint8_t *txbuf, size_t txbytes,
                                      uint8_t *rxbuf, size_t rxbytes,
                                      systime_t timeout) {

  msg_t msg;
  systime_t start, end;

  uint8_t op = (i2cp->intstate == STATE_SEND) ? 0 : 1;

  i2cp->errors = I2C_NO_ERROR;
  i2cp->addr = addr;

  i2cp->txbuf = txbuf;
  i2cp->txbytes = txbytes;
  i2cp->txidx = 0;

  i2cp->rxbuf = rxbuf;
  i2cp->rxbytes = rxbytes;
  i2cp->rxidx = 0;

#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
  i2cp->rsta_workaround = RSTA_WORKAROUND_OFF;
#endif /* KL27Z RST workaround */

  /* clear status flags */
#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
  i2cp->i2c->S = I2Cx_S_IICIF|I2Cx_S_ARBL;

  /* acquire the bus */
  /* check to see if we already have the bus */
  if(i2cp->i2c->C1 & I2Cx_C1_MST) {

#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
    /* need to wait for STARTF interrupt after issuing repeated start,
     * otherwise the double buffering mechanism sends the last sent byte
     * instead of the slave address.
     * https://community.freescale.com/thread/377611
     */
    i2cp->rsta_workaround = RSTA_WORKAROUND_ON;
    /* clear any interrupt bits and enable STARTF/STOPF interrupts */
    i2cp->i2c->FLT |= I2Cx_FLT_STOPF|I2Cx_FLT_STARTF;
    i2cp->i2c->S |= I2Cx_S_IICIF|I2Cx_S_ARBL;
    i2cp->i2c->FLT |= I2Cx_FLT_SSIE;
#endif /* KL27Z RST workaround */

    /* send repeated start */
    i2cp->i2c->C1 |= I2Cx_C1_RSTA | I2Cx_C1_TX;

#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
    /* wait for the STARTF interrupt */
    msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
    /* abort if this didn't go well (timed out) */
    if (msg != MSG_OK) {
      /* release bus - RX mode, send STOP */
      i2cp->i2c->C1 &= ~(I2Cx_C1_TX | I2Cx_C1_MST);
      return msg;
    }
#endif /* KL27Z RST workaround */

  } else {
    /* unlock during the wait, so that tasks with
     * higher priority can get attention */
    osalSysUnlock();

    /* wait until the bus is released */
    /* Calculating the time window for the timeout on the busy bus condition.*/
    start = osalOsGetSystemTimeX();
    end = start + OSAL_MS2ST(KINETIS_I2C_BUSY_TIMEOUT);

    while(true) {
      osalSysLock();
      /* If the bus is not busy then the operation can continue, note, the
         loop is exited in the locked state.*/
      if(!(i2cp->i2c->S & I2Cx_S_BUSY))
        break;
      /* If the system time went outside the allowed window then a timeout
         condition is returned.*/
      if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), start, end)) {
        return MSG_TIMEOUT;
      }
      osalSysUnlock();
    }

    /* send START */
    i2cp->i2c->C1 |= I2Cx_C1_MST|I2Cx_C1_TX;
  }

  /* send slave address */
  i2cp->i2c->D = addr << 1 | op;

  /* wait for the ISR to signal that the transmission (or receive if no transmission) phase is complete */
  msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);

  /* FIXME */
  //if (i2cp->i2c->S & I2Cx_S_RXAK)
  //  i2cp->errors |= I2C_ACK_FAILURE;

  /* the transmitting (or receiving if no transmission) phase has finished,
   * do we expect to receive something? */
  if (msg == MSG_OK && rxbuf != NULL && rxbytes > 0 && i2cp->rxidx < rxbytes) {

#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
    /* the same KL27Z RST workaround as above */
    i2cp->rsta_workaround = RSTA_WORKAROUND_ON;
    /* clear any interrupt bits and enable STARTF/STOPF interrupts */
    i2cp->i2c->FLT |= I2Cx_FLT_STOPF|I2Cx_FLT_STARTF;
    i2cp->i2c->S |= I2Cx_S_IICIF|I2Cx_S_ARBL;
    i2cp->i2c->FLT |= I2Cx_FLT_SSIE;
#endif /* KL27Z RST workaround */

    /* send repeated start */
    i2cp->i2c->C1 |= I2Cx_C1_RSTA;

#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
    /* wait for the STARTF interrupt */
    msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
    /* abort if this didn't go well (timed out) */
    if (msg != MSG_OK) {
      /* release bus - RX mode, send STOP */
      i2cp->i2c->C1 &= ~(I2Cx_C1_TX | I2Cx_C1_MST);
      return msg;
    }
#endif /* KL27Z RST workaround */

    /* FIXME */
    // while (!(i2cp->i2c->S & I2Cx_S_BUSY));

    i2cp->intstate = STATE_RECV;
    i2cp->i2c->D = i2cp->addr << 1 | 1;

    msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
  }

  /* release bus - RX mode, send STOP */
  // other kinetis I2C drivers wait here for 1us. is this needed?
  i2cp->i2c->C1 &= ~(I2Cx_C1_TX | I2Cx_C1_MST);
  /* FIXME */
  // while (i2cp->i2c->S & I2Cx_S_BUSY);

  return msg;
}
Ejemplo n.º 10
0
/**
 * @brief   Transmits data via the I2C bus as master.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] addr      slave device address
 * @param[in] txbuf     pointer to the transmit buffer
 * @param[in] txbytes   number of bytes to be transmitted
 * @param[out] rxbuf    pointer to the receive buffer
 * @param[in] rxbytes   number of bytes to be received
 * @param[in] timeout   the number of ticks before the operation timeouts,
 *                      the following special values are allowed:
 *                      - @a TIME_INFINITE no timeout.
 *                      .
 * @return              The operation status.
 * @retval RDY_OK       if the function succeeded.
 * @retval RDY_RESET    if one or more I2C errors occurred, the errors can
 *                      be retrieved using @p i2cGetErrors().
 * @retval RDY_TIMEOUT  if a timeout occurred before operation end. <b>After a
 *                      timeout the driver must be stopped and restarted
 *                      because the bus is in an uncertain state</b>.
 *
 * @notapi
 */
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                      const uint8_t *txbuf, size_t txbytes,
                                      uint8_t *rxbuf, size_t rxbytes,
                                      systime_t timeout)
{
  I2C_TypeDef *dp = i2cp->i2c;
  systime_t start, end;

  i2cp->rxbuf = rxbuf;
  i2cp->rxbytes = rxbytes;
  i2cp->txbuf = txbuf;
  i2cp->txbytes = txbytes;

  /* Resetting error flags for this transfer.*/
  i2cp->errors = I2C_NO_ERROR;

  /* Releases the lock from high level driver.*/
  osalSysUnlock();

  /* Calculating the time window for the timeout on the busy bus condition.*/
  start = osalOsGetSystemTimeX();
  end = start + OSAL_MS2ST(TIVA_I2C_BUSY_TIMEOUT);

  /* Waits until BUSY flag is reset or, alternatively, for a timeout
     condition.*/
  while (true) {
    osalSysLock();

    /* If the bus is not busy then the operation can continue, note, the
       loop is exited in the locked state.*/
    if ((dp->MCS & TIVA_MCS_BUSY) == 0)
      break;

    /* If the system time went outside the allowed window then a timeout
       condition is returned.*/
    if (!osalOsIsTimeWithinX(osalOsGetSystemTimeX(), start, end))
      return MSG_TIMEOUT;

    osalSysUnlock();
  }

  /* Initializes driver fields, LSB = 0 -> write.*/
  i2cp->addr = addr << 1 | 0;

  /* set slave address */
  dp->MSA = i2cp->addr;

  /* enable interrupts */
  dp->MIMR = TIVA_MIMR_IM;

  /* put data in register */
  dp->MDR = *(i2cp->txbuf);

  /* check if 1 or more bytes */
  if (i2cp->txbytes == 1) {
    if (i2cp->rxbytes == 1) {
      // one byte read
      i2cp->intstate = STATE_READ_ONE;
    }
    else {
      // multiple byte read
      i2cp->intstate = STATE_READ_FIRST;
    }
    // single byte send
    dp->MCS = TIVA_I2C_SIGNLE_SEND;
  }
  else {
    if (i2cp->txbytes == 2) {
      // 2 bytes
      i2cp->intstate = STATE_WRITE_FINAL;
    }
    else {
      // more then 2 bytes
      i2cp->intstate = STATE_WRITE_NEXT;
    }
    // multiple bytes start send
    dp->MCS = TIVA_I2C_BURST_SEND_START;
  }

  i2cp->txbuf++;
  i2cp->txbytes--;

  /* Waits for the operation completion or a timeout.*/
  return osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
}