Import Mbed OS hard-float snapshot
This commit is contained in:
358
targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c
Normal file
358
targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/i2c_api.c
Normal file
@@ -0,0 +1,358 @@
|
||||
/* 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;
|
||||
|
||||
#if STATIC_PINMAP_READY
|
||||
#define I2C_INIT_DIRECT i2c_init_direct
|
||||
void i2c_init_direct(i2c_t *obj, const i2c_pinmap_t *pinmap)
|
||||
#else
|
||||
#define I2C_INIT_DIRECT _i2c_init_direct
|
||||
static void _i2c_init_direct(i2c_t *obj, const i2c_pinmap_t *pinmap)
|
||||
#endif
|
||||
{
|
||||
PORT_Type *port_addrs[] = PORT_BASE_PTRS;
|
||||
PORT_Type *base = port_addrs[pinmap->sda_pin >> GPIO_PORT_SHIFT];
|
||||
|
||||
obj->instance = (uint32_t) pinmap->peripheral;
|
||||
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);
|
||||
|
||||
pin_function(pinmap->sda_pin, pinmap->sda_function);
|
||||
pin_mode(pinmap->sda_pin, PullNone);
|
||||
pin_function(pinmap->scl_pin, pinmap->scl_function);
|
||||
pin_mode(pinmap->scl_pin, PullNone);
|
||||
|
||||
/* Enable internal pullup resistor */
|
||||
base->PCR[pinmap->sda_pin & 0xFF] |= (PORT_PCR_PE_MASK | PORT_PCR_PS_MASK);
|
||||
base->PCR[pinmap->scl_pin & 0xFF] |= (PORT_PCR_PE_MASK | PORT_PCR_PS_MASK);
|
||||
|
||||
#if defined(FSL_FEATURE_PORT_HAS_OPEN_DRAIN) && FSL_FEATURE_PORT_HAS_OPEN_DRAIN
|
||||
base->PCR[pinmap->sda_pin & 0xFF] |= PORT_PCR_ODE_MASK;
|
||||
base->PCR[pinmap->scl_pin & 0xFF] |= PORT_PCR_ODE_MASK;
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
int peripheral = (int)pinmap_merge(i2c_sda, i2c_scl);
|
||||
|
||||
int sda_function = (int)pinmap_find_function(sda, PinMap_I2C_SDA);
|
||||
int scl_function = (int)pinmap_find_function(scl, PinMap_I2C_SCL);
|
||||
|
||||
const i2c_pinmap_t explicit_i2c_pinmap = {peripheral, sda, sda_function, scl, scl_function};
|
||||
|
||||
I2C_INIT_DIRECT(obj, &explicit_i2c_pinmap);
|
||||
}
|
||||
|
||||
int i2c_start(i2c_t *obj)
|
||||
{
|
||||
I2C_Type *base = i2c_addrs[obj->instance];
|
||||
uint32_t statusFlags = I2C_MasterGetStatusFlags(base);
|
||||
|
||||
/* Check if the bus is already in use. */
|
||||
if (statusFlags & kI2C_BusBusyFlag) {
|
||||
/* Send a repeat START signal. */
|
||||
base->C1 |= I2C_C1_RSTA_MASK;
|
||||
} else {
|
||||
/* 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)
|
||||
{
|
||||
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];
|
||||
|
||||
/* Setup the I2C peripheral to receive data. */
|
||||
base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
|
||||
|
||||
if (last) {
|
||||
base->C1 |= I2C_C1_TXAK_MASK; // NACK
|
||||
}
|
||||
|
||||
/* Read dummy to release the bus. */
|
||||
data = base->D;
|
||||
|
||||
/* Wait until data transfer complete. */
|
||||
while (!(base->S & kI2C_IntPendingFlag)) {
|
||||
}
|
||||
|
||||
/* Clear the IICIF flag. */
|
||||
base->S = kI2C_IntPendingFlag;
|
||||
|
||||
/* Change direction to Tx to avoid extra clocks. */
|
||||
base->C1 |= I2C_C1_TX_MASK;
|
||||
|
||||
data = (base->D & 0xFF);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
int i2c_byte_write(i2c_t *obj, int data)
|
||||
{
|
||||
int ret_value = 1;
|
||||
uint8_t statusFlags = 0;
|
||||
I2C_Type *base = i2c_addrs[obj->instance];
|
||||
|
||||
/* Setup the I2C peripheral to transmit data. */
|
||||
base->C1 |= I2C_C1_TX_MASK;
|
||||
|
||||
/* Send a byte of data. */
|
||||
base->D = data;
|
||||
|
||||
/* Wait until data transfer complete. */
|
||||
while (!(base->S & kI2C_IntPendingFlag)) {
|
||||
}
|
||||
|
||||
statusFlags = base->S;
|
||||
|
||||
/* Clear the IICIF flag. */
|
||||
base->S = kI2C_IntPendingFlag;
|
||||
|
||||
/* Check if arbitration lost */
|
||||
if (statusFlags & kI2C_ArbitrationLostFlag) {
|
||||
base->S = kI2C_ArbitrationLostFlag;
|
||||
ret_value = 2;
|
||||
}
|
||||
|
||||
/* Check if no acknowledgement (NAK) */
|
||||
if (statusFlags & kI2C_ReceiveNakFlag) {
|
||||
base->S = kI2C_ReceiveNakFlag;
|
||||
ret_value = 0;
|
||||
}
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
const PinMap *i2c_master_sda_pinmap()
|
||||
{
|
||||
return PinMap_I2C_SDA;
|
||||
}
|
||||
|
||||
const PinMap *i2c_master_scl_pinmap()
|
||||
{
|
||||
return PinMap_I2C_SCL;
|
||||
}
|
||||
|
||||
const PinMap *i2c_slave_sda_pinmap()
|
||||
{
|
||||
return PinMap_I2C_SDA;
|
||||
}
|
||||
|
||||
const PinMap *i2c_slave_scl_pinmap()
|
||||
{
|
||||
return PinMap_I2C_SCL;
|
||||
}
|
||||
|
||||
|
||||
#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
|
||||
Reference in New Issue
Block a user