diff --git a/flight/Makefile b/flight/Makefile
index bb0345e2a..8f6e2e781 100644
--- a/flight/Makefile
+++ b/flight/Makefile
@@ -95,6 +95,7 @@ SRC += $(PIOSSTM32F10X)/pios_usart.c
SRC += $(PIOSSTM32F10X)/pios_irq.c
SRC += $(PIOSSTM32F10X)/pios_adc.c
SRC += $(PIOSSTM32F10X)/pios_servo.c
+SRC += $(PIOSSTM32F10X)/pios_i2c.c
## PIOS Hardware (Common)
SRC += $(PIOSCOMMON)/pios_settings.c
diff --git a/flight/PiOS/STM32F10x/pios_i2c.c b/flight/PiOS/STM32F10x/pios_i2c.c
new file mode 100644
index 000000000..54b3b6555
--- /dev/null
+++ b/flight/PiOS/STM32F10x/pios_i2c.c
@@ -0,0 +1,574 @@
+/**
+ ******************************************************************************
+ *
+ * @file pios_i2c.c
+ * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2009.
+ * @brief I2C Enable/Disable routines
+ * @see The GNU Public License (GPL) Version 3
+ * @defgroup PIOS_I2C I2C Communication Functions
+ * @{
+ *
+ *****************************************************************************/
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* Project Includes */
+#include "pios.h"
+
+/* Global Variables */
+volatile uint32_t PIOS_I2C_UnexpectedEvent;
+
+/* Local types */
+typedef union {
+ struct {
+ unsigned ALL:8;
+ };
+ struct {
+ unsigned BUSY:1;
+ unsigned STOP_REQUESTED:1;
+ unsigned ABORT_IF_FIRST_BYTE_0:1;
+ unsigned WRITE_WITHOUT_STOP:1;
+ };
+} TransferStateTypeDef;
+
+
+typedef struct {
+ I2C_TypeDef *base;
+
+ uint8_t i2c_address;
+ uint8_t *tx_buffer_ptr;
+ uint8_t *rx_buffer_ptr;
+ volatile uint16_t buffer_len;
+ volatile uint16_t buffer_ix;
+
+ volatile TransferStateTypeDef transfer_state;
+ volatile int32_t transfer_error;
+ volatile int32_t last_transfer_error;
+
+ volatile uint8_t i2c_semaphore;
+} I2CRecTypeDef;
+
+/* Local Prototypes */
+static void PIOS_I2C_InitPeripheral(void);
+static void EV_IRQHandler(I2CRecTypeDef *i2cx);
+static void ER_IRQHandler(I2CRecTypeDef *i2cx);
+
+/* Local Variables */
+static I2CRecTypeDef I2CRec;
+
+/**
+* Initializes IIC driver
+* \param[in] mode currently only mode 0 supported
+* \return < 0 if initialisation failed
+*/
+int32_t PIOS_I2C_Init(void)
+{
+ /* Configure IIC pins in open drain mode */
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_StructInit(&GPIO_InitStructure);
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
+
+ GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN;
+ GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStructure);
+
+ GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN;
+ GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStructure);
+
+ PIOS_I2C_InitPeripheral();
+
+ /* Now accessible for other tasks */
+ I2CRec.i2c_semaphore = 0;
+ I2CRec.last_transfer_error = 0;
+
+ /* Configure and enable I2C2 interrupts */
+ NVIC_InitTypeDef NVIC_InitStructure;
+ NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = IRQ_I2C_EV_PRIORITY;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ NVIC_InitStructure.NVIC_IRQChannel = I2C2_ER_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = IRQ_I2C_ER_PRIORITY;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* No error */
+ return 0;
+}
+
+
+/**
+* Internal function to (re-)initialize the I2C peripheral
+*/
+static void PIOS_I2C_InitPeripheral(void)
+{
+ I2C_InitTypeDef I2C_InitStructure;
+ I2CRecTypeDef *i2cx = &I2CRec;
+
+ /* Prepare I2C init-struct */
+ I2C_StructInit(&I2C_InitStructure);
+ I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
+ I2C_InitStructure.I2C_OwnAddress1 = 0;
+ I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
+ I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
+
+ /* Define base address */
+ i2cx->base = I2C2;
+
+ /* enable peripheral clock of I2C */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
+
+ /* Set I2C clock bus clock params */
+ /* Note that the STM32 driver handles value <= 100kHz differently! (duty cycle always 1:1) */
+ /* Important: bus frequencies > 400kHz don't work stable */
+ I2C_InitStructure.I2C_DutyCycle = I2C_DUTY_CYCLE;
+ I2C_InitStructure.I2C_ClockSpeed = I2C_BUS_FREQUENCY;
+
+ /* Trigger software reset via I2C_DeInit */
+ I2C_DeInit(i2cx->base);
+
+ /* Clear transfer state and error value */
+ i2cx->transfer_state.ALL = 0;
+ i2cx->transfer_error = 0;
+
+
+ /* Configure I2C peripheral */
+ I2C_Init(i2cx->base, &I2C_InitStructure);
+}
+
+
+/**
+* Semaphore handling: requests the IIC interface
+* \param[in] semaphore_type is either IIC_Blocking or IIC_Non_Blocking
+* \return Non_Blocking: returns -1 to request a retry
+* \return 0 if IIC interface free
+*/
+int32_t PIOS_I2C_TransferBegin(I2CSemaphoreTypeDef semaphore_type)
+{
+ I2CRecTypeDef *i2cx = &I2CRec;
+ int32_t status = -1;
+
+ do {
+ PIOS_IRQ_Disable();
+ if(!i2cx->i2c_semaphore) {
+ i2cx->i2c_semaphore = 1;
+ status = 0;
+ }
+ PIOS_IRQ_Enable();
+ } while(semaphore_type == I2C_Blocking && status != 0);
+
+ /* Clear transfer errors of last transmission */
+ i2cx->last_transfer_error = 0;
+ i2cx->transfer_error = 0;
+
+ return status;
+}
+
+
+/**
+* Semaphore handling: releases the IIC interface for other tasks
+* \return < 0 on errors
+*/
+int32_t PIOS_I2C_TransferFinished(void)
+{
+ I2CRec.i2c_semaphore = 0;
+
+ /* No error */
+ return 0;
+}
+
+/**
+* Returns the last transfer error
+* Will be updated by PIOS_I2C_TransferCheck(), so that the error status
+* doesn't get lost (the check function will return 0 when called again)
+* Will be cleared when a new transfer has been started successfully
+* \return last error status
+*/
+int32_t MIOS32_IIC_LastErrorGet(void)
+{
+ return I2CRec.last_transfer_error;
+}
+
+
+/**
+* Checks if transfer is finished
+* \return 0 if no ongoing transfer
+* \return 1 if ongoing transfer
+* \return < 0 if error during transfer
+* \note Note that the semaphore will be released automatically after an error
+* (PIOS_I2C_TransferBegin() has to be called again)
+*/
+int32_t PIOS_I2C_TransferCheck(void)
+{
+ I2CRecTypeDef *i2cx = &I2CRec;
+
+ /* Ongoing transfer? */
+ if(i2cx->transfer_state.BUSY) {
+ return 1;
+ }
+
+ /* Error during transfer? */
+ /* (must be done *after* BUSY check to avoid race conditon!) */
+ if(i2cx->transfer_error) {
+ /* Store error status for MIOS32_IIC_LastErrorGet() function */
+ i2cx->last_transfer_error = i2cx->transfer_error;
+ /* Clear current error status */
+ i2cx->transfer_error = 0;
+ /* Release semaphore for easier programming at user level */
+ i2cx->i2c_semaphore = 0;
+ /* And exit */
+ return i2cx->last_transfer_error;
+ }
+
+ /* No transfer */
+ return 0;
+}
+
+
+/**
+* Waits until transfer is finished
+* \return 0 if no ongoing transfer
+* \return < 0 if error during transfer
+* \note Note that the semaphore will be released automatically after an error
+* (PIOS_I2C_TransferBegin() has to be called again)
+*/
+int32_t PIOS_I2C_TransferWait(void)
+{
+ I2CRecTypeDef *i2cx = &I2CRec;
+
+ uint32_t repeat_ctr = I2C_TIMEOUT_VALUE;
+ uint16_t last_buffer_ix = i2cx->buffer_ix;
+
+ while(--repeat_ctr > 0) {
+ /* Check if buffer index has changed - if so, reload repeat counter */
+ if(i2cx->buffer_ix != last_buffer_ix) {
+ repeat_ctr = I2C_TIMEOUT_VALUE;
+ last_buffer_ix = i2cx->buffer_ix;
+ }
+
+ /* Get transfer state */
+ int32_t check_state = PIOS_I2C_TransferCheck();
+
+ /* Exit if transfer finished or error detected */
+ if(check_state <= 0) {
+ if(check_state < 0) {
+ /* Release semaphore for easier programming at user level */
+ i2cx->i2c_semaphore = 0;
+ }
+ return check_state;
+ }
+ }
+
+ /* Timeout error - something is stalling... */
+
+ /* Send stop condition */
+ I2C_GenerateSTOP(i2cx->base, ENABLE);
+
+ /* Re-initialize peripheral */
+ PIOS_I2C_InitPeripheral();
+
+ /* Release semaphore (!) */
+ i2cx->i2c_semaphore = 0;
+
+ return (i2cx->last_transfer_error = I2C_ERROR_TIMEOUT);
+}
+
+
+/**
+* Starts a new transfer. If this function is called during an ongoing
+* transfer, we wait until it has been finished and setup the new transfer
+* \param[in] transfer type:
+*
+* - I2C_Read: a common Read transfer
+*
- I2C_Write: a common Write transfer
+*
- I2C_Write_WithoutStop: don't send stop condition after transfer to allow
+* a restart condition (e.g. used to access EEPROMs)
+* \param[in] address of I2C device (bit 0 always cleared)
+* \param[in] *buffer pointer to transmit/receive buffer
+* \param[in] len number of bytes which should be transmitted/received
+* \return 0 no error
+* \return < 0 on errors, if PIOS_I2C_ERROR_PREV_OFFSET is added, the previous
+* transfer got an error (the previous task didn't use \ref PIOS_I2C_TransferWait
+* to poll the transfer state)
+* \note Note that the semaphore will be released automatically after an error
+* (PIOS_I2C_TransferBegin() has to be called again)
+*/
+int32_t PIOS_I2C_Transfer(I2CTransferTypeDef transfer, uint8_t address, uint8_t *buffer, uint16_t len)
+{
+ I2CRecTypeDef *i2cx = &I2CRec;
+ int32_t error;
+
+ /* Wait until previous transfer finished */
+ if((error = PIOS_I2C_TransferWait())) {
+ /* Transmission error during previous transfer */
+
+ /* Release semaphore for easier programming at user level */
+ i2cx->i2c_semaphore = 0;
+ return error + I2C_ERROR_PREV_OFFSET;
+ }
+
+ /* Disable interrupts */
+ I2C_ITConfig(i2cx->base, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
+
+ /* Clear transfer state and error value */
+ i2cx->transfer_state.ALL = 0;
+ i2cx->transfer_error = 0;
+
+ /* Set buffer length and start index */
+ i2cx->buffer_len = len;
+ i2cx->buffer_ix = 0;
+
+ /* Branch depending on read/write */
+ if(transfer == I2C_Read) {
+ /* Take new address/buffer/len */
+ /* Set bit 0 for read operation */
+ i2cx->i2c_address = address | 1;
+ /* Ensure that previous TX buffer won't be accessed */
+ i2cx->tx_buffer_ptr = NULL;
+ i2cx->rx_buffer_ptr = buffer;
+ } else if(transfer == I2C_Write || transfer == I2C_Write_WithoutStop) {
+ /* Take new address/buffer/len */
+ /* Clear bit 0 for write operation */
+ i2cx->i2c_address = address & 0xfe;
+ i2cx->tx_buffer_ptr = buffer;
+ /* Ensure that nothing will be received */
+ i2cx->rx_buffer_ptr = NULL;
+ /* Option to skip stop-condition generation after successful write */
+ i2cx->transfer_state.WRITE_WITHOUT_STOP = transfer == I2C_Write_WithoutStop ? 1 : 0;
+ } else {
+ /* Release semaphore for easier programming at user level */
+ i2cx->i2c_semaphore = 0;
+ return (i2cx->last_transfer_error=I2C_ERROR_UNSUPPORTED_TRANSFER_TYPE);
+ }
+
+ /* Start with ACK */
+ I2C_AcknowledgeConfig(i2cx->base, ENABLE);
+
+ /* Clear last error status */
+ i2cx->last_transfer_error = 0;
+
+ /* Notify that transfer has started */
+ i2cx->transfer_state.BUSY = 1;
+
+ /* Send start condition */
+ I2C_GenerateSTART(i2cx->base, ENABLE);
+
+ /* Enable I2V2 event, buffer and error interrupt */
+ /* This must be done *after* GenerateStart, for the case last transfer was WRITE_WITHOUT_STOP. */
+ /* In this case, start was already generated at the end of the last communication! */
+ I2C_ITConfig(i2cx->base, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, ENABLE);
+
+ /* No error */
+ return 0;
+}
+
+/**
+* Internal function for handling IIC event interrupts
+*/
+static void EV_IRQHandler(I2CRecTypeDef *i2cx)
+{
+ uint8_t b;
+
+ /* Read SR1 and SR2 at the beginning (if not done so, flags may get lost) */
+ uint32_t event = I2C_GetLastEvent(i2cx->base);
+
+ /* The order of the handling blocks is chosen by test results @ 1MHZ */
+ /* Don't change this order */
+
+ /* RxNE set, will be cleared by reading/writing DR */
+ /* Note: also BTF will be reset after a read of SR1 (TxE flag) followed by either read/write DR */
+ /* Or a START or STOP condition generated */
+ /* Failsave: really requested a receive transfer? If not, continue to check TXE flag, if not set, */
+ /* We'll end up in the unexpected event handler. */
+ if(event & I2C_FLAG_RXNE && i2cx->rx_buffer_ptr != NULL) {
+ /* Get received data */
+ b = I2C_ReceiveData(i2cx->base);
+
+ /* Failsave: still place in buffer? */
+ if(i2cx->buffer_ix < i2cx->buffer_len) {
+ i2cx->rx_buffer_ptr[i2cx->buffer_ix++] = b;
+ }
+
+ /* Last byte received, disable interrupts and return. */
+ if(i2cx->transfer_state.STOP_REQUESTED) {
+ /* Transfer finished */
+ i2cx->transfer_state.BUSY = 0;
+ /* Disable all interrupts */
+ I2C_ITConfig(i2cx->base, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
+ return;
+ }
+
+ /* Request NAK and stop condition before receiving last data */
+ if(i2cx->buffer_ix >= i2cx->buffer_len-1) {
+ /* Request NAK */
+ I2C_AcknowledgeConfig(i2cx->base, DISABLE);
+ /* Request stop condition */
+ I2C_GenerateSTOP(i2cx->base, ENABLE);
+ i2cx->transfer_state.STOP_REQUESTED = 1;
+ }
+
+ return;
+ }
+
+ /* ADDR set, TRA flag not set (indicates transmitter/receiver mode). */
+ /* ADDR will be cleared by a read of SR1 followed by a read of SR2 (done by I2C_GetLastEvent) */
+ /* If transmitter mode is selected (TRA set), we go on, TXE will be catched to send the first byte */
+ if((event & I2C_FLAG_ADDR) && !(event & I2C_FLAG_TRA)) {
+ /* Address sent (receiver mode), receiving first byte - check if we already have to request NAK/Stop */
+ if(i2cx->buffer_len == 1) {
+ /* Request NAK */
+ I2C_AcknowledgeConfig(i2cx->base, DISABLE);
+ /* Request stop condition */
+ I2C_GenerateSTOP(i2cx->base, ENABLE);
+ i2cx->transfer_state.STOP_REQUESTED = 1;
+ }
+
+ return;
+ }
+
+ /* TxE set, will be cleared by writing DR, or after START or STOP was generated */
+ /* This handling also applies for BTF, as TXE will alway be set if BTF is. */
+ /* Note: also BTF will be reset after a read of SR1 (TxE flag) followed by either read/write DR */
+ /* Or a START or STOP condition generated */
+ if(event & I2C_FLAG_TXE) {
+ /* Last byte already sent, disable interrupts and return. */
+ if(i2cx->transfer_state.STOP_REQUESTED) {
+ /* Transfer finished */
+ i2cx->transfer_state.BUSY = 0;
+ /* Disable all interrupts */
+ I2C_ITConfig(i2cx->base, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
+ return;
+ }
+
+ if(i2cx->buffer_ix < i2cx->buffer_len) {
+ /* Checking tx_buffer_ptr for NULL is a failsafe measure. */
+ I2C_SendData(i2cx->base, (i2cx->tx_buffer_ptr == NULL) ? 0 : i2cx->tx_buffer_ptr[i2cx->buffer_ix++]);
+ return;
+ }
+
+ /* Peripheral is transfering last byte, request stop condition / */
+ /* On write-without-stop transfer-type, request start condition instead */
+ if(!i2cx->transfer_state.WRITE_WITHOUT_STOP) {
+ I2C_GenerateSTOP(i2cx->base, ENABLE);
+ } else {
+ I2C_GenerateSTART(i2cx->base, ENABLE);
+ i2cx->transfer_state.STOP_REQUESTED = 1;
+ }
+
+ if(i2cx->buffer_len == 0) {
+ /* Transfer finished */
+ i2cx->transfer_state.BUSY = 0;
+ /* Disable all interrupts */
+ I2C_ITConfig(i2cx->base, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
+ } else {
+ /* Disable the I2C_IT_BUF interrupt after sending the last buffer data */
+ /* (last EV8) to not allow a new interrupt just with TxE - only BTF will generate it */
+ /* If this is not done, BUSY will be cleared before the transfer is finished */
+ I2C_ITConfig(i2cx->base, I2C_IT_BUF, DISABLE);
+ }
+
+ return;
+ }
+
+ /* SB set, cleared by reading SR1 (done by I2C_GetLastEvent) followed by writing DR register */
+ if(event & I2C_FLAG_SB) {
+ /* Don't send address if stop was requested (WRITE_WITHOUT_STOP - mode, start condition was sent) */
+ /* We have to wait for the application to start the next transfer */
+ if(i2cx->transfer_state.STOP_REQUESTED) {
+ /* Transfer finished */
+ i2cx->transfer_state.BUSY = 0;
+ /* Disable all interrupts */
+ I2C_ITConfig(i2cx->base, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
+ return;
+ }
+
+ /* Send IIC address */
+ I2C_Send7bitAddress(i2cx->base, i2cx->i2c_address,
+ (i2cx->i2c_address & 1)
+ ? I2C_Direction_Receiver
+ : I2C_Direction_Transmitter);
+ return;
+ }
+
+ /* This code is only reached if something got wrong, e.g. interrupt handler is called too late, */
+ /* The device reset itself (while testing, it was always event 0x00000000). we have to stop the transfer, */
+ /* Else read/write of corrupt data may be the result. */
+ I2C_ITConfig(i2cx->base, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
+
+ /* Notify error */
+ PIOS_I2C_UnexpectedEvent = event;
+ i2cx->transfer_error = I2C_ERROR_UNEXPECTED_EVENT;
+ i2cx->transfer_state.BUSY = 0;
+
+ /* Do dummy read to send NAK + STOP condition */
+ I2C_AcknowledgeConfig(i2cx->base, DISABLE);
+ b = I2C_ReceiveData(i2cx->base);
+ I2C_GenerateSTOP(i2cx->base, ENABLE);
+}
+
+
+/**
+* Internal function for handling IIC error interrupts
+*/
+static void ER_IRQHandler(I2CRecTypeDef *i2cx)
+{
+ /* Read SR1 and SR2 at the beginning (if not done so, flags may get lost) */
+ uint32_t event = I2C_GetLastEvent(i2cx->base);
+
+ /* Note that only one error number is available */
+ /* The order of these checks defines the priority */
+
+ /* Bus error (start/stop condition during read */
+ /* Unlikely, should only be relevant for slave mode?) */
+ if(event & I2C_FLAG_BERR) {
+ I2C_ClearITPendingBit(i2cx->base, I2C_IT_BERR);
+ i2cx->transfer_error = I2C_ERROR_BUS;
+ }
+
+ /* Arbitration lost */
+ if(event & I2C_FLAG_ARLO) {
+ I2C_ClearITPendingBit(i2cx->base, I2C_IT_ARLO);
+ i2cx->transfer_error = I2C_ERROR_ARBITRATION_LOST;
+ }
+
+ /* No acknowledge received from slave (e.g. slave not connected) */
+ if(event & I2C_FLAG_AF) {
+ I2C_ClearITPendingBit(i2cx->base, I2C_IT_AF);
+ i2cx->transfer_error = I2C_ERROR_SLAVE_NOT_CONNECTED;
+ /* Send stop condition to release bus */
+ I2C_GenerateSTOP(i2cx->base, ENABLE);
+ }
+
+ /* Disable interrupts */
+ I2C_ITConfig(i2cx->base, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
+
+ /* Notify that transfer has finished (due to the error) */
+ i2cx->transfer_state.BUSY = 0;
+}
+
+
+/* Interrupt vectors */
+void I2C2_EV_IRQHandler(void)
+{
+ EV_IRQHandler((I2CRecTypeDef *)&I2CRec);
+}
+
+void I2C2_ER_IRQHandler(void)
+{
+ ER_IRQHandler((I2CRecTypeDef *)&I2CRec);
+}
diff --git a/flight/PiOS/inc/pios_board.h b/flight/PiOS/inc/pios_board.h
index c5ea942c8..1d88a9f11 100644
--- a/flight/PiOS/inc/pios_board.h
+++ b/flight/PiOS/inc/pios_board.h
@@ -66,6 +66,11 @@
#define I2C_GPIO_PORT GPIOB
#define I2C_SDA_PIN GPIO_Pin_11
#define I2C_SCL_PIN GPIO_Pin_10
+#define I2C_DUTY_CYCLE I2C_DutyCycle_2
+#define I2C_BUS_FREQUENCY 400000
+#define I2C_TIMEOUT_VALUE 5000
+#define IRQ_I2C_EV_PRIORITY 2
+#define IRQ_I2C_ER_PRIORITY 2
//------------------------
// Onboard Pressure sensor
diff --git a/flight/PiOS/inc/pios_i2c.h b/flight/PiOS/inc/pios_i2c.h
new file mode 100644
index 000000000..116d57ba6
--- /dev/null
+++ b/flight/PiOS/inc/pios_i2c.h
@@ -0,0 +1,62 @@
+/**
+ ******************************************************************************
+ *
+ * @file pios_i2c.h
+ * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2009.
+ * @brief I2C functions header.
+ * @see The GNU Public License (GPL) Version 3
+ *
+ *****************************************************************************/
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PIOS_I2C_H
+#define PIOS_I2C_H
+
+/* Local defines */
+#define I2C_ERROR_INVALID_PORT -1
+#define I2C_ERROR_GENERAL -2
+#define I2C_ERROR_UNSUPPORTED_TRANSFER_TYPE -3
+#define I2C_ERROR_TIMEOUT -4
+#define I2C_ERROR_ARBITRATION_LOST -5
+#define I2C_ERROR_BUS -6
+#define I2C_ERROR_SLAVE_NOT_CONNECTED -7
+#define I2C_ERROR_UNEXPECTED_EVENT -8
+#define I2C_ERROR_RX_BUFFER_OVERRUN -9
+#define I2C_ERROR_PREV_OFFSET -128
+
+/* Global Types */
+typedef enum {
+ I2C_Blocking,
+ I2C_Non_Blocking
+} I2CSemaphoreTypeDef;
+
+typedef enum {
+ I2C_Read,
+ I2C_Write,
+ I2C_Write_WithoutStop
+} I2CTransferTypeDef;
+
+/* Public Functions */
+extern int32_t PIOS_I2C_Init(void);
+extern int32_t PIOS_I2C_TransferBegin(I2CSemaphoreTypeDef semaphore_type);
+extern int32_t PIOS_I2C_TransferFinished(void);
+extern int32_t PIOS_I2C_LastErrorGet(void);
+extern int32_t PIOS_I2C_TransferCheck(void);
+extern int32_t PIOS_I2C_TransferWait(void);
+extern int32_t PIOS_I2C_Transfer(I2CTransferTypeDef transfer, uint8_t address, uint8_t *buffer, uint16_t len);
+
+#endif /* PIOS_I2C_H */
diff --git a/flight/PiOS/pios.h b/flight/PiOS/pios.h
index 85c586de7..8f2b7dfd8 100644
--- a/flight/PiOS/pios.h
+++ b/flight/PiOS/pios.h
@@ -57,6 +57,7 @@
#include "pios_irq.h"
#include "pios_adc.h"
#include "pios_servo.h"
+#include "pios_i2c.h"
/* PIOS Hardware Includes (Common) */
#include "pios_settings.h"