示例#1
0
static inline void PPRZ_I2C_SEND_START(struct i2c_periph *periph)
{
  uint32_t i2c = (uint32_t) periph->reg_addr;

  // Reset the buffer pointer to the first byte
  periph->idx_buf = 0;

#ifdef I2C_DEBUG_LED
  LED_SHOW_ACTIVE_BITS(regs);

  LED2_ON();
  LED1_ON();
  LED1_OFF();
  LED1_ON();
  LED1_OFF();
  LED1_ON();
  LED1_OFF();
  LED2_OFF();
#endif

  // Enable Error IRQ, Event IRQ but disable Buffer IRQ
  i2c_enable_interrupt(i2c, I2C_CR2_ITERREN);
  i2c_enable_interrupt(i2c, I2C_CR2_ITEVTEN);
  i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN);

  // Issue a new start
  i2c_nack_current(i2c);
  i2c_disable_ack(i2c);
  i2c_clear_stop(i2c);
  i2c_peripheral_enable(i2c);
  i2c_send_start(i2c);
  periph->status = I2CStartRequested;

}
示例#2
0
/** Start i2c asynchronous transfer.
 *  @param obj     The I2C object
 *  @param tx        The buffer to send
 *  @param tx_length The number of words to transmit
 *  @param rx        The buffer to receive
 *  @param rx_length The number of words to receive
 *  @param address The address to be set - 7bit or 9 bit
 *  @param stop    If true, stop will be generated after the transfer is done
 *  @param handler The I2C IRQ handler to be set
 *  @param hint    DMA hint usage
 */
void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint32_t address, uint32_t stop, uint32_t handler, uint32_t event, DMAUsage hint)
{
    I2C_TransferReturn_TypeDef retval;
    if(i2c_active(obj)) return;
    if((tx_length == 0) && (rx_length == 0)) return;
    // For now, we are assuming a solely interrupt-driven implementation.

    // Store transfer config
    obj->i2c.xfer.addr = address;

    // Some combination of tx_length and rx_length will tell us what to do
    if((tx_length > 0) && (rx_length == 0)) {
        obj->i2c.xfer.flags = I2C_FLAG_WRITE;
        //Store buffer info
        obj->i2c.xfer.buf[0].data = (void *)tx;
        obj->i2c.xfer.buf[0].len  = (uint16_t) tx_length;
    } else if ((tx_length == 0) && (rx_length > 0)) {
        obj->i2c.xfer.flags = I2C_FLAG_READ;
        //Store buffer info
        obj->i2c.xfer.buf[0].data = rx;
        obj->i2c.xfer.buf[0].len  = (uint16_t) rx_length;
    } else if ((tx_length > 0) && (rx_length > 0)) {
        obj->i2c.xfer.flags = I2C_FLAG_WRITE_READ;
        //Store buffer info
        obj->i2c.xfer.buf[0].data = (void *)tx;
        obj->i2c.xfer.buf[0].len  = (uint16_t) tx_length;
        obj->i2c.xfer.buf[1].data = rx;
        obj->i2c.xfer.buf[1].len  = (uint16_t) rx_length;
    }

    if(address > 255) obj->i2c.xfer.flags |= I2C_FLAG_10BIT_ADDR;

    // Store event flags
    obj->i2c.events = event;

    // Enable interrupt
    i2c_enable_interrupt(obj, handler, true);

    // Kick off the transfer
    retval = I2C_TransferInit(obj->i2c.i2c, &(obj->i2c.xfer));

    if(retval == i2cTransferInProgress) {
        blockSleepMode(EM1);
    } else {
        // something happened, and the transfer did not go through
        // So, we need to clean up

        // Disable interrupt
        i2c_enable_interrupt(obj, 0, false);

        // Block until free
        while(i2c_active(obj));
    }
}
示例#3
0
// Doc ID 13902 Rev 11 p 714/1072
// Transfer Sequence Diagram for Master Receiver for N=1
static inline enum STMI2CSubTransactionStatus stmi2c_read1(uint32_t i2c, struct i2c_periph *periph, struct i2c_transaction *trans)
{
  uint16_t SR1 = I2C_SR1(i2c);

  // Start Condition Was Just Generated
  if (BIT_X_IS_SET_IN_REG( I2C_SR1_SB, SR1 ) )
  {
    i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN);
    i2c_send_data(i2c, trans->slave_addr | 0x01);

    // Document the current Status
    periph->status = I2CAddrRdSent;
  }
  // Address Was Sent
  else if (BIT_X_IS_SET_IN_REG(I2C_SR1_ADDR, SR1) )
  {
    // First Clear the ACK bit: after the next byte we do not want new bytes
    i2c_nack_current(i2c);
    i2c_disable_ack(i2c);

    // --- next to steps MUST be executed together to avoid missing the stop
    __I2C_REG_CRITICAL_ZONE_START;

    // Only after setting ACK, read SR2 to clear the ADDR (next byte will start arriving)
    uint16_t SR2 __attribute__ ((unused)) = I2C_SR2(i2c);

    // Schedule a Stop
    PPRZ_I2C_SEND_STOP(i2c);

    __I2C_REG_CRITICAL_ZONE_STOP;
    // --- end of critical zone -----------

    // Enable the RXNE: it will trigger as soon as the 1 byte is received to get the result
    i2c_enable_interrupt(i2c, I2C_CR2_ITBUFEN);

    // Document the current Status
    periph->status = I2CReadingLastByte;
  }
  // As soon as there is 1 byte ready to read, we have our byte
  else if (BIT_X_IS_SET_IN_REG(I2C_SR1_RxNE, SR1) )
  {
    i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN);
    trans->buf[0] = I2C_DR(i2c);

    // We got all the results (stop condition might still be in progress but this is the last interrupt)
    trans->status = I2CTransSuccess;

    // Document the current Status:
    // -the stop was actually already requested in the previous step
    periph->status = I2CStopRequested;

    return STMI2C_SubTra_Ready_StopRequested;
  }
  else // Event Logic Error
  {
    return STMI2C_SubTra_Error;
  }

  return STMI2C_SubTra_Busy;
}
示例#4
0
void i2c3_ev_isr(void) {
  uint32_t i2c = (uint32_t) i2c3.reg_addr;
  i2c_disable_interrupt(i2c, I2C_CR2_ITERREN);
  i2c3.watchdog = 0; // restart watchdog
  i2c_irq(&i2c3);
  i2c_enable_interrupt(i2c, I2C_CR2_ITERREN);
}
示例#5
0
void i2c2_er_isr(void) {
  uint32_t i2c = (uint32_t) i2c2.reg_addr;
  i2c_disable_interrupt(i2c, I2C_CR2_ITEVTEN);
  i2c2.watchdog = 0; // restart watchdog
  i2c_irq(&i2c2);
  i2c_enable_interrupt(i2c, I2C_CR2_ITEVTEN);
}
示例#6
0
/* Function to init EEPROM driver and I2C peripheral */
void eeprom_init(void)
{
	/* Enable GPIOB clock. */
	rcc_periph_clock_enable(RCC_GPIOB);
	/* set I2C1_SCL and I2C1_SDA, external pull-up resistors */
	gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6 | GPIO7);
	/* Open Drain, Speed 100 MHz */
	gpio_set_output_options(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_100MHZ, GPIO6 | GPIO7);
	/* Alternate Function: I2C1 */
	gpio_set_af(GPIOB, GPIO_AF4,  GPIO6 | GPIO7);

	/* Enable I2C1 clock. */
	rcc_periph_clock_enable(RCC_I2C1);
	/* Enable I2C1 interrupt. */
	nvic_enable_irq(NVIC_I2C1_EV_IRQ);
	/* reset I2C1 */
	i2c_reset(I2C1);
	/* standard mode */
	i2c_set_standard_mode(I2C1);
	/* clock and bus frequencies */
	i2c_set_clock_frequency(I2C1, I2C_CR2_FREQ_2MHZ);
	i2c_set_ccr(I2C1, 20);
	/* enable error event interrupt only */
	i2c_enable_interrupt(I2C1, I2C_CR2_ITERREN);
	/* enable I2C */
	i2c_peripheral_enable(I2C1);
}
示例#7
0
/** The asynchronous IRQ handler
 *  @param obj The I2C object which holds the transfer information
 *  @return Returns event flags if a transfer termination condition was met or 0 otherwise.
 */
uint32_t i2c_irq_handler_asynch(i2c_t *obj)
{

    // For now, we are assuming a solely interrupt-driven implementation.

    I2C_TransferReturn_TypeDef status = I2C_Transfer(obj->i2c.i2c);
    switch(status) {
        case i2cTransferInProgress:
            // Still busy transferring, so let it.
            return 0;
        case i2cTransferDone:
            // Transfer has completed

            // Disable interrupt
            i2c_enable_interrupt(obj, 0, false);

            unblockSleepMode(EM1);

            return I2C_EVENT_TRANSFER_COMPLETE & obj->i2c.events;
        case i2cTransferNack:
            // A NACK has been received while an ACK was expected. This is usually because the slave did not respond to the address.
            // Disable interrupt
            i2c_enable_interrupt(obj, 0, false);

            unblockSleepMode(EM1);

            return I2C_EVENT_ERROR_NO_SLAVE & obj->i2c.events;
        default:
            // An error situation has arisen.
            // Disable interrupt
            i2c_enable_interrupt(obj, 0, false);

            unblockSleepMode(EM1);

            // return error
            return I2C_EVENT_ERROR & obj->i2c.events;
    }
}
示例#8
0
void i2c1_hw_init(void) {

  i2c1.reg_addr = (void *)I2C1;
  i2c1.init_struct = NULL;
  i2c1.errors = &i2c1_errors;
  i2c1.watchdog = -1;

  /* zeros error counter */
  ZEROS_ERR_COUNTER(i2c1_errors);

  // Extra
#ifdef I2C_DEBUG_LED
  LED_INIT();
#else

  /* reset peripheral to default state ( sometimes not achieved on reset :(  ) */
  //rcc_periph_reset_pulse(RST_I2C1);

  /* Configure and enable I2C1 event interrupt --------------------------------*/
  nvic_set_priority(NVIC_I2C1_EV_IRQ, NVIC_I2C1_IRQ_PRIO);
  nvic_enable_irq(NVIC_I2C1_EV_IRQ);

  /* Configure and enable I2C1 err interrupt ----------------------------------*/
  nvic_set_priority(NVIC_I2C1_ER_IRQ, NVIC_I2C1_IRQ_PRIO+1);
  nvic_enable_irq(NVIC_I2C1_ER_IRQ);

  /* Enable peripheral clocks -------------------------------------------------*/
  /* Enable I2C1 clock */
  rcc_periph_clock_enable(RCC_I2C1);
  /* setup gpio clock and pins */
  i2c_setup_gpio(I2C1);

  rcc_periph_reset_pulse(RST_I2C1);

  // enable peripheral
  i2c_peripheral_enable(I2C1);

  /*
   * XXX: there is a function to do that already in libopencm3 but I am not
   * sure if it is correct, using direct register instead (esden)
   */
  //i2c_set_own_7bit_slave_address(I2C1, 0);
  I2C_OAR1(I2C1) = 0 | 0x4000;

  // enable error interrupts
  i2c_enable_interrupt(I2C1, I2C_CR2_ITERREN);

  i2c_setbitrate(&i2c1, I2C1_CLOCK_SPEED);
#endif
}
示例#9
0
/** Abort ongoing asynchronous transaction.
 *  @param obj The I2C object
 */
void i2c_abort_asynch(i2c_t *obj)
{
    // Do not deactivate I2C twice
    if (!i2c_active(obj)) return;

    // Disable interrupt
    i2c_enable_interrupt(obj, 0, false);

    // Abort
    obj->i2c.i2c->CMD = I2C_CMD_STOP | I2C_CMD_ABORT;

    // Block until free
    while(i2c_active(obj));

    unblockSleepMode(EM1);
}
示例#10
0
// Doc ID 13902 Rev 11 p 712/1072
// Transfer Sequence Diagram for Master Receiver for N>2
static inline enum STMI2CSubTransactionStatus stmi2c_readmany(uint32_t i2c, struct i2c_periph *periph, struct i2c_transaction *trans)
{
  uint16_t SR1 = I2C_SR1(i2c);

  // Start Condition Was Just Generated
  if (BIT_X_IS_SET_IN_REG( I2C_SR1_SB, SR1 ) )
  {
    i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN);
    // The first data byte will be acked in read many so the slave knows it should send more
    i2c_nack_current(i2c);
    i2c_enable_ack(i2c);
    // Clear the SB flag
    i2c_send_data(i2c, trans->slave_addr | 0x01);

    // Document the current Status
    periph->status = I2CAddrRdSent;
  }
  // Address Was Sent
  else if (BIT_X_IS_SET_IN_REG(I2C_SR1_ADDR, SR1) )
  {
    periph->idx_buf = 0;

    // Enable RXNE: receive an interrupt any time a byte is available
    // only enable if MORE than 3 bytes need to be read
    if (periph->idx_buf < (trans->len_r - 3))
    {
      i2c_enable_interrupt(i2c, I2C_CR2_ITBUFEN);
    }

    // ACK is still on to get more DATA
    // Read SR2 to clear the ADDR (next byte will start arriving)
    uint16_t SR2 __attribute__ ((unused)) = I2C_SR2(i2c);

    // Document the current Status
    periph->status = I2CReadingByte;
  }
  // one or more bytes are available AND we were interested in Buffer interrupts
  else if ( (BIT_X_IS_SET_IN_REG(I2C_SR1_RxNE, SR1) ) && (BIT_X_IS_SET_IN_REG(I2C_CR2_ITBUFEN, I2C_CR2(i2c)))  )
  {
    // read byte until 3 bytes remain to be read (e.g. len_r = 6, -> idx=3 means idx 3,4,5 = 3 remain to be read
    if (periph->idx_buf < (trans->len_r - 3))
    {
      trans->buf[periph->idx_buf] = I2C_DR(i2c);
      periph->idx_buf ++;
    }
    // from : 3bytes -> last byte: do nothing
    //
    // finally: this was the last byte
    else if (periph->idx_buf >= (trans->len_r - 1))
    {
      i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN);

      // Last Value
      trans->buf[periph->idx_buf] = i2c_get_data(i2c);
      periph->idx_buf ++;

      // We got all the results
      trans->status = I2CTransSuccess;

      return STMI2C_SubTra_Ready_StopRequested;
    }

    // Check for end of transaction: start waiting for BTF instead of RXNE
    if (periph->idx_buf < (trans->len_r - 3))
    {
      i2c_enable_interrupt(i2c, I2C_CR2_ITBUFEN);
    }
    else // idx >= len-3: there are 3 bytes to be read
    {
      // We want to halt I2C to have sufficient time to clear ACK, so:
      // Stop listening to RXNE as it will be triggered infinitely since we did not empty the buffer
      // on the next (second in buffer) received byte BTF will be set (buffer full and I2C halted)
      i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN);
    }
  }
  // Buffer is full while this was not a RXNE interrupt
  else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BTF, SR1) )
  {
    // Now the shift register and data register contain data(n-2) and data(n-1)
    // And I2C is halted so we have time

    // --- Make absolutely sure the next 2 I2C actions are performed with no delay
    __I2C_REG_CRITICAL_ZONE_START;

    // First we clear the ACK while the SCL is held low by BTF
    i2c_disable_ack(i2c);

    // Now that ACK is cleared we read one byte: instantly the last byte is being clocked in...
    trans->buf[periph->idx_buf] = i2c_get_data(i2c);
    periph->idx_buf ++;

    // Now the last byte is being clocked. Stop in MUST be set BEFORE the transfer of the last byte is complete
    PPRZ_I2C_SEND_STOP(i2c);

    __I2C_REG_CRITICAL_ZONE_STOP;


    // --- end of critical zone -----------

    // Document the current Status
    periph->status = I2CStopRequested;

    // read the byte2 we had in the buffer (BTF means 2 bytes available)
    trans->buf[periph->idx_buf] = i2c_get_data(i2c);
    periph->idx_buf ++;

    // Ask for an interrupt to read the last byte (which is normally still busy now)
    // The last byte will be received with RXNE
    i2c_enable_interrupt(i2c, I2C_CR2_ITBUFEN);
  }
  else // Event Logic Error
  {
    return STMI2C_SubTra_Error;
  }

  return STMI2C_SubTra_Busy;
}
示例#11
0
// Doc ID 13902 Rev 11 p 710/1072
// Transfer Sequence Diagram for Master Transmitter
static inline enum STMI2CSubTransactionStatus stmi2c_send(uint32_t i2c, struct i2c_periph *periph, struct i2c_transaction *trans)
{
  uint16_t SR1 = I2C_SR1(i2c);

  // Start Condition Was Just Generated
  if (BIT_X_IS_SET_IN_REG( I2C_SR1_SB, SR1 ) )
  {
    // Disable buffer interrupt
    i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN);
    // Send Slave address and wait for ADDR interrupt
    i2c_send_data(i2c, trans->slave_addr);
    // Document the current Status
    periph->status = I2CAddrWrSent;
  }
  // Address Was Sent
  else if (BIT_X_IS_SET_IN_REG(I2C_SR1_ADDR, SR1) )
  {
    // Now read SR2 to clear the ADDR status Bit
    uint16_t SR2  __attribute__ ((unused)) = I2C_SR2(i2c);

    // Maybe check we are transmitting (did not loose arbitration for instance)
    // if (! BIT_X_IS_SET_IN_REG(I2C_SR2_TRA, SR2)) { }
    // update: this should be caught by the ARLO error: so we will not arrive here

    // Send First max 2 bytes
    i2c_send_data(i2c, trans->buf[0]);
    if (trans->len_w > 1)
    {
      i2c_send_data(i2c, trans->buf[1]);
      periph->idx_buf = 2;
    }
    else
    {
      periph->idx_buf = 1;
    }

    // Enable buffer-space available interrupt
    // only if there is more to send: wait for TXE, no more to send: wait for BTF
    if ( periph->idx_buf < trans->len_w)
      i2c_enable_interrupt(i2c, I2C_CR2_ITBUFEN);

    // Document the current Status
    periph->status = I2CSendingByte;
  }
  // The buffer is not full anymore AND we were not waiting for BTF
  else if ((BIT_X_IS_SET_IN_REG(I2C_SR1_TxE, SR1) ) && (BIT_X_IS_SET_IN_REG(I2C_CR2_ITBUFEN, I2C_CR2(i2c)))  )
  {
    // Send the next byte
    i2c_send_data(i2c, trans->buf[periph->idx_buf]);
    periph->idx_buf++;

    // All bytes Sent? Then wait for BTF instead
    if ( periph->idx_buf >= trans->len_w)
    {
      // Not interested anymore to know the buffer has space left
      i2c_disable_interrupt(i2c, I2C_CR2_ITBUFEN);
      // Next interrupt will be BTF (or error)
    }
  }
  // BTF: means last byte was sent
  else if (BIT_X_IS_SET_IN_REG(I2C_SR1_BTF, SR1) )
  {
    if (trans->type == I2CTransTx)
    {
      // Tell the driver we are ready
      trans->status = I2CTransSuccess;
    }
    // Otherwise we still need to do the receiving part

    return STMI2C_SubTra_Ready;
  }
  else // Event Logic Error
  {
    return STMI2C_SubTra_Error;
  }

  return STMI2C_SubTra_Busy;
}
示例#12
0
static void i2c_wd_check(struct i2c_periph *periph) {
  uint32_t i2c = (uint32_t) periph->reg_addr;

  if (periph->watchdog > WD_DELAY) {
    if (periph->watchdog == WD_DELAY + 1) {

      i2c_disable_interrupt(i2c, I2C_CR2_ITEVTEN);
      i2c_disable_interrupt(i2c, I2C_CR2_ITERREN);

      i2c_peripheral_disable(i2c);

#if USE_I2C1
      if (i2c == I2C1) {
        gpio_setup_output(I2C1_GPIO_PORT, I2C1_GPIO_SCL);
        gpio_setup_input(I2C1_GPIO_PORT, I2C1_GPIO_SDA);
      }
#endif
#if USE_I2C2
      if (i2c == I2C2) {
        gpio_setup_output(I2C2_GPIO_PORT, I2C2_GPIO_SCL);
        gpio_setup_input(I2C2_GPIO_PORT, I2C2_GPIO_SDA);
      }
#endif
#if USE_I2C3
      if (i2c == I2C3) {
        gpio_setup_output(I2C3_GPIO_PORT_SCL, I2C3_GPIO_SCL);
        gpio_setup_input(I2C3_GPIO_PORT_SDA,I2C3_GPIO_SDA);
      }
#endif

      i2c_scl_clear(i2c);
    }
    else if (periph->watchdog < WD_DELAY + WD_RECOVERY_TICKS) {
      if ((periph->watchdog - WD_DELAY) % 2)
        i2c_scl_clear(i2c);
      else
        i2c_scl_set(i2c);
    }
    else {
      i2c_scl_set(i2c);

      /* setup gpios for normal i2c operation again */
      i2c_setup_gpio(i2c);

      periph->trans_insert_idx = 0;
      periph->trans_extract_idx = 0;
      periph->status = I2CIdle;

      i2c_enable_interrupt(i2c, I2C_CR2_ITEVTEN);
      i2c_enable_interrupt(i2c, I2C_CR2_ITERREN);

      i2c_peripheral_enable(i2c);
      periph->watchdog = 0; // restart watchdog

      periph->errors->timeout_tlow_cnt++;

      return;
    }
  }
  if (periph->watchdog >= 0)
    periph->watchdog++;
}
示例#13
0
static void setup_i2c_port(enum I2C_FREQ I2C_speed)
{
	// Disable I2C if it happens to be enabled
	i2c_peripheral_disable(I2C_PORT);
	dma_channel_reset(I2C_TX_DMA, I2C_TX_DMA_CHANNEL);
	i2c_disable_interrupt(I2C_PORT, (I2C_CR2_ITEVTEN | I2C_CR2_ITERREN));
	DISABLE_I2C_INTERRUPT();
	reset_i2c_pins();

	// set: Source, Destination, and Amount (DMA channel must be disabled)
	dma_set_peripheral_address(I2C_TX_DMA, I2C_TX_DMA_CHANNEL, (uint32_t)&I2C_DR(I2C_PORT));
	dma_set_memory_address(I2C_TX_DMA, I2C_TX_DMA_CHANNEL, 0);
	dma_set_number_of_data(I2C_TX_DMA, I2C_TX_DMA_CHANNEL, 0);
	// set the DMA Configuration (DMA_CCRx)
	//			 (BIT 14) mem2mem_mode disabled
	dma_set_priority(I2C_TX_DMA, I2C_TX_DMA_CHANNEL, DMA_CCR_PL_HIGH); // (BIT 12:13)
	dma_set_memory_size(I2C_TX_DMA, I2C_TX_DMA_CHANNEL, DMA_CCR_MSIZE_8BIT); // (BIT 10:11)
	dma_set_peripheral_size(I2C_TX_DMA, I2C_TX_DMA_CHANNEL, DMA_CCR_PSIZE_8BIT); // (BIT 8:9)
	dma_enable_memory_increment_mode(I2C_TX_DMA, I2C_TX_DMA_CHANNEL); // (BIT 7)
	dma_disable_peripheral_increment_mode(I2C_TX_DMA, I2C_TX_DMA_CHANNEL); // (BIT 6)
	//			 (BIT 5) Circular mode is disabled
	dma_set_read_from_memory(I2C_TX_DMA, I2C_TX_DMA_CHANNEL);	// (BIT 4)
	dma_enable_transfer_error_interrupt(I2C_TX_DMA, I2C_TX_DMA_CHANNEL); // (BIT 3)
	dma_disable_half_transfer_interrupt(I2C_TX_DMA, I2C_TX_DMA_CHANNEL); // (BIT 2)
	dma_enable_transfer_complete_interrupt(I2C_TX_DMA, I2C_TX_DMA_CHANNEL); // (BIT 1)

	// This is the slave address when not transmitting data
	i2c_set_own_7bit_slave_address(I2C_PORT, 0x32);
	// do not respond to the specified slave address
	i2c_disable_ack(I2C_PORT);
	// Use DMA to send I2C data
	i2c_enable_dma(I2C_PORT);
	// set which interrupts I2C uses
	i2c_enable_interrupt(I2C_PORT, (I2C_CR2_ITEVTEN | I2C_CR2_ITERREN));
	// APB1 is running at 36MHz = T(PCLK1) = 1/36000000 sec.
	i2c_set_clock_frequency(I2C_PORT, I2C_CR2_FREQ_36MHZ);
	// Set up the hardware for the particular speed
	switch (I2C_speed) {
		// Values found on Internet for the I2C standard
		//   STANDARD : SCL max rise time = 1000ns = 1000/1000000000 sec
		//       FAST : SCL max rise time =  300ns =  300/1000000000 sec
		// 
		// DATASHEET Function:
		//   TRISE = (T(MAX_SCL_RISE) / T(PCLK1)) + 1
		// 
		// DATASHEET Functions:
		//   STANDARD :      
		//     T(high) =      CCR * T(PCLK1)
		//     T(low)  =      CCR * T(PCLK1)
		//   FAST (DUTY=I2C_CCR_DUTY_DIV2)
		//     T(high) =      CCR * T(PCLK1)
		//     T(low)  =  2 * CCR * T(PCLK1)
		//   FAST (DUTY=I2C_CCR_DUTY_16_DIV_9)   [To reach 400KHz]
		//     T(high) =  9 * CCR * T(PCLK1)
		//     T(low)  = 16 * CCR * T(PCLK1)
		// 
		// I2C PERIOD:
		//   STANDARD
		//     PERIOD = T(high) + T(low) = (2 * CCR * T(PCLK1))
		//   FAST (DUTY=I2C_CCR_DUTY_DIV2)
		//     PERIOD = T(high) + T(low) = (3 * CCR * T(PCLK1))
		//   FAST (DUTY=I2C_CCR_DUTY_16_DIV_9)
		//     PERIOD = T(high) + T(low) = (25 * CCR * T(PCLK1))
		case I2C_400KHz:
			// I2C PERIOD: 400KHz = 400000Hz = 1/400000 sec.
			i2c_set_fast_mode(I2C_PORT);
			// I2C_CCR_DUTY_DIV2 or I2C_CCR_DUTY_16_DIV_9
			i2c_set_dutycycle(I2C_PORT, I2C_CCR_DUTY_16_DIV_9);
			// CCR = PERIOD / (25 * T(PCLK1))
			// CCR = (1/400000) / (25/36000000) = 18/5 = 3.6
			// CCR = 4 => I2C PERIOD = 360kHz
			// CCR = 3 => I2C PERIOD = 480kHz
			i2c_set_ccr(I2C_PORT, 4);	// Only fast mode can have a value less than 0x04
			// TRISE = ( (300/1000000000) / (1/36000000) ) + 1 = 59/5 = 11.8
			// TRISE = 12 => SCL max rise time ~= 305.555ns
			// TRISE = 11 => SCL max rise time ~= 277.777ns
			i2c_set_trise(I2C_PORT, 11);
			break;
		case I2C_100KHz:
			// I2C PERIOD: 100KHz = 100000Hz = 1/100000 sec.
			i2c_set_standard_mode(I2C_PORT);
			// I2C_CCR_DUTY_DIV2 or I2C_CCR_DUTY_16_DIV_9
			i2c_set_dutycycle(I2C_PORT, I2C_CCR_DUTY_DIV2);
			// CCR = PERIOD / (2 * T(PCLK1))
			// CCR = (1/100000) / (2/36000000) = 180
			i2c_set_ccr(I2C_PORT, 180);
			// TRISE = ( (1000/1000000000) / (1/36000000) ) + 1 = 37
			i2c_set_trise(I2C_PORT, 37);
			break;
		case I2C_53KHz:
			// ~= 52.91kHz is the slowest I could get to work
			// CCR value of 341 works but not 342 or higher
		case I2C_50KHz:
		default:
			// I2C PERIOD: 50KHz = 50000Hz = 1/50000 sec.
			i2c_set_standard_mode(I2C_PORT);
			// I2C_CCR_DUTY_DIV2 or I2C_CCR_DUTY_16_DIV_9
			i2c_set_dutycycle(I2C_PORT, I2C_CCR_DUTY_DIV2);
			// CCR = PERIOD / (2 * T(PCLK1))
			// CCR = (1/50000) / (2/36000000) = 360
			//   (341 works but not 342 or higher)
			i2c_set_ccr(I2C_PORT, 341);
			// TRISE = ( (1000/1000000000) / (1/36000000) ) + 1 = 37
			i2c_set_trise(I2C_PORT, 37);
			break;
	}
	i2c_peripheral_enable(I2C_PORT);

	// set the priorities for the interrupts
	nvic_set_priority(I2C_EV_IRQ, IRQ_PRI_I2C);
	nvic_set_priority(I2C_ER_IRQ, IRQ_PRI_ER_I2C);
	nvic_set_priority(I2C_DMA_IRQ, IRQ_PRI_DMA_I2C);
}