diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMR21G18A/device.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMR21G18A/device.h
index 2f8646162c..3fb36eb1eb 100644
--- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMR21G18A/device.h
+++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/TARGET_SAMR21G18A/device.h
@@ -29,8 +29,9 @@
#define DEVICE_SERIAL_FC 1
#define DEVICE_SERIAL_ASYNCH 1
-#define DEVICE_I2C 0
-#define DEVICE_I2CSLAVE 0
+#define DEVICE_I2C 1
+#define DEVICE_I2CSLAVE 1
+#define DEVICE_I2C_ASYNCH 1
#define DEVICE_SPI 1
#define DEVICE_SPISLAVE 1
diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/sercom/i2c/i2c_master_interrupt.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/sercom/i2c/i2c_master_interrupt.h
new file mode 100644
index 0000000000..ca5580515d
--- /dev/null
+++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/sercom/i2c/i2c_master_interrupt.h
@@ -0,0 +1,202 @@
+/**
+ * \file
+ *
+ * \brief SAM SERCOM I2C Master Interrupt Driver
+ *
+ * Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/**
+* Support and FAQ: visit Atmel Support
+*/
+
+#ifndef I2C_MASTER_INTERRUPT_H_INCLUDED
+#define I2C_MASTER_INTERRUPT_H_INCLUDED
+
+#include "i2c_master.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \addtogroup asfdoc_sam0_sercom_i2c_group
+ * @{
+ *
+ */
+
+/**
+ * \name Callbacks
+ * @{
+ */
+#if !defined(__DOXYGEN__)
+void _i2c_master_interrupt_handler(
+ uint8_t instance);
+#endif
+
+void i2c_master_register_callback(
+ struct i2c_master_module *const module,
+ i2c_master_callback_t callback,
+ enum i2c_master_callback callback_type);
+
+void i2c_master_unregister_callback(
+ struct i2c_master_module *const module,
+ enum i2c_master_callback callback_type);
+
+/**
+ * \brief Enables callback
+ *
+ * Enables the callback specified by the callback_type.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback_type Callback type to enable
+ */
+static inline void i2c_master_enable_callback(
+ struct i2c_master_module *const module,
+ enum i2c_master_callback callback_type)
+{
+ /* Sanity check. */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Mark callback as enabled. */
+ module->enabled_callback |= (1 << callback_type);
+}
+
+/**
+ * \brief Disables callback
+ *
+ * Disables the callback specified by the callback_type.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback_type Callback type to disable
+ */
+static inline void i2c_master_disable_callback(
+ struct i2c_master_module *const module,
+ enum i2c_master_callback callback_type)
+{
+ /* Sanity check. */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Mark callback as disabled. */
+ module->enabled_callback &= ~(1 << callback_type);
+}
+
+/** @} */
+
+/**
+ * \name Read and Write, Interrupt-Driven
+ * @{
+ */
+
+enum status_code i2c_master_read_packet_job(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+enum status_code i2c_master_read_packet_job_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+enum status_code i2c_master_write_packet_job(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+enum status_code i2c_master_write_packet_job_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+/**
+ * \brief Cancel any currently ongoing operation
+ *
+ * Terminates the running transfer operation.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static inline void i2c_master_cancel_job(
+ struct i2c_master_module *const module)
+{
+ /* Sanity check. */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Set buffer to 0. */
+ module->buffer_remaining = 0;
+ /* Update status*/
+ module->status = STATUS_ABORTED;
+}
+
+/**
+ * \brief Get status from ongoing job
+ *
+ * Will return the status of a transfer operation.
+ *
+ * \param[in] module Pointer to software module structure
+ *
+ * \return Last status code from transfer operation.
+ * \retval STATUS_OK No error has occurred
+ * \retval STATUS_BUSY If transfer is in progress
+ * \retval STATUS_BUSY If master module is busy
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ * \retval STATUS_ERR_TIMEOUT If timeout occurred
+ * \retval STATUS_ERR_OVERFLOW If slave did not acknowledge last sent
+ * data, indicating that slave does not
+ * want more data and was not able to read
+ */
+static inline enum status_code i2c_master_get_job_status(
+ struct i2c_master_module *const module)
+{
+ /* Check sanity. */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Return current status code. */
+ return module->status;
+}
+
+/** @} */
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* I2C_MASTER_INTERRUPT_H_INCLUDED */
diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/sercom/i2c/i2c_samd21_r21_d10_d11_l21/i2c_master_interrupt.c b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/sercom/i2c/i2c_samd21_r21_d10_d11_l21/i2c_master_interrupt.c
new file mode 100644
index 0000000000..166dc8921f
--- /dev/null
+++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/sercom/i2c/i2c_samd21_r21_d10_d11_l21/i2c_master_interrupt.c
@@ -0,0 +1,633 @@
+/**
+ * \file
+ *
+ * \brief SAM I2C Master Interrupt Driver
+ *
+ * Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/**
+* Support and FAQ: visit Atmel Support
+*/
+
+#include "i2c_master_interrupt.h"
+
+extern enum status_code _i2c_master_wait_for_bus(
+ struct i2c_master_module *const module);
+
+extern enum status_code _i2c_master_address_response(
+ struct i2c_master_module *const module);
+
+extern enum status_code _i2c_master_send_hs_master_code(
+ struct i2c_master_module *const module,
+ uint8_t hs_master_code);;
+
+/**
+ * \internal
+ * Read next data. Used by interrupt handler to get next data byte from slave.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static void _i2c_master_read(
+ struct i2c_master_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+ bool sclsm_flag = i2c_module->CTRLA.bit.SCLSM;
+
+ /* Find index to save next value in buffer */
+ uint16_t buffer_index = module->buffer_length;
+ buffer_index -= module->buffer_remaining;
+
+ module->buffer_remaining--;
+
+ if (sclsm_flag) {
+ if (module->buffer_remaining == 1) {
+ /* Set action to NACK. */
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+ }
+ } else {
+ if (module->buffer_remaining == 0) {
+ /* Set action to NACK. */
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+ }
+ }
+
+ if (module->buffer_remaining == 0) {
+ if (module->send_stop) {
+ /* Send stop condition */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+ }
+ }
+
+ /* Read byte from slave and put in buffer */
+ _i2c_master_wait_for_sync(module);
+ module->buffer[buffer_index] = i2c_module->DATA.reg;
+}
+
+/**
+ * \internal
+ *
+ * Write next data. Used by interrupt handler to send next data byte to slave.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static void _i2c_master_write(struct i2c_master_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Check for ack from slave */
+ if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) {
+ /* Set status */
+ module->status = STATUS_ERR_OVERFLOW;
+ /* Do not write more data */
+ return;
+ }
+
+ /* Find index to get next byte in buffer */
+ uint16_t buffer_index = module->buffer_length;
+ buffer_index -= module->buffer_remaining;
+
+ module->buffer_remaining--;
+
+ /* Write byte from buffer to slave */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->DATA.reg = module->buffer[buffer_index];
+}
+
+/**
+ * \internal
+ * Acts on slave address response. Checks for errors concerning master->slave
+ * handshake.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static void _i2c_master_async_address_response(
+ struct i2c_master_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Check for error. Ignore bus-error; workaround for bus state stuck in
+ * BUSY.
+ */
+ if (i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB) {
+ /* Clear write interrupt flag */
+ i2c_module->INTFLAG.reg = SERCOM_I2CM_INTENCLR_MB;
+
+ /* Check arbitration */
+ if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_ARBLOST) {
+ /* Return busy */
+ module->status = STATUS_ERR_PACKET_COLLISION;
+ }
+ } else if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) {
+ /* Return bad address value */
+ module->status = STATUS_ERR_BAD_ADDRESS;
+ module->buffer_remaining = 0;
+
+ if (module->send_stop) {
+ /* Send stop condition */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+ }
+ }
+
+ module->buffer_length = module->buffer_remaining;
+
+ /* Check for status OK. */
+ if (module->status == STATUS_BUSY) {
+ /* Call function based on transfer direction. */
+ if (module->transfer_direction == I2C_TRANSFER_WRITE) {
+ _i2c_master_write(module);
+ } else {
+ _i2c_master_read(module);
+ }
+ }
+}
+
+/**
+ * \brief Registers callback for the specified callback type
+ *
+ * Associates the given callback function with the
+ * specified callback type.
+ *
+ * To enable the callback, the \ref i2c_master_enable_callback function
+ * must be used.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback Pointer to the function desired for the
+ * specified callback
+ * \param[in] callback_type Callback type to register
+ */
+void i2c_master_register_callback(
+ struct i2c_master_module *const module,
+ const i2c_master_callback_t callback,
+ enum i2c_master_callback callback_type)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(callback);
+
+ /* Register callback */
+ module->callbacks[callback_type] = callback;
+
+ /* Set corresponding bit to set callback as registered */
+ module->registered_callback |= (1 << callback_type);
+}
+
+/**
+ * \brief Unregisters callback for the specified callback type
+ *
+ * When called, the currently registered callback for the given callback type
+ * will be removed.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback_type Specifies the callback type to unregister
+ */
+void i2c_master_unregister_callback(
+ struct i2c_master_module *const module,
+ enum i2c_master_callback callback_type)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Register callback */
+ module->callbacks[callback_type] = NULL;
+
+ /* Clear corresponding bit to set callback as unregistered */
+ module->registered_callback &= ~(1 << callback_type);
+}
+
+/**
+ * \internal
+ * Starts a read packet operation.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I2C packet to transfer
+ *
+ * \return Status of starting reading I2C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+static enum status_code _i2c_master_read_packet(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+ enum status_code tmp_status;
+
+ /* Save packet to software module */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->transfer_direction = I2C_TRANSFER_READ;
+ module->status = STATUS_BUSY;
+
+ /* Switch to high speed mode */
+ if (packet->high_speed) {
+ _i2c_master_send_hs_master_code(module, packet->hs_master_code);
+ }
+
+ /* Set action to ACK. */
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+
+ if (packet->ten_bit_address) {
+ /*
+ * Write ADDR.ADDR[10:1] with the 10-bit address. ADDR.TENBITEN must
+ * be set and read/write bit (ADDR.ADDR[0]) equal to 0.
+ */
+ i2c_module->ADDR.reg = (packet->address << 1) |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) |
+ SERCOM_I2CM_ADDR_TENBITEN;
+
+ /* Wait for response on bus. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+
+ /* Set action to ack. */
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+
+ /* Check for address response error unless previous error is
+ * detected. */
+ if (tmp_status == STATUS_OK) {
+ tmp_status = _i2c_master_address_response(module);
+ }
+
+ if (tmp_status == STATUS_OK) {
+ /* Enable interrupts */
+ i2c_module->INTENSET.reg =
+ SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB;
+
+ /*
+ * Write ADDR[7:0] register to 鈥10 address[9:8] 1鈥
+ * ADDR.TENBITEN must be cleared
+ */
+ i2c_module->ADDR.reg = (((packet->address >> 8) | 0x78) << 1) |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) |
+ I2C_TRANSFER_READ;
+ } else {
+ return tmp_status;
+ }
+ } else {
+ /* Enable interrupts */
+ i2c_module->INTENSET.reg =
+ SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB;
+
+ /* Set address and direction bit. Will send start command on bus */
+ i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_READ |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos);
+ }
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Initiates a read packet operation
+ *
+ * Reads a data packet from the specified slave address on the I2C
+ * bus. This is the non-blocking equivalent of \ref i2c_master_read_packet_wait.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I2C packet to transfer
+ *
+ * \return Status of starting reading I2C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_master_read_packet_job(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with a job */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Make sure we send STOP */
+ module->send_stop = true;
+
+ /* Start reading */
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \brief Initiates a read packet operation without sending a STOP condition when done
+ *
+ * Reads a data packet from the specified slave address on the I2C bus without
+ * sending a stop condition, thus retaining ownership of the bus when done.
+ * To end the transaction, a \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition must be
+ * performed.
+ *
+ * This is the non-blocking equivalent of \ref i2c_master_read_packet_wait_no_stop.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I2C packet to transfer
+ *
+ * \return Status of starting reading I2C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another operation
+ */
+enum status_code i2c_master_read_packet_job_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with a job */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Make sure we don't send STOP */
+ module->send_stop = false;
+
+ /* Start reading */
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \internal Initiates a write packet operation
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I2C packet to transfer
+ *
+ * \return Status of starting writing I2C packet job.
+ * \retval STATUS_OK If writing was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+static enum status_code _i2c_master_write_packet(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Switch to high speed mode */
+ if (packet->high_speed) {
+ _i2c_master_send_hs_master_code(module, packet->hs_master_code);
+ }
+
+ /* Set action to ACK. */
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+
+ /* Save packet to software module */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->transfer_direction = I2C_TRANSFER_WRITE;
+ module->status = STATUS_BUSY;
+
+ /* Enable interrupts */
+ i2c_module->INTENSET.reg =
+ SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB;
+
+ /* Set address and direction bit, will send start command on bus */
+ if (packet->ten_bit_address) {
+ i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) |
+ SERCOM_I2CM_ADDR_TENBITEN;
+ } else {
+ i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos);
+ }
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Initiates a write packet operation
+ *
+ * Writes a data packet to the specified slave address on the I2C
+ * bus. This is the non-blocking equivalent of \ref i2c_master_write_packet_wait.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I2C packet to transfer
+ *
+ * \return Status of starting writing I2C packet job.
+ * \retval STATUS_OK If writing was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_master_write_packet_job(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with another job. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Make sure we send STOP at end*/
+ module->send_stop = true;
+
+ /* Start write operation */
+ return _i2c_master_write_packet(module, packet);
+}
+
+/**
+ * \brief Initiates a write packet operation without sending a STOP condition when done
+ *
+ * Writes a data packet to the specified slave address on the I2C bus
+ * without sending a stop condition, thus retaining ownership of the bus when
+ * done. To end the transaction, a \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition or sending
+ * a stop with the \ref i2c_master_send_stop function must be performed.
+ *
+ * This is the non-blocking equivalent of \ref i2c_master_write_packet_wait_no_stop.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I2C packet to transfer
+ *
+ * \return Status of starting writing I2C packet job.
+ * \retval STATUS_OK If writing was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another
+ */
+enum status_code i2c_master_write_packet_job_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with another job. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Do not send stop condition when done */
+ module->send_stop = false;
+
+ /* Start write operation */
+ return _i2c_master_write_packet(module, packet);
+}
+
+/**
+ * \internal
+ * Interrupt handler for I2C master.
+ *
+ * \param[in] instance SERCOM instance that triggered the interrupt
+ */
+void _i2c_master_interrupt_handler(
+ uint8_t instance)
+{
+ /* Get software module for callback handling */
+ struct i2c_master_module *module =
+ (struct i2c_master_module*)_sercom_instances[instance];
+
+ Assert(module);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+ bool sclsm_flag = i2c_module->CTRLA.bit.SCLSM;
+
+ /* Combine callback registered and enabled masks */
+ uint8_t callback_mask = module->enabled_callback;
+ callback_mask &= module->registered_callback;
+
+ /* Check if the module should respond to address ack */
+ if ((module->buffer_length <= 0) && (module->buffer_remaining > 0)) {
+ /* Call function for address response */
+ _i2c_master_async_address_response(module);
+
+ /* Check if buffer write is done */
+ } else if ((module->buffer_length > 0) && (module->buffer_remaining <= 0) &&
+ (module->status == STATUS_BUSY) &&
+ (module->transfer_direction == I2C_TRANSFER_WRITE)) {
+ /* Stop packet operation */
+ i2c_module->INTENCLR.reg =
+ SERCOM_I2CM_INTENCLR_MB | SERCOM_I2CM_INTENCLR_SB;
+
+ module->buffer_length = 0;
+ module->status = STATUS_OK;
+
+ if (module->send_stop) {
+ /* Send stop condition */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+ }
+ if (callback_mask & (1 << I2C_MASTER_CALLBACK_WRITE_COMPLETE)) {
+ module->callbacks[I2C_MASTER_CALLBACK_WRITE_COMPLETE](module);
+ }
+
+ /* Continue buffer write/read */
+ } else if ((module->buffer_length > 0) && (module->buffer_remaining > 0)) {
+ /* Check that bus ownership is not lost */
+ if ((!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) &&
+ (!(sclsm_flag && (module->buffer_remaining == 1)))) {
+ module->status = STATUS_ERR_PACKET_COLLISION;
+ } else if (module->transfer_direction == I2C_TRANSFER_WRITE) {
+ _i2c_master_write(module);
+ } else {
+ _i2c_master_read(module);
+ }
+ }
+
+ /* Check if read buffer transfer is complete */
+ if ((module->buffer_length > 0) && (module->buffer_remaining <= 0) &&
+ (module->status == STATUS_BUSY) &&
+ (module->transfer_direction == I2C_TRANSFER_READ)) {
+
+ /* Stop packet operation */
+ i2c_module->INTENCLR.reg =
+ SERCOM_I2CM_INTENCLR_MB | SERCOM_I2CM_INTENCLR_SB;
+ module->buffer_length = 0;
+ module->status = STATUS_OK;
+
+ /* Call appropriate callback if enabled and registered */
+ if ((callback_mask & (1 << I2C_MASTER_CALLBACK_READ_COMPLETE))
+ && (module->transfer_direction == I2C_TRANSFER_READ)) {
+ module->callbacks[I2C_MASTER_CALLBACK_READ_COMPLETE](module);
+ } else if ((callback_mask & (1 << I2C_MASTER_CALLBACK_WRITE_COMPLETE))
+ && (module->transfer_direction == I2C_TRANSFER_WRITE)) {
+ module->callbacks[I2C_MASTER_CALLBACK_WRITE_COMPLETE](module);
+ }
+ }
+
+ /* Check for error */
+ if ((module->status != STATUS_BUSY) && (module->status != STATUS_OK)) {
+ /* Stop packet operation */
+ i2c_module->INTENCLR.reg = SERCOM_I2CM_INTENCLR_MB |
+ SERCOM_I2CM_INTENCLR_SB;
+
+ module->buffer_length = 0;
+ module->buffer_remaining = 0;
+
+ /* Send nack and stop command unless arbitration is lost */
+ if ((module->status != STATUS_ERR_PACKET_COLLISION) &&
+ module->send_stop) {
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT |
+ SERCOM_I2CM_CTRLB_CMD(3);
+ }
+
+ /* Call error callback if enabled and registered */
+ if (callback_mask & (1 << I2C_MASTER_CALLBACK_ERROR)) {
+ module->callbacks[I2C_MASTER_CALLBACK_ERROR](module);
+ }
+ }
+}
diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/sercom/i2c/quick_start_master_callback/qs_i2c_master_callback.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/sercom/i2c/quick_start_master_callback/qs_i2c_master_callback.h
new file mode 100644
index 0000000000..e07fab28c2
--- /dev/null
+++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/drivers/sercom/i2c/quick_start_master_callback/qs_i2c_master_callback.h
@@ -0,0 +1,131 @@
+/**
+ * \file
+ *
+ * \brief SAM SERCOM I2C Master Interface Driver
+ *
+ * Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+
+/**
+ * \page asfdoc_sam0_sercom_i2c_master_callback_use_case Quick Start Guide for SERCOM I2C Master - Callback
+ *
+ * In this use case, the I2C will used and set up as follows:
+ * - Master mode
+ * - 100KHz operation speed
+ * - Not operational in standby
+ * - 65535 unknown bus state timeout value
+ *
+ * \section asfdoc_sam0_sercom_i2c_master_callback_use_case_prereq Prerequisites
+ * The device must be connected to an I2C slave.
+ *
+ * \section asfdoc_sam0_sercom_i2c_master_callback_use_case_setup Setup
+ *
+ * \subsection asfdoc_sam0_sercom_i2c_master_callback_use_case_setup_code Code
+ * The following must be added to the user application:
+ *
+ * A sample buffer to write from, a reversed buffer to write from and length of
+ * buffers.
+ * \snippet qs_i2c_master_callback.c packet_data
+ *
+ * Address of slave:
+ * \snippet qs_i2c_master_callback.c address
+ *
+ * Globally accessible module structure:
+ * \snippet qs_i2c_master_callback.c dev_inst
+ *
+ * Globally accessible packet:
+ * \snippet qs_i2c_master_callback.c packet_glob
+ *
+ * Function for setting up module:
+ * \snippet qs_i2c_master_callback.c initialize_i2c
+ *
+ * Callback function for write complete:
+ * \snippet qs_i2c_master_callback.c callback_func
+ *
+ * Function for setting up the callback functionality of the driver:
+ * \snippet qs_i2c_master_callback.c setup_callback
+ *
+ * Add to user application \c main():
+ * \snippet qs_i2c_master_callback.c run_initialize_i2c
+ *
+ * \subsection asfdoc_sam0_sercom_i2c_master_callback_use_case_setup_workflow Workflow
+ * -# Configure and enable module.
+ * \snippet qs_i2c_master_callback.c config
+ * -# Create and initialize configuration structure.
+ * \snippet qs_i2c_master_callback.c init_conf
+ * -# Change settings in the configuration.
+ * \snippet qs_i2c_master_callback.c conf_change
+ * -# Initialize the module with the set configurations.
+ * \snippet qs_i2c_master_callback.c init_module
+ * -# Enable the module.
+ * \snippet qs_i2c_master_callback.c enable_module
+ * -# Configure callback functionality.
+ * \snippet qs_i2c_master_callback.c config_callback
+ * -# Register write complete callback.
+ * \snippet qs_i2c_master_callback.c callback_reg
+ * -# Enable write complete callback.
+ * \snippet qs_i2c_master_callback.c callback_en
+ * -# Create a packet to send to slave.
+ * \snippet qs_i2c_master_callback.c write_packet
+ *
+ * \section asfdoc_sam0_sercom_i2c_master_callback_use_case_implementation Implementation
+ * \subsection asfdoc_sam0_sercom_i2c_master_callback_use_case_code Code
+ * Add to user application \c main():
+ * \snippet qs_i2c_master_callback.c while
+ * \subsection asfdoc_sam0_sercom_i2c_master_callback_use_case_implementation_workflow Workflow
+ * -# Write packet to slave.
+ * \snippet qs_i2c_master_callback.c write_packet
+ * -# Infinite while loop, while waiting for interaction with slave.
+ * \snippet qs_i2c_master_callback.c while
+ *
+ * \section asfdoc_sam0_sercom_i2c_master_callback_use_case_callback Callback
+ * Each time a packet is sent, the callback function will be called.
+ *
+ * \subsection asfdoc_sam0_sercom_i2c_master_callback_use_case_callback_workflow Workflow
+ * - Write complete callback:
+ * -# Send every other packet in reversed order.
+ * \snippet qs_i2c_master_callback.c revert_order
+ * -# Write new packet to slave.
+ * \snippet qs_i2c_master_callback.c write_packet
+ *
+ */
+/**
+* Support and FAQ: visit Atmel Support
+*/
+
+#include
+#include
+
diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/i2c_api.c b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/i2c_api.c
new file mode 100644
index 0000000000..a063ebc14e
--- /dev/null
+++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/i2c_api.c
@@ -0,0 +1,997 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "mbed_assert.h"
+#include "dma_api.h"
+#include "i2c_api.h"
+
+#include
+
+#include "cmsis.h"
+#include "pinmap.h"
+#include "sercom.h"
+#include "i2c_master.h"
+#include "i2c_slave.h"
+
+#include "pinmap_function.h"
+
+#if DEVICE_I2C_ASYNCH
+#include "i2c_master_interrupt.h"
+#endif
+
+
+#if DEVICE_I2C_ASYNCH
+#define pI2C_S(obj) (&obj->i2c)
+#else
+#define pI2C_S(obj) obj
+#endif
+
+#define I2C_MASTER_DEFAULT_BAUD 100000
+
+/**
+ * \brief I2C modes enum
+ *
+ * I2C mode selection.
+ */
+enum i2c_mode {
+ /** Master mode. */
+ I2C_MODE_MASTER = 0x5,
+ /** Slave mode. */
+ I2C_MODE_SLAVE = 0x4,
+};
+
+/* Extern Variables */
+extern uint8_t g_sys_init;
+
+typedef void (*I2CHandler)(void);
+
+#if DEVICE_I2C_ASYNCH
+#define _SERCOM_INTERRUPT_HANDLERS(n, unused) (uint32_t)SERCOM##n##_Handler,
+
+/* To save the i2c objects */
+static uint32_t i2c_instances[SERCOM_INST_NUM] = {0};
+const uint32_t sercom_irq_handlers[SERCOM_INST_NUM] = {
+ MREPEAT(SERCOM_INST_NUM, _SERCOM_INTERRUPT_HANDLERS, ~)
+};
+#endif
+
+/* Forward declaration */
+enum status_code _i2c_master_wait_for_bus(
+ struct i2c_master_module *const module);
+
+enum status_code _i2c_master_address_response(
+ struct i2c_master_module *const module);
+
+enum status_code _i2c_master_send_hs_master_code(
+ struct i2c_master_module *const module,
+ uint8_t hs_master_code);
+
+/* Adding function from ASF for compatibility */
+static enum status_code _i2c_slave_wait_for_bus(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check arguments. */
+ MBED_ASSERT(module);
+ MBED_ASSERT(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ /* Wait for reply. */
+ uint16_t timeout_counter = 0;
+ while ((!(i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_DRDY)) &&
+ (!(i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC)) &&
+ (!(i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH))) {
+
+ /* Check timeout condition. */
+ if (++timeout_counter >= module->buffer_timeout) {
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+ return STATUS_OK;
+}
+
+/** Initialize the I2C peripheral
+ *
+ * Configures the pins used by I2C, sets a default format and frequency, and enables the peripheral
+ * @param[out] obj The I2C object to initialize
+ * @param[in] sda The pin to use for SDA
+ * @param[in] scl The pin to use for SCL
+ * @return void
+ */
+void i2c_init(i2c_t *obj, PinName sda, PinName scl)
+{
+ Sercom* hw;
+ uint32_t mux_func;
+ struct i2c_master_config config_i2c_master;
+
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(sda != NC);
+ MBED_ASSERT(scl != NC);
+
+ if (g_sys_init == 0) {
+ system_init();
+ g_sys_init = 1;
+ }
+
+ pI2C_S(obj)->pins[0] = sda;
+ pI2C_S(obj)->pins[1] = scl;
+
+ /* Calculate SERCOM instance from pins */
+ uint32_t sercom_index = pinmap_merge_sercom(sda, scl);
+ if (sercom_index == (uint32_t)NC) {
+ return;
+ }
+ hw = (Sercom*)pinmap_peripheral_sercom(NC, sercom_index);
+
+ i2c_master_get_config_defaults(&config_i2c_master);
+
+ /* SERCOM PAD0 - SDA */
+ mux_func = pinmap_function_sercom(sda, sercom_index);
+ if (mux_func == (uint32_t)NC) return;
+ config_i2c_master.pinmux_pad0 = (sda << 16) | (mux_func & 0xFFFF);
+
+ /* SERCOM PAD1 - SCL */
+ mux_func = pinmap_function_sercom(scl, sercom_index);
+ if (mux_func == (uint32_t)NC) return;
+ config_i2c_master.pinmux_pad1 = (scl << 16) | (mux_func & 0xFFFF);
+
+ config_i2c_master.start_hold_time = I2C_MASTER_START_HOLD_TIME_DISABLED;
+
+ /* Default baud rate is set to 100kHz */
+ pI2C_S(obj)->baud_rate = I2C_MASTER_DEFAULT_BAUD;
+ config_i2c_master.baud_rate = pI2C_S(obj)->baud_rate / 1000;
+
+ while(i2c_master_init(&pI2C_S(obj)->master, hw, &config_i2c_master) != STATUS_OK);
+ pI2C_S(obj)->mode = I2C_MODE_MASTER;
+
+#if DEVICE_I2C_ASYNCH
+ /* Save the i2c object */
+ i2c_instances[sercom_index] = (uint32_t)obj;
+#endif
+
+ i2c_master_enable(&pI2C_S(obj)->master);
+}
+
+/** Configure the I2C frequency.
+ * @param obj The i2c object
+ * @param hz Frequency in Hz
+ */
+void i2c_frequency(i2c_t *obj, int hz)
+{
+ /* Temporary variables. */
+ int32_t baud_rate;
+ int32_t tmp_baud;
+ int32_t tmp_baud_hs;
+ enum status_code tmp_status_code;
+
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->master.hw);
+
+ /* Return if in Slave mode, slave do not have any baud to set */
+ if (pI2C_S(obj)->mode != I2C_MODE_MASTER) return;
+
+ SercomI2cm *const i2c_module = &(pI2C_S(obj)->master.hw->I2CM);
+
+ /* Disable I2C Module */
+ i2c_master_disable(&pI2C_S(obj)->master);
+
+ baud_rate = hz / 1000; /* To kHz */
+
+ /* Give a dummy supported value */
+ pI2C_S(obj)->baud_rate_high_speed = I2C_MASTER_BAUD_RATE_3400KHZ;
+
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(pI2C_S(obj)->master.hw);
+
+ /* Find and set baudrate. */
+ tmp_baud = (int32_t)(div_ceil(
+ system_gclk_chan_get_hz(SERCOM0_GCLK_ID_CORE + sercom_index), (2000*(baud_rate))) - 5);
+
+ /* Check that baudrate is supported at current speed. */
+ if (tmp_baud > 255 || tmp_baud < 0) {
+ /* Baud rate not supported. */
+ tmp_status_code = STATUS_ERR_BAUDRATE_UNAVAILABLE;
+ } else {
+ /* Find baudrate for high speed */
+ tmp_baud_hs = (int32_t)(div_ceil(
+ system_gclk_chan_get_hz(SERCOM0_GCLK_ID_CORE + sercom_index),
+ (2000*(pI2C_S(obj)->baud_rate_high_speed))) - 1);
+
+ /* Check that baudrate is supported at current speed. */
+ if (tmp_baud_hs > 255 || tmp_baud_hs < 0) {
+ /* Baud rate not supported. */
+ tmp_status_code = STATUS_ERR_BAUDRATE_UNAVAILABLE;
+ }
+ }
+ if (tmp_status_code != STATUS_ERR_BAUDRATE_UNAVAILABLE) {
+ /* Baud rate acceptable. */
+ i2c_module->BAUD.reg = SERCOM_I2CM_BAUD_BAUD(tmp_baud) | SERCOM_I2CM_BAUD_HSBAUD(tmp_baud_hs);
+ pI2C_S(obj)->baud_rate = hz;
+ }
+
+ /* Enable back the I2C Module */
+ i2c_master_enable(&pI2C_S(obj)->master);
+}
+
+/** Send START command.
+ * @param obj The i2c object
+ */
+int i2c_start(i2c_t *obj)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+
+ if (pI2C_S(obj)->mode == I2C_MODE_MASTER) {
+ pI2C_S(obj)->start_pending = 1;
+ }
+ return 0;
+}
+
+/** Send STOP command.
+ * @param obj The i2c object
+ */
+int i2c_stop(i2c_t *obj)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+
+ if (pI2C_S(obj)->mode == I2C_MODE_MASTER) {
+ /* Send STOP command */
+ i2c_master_send_stop(&pI2C_S(obj)->master);
+ } else {
+ SercomI2cs *const i2c_hw = &(pI2C_S(obj)->slave.hw->I2CS);
+ /* Release line and wait for next start condition */
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x2);
+ }
+
+ pI2C_S(obj)->start_pending = 0;
+
+ /* TODO: Wait till STOP is send */
+ return 0;
+}
+
+/** Blocking reading data.
+ * @param obj The i2c object
+ * @param address 7-bit address (last bit is 1)
+ * @param data The buffer for receiving
+ * @param length Number of bytes to read
+ * @param stop Stop to be generated after the transfer is done
+ * @return Number of read bytes
+ */
+int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->master.hw);
+
+ enum status_code tmp_status;
+
+#if DEVICE_I2C_ASYNCH
+ if (i2c_active(obj)) {
+ /* I2C is busy with a job */
+ return 0;
+ }
+#endif
+
+ struct i2c_master_packet packet;
+ packet.address = address >> 1;
+ packet.data_length = length;
+ packet.data = (uint8_t*)data;
+ packet.ten_bit_address = false;
+ packet.high_speed = false;
+
+ if (stop) {
+ tmp_status = i2c_master_read_packet_wait(&pI2C_S(obj)->master, &packet);
+ } else {
+ tmp_status = i2c_master_read_packet_wait_no_stop(&pI2C_S(obj)->master, &packet);
+ }
+
+ if (tmp_status == STATUS_OK) {
+ return length;
+ } else {
+ /* Currently, no way to track no of bytes received, so return 0 if fail */
+ return 0;
+ }
+}
+
+/** Blocking sending data.
+ * @param obj The i2c object
+ * @param address 7-bit address (last bit is 0)
+ * @param data The buffer for sending
+ * @param length Number of bytes to write
+ * @param stop Stop to be generated after the transfer is done
+ * @return Number of written bytes
+ */
+int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->master.hw);
+
+ enum status_code tmp_status;
+
+#if DEVICE_I2C_ASYNCH
+ if (i2c_active(obj)) {
+ /* I2C is busy with a job */
+ return 0;
+ }
+#endif
+
+ struct i2c_master_packet packet;
+ packet.address = address >> 1;
+ packet.data_length = length;
+ packet.data = data;
+ packet.ten_bit_address = false;
+ packet.high_speed = false;
+
+ if (stop) {
+ tmp_status = i2c_master_write_packet_wait(&pI2C_S(obj)->master, &packet);
+ } else {
+ tmp_status = i2c_master_write_packet_wait_no_stop(&pI2C_S(obj)->master, &packet);
+ }
+
+ if (tmp_status == STATUS_OK) {
+ return length;
+ } else {
+ /* Currently, no way to track no of bytes transmitted, so return 0 if fail */
+ return 0;
+ }
+}
+
+/** Reset I2C peripheral. TODO: The action here. Most of the implementation sends stop().
+ * @param obj The i2c object
+ */
+void i2c_reset(i2c_t *obj)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+
+ /* Send STOP */
+ i2c_stop(obj);
+
+ if (pI2C_S(obj)->mode == I2C_MODE_MASTER) {
+ pI2C_S(obj)->start_pending = 0;
+ /* Reset the master module */
+ i2c_master_reset(&pI2C_S(obj)->master);
+ } else {
+ /* Reset the slave module */
+ i2c_slave_reset(&pI2C_S(obj)->slave);
+ }
+}
+
+/** Write address preceded by START condition.
+ * @param obj The i2c object
+ * @param address Address to be placed
+ * @param rw_flag read or write flag
+ * @return 1 if NAK was received, 0 if ACK was received, 2 for timeout.
+ */
+int i2c_write_address(i2c_t *obj, int address, int rw_flag)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->master.hw);
+
+ enum status_code tmp_status;
+ SercomI2cm *const i2c_module = &(pI2C_S(obj)->master.hw->I2CM);
+
+ _i2c_master_wait_for_sync(&pI2C_S(obj)->master);
+
+ /* Set action to ACK. */
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+
+ i2c_module->ADDR.reg = (address << 1) | rw_flag | (0 << SERCOM_I2CM_ADDR_HS_Pos);
+
+ /* Wait for response on bus. */
+ tmp_status = _i2c_master_wait_for_bus(&pI2C_S(obj)->master);
+ /* Check for error. */
+ if (tmp_status != STATUS_OK) {
+ return I2C_ERROR_BUS_BUSY;
+ }
+ /* Check for address response error unless previous error is detected. */
+ tmp_status = _i2c_master_address_response(&pI2C_S(obj)->master);
+ if (tmp_status != STATUS_OK) {
+ return I2C_ERROR_NO_SLAVE;
+ }
+
+ return 0;
+}
+
+/** Read one byte.
+ * @param obj The i2c object
+ * @param last Acknowledge
+ * @return The read byte
+ */
+int i2c_byte_read(i2c_t *obj, int last)
+{
+ int data = -1;
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->master.hw);
+
+ enum status_code tmp_status;
+
+ if (pI2C_S(obj)->mode == I2C_MODE_MASTER) {
+ SercomI2cm *const i2c_module = &(pI2C_S(obj)->master.hw->I2CM);
+
+ if (last) {
+ /* Set action to nack. */
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+ } else {
+ /* Set action to ack. */
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+ }
+
+ /* Check that bus ownership is not lost. */
+ if (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) {
+ return -1; /* Return invalid data*/
+ }
+
+ /* Save data to buffer. */
+ _i2c_master_wait_for_sync(&pI2C_S(obj)->master);
+ data = i2c_module->DATA.reg;
+ /* Wait for response. */
+ tmp_status = _i2c_master_wait_for_bus(&pI2C_S(obj)->master);
+
+ /* Check for error. */
+ if (tmp_status != STATUS_OK) {
+ return -1; /* Return invalid data*/
+ }
+
+ } else {
+#if DEVICE_I2CSLAVE
+ SercomI2cs *const i2c_hw = &(pI2C_S(obj)->slave.hw->I2CS);
+
+ /* Check direction */
+ if (i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_DIR) {
+ /* Write request from master, send NACK and return */
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_ACKACT;
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x3);
+ return -1; /* Return invalid data*/
+ }
+
+ if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH) {
+ /* Request from master, Address not yet acknowledged */
+ i2c_hw->CTRLB.reg &= ~SERCOM_I2CS_CTRLB_ACKACT;
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x3);
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_AMATCH;
+ }
+ if (last) {
+ /* Set action to nack. */
+ i2c_hw->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+ } else {
+ /* Set action to ack. */
+ i2c_hw->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+ }
+
+ /* Wait for next byte or stop condition */
+ tmp_status = _i2c_slave_wait_for_bus(&pI2C_S(obj)->slave);
+ if (tmp_status != STATUS_OK) {
+ /* Timeout, return */
+ return -1;
+ }
+
+ if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC) {
+ /* Master sent stop condition, or repeated start, read done */
+ /* Clear stop flag */
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC;
+ return -1;
+ }
+
+ /* Read data */
+ _i2c_slave_wait_for_sync(&pI2C_S(obj)->slave);
+ data = i2c_hw->DATA.reg;
+#endif
+ }
+
+ return data;
+}
+
+/** Write one byte.
+ * @param obj The i2c object
+ * @param data Byte to be written
+ * @return 1 if NAK was received, 0 if ACK was received, 2 for timeout.
+ */
+int i2c_byte_write(i2c_t *obj, int data)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->master.hw);
+
+ enum status_code tmp_status;
+
+ if (pI2C_S(obj)->mode == I2C_MODE_MASTER) {
+ SercomI2cm *const i2c_module = &(pI2C_S(obj)->master.hw->I2CM);
+
+ if (pI2C_S(obj)->start_pending) {
+ pI2C_S(obj)->start_pending = 0;
+ /* Write address */
+ return i2c_write_address(obj, (data >> 1), (data & 0x01));
+ } else {
+ /* Write data */
+ /* Check that bus ownership is not lost. */
+ if (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) {
+ return I2C_ERROR_NO_SLAVE;
+ }
+
+ /* Write byte to slave. */
+ _i2c_master_wait_for_sync(&pI2C_S(obj)->master);
+ i2c_module->DATA.reg = data;
+
+ /* Wait for response. */
+ tmp_status = _i2c_master_wait_for_bus(&pI2C_S(obj)->master);
+ /* Check for error. */
+ if (tmp_status != STATUS_OK) {
+ return I2C_ERROR_BUS_BUSY;
+ }
+
+ /* Check for NACK from slave. */
+ if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) {
+ /* Return bad data value. */
+ return I2C_ERROR_NO_SLAVE;
+ }
+ }
+ } else {
+#if DEVICE_I2CSLAVE
+ SercomI2cs *const i2c_hw = &(pI2C_S(obj)->slave.hw->I2CS);
+
+ if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH) {
+ /* Read request from master, Address not yet acknowledged */
+ i2c_hw->CTRLB.reg &= ~SERCOM_I2CS_CTRLB_ACKACT;
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x3);
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_AMATCH;
+ }
+
+ /* Write data */
+ _i2c_slave_wait_for_sync(&pI2C_S(obj)->slave);
+ i2c_hw->DATA.reg = data;
+
+ /* Wait for response from master */
+ tmp_status = _i2c_slave_wait_for_bus(&pI2C_S(obj)->slave);
+
+ if (tmp_status != STATUS_OK) {
+ /* Timeout, return */
+ return I2C_ERROR_BUS_BUSY;
+ }
+
+ if (i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_RXNACK) {
+ /* NACK from master, abort */
+ /* Release line */
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x02);
+
+ return I2C_ERROR_NO_SLAVE;
+ }
+#endif
+ }
+
+ return 0;
+}
+
+
+#if DEVICE_I2CSLAVE
+
+/**
+ * \defgroup SynchI2C Synchronous I2C Hardware Abstraction Layer for slave
+ * @{
+ */
+
+/** Configure I2C as slave or master.
+ * @param obj The I2C object
+ * @param enable_slave configure I2C in slave mode or not
+ * @return void
+ */
+void i2c_slave_mode(i2c_t *obj, int enable_slave)
+{
+ int i;
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->master.hw);
+
+ uint32_t mux_func[2];
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(pI2C_S(obj)->master.hw);
+ for (i=0; i<2; i++) {
+ mux_func[i] = pinmap_function_sercom(pI2C_S(obj)->pins[0], sercom_index);
+ if (mux_func[i] == NC) return;
+ }
+
+ if (enable_slave) {
+ /* Disable I2C Master module if active */
+ i2c_master_disable(&pI2C_S(obj)->master);
+
+ struct i2c_slave_config config_i2c_slave;
+ i2c_slave_get_config_defaults(&config_i2c_slave);
+
+ /* SERCOM PAD0 - SDA */
+ config_i2c_slave.pinmux_pad0 = (pI2C_S(obj)->pins[0] << 16) | (mux_func[0] & 0xFFFF);
+ /* SERCOM PAD1 - SCL */
+ config_i2c_slave.pinmux_pad1 = (pI2C_S(obj)->pins[1] << 16) | (mux_func[1] & 0xFFFF);
+
+ config_i2c_slave.sda_hold_time = I2C_SLAVE_SDA_HOLD_TIME_DISABLED;
+
+ i2c_slave_init(&pI2C_S(obj)->slave, pI2C_S(obj)->master.hw, &config_i2c_slave);
+
+ pI2C_S(obj)->mode = I2C_MODE_SLAVE;
+
+ i2c_slave_enable(&pI2C_S(obj)->slave);
+ } else {
+ if ((pI2C_S(obj)->master.hw) && (pI2C_S(obj)->mode == I2C_MODE_MASTER)) {
+ /* Already configured, enable and return */
+ i2c_master_enable(&pI2C_S(obj)->master);
+ return;
+ } else if ((pI2C_S(obj)->slave.hw) && (pI2C_S(obj)->mode == I2C_MODE_SLAVE)) {
+ /* Disable slave */
+ i2c_slave_disable(&pI2C_S(obj)->slave);
+ }
+
+ struct i2c_master_config config_i2c_master;
+ /* SERCOM PAD0 - SDA */
+ config_i2c_master.pinmux_pad0 = (pI2C_S(obj)->pins[0] << 16) | (mux_func[0] & 0xFFFF);
+ /* SERCOM PAD1 - SCL */
+ config_i2c_master.pinmux_pad1 = (pI2C_S(obj)->pins[1] << 16) | (mux_func[1] & 0xFFFF);
+ /* Baud rate */
+ config_i2c_master.baud_rate = pI2C_S(obj)->baud_rate / 1000;
+
+ while(i2c_master_init(&pI2C_S(obj)->master, pI2C_S(obj)->master.hw, &config_i2c_master) != STATUS_OK);
+ pI2C_S(obj)->mode = I2C_MODE_MASTER;
+
+ i2c_master_enable(&pI2C_S(obj)->master);
+ }
+}
+
+/** Check to see if the I2C slave has been addressed.
+ * @param obj The I2C object
+ * @return The status - 1 - read addresses, 2 - write to all slaves,
+ * 3 write addressed, 0 - the slave has not been addressed
+ */
+int i2c_slave_receive(i2c_t *obj)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->slave.hw);
+
+ SercomI2cs *const i2c_module = &(pI2C_S(obj)->slave.hw->I2CS);
+
+ /* TODO: Currently not checking "write to all" condition */
+ if (i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH) {
+ if (i2c_module->STATUS.reg & SERCOM_I2CS_STATUS_DIR) {
+ /* Slave is read addressed */
+ return 1;
+ } else {
+ /* Slave is write addressed */
+ return 3;
+ }
+ }
+
+ return 0;
+}
+
+/** Blocking reading data.
+ * @param obj The i2c slave object
+ * @param data The buffer for receiving
+ * @param length Number of bytes to read
+ * @return Number of read bytes
+ */
+int i2c_slave_read(i2c_t *obj, char *data, int length)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->slave.hw);
+
+ if (!data || !length) return 0;
+
+ enum status_code tmp_status;
+
+ struct i2c_slave_packet packet;
+ packet.data_length = length;
+ packet.data = (uint8_t*)data;
+
+ tmp_status = i2c_slave_read_packet_wait(&pI2C_S(obj)->slave, &packet);
+
+ if (tmp_status == STATUS_OK) {
+ return length;
+ } else {
+ /* Currently, no way to track no of bytes transmitted, so return 0 */
+ return 0;
+ }
+
+}
+
+/** Blocking writing data.
+ * @param obj The i2c slave object
+ * @param data The buffer for transmitting
+ * @param length Number of bytes to write
+ * @return Number of bytes written
+ */
+int i2c_slave_write(i2c_t *obj, const char *data, int length)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->slave.hw);
+
+ if (!data || !length) return 0;
+
+ enum status_code tmp_status;
+
+ struct i2c_slave_packet packet;
+ packet.data_length = length;
+ packet.data = data;
+
+ tmp_status = i2c_slave_write_packet_wait(&pI2C_S(obj)->slave, &packet);
+
+ if (tmp_status == STATUS_OK) {
+ return length;
+ } else {
+ /* Currently, no way to track no of bytes transmitted, so return 0 */
+ return 0;
+ }
+}
+
+/** Configure I2C slave address.
+ * @param obj The I2C object
+ * @param idx Currently not used
+ * @param address The address to be set
+ * @param mask Currently not used
+ */
+void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->slave.hw);
+
+ /* Disable I2C Module */
+ i2c_slave_disable(&pI2C_S(obj)->slave);
+
+ SercomI2cs *const i2c_hw = &(pI2C_S(obj)->slave.hw->I2CS);
+
+ address = address >> 1;
+ if (!mask) {
+ mask = (0xFE >> 1);
+ }
+ /* Set the address and address mask */
+ i2c_hw->ADDR.reg = (address << SERCOM_I2CS_ADDR_ADDR_Pos) |
+ (mask << SERCOM_I2CS_ADDR_ADDRMASK_Pos) |
+ (0 << SERCOM_I2CS_ADDR_TENBITEN_Pos) |
+ (1 << SERCOM_I2CS_ADDR_GENCEN_Pos);
+
+ /* Enable I2C Module */
+ i2c_slave_enable(&pI2C_S(obj)->slave);
+}
+
+#endif /* DEVICE_I2CSLAVE */
+
+/**@}*/
+
+#if DEVICE_I2C_ASYNCH
+
+/**
+ * \defgroup AsynchI2C Asynchronous I2C Hardware Abstraction Layer
+ * @{
+ */
+
+/**
+* \internal
+* Callback for transfer finish.
+*
+* \param[in,out] module Pointer to SPI software instance struct
+*/
+void i2c_transfer_complete_callback(struct i2c_master_module *const module)
+{
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
+
+ if (sercom_index >= SERCOM_INST_NUM) {
+ /* TODO: Abort operation */
+ return;
+ }
+
+ i2c_t *obj = (i2c_t*)i2c_instances[sercom_index];
+
+ i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_WRITE_COMPLETE);
+ i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_READ_COMPLETE);
+ i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_ERROR);
+
+ /* Call the handler function */
+ if (pI2C_S(obj)->handler) {
+ ((I2CHandler)pI2C_S(obj)->handler)();
+ }
+}
+
+/**
+* \internal
+* Callback for write complete. Initiate read from here.
+*
+* \param[in,out] module Pointer to SPI software instance struct
+*/
+void i2c_write_complete_callback(struct i2c_master_module *const module)
+{
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
+
+ if (sercom_index >= SERCOM_INST_NUM) {
+ /* TODO: Abort operation */
+ return;
+ }
+
+ i2c_t *obj = (i2c_t*)i2c_instances[sercom_index];
+
+ if (!(pI2C_S(obj)->rd_packet.data) || (pI2C_S(obj)->rd_packet.data_length == 0)) {
+ /* Call the handler function */
+ if (pI2C_S(obj)->handler) {
+ ((I2CHandler)pI2C_S(obj)->handler)();
+ }
+ } else {
+ i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_WRITE_COMPLETE);
+
+ /* TODO: Register read complete callback */
+ i2c_master_register_callback(&pI2C_S(obj)->master, i2c_transfer_complete_callback, I2C_MASTER_CALLBACK_READ_COMPLETE);
+ i2c_master_enable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_READ_COMPLETE);
+
+ /* Initiate read operation */
+ if (pI2C_S(obj)->master.send_stop) {
+ i2c_master_read_packet_job(&pI2C_S(obj)->master,&pI2C_S(obj)->rd_packet);
+ } else {
+ i2c_master_read_packet_job_no_stop(&pI2C_S(obj)->master, &pI2C_S(obj)->rd_packet);
+ }
+ }
+}
+
+/** 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)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->master.hw);
+
+ /* Return if in Slave mode */
+ if (pI2C_S(obj)->mode != I2C_MODE_MASTER) return;
+
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(pI2C_S(obj)->master.hw);
+
+ /* Init i2c packet. */
+ pI2C_S(obj)->wr_packet.address = address >> 1;
+ pI2C_S(obj)->wr_packet.data_length = tx_length;
+ pI2C_S(obj)->wr_packet.data = tx;
+
+ pI2C_S(obj)->rd_packet.address = address >> 1;
+ pI2C_S(obj)->rd_packet.data_length = rx_length;
+ pI2C_S(obj)->rd_packet.data = rx;
+
+ /* Save event mask and handler function pointer */
+ pI2C_S(obj)->events = event;
+ pI2C_S(obj)->handler = handler;
+
+ /* TODO: Current implementation is interrupt based only */
+
+ /* TODO: Set interrupt handler to default handler of ASF */
+ /* Enable interrupt */
+ NVIC_SetVector((SERCOM0_IRQn + sercom_index), sercom_irq_handlers[sercom_index]);
+ NVIC_EnableIRQ(SERCOM0_IRQn + sercom_index);
+
+ /* Register callbacks */
+ i2c_master_register_callback(&pI2C_S(obj)->master, i2c_transfer_complete_callback, I2C_MASTER_CALLBACK_ERROR);
+ i2c_master_enable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_ERROR);
+ if (tx && tx_length) {
+ i2c_master_register_callback(&pI2C_S(obj)->master, i2c_write_complete_callback, I2C_MASTER_CALLBACK_WRITE_COMPLETE);
+ i2c_master_enable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_WRITE_COMPLETE);
+
+ /* Start I2C write */
+ if (stop) {
+ i2c_master_write_packet_job(&pI2C_S(obj)->master, &pI2C_S(obj)->wr_packet);
+ } else {
+ i2c_master_write_packet_job_no_stop(&pI2C_S(obj)->master, &pI2C_S(obj)->wr_packet);
+ }
+ } else if (rx && rx_length) {
+ i2c_master_register_callback(&pI2C_S(obj)->master, i2c_transfer_complete_callback, I2C_MASTER_CALLBACK_READ_COMPLETE);
+ i2c_master_enable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_READ_COMPLETE);
+
+ /* Start I2C read */
+ if (stop) {
+ i2c_master_read_packet_job(&pI2C_S(obj)->master,&pI2C_S(obj)->rd_packet);
+ } else {
+ i2c_master_read_packet_job_no_stop(&pI2C_S(obj)->master, &pI2C_S(obj)->rd_packet);
+ }
+ }
+}
+
+/** The asynchronous IRQ handler
+ * @param obj The I2C object which holds the transfer information
+ * @return event flags if a transfer termination condition was met or 0 otherwise.
+ */
+uint32_t i2c_irq_handler_asynch(i2c_t *obj)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->master.hw);
+
+ uint32_t event_mask = pI2C_S(obj)->events;
+
+ /* TODO: Current implementation is interrupt based only */
+
+ switch (pI2C_S(obj)->master.status) {
+ case STATUS_OK:
+ /* Transfer is complete */
+ return (I2C_EVENT_TRANSFER_COMPLETE & event_mask);
+ break;
+ case STATUS_ERR_BAD_ADDRESS:
+ /* Received a NACK */
+ return (I2C_EVENT_ERROR_NO_SLAVE & event_mask);
+ break;
+ case STATUS_ERR_PACKET_COLLISION:
+ /* An error occurred in between transfer */
+ return (I2C_EVENT_ERROR & event_mask);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+/** Attempts to determine if I2C peripheral is already in use.
+ * @param obj The I2C object
+ * @return non-zero if the I2C module is active or zero if it is not
+ */
+uint8_t i2c_active(i2c_t *obj)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->master.hw);
+
+ return (pI2C_S(obj)->master.status == STATUS_BUSY);
+}
+
+/** Abort ongoing asynchronous transaction.
+ * @param obj The I2C object
+ */
+void i2c_abort_asynch(i2c_t *obj)
+{
+ /* Sanity check arguments */
+ MBED_ASSERT(obj);
+ MBED_ASSERT(pI2C_S(obj)->master.hw);
+
+ /* Pointer to the hardware module instance */
+ SercomI2cm *const i2c_module = &(pI2C_S(obj)->master.hw->I2CM);
+
+ /* Abort ongoing job */
+
+ /* Stop packet operation */
+ i2c_module->INTENCLR.reg = SERCOM_I2CM_INTENCLR_MB | SERCOM_I2CM_INTENCLR_SB;
+
+ pI2C_S(obj)->master.buffer_length = 0;
+ pI2C_S(obj)->master.buffer_remaining = 0;
+
+ /* Send nack and stop command unless arbitration is lost */
+ if ((pI2C_S(obj)->master.status != STATUS_ERR_PACKET_COLLISION) && pI2C_S(obj)->master.send_stop) {
+ _i2c_master_wait_for_sync(&pI2C_S(obj)->master);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT | SERCOM_I2CM_CTRLB_CMD(3);
+ }
+
+ /* Disable any registered callback */
+ i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_WRITE_COMPLETE);
+ i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_READ_COMPLETE);
+ i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_ERROR);
+
+ pI2C_S(obj)->master.status = STATUS_ABORTED;
+}
+
+#endif
diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/objects.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/objects.h
index b64497c7aa..119dc9b630 100644
--- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/objects.h
+++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM0/objects.h
@@ -22,6 +22,9 @@
#include "gpio_object.h"
#include "adc.h"
#include "extint.h"
+#include "i2c_master.h"
+#include "i2c_slave.h"
+#include "dma_api.h"
#ifdef __cplusplus
extern "C" {
@@ -71,6 +74,22 @@ struct analogin_s {
struct pwmout_s {
};
+struct i2c_s {
+ struct i2c_master_module master;
+ struct i2c_slave_module slave;
+ uint8_t mode;
+ uint32_t baud_rate;
+ uint32_t baud_rate_high_speed;
+ uint8_t start_pending;
+ PinName pins[2];
+#if DEVICE_I2C_ASYNCH
+ uint32_t events;
+ uint32_t handler;
+ struct i2c_master_packet wr_packet;
+ struct i2c_master_packet rd_packet;
+#endif
+};
+
struct spi_s {
Sercom *spi;
uint8_t mode;
diff --git a/workspace_tools/targets.py b/workspace_tools/targets.py
index 4c40b26f1b..9881ce09ce 100755
--- a/workspace_tools/targets.py
+++ b/workspace_tools/targets.py
@@ -1531,7 +1531,7 @@ class SAMR21G18A(Target):
Target.__init__(self)
self.core = "Cortex-M0+"
self.extra_labels = ['Atmel', 'SAM0', 'SAMR21']
- self.macros = ['__SAMR21G18A__']
+ self.macros = ['__SAMR21G18A__', 'I2C_MASTER_CALLBACK_MODE=true']
self.supported_toolchains = ["GCC_ARM"]
self.default_toolchain = "GCC_ARM"