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.
Fork of mbed-src by
Diff: targets/hal/TARGET_NXP/TARGET_LPC82X/i2c_api.c
- Revision:
- 337:6ed01c00b962
- Child:
- 350:a00142a134db
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/hal/TARGET_NXP/TARGET_LPC82X/i2c_api.c Mon Oct 06 10:00:08 2014 +0100 @@ -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 <stdlib.h> +#include <string.h> + +#include "i2c_api.h" +#include "cmsis.h" +#include "pinmap.h" + +#include "rom_i2c_8xx.h" + +#if DEVICE_I2C + +typedef struct ROM_API { + const uint32_t unused[5]; + const I2CD_API_T *pI2CD; /*!< I2C driver routines functions table */ +} LPC_ROM_API_T; + + +/* Pointer to ROM API function address */ +#define LPC_ROM_API_BASE_LOC 0x1FFF1FF8UL +#define LPC_ROM_API (*(LPC_ROM_API_T * *) LPC_ROM_API_BASE_LOC) + +/* Pointer to @ref I2CD_API_T functions in ROM */ +#define LPC_I2CD_API ((LPC_ROM_API)->pI2CD) + +static const SWM_Map SWM_I2C_SDA[] = { + { 9, 8}, + { 9, 24}, + {10, 8}, +}; + +static const SWM_Map SWM_I2C_SCL[] = { + { 9, 16}, + {10, 0}, + {10, 16}, +}; + + +static int i2c_used = 0; +static uint8_t repeated_start = 0; +static uint32_t *i2c_buffer; + +#define I2C_DAT(x) (x->i2c->MSTDAT) +#define I2C_STAT(x) ((x->i2c->STAT >> 1) & (0x07)) + +static inline int i2c_status(i2c_t *obj) +{ + return I2C_STAT(obj); +} + +// Wait until the Serial Interrupt (SI) is set +static int i2c_wait_SI(i2c_t *obj) +{ + volatile int timeout = 0; + while (!(obj->i2c->STAT & (1 << 0))) { + timeout++; + if (timeout > 100000) return -1; + } + return 0; +} + +static inline void i2c_interface_enable(i2c_t *obj) +{ + obj->i2c->CFG |= 1; +} + +static inline void i2c_power_enable(int ch) +{ + switch(ch) { + case 0: + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 5); + LPC_SYSCON->PRESETCTRL &= ~(1 << 6); + LPC_SYSCON->PRESETCTRL |= (1 << 6); + break; + case 1: + case 2: + case 3: + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << (20 + ch)); + LPC_SYSCON->PRESETCTRL &= ~(1 << (13 + ch)); + LPC_SYSCON->PRESETCTRL |= (1 << (13 + ch)); + break; + default: + break; + } +} + + +static int get_available_i2c(void) { + int i; + for (i=0; i<3; i++) { + if ((i2c_used & (1 << i)) == 0) + return i+1; + } + return -1; +} + +void i2c_init(i2c_t *obj, PinName sda, PinName scl) +{ + const SWM_Map *swm; + uint32_t regVal; + int i2c_ch = 0; + + if (sda == I2C_SDA && scl == I2C_SCL) { + LPC_SWM->PINENABLE0 &= ~(0x3 << 11); + } + else { + i2c_ch = get_available_i2c(); + if (i2c_ch == -1) + return; + + swm = &SWM_I2C_SDA[i2c_ch - 1]; + regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset); + LPC_SWM->PINASSIGN[swm->n] = regVal | ((sda >> PIN_SHIFT) << swm->offset); + + swm = &SWM_I2C_SCL[i2c_ch - 1]; + regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset); + LPC_SWM->PINASSIGN[swm->n] = regVal | ((scl >> PIN_SHIFT) << swm->offset); + } + + switch(i2c_ch) { + case 0: + obj->i2c = (LPC_I2C0_Type *)LPC_I2C0; + break; + case 1: + obj->i2c = (LPC_I2C0_Type *)LPC_I2C1; + break; + case 2: + obj->i2c = (LPC_I2C0_Type *)LPC_I2C2; + break; + case 3: + obj->i2c = (LPC_I2C0_Type *)LPC_I2C3; + break; + default: + break; + } + + // enable power + i2c_power_enable(i2c_ch); + i2c_interface_enable(obj); + + uint32_t size_in_bytes = LPC_I2CD_API->i2c_get_mem_size(); + i2c_buffer = malloc(size_in_bytes); + obj->handler = LPC_I2CD_API->i2c_setup((uint32_t)(obj->i2c), i2c_buffer); + LPC_I2CD_API->i2c_set_bitrate(obj->handler, SystemCoreClock, 100000); + LPC_I2CD_API->i2c_set_timeout(obj->handler, 100000); +} + +inline int i2c_start(i2c_t *obj) +{ + int status = 0; + if (repeated_start) { + obj->i2c->MSTCTL = (1 << 1) | (1 << 0); + repeated_start = 0; + } else { + obj->i2c->MSTCTL = (1 << 1); + } + return status; +} + +inline int i2c_stop(i2c_t *obj) +{ + volatile int timeout = 0; + + obj->i2c->MSTCTL = (1 << 2) | (1 << 0); + while ((obj->i2c->STAT & ((1 << 0) | (7 << 1))) != ((1 << 0) | (0 << 1))) { + timeout ++; + if (timeout > 100000) return 1; + } + + return 0; +} + +static inline int i2c_do_write(i2c_t *obj, int value, uint8_t addr) +{ + // write the data + I2C_DAT(obj) = value; + + if (!addr) + obj->i2c->MSTCTL = (1 << 0); + + // wait and return status + i2c_wait_SI(obj); + return i2c_status(obj); +} + +static inline int i2c_do_read(i2c_t *obj, int last) +{ + // wait for it to arrive + i2c_wait_SI(obj); + if (!last) + obj->i2c->MSTCTL = (1 << 0); + + // return the data + return (I2C_DAT(obj) & 0xFF); +} + +void i2c_frequency(i2c_t *obj, int hz) +{ + LPC_I2CD_API->i2c_set_bitrate(obj->handler, SystemCoreClock, 100000); +} + +int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) +{ + ErrorCode_t err; + I2C_PARAM_T i2c_param; + I2C_RESULT_T i2c_result; + + uint8_t *buf = malloc(length + 1); + buf[0] = (uint8_t)((address | 0x01) & 0xFF); + i2c_param.buffer_ptr_rec = buf; + i2c_param.num_bytes_rec = length + 1; + i2c_param.stop_flag = stop; + err = LPC_I2CD_API->i2c_master_receive_poll(obj->handler, &i2c_param, &i2c_result); + memcpy(data, buf + 1, i2c_result.n_bytes_recd); + free(buf); + if (err == 0) + return i2c_result.n_bytes_recd; + else + return -1; +} + +int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) +{ + ErrorCode_t err; + I2C_PARAM_T i2c_param; + I2C_RESULT_T i2c_result; + + uint8_t *buf = malloc(length + 1); + buf[0] = (uint8_t)(address & 0xFE); + memcpy(buf + 1, data, length); + i2c_param.buffer_ptr_send = buf; + i2c_param.num_bytes_send = length + 1; + i2c_param.stop_flag = stop; + err = LPC_I2CD_API->i2c_master_transmit_poll(obj->handler, &i2c_param, &i2c_result); + free(buf); + if (err == 0) + return i2c_result.n_bytes_sent; + else + return -1; +} + +void i2c_reset(i2c_t *obj) +{ + i2c_stop(obj); +} + +int i2c_byte_read(i2c_t *obj, int last) +{ + return (i2c_do_read(obj, last) & 0xFF); +} + +int i2c_byte_write(i2c_t *obj, int data) +{ + int ack; + int status = i2c_do_write(obj, (data & 0xFF), 0); + + switch(status) { + case 2: + ack = 1; + break; + default: + ack = 0; + break; + } + + return ack; +} + +#if DEVICE_I2CSLAVE + + void i2c_slave_mode(i2c_t *obj, int enable_slave) +{ + obj->handler = LPC_I2CD_API->i2c_setup((uint32_t)(obj->i2c), i2c_buffer); + if (enable_slave != 0) { + obj->i2c->CFG &= ~(1 << 0); + obj->i2c->CFG |= (1 << 1); + } + else { + obj->i2c->CFG |= (1 << 0); + obj->i2c->CFG &= ~(1 << 1); + } + +} + +int i2c_slave_receive(i2c_t *obj) +{ + CHIP_I2C_MODE_T mode; + int ret; + + mode = LPC_I2CD_API->i2c_get_status(obj->handler); + switch(mode) { + case SLAVE_SEND: + ret = 1; + break; + case SLAVE_RECEIVE: + ret = 3; + break; + case MASTER_SEND: + case MASTER_RECEIVE: + default: + ret = 0; + break; + } + return ret; +} + +int i2c_slave_read(i2c_t *obj, char *data, int length) +{ + ErrorCode_t err; + I2C_PARAM_T i2c_param; + I2C_RESULT_T i2c_result; + + i2c_param.buffer_ptr_send = (uint8_t *)data; + i2c_param.num_bytes_send = length; + err = LPC_I2CD_API->i2c_slave_transmit_poll(obj->handler, &i2c_param, &i2c_result); + if (err == 0) + return i2c_result.n_bytes_sent; + else + return -1; +} + +int i2c_slave_write(i2c_t *obj, const char *data, int length) +{ + ErrorCode_t err; + I2C_PARAM_T i2c_param; + I2C_RESULT_T i2c_result; + + i2c_param.buffer_ptr_rec = (uint8_t *)data; + i2c_param.num_bytes_rec = length; + err = LPC_I2CD_API->i2c_slave_receive_poll(obj->handler, &i2c_param, &i2c_result); + if (err == 0) + return i2c_result.n_bytes_recd; + else + return -1; +} + +void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) +{ + LPC_I2CD_API->i2c_set_slave_addr(obj->handler, address, 0); +} + +#endif + +#endif