Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: mbed-dev/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c
- Revision:
- 18:6a4db94011d3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-dev/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c Sun May 14 23:18:57 2017 +0000
@@ -0,0 +1,286 @@
+/* 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 "i2c_api.h"
+
+#if DEVICE_I2C
+
+#include "cmsis.h"
+#include "pinmap.h"
+#include "fsl_i2c.h"
+#include "fsl_port.h"
+#include "peripheral_clock_defines.h"
+#include "PeripheralPins.h"
+
+/* 7 bit IIC addr - R/W flag not included */
+static int i2c_address = 0;
+/* Array of I2C peripheral base address. */
+static I2C_Type *const i2c_addrs[] = I2C_BASE_PTRS;
+/* Array of I2C bus clock frequencies */
+static clock_name_t const i2c_clocks[] = I2C_CLOCK_FREQS;
+
+void i2c_init(i2c_t *obj, PinName sda, PinName scl)
+{
+ uint32_t i2c_sda = pinmap_peripheral(sda, PinMap_I2C_SDA);
+ uint32_t i2c_scl = pinmap_peripheral(scl, PinMap_I2C_SCL);
+ obj->instance = pinmap_merge(i2c_sda, i2c_scl);
+ obj->next_repeated_start = 0;
+ MBED_ASSERT((int)obj->instance != NC);
+
+ i2c_master_config_t master_config;
+
+ I2C_MasterGetDefaultConfig(&master_config);
+ I2C_MasterInit(i2c_addrs[obj->instance], &master_config, CLOCK_GetFreq(i2c_clocks[obj->instance]));
+ I2C_EnableInterrupts(i2c_addrs[obj->instance], kI2C_GlobalInterruptEnable);
+
+ pinmap_pinout(sda, PinMap_I2C_SDA);
+ pinmap_pinout(scl, PinMap_I2C_SCL);
+
+#if defined(FSL_FEATURE_PORT_HAS_OPEN_DRAIN) && FSL_FEATURE_PORT_HAS_OPEN_DRAIN
+ PORT_Type *port_addrs[] = PORT_BASE_PTRS;
+ PORT_Type *base = port_addrs[sda >> GPIO_PORT_SHIFT];
+
+ base->PCR[sda & 0xFF] |= PORT_PCR_ODE_MASK;
+ base->PCR[scl & 0xFF] |= PORT_PCR_ODE_MASK;
+#endif
+}
+
+int i2c_start(i2c_t *obj)
+{
+ I2C_Type *base = i2c_addrs[obj->instance];
+ uint32_t statusFlags = I2C_MasterGetStatusFlags(base);
+
+ /* Return an error if the bus is already in use. */
+ if (statusFlags & kI2C_BusBusyFlag) {
+ return 1;
+ }
+ /* Send the START signal. */
+ base->C1 |= I2C_C1_MST_MASK | I2C_C1_TX_MASK;
+
+#if defined(FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING) && FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING
+ while (!(base->S2 & I2C_S2_EMPTY_MASK))
+ {
+ }
+#endif /* FSL_FEATURE_I2C_HAS_DOUBLE_BUFFERING */
+
+ return 0;
+}
+
+int i2c_stop(i2c_t *obj)
+{
+ obj->next_repeated_start = 0;
+ if (I2C_MasterStop(i2c_addrs[obj->instance]) != kStatus_Success) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void i2c_frequency(i2c_t *obj, int hz)
+{
+ uint32_t busClock;
+
+ busClock = CLOCK_GetFreq(i2c_clocks[obj->instance]);
+ I2C_MasterSetBaudRate(i2c_addrs[obj->instance], hz, busClock);
+}
+
+int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
+{
+ I2C_Type *base = i2c_addrs[obj->instance];
+ i2c_master_transfer_t master_xfer;
+
+ i2c_address = address >> 1;
+ memset(&master_xfer, 0, sizeof(master_xfer));
+ master_xfer.slaveAddress = address >> 1;
+ master_xfer.direction = kI2C_Read;
+ master_xfer.data = (uint8_t *)data;
+ master_xfer.dataSize = length;
+ if (obj->next_repeated_start) {
+ master_xfer.flags |= kI2C_TransferRepeatedStartFlag;
+ }
+ if (!stop) {
+ master_xfer.flags |= kI2C_TransferNoStopFlag;
+ }
+ obj->next_repeated_start = master_xfer.flags & kI2C_TransferNoStopFlag ? 1 : 0;
+
+ /* The below function will issue a STOP signal at the end of the transfer.
+ * This is required by the hardware in order to receive the last byte
+ */
+ if (I2C_MasterTransferBlocking(base, &master_xfer) != kStatus_Success) {
+ return I2C_ERROR_NO_SLAVE;
+ }
+
+ return length;
+}
+
+int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
+{
+ I2C_Type *base = i2c_addrs[obj->instance];
+ i2c_master_transfer_t master_xfer;
+
+ if (length == 0) {
+ if (I2C_MasterStart(base, address >> 1, kI2C_Write) != kStatus_Success) {
+ return I2C_ERROR_NO_SLAVE;
+ }
+
+ while (!(base->S & kI2C_IntPendingFlag)) {
+ }
+
+ base->S = kI2C_IntPendingFlag;
+
+ if (base->S & kI2C_ReceiveNakFlag) {
+ i2c_stop(obj);
+ return I2C_ERROR_NO_SLAVE;
+ } else {
+ i2c_stop(obj);
+ return length;
+ }
+ }
+
+ memset(&master_xfer, 0, sizeof(master_xfer));
+ master_xfer.slaveAddress = address >> 1;
+ master_xfer.direction = kI2C_Write;
+ master_xfer.data = (uint8_t *)data;
+ master_xfer.dataSize = length;
+ if (obj->next_repeated_start) {
+ master_xfer.flags |= kI2C_TransferRepeatedStartFlag;
+ }
+ if (!stop) {
+ master_xfer.flags |= kI2C_TransferNoStopFlag;
+ }
+ obj->next_repeated_start = master_xfer.flags & kI2C_TransferNoStopFlag ? 1 : 0;
+
+ if (I2C_MasterTransferBlocking(base, &master_xfer) != kStatus_Success) {
+ return I2C_ERROR_NO_SLAVE;
+ }
+
+ return length;
+}
+
+void i2c_reset(i2c_t *obj)
+{
+ i2c_stop(obj);
+}
+
+int i2c_byte_read(i2c_t *obj, int last)
+{
+ uint8_t data;
+ I2C_Type *base = i2c_addrs[obj->instance];
+ i2c_master_transfer_t master_xfer;
+
+ memset(&master_xfer, 0, sizeof(master_xfer));
+ master_xfer.slaveAddress = i2c_address;
+ master_xfer.direction = kI2C_Read;
+ master_xfer.data = &data;
+ master_xfer.dataSize = 1;
+
+ /* The below function will issue a STOP signal at the end of the transfer.
+ * This is required by the hardware in order to receive the last byte
+ */
+ if (I2C_MasterTransferBlocking(base, &master_xfer) != kStatus_Success) {
+ return I2C_ERROR_NO_SLAVE;
+ }
+ return data;
+}
+
+int i2c_byte_write(i2c_t *obj, int data)
+{
+ status_t ret_value;
+#if FSL_I2C_DRIVER_VERSION > MAKE_VERSION(2, 0, 1)
+ ret_value = I2C_MasterWriteBlocking(i2c_addrs[obj->instance], (uint8_t *)(&data), 1, kI2C_TransferNoStopFlag);
+#else
+ ret_value = I2C_MasterWriteBlocking(i2c_addrs[obj->instance], (uint8_t *)(&data), 1);
+#endif
+
+ if (ret_value == kStatus_Success) {
+ return 1;
+ } else if (ret_value == kStatus_I2C_Nak) {
+ return 0;
+ } else {
+ return 2;
+ }
+}
+
+
+#if DEVICE_I2CSLAVE
+void i2c_slave_mode(i2c_t *obj, int enable_slave)
+{
+ i2c_slave_config_t slave_config;
+ I2C_SlaveGetDefaultConfig(&slave_config);
+ slave_config.slaveAddress = 0;
+ slave_config.enableSlave = (bool)enable_slave;
+#if FSL_I2C_DRIVER_VERSION > MAKE_VERSION(2, 0, 1)
+ I2C_SlaveInit(i2c_addrs[obj->instance], &slave_config, CLOCK_GetFreq(i2c_clocks[obj->instance]));
+#else
+ I2C_SlaveInit(i2c_addrs[obj->instance], &slave_config);
+#endif
+}
+
+int i2c_slave_receive(i2c_t *obj)
+{
+ uint32_t status_flags = I2C_SlaveGetStatusFlags(i2c_addrs[obj->instance]);
+
+ if (status_flags & kI2C_AddressMatchFlag) {
+ if (status_flags & kI2C_TransferDirectionFlag) {
+ // read addressed
+ return 1;
+ } else {
+ // write addressed
+ return 3;
+ }
+ } else {
+ // slave not addressed
+ return 0;
+ }
+}
+
+int i2c_slave_read(i2c_t *obj, char *data, int length)
+{
+ I2C_Type *base = i2c_addrs[obj->instance];
+
+ if (base->S & kI2C_AddressMatchFlag) {
+ /* Slave receive, master writing to slave. */
+ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
+ /* Read dummy to release the bus. */
+ base->D;
+ }
+
+ I2C_SlaveReadBlocking(base, (uint8_t *)data, length);
+
+ return length;
+}
+
+int i2c_slave_write(i2c_t *obj, const char *data, int length)
+{
+ I2C_Type *base = i2c_addrs[obj->instance];
+
+ I2C_SlaveWriteBlocking(base, (uint8_t *)data, length);
+
+ /* Switch to receive mode. */
+ base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
+ /* Read dummy to release bus. */
+ base->D;
+
+ return length;
+}
+
+void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask)
+{
+ i2c_addrs[obj->instance]->A1 = address & 0xfe;
+}
+#endif
+
+#endif