2014-10-24 02:05:17 +00:00
|
|
|
/* 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.
|
|
|
|
*/
|
2019-06-19 21:08:55 +00:00
|
|
|
#include "i2c_api.h"
|
|
|
|
|
|
|
|
#if DEVICE_I2C
|
|
|
|
|
2014-10-24 02:05:17 +00:00
|
|
|
#include "mbed_assert.h"
|
2016-03-24 07:08:43 +00:00
|
|
|
#include "dma_api.h"
|
2014-10-24 02:05:17 +00:00
|
|
|
#include "cmsis.h"
|
Commonalize the files in "targets/TARGET_RENESAS/TARGET_RZ_A1XX" directory
I made be available in common whatever the board related to RZ_A1 in the below files.
- Since there are the table code of Pinmap differs for each board, I moved the code to "PeripheralPins" file for each board, and changed to include PeripheralPins.h.
analogin_api.c, can_api.c, gpio_irq_api.c, i2c_api.c, pinmap.c, port_api.c, pwmout_api.c, serial_api.c, spi_api.c and us_ticker.c
- Since there are some board-specific processes, I enclosed the processes with "#ifdef" and rearranged the functions to make be easier to enclose.
can_api.c, ethernet_api.c and serial_api.c
- Since there are the driver configuration values differs for each board, I added "mbed_drv_cfg.h" file for each board and defined macros for the values, and changed to refer to the macros.
can_api.c, gpio_api.c, pwmout_api.c and rtc_api.c
2018-01-09 09:20:50 +00:00
|
|
|
#include "PeripheralPins.h"
|
2014-12-18 09:40:44 +00:00
|
|
|
#include "r_typedefs.h"
|
2014-10-24 02:05:17 +00:00
|
|
|
|
Commonalize the files in "targets/TARGET_RENESAS/TARGET_RZ_A1XX" directory
I made be available in common whatever the board related to RZ_A1 in the below files.
- Since there are the table code of Pinmap differs for each board, I moved the code to "PeripheralPins" file for each board, and changed to include PeripheralPins.h.
analogin_api.c, can_api.c, gpio_irq_api.c, i2c_api.c, pinmap.c, port_api.c, pwmout_api.c, serial_api.c, spi_api.c and us_ticker.c
- Since there are some board-specific processes, I enclosed the processes with "#ifdef" and rearranged the functions to make be easier to enclose.
can_api.c, ethernet_api.c and serial_api.c
- Since there are the driver configuration values differs for each board, I added "mbed_drv_cfg.h" file for each board and defined macros for the values, and changed to refer to the macros.
can_api.c, gpio_api.c, pwmout_api.c and rtc_api.c
2018-01-09 09:20:50 +00:00
|
|
|
#include "iodefine.h"
|
2014-12-01 11:09:11 +00:00
|
|
|
#include "RZ_A1_Init.h"
|
2014-10-24 02:05:17 +00:00
|
|
|
|
|
|
|
volatile struct st_riic *RIIC[] = RIIC_ADDRESS_LIST;
|
|
|
|
|
|
|
|
#define REG(N) \
|
2016-03-24 07:08:43 +00:00
|
|
|
RIIC[obj->i2c.i2c]->RIICn##N
|
2014-10-24 02:05:17 +00:00
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
/* RIICnCR1 */
|
|
|
|
#define CR1_RST (1 << 6)
|
|
|
|
#define CR1_ICE (1 << 7)
|
|
|
|
|
|
|
|
/* RIICnCR2 */
|
|
|
|
#define CR2_ST (1 << 1)
|
2015-01-29 07:40:16 +00:00
|
|
|
#define CR2_RS (1 << 2)
|
2014-12-18 09:40:44 +00:00
|
|
|
#define CR2_SP (1 << 3)
|
2015-01-29 07:40:16 +00:00
|
|
|
#define CR2_TRS (1 << 5)
|
2014-12-18 09:40:44 +00:00
|
|
|
#define CR2_BBSY (1 << 7)
|
|
|
|
|
|
|
|
/* RIICnMR3 */
|
|
|
|
#define MR3_ACKBT (1 << 3)
|
|
|
|
#define MR3_ACKWP (1 << 4)
|
|
|
|
#define MR3_WAIT (1 << 6)
|
|
|
|
|
2015-01-29 07:40:16 +00:00
|
|
|
/* RIICnSER */
|
|
|
|
#define SER_SAR0E (1 << 0)
|
|
|
|
|
|
|
|
/* RIICnSR1 */
|
|
|
|
#define SR1_AAS0 (1 << 0)
|
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
/* RIICnSR2 */
|
2015-01-29 07:40:16 +00:00
|
|
|
#define SR2_START (1 << 2)
|
2014-12-18 09:40:44 +00:00
|
|
|
#define SR2_STOP (1 << 3)
|
|
|
|
#define SR2_NACKF (1 << 4)
|
|
|
|
#define SR2_RDRF (1 << 5)
|
|
|
|
#define SR2_TEND (1 << 6)
|
|
|
|
#define SR2_TDRE (1 << 7)
|
|
|
|
|
2015-05-13 02:00:35 +00:00
|
|
|
#define WAIT_TIMEOUT (3600000) /* Loop counter : Time-out is about 1s. By 3600000 loops, measured value is 969ms. */
|
2014-10-24 02:05:17 +00:00
|
|
|
|
|
|
|
static inline int i2c_status(i2c_t *obj) {
|
|
|
|
return REG(SR2.UINT8[0]);
|
|
|
|
}
|
|
|
|
|
2014-11-18 04:54:39 +00:00
|
|
|
static void i2c_reg_reset(i2c_t *obj) {
|
2014-12-18 09:40:44 +00:00
|
|
|
/* full reset */
|
|
|
|
REG(CR1.UINT8[0]) &= ~CR1_ICE; // CR1.ICE off
|
|
|
|
REG(CR1.UINT8[0]) |= CR1_RST; // CR1.IICRST on
|
|
|
|
REG(CR1.UINT8[0]) |= CR1_ICE; // CR1.ICE on
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
REG(MR1.UINT8[0]) = 0x08; // P_phi /x 9bit (including Ack)
|
|
|
|
REG(SER.UINT8[0]) = 0x00; // no slave addr enabled
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
/* set frequency */
|
2016-03-24 07:08:43 +00:00
|
|
|
REG(MR1.UINT8[0]) |= obj->i2c.pclk_bit;
|
|
|
|
REG(BRL.UINT8[0]) = obj->i2c.width_low;
|
|
|
|
REG(BRH.UINT8[0]) = obj->i2c.width_hi;
|
2014-11-18 04:54:39 +00:00
|
|
|
|
|
|
|
REG(MR2.UINT8[0]) = 0x07;
|
|
|
|
REG(MR3.UINT8[0]) = 0x00;
|
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
REG(FER.UINT8[0]) = 0x72; // SCLE, NFE enabled, TMOT
|
|
|
|
REG(IER.UINT8[0]) = 0x00; // no interrupt
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
REG(CR1.UINT32) &= ~CR1_RST; // CR1.IICRST negate reset
|
2014-11-18 04:54:39 +00:00
|
|
|
}
|
|
|
|
|
2015-01-29 07:40:16 +00:00
|
|
|
static inline int i2c_wait_RDRF(i2c_t *obj) {
|
|
|
|
int timeout = 0;
|
|
|
|
|
|
|
|
/* There is no timeout, but the upper limit value is set to avoid an infinite loop. */
|
2015-05-13 02:00:35 +00:00
|
|
|
while ((i2c_status(obj) & SR2_RDRF) == 0) {
|
2015-01-29 07:40:16 +00:00
|
|
|
timeout ++;
|
2015-04-07 07:46:17 +00:00
|
|
|
if (timeout >= WAIT_TIMEOUT) {
|
2015-01-29 07:40:16 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-10-24 02:05:17 +00:00
|
|
|
static int i2c_wait_TDRE(i2c_t *obj) {
|
|
|
|
int timeout = 0;
|
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
/* There is no timeout, but the upper limit value is set to avoid an infinite loop. */
|
2015-05-13 02:00:35 +00:00
|
|
|
while ((i2c_status(obj) & SR2_TDRE) == 0) {
|
2014-11-18 04:54:39 +00:00
|
|
|
timeout ++;
|
2015-04-07 07:46:17 +00:00
|
|
|
if (timeout >= WAIT_TIMEOUT) {
|
2014-12-18 09:40:44 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
static int i2c_wait_TEND(i2c_t *obj) {
|
2014-11-18 04:54:39 +00:00
|
|
|
int timeout = 0;
|
2014-12-18 09:40:44 +00:00
|
|
|
|
|
|
|
/* There is no timeout, but the upper limit value is set to avoid an infinite loop. */
|
2015-05-13 02:00:35 +00:00
|
|
|
while ((i2c_status(obj) & SR2_TEND) == 0) {
|
2014-11-18 04:54:39 +00:00
|
|
|
timeout ++;
|
2015-04-07 07:46:17 +00:00
|
|
|
if (timeout >= WAIT_TIMEOUT) {
|
2014-12-18 09:40:44 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2014-11-18 04:54:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-29 07:40:16 +00:00
|
|
|
static int i2c_wait_START(i2c_t *obj) {
|
|
|
|
int timeout = 0;
|
|
|
|
|
|
|
|
/* There is no timeout, but the upper limit value is set to avoid an infinite loop. */
|
2015-05-13 02:00:35 +00:00
|
|
|
while ((i2c_status(obj) & SR2_START) == 0) {
|
2015-01-29 07:40:16 +00:00
|
|
|
timeout ++;
|
2015-04-07 07:46:17 +00:00
|
|
|
if (timeout >= WAIT_TIMEOUT) {
|
2015-01-29 07:40:16 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-08 07:47:28 +00:00
|
|
|
static int i2c_wait_STOP(i2c_t *obj) {
|
2014-12-18 09:40:44 +00:00
|
|
|
int timeout = 0;
|
|
|
|
|
|
|
|
/* There is no timeout, but the upper limit value is set to avoid an infinite loop. */
|
2015-05-13 02:00:35 +00:00
|
|
|
while ((i2c_status(obj) & SR2_STOP) == 0) {
|
2014-12-18 09:40:44 +00:00
|
|
|
timeout ++;
|
2015-04-07 07:46:17 +00:00
|
|
|
if (timeout >= WAIT_TIMEOUT) {
|
2014-12-18 09:40:44 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2014-12-08 07:47:28 +00:00
|
|
|
}
|
2014-12-18 09:40:44 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-13 02:00:35 +00:00
|
|
|
static int i2c_set_STOP(i2c_t *obj) {
|
|
|
|
/* SR2.STOP = 0 */
|
|
|
|
REG(SR2.UINT32) &= ~SR2_STOP;
|
|
|
|
/* Stop condition */
|
|
|
|
REG(CR2.UINT32) |= CR2_SP;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-29 07:40:16 +00:00
|
|
|
static void i2c_set_SR2_NACKF_STOP(i2c_t *obj) {
|
2014-12-08 07:47:28 +00:00
|
|
|
/* SR2.NACKF = 0 */
|
2014-12-18 09:40:44 +00:00
|
|
|
REG(SR2.UINT32) &= ~SR2_NACKF;
|
2015-01-29 07:40:16 +00:00
|
|
|
/* SR2.STOP = 0 */
|
2014-12-18 09:40:44 +00:00
|
|
|
REG(SR2.UINT32) &= ~SR2_STOP;
|
2014-12-08 07:47:28 +00:00
|
|
|
}
|
|
|
|
|
2015-01-29 07:40:16 +00:00
|
|
|
static void i2c_set_MR3_NACK(i2c_t *obj) {
|
|
|
|
/* send a NOT ACK */
|
|
|
|
REG(MR3.UINT32) |= MR3_ACKWP;
|
|
|
|
REG(MR3.UINT32) |= MR3_ACKBT;
|
|
|
|
REG(MR3.UINT32) &= ~MR3_ACKWP;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c_set_MR3_ACK(i2c_t *obj) {
|
|
|
|
/* send a ACK */
|
|
|
|
REG(MR3.UINT32) |= MR3_ACKWP;
|
|
|
|
REG(MR3.UINT32) &= ~MR3_ACKBT;
|
|
|
|
REG(MR3.UINT32) &= ~MR3_ACKWP;
|
2014-12-18 09:40:44 +00:00
|
|
|
}
|
2014-12-08 07:47:28 +00:00
|
|
|
|
2014-10-24 02:05:17 +00:00
|
|
|
static inline void i2c_power_enable(i2c_t *obj) {
|
|
|
|
volatile uint8_t dummy;
|
2016-03-24 07:08:43 +00:00
|
|
|
switch ((int)obj->i2c.i2c) {
|
2015-01-29 07:40:16 +00:00
|
|
|
case I2C_0:
|
|
|
|
CPGSTBCR9 &= ~(0x80);
|
|
|
|
break;
|
|
|
|
case I2C_1:
|
|
|
|
CPGSTBCR9 &= ~(0x40);
|
|
|
|
break;
|
|
|
|
case I2C_2:
|
|
|
|
CPGSTBCR9 &= ~(0x20);
|
|
|
|
break;
|
|
|
|
case I2C_3:
|
|
|
|
CPGSTBCR9 &= ~(0x10);
|
|
|
|
break;
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
dummy = CPGSTBCR9;
|
Commonalize the files in "targets/TARGET_RENESAS/TARGET_RZ_A1XX" directory
I made be available in common whatever the board related to RZ_A1 in the below files.
- Since there are the table code of Pinmap differs for each board, I moved the code to "PeripheralPins" file for each board, and changed to include PeripheralPins.h.
analogin_api.c, can_api.c, gpio_irq_api.c, i2c_api.c, pinmap.c, port_api.c, pwmout_api.c, serial_api.c, spi_api.c and us_ticker.c
- Since there are some board-specific processes, I enclosed the processes with "#ifdef" and rearranged the functions to make be easier to enclose.
can_api.c, ethernet_api.c and serial_api.c
- Since there are the driver configuration values differs for each board, I added "mbed_drv_cfg.h" file for each board and defined macros for the values, and changed to refer to the macros.
can_api.c, gpio_api.c, pwmout_api.c and rtc_api.c
2018-01-09 09:20:50 +00:00
|
|
|
(void)dummy;
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void i2c_init(i2c_t *obj, PinName sda, PinName scl) {
|
2014-12-18 09:40:44 +00:00
|
|
|
/* determine the I2C to use */
|
2014-10-24 02:05:17 +00:00
|
|
|
I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA);
|
|
|
|
I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL);
|
2016-03-24 07:08:43 +00:00
|
|
|
obj->i2c.i2c = pinmap_merge(i2c_sda, i2c_scl);
|
|
|
|
MBED_ASSERT((int)obj->i2c.i2c != NC);
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
/* enable power */
|
2014-10-24 02:05:17 +00:00
|
|
|
i2c_power_enable(obj);
|
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
/* set default frequency at 100k */
|
2014-12-04 06:40:38 +00:00
|
|
|
i2c_frequency(obj, 100000);
|
|
|
|
|
2014-10-24 02:05:17 +00:00
|
|
|
pinmap_pinout(sda, PinMap_I2C_SDA);
|
|
|
|
pinmap_pinout(scl, PinMap_I2C_SCL);
|
2015-01-29 07:40:16 +00:00
|
|
|
|
2016-03-24 07:08:43 +00:00
|
|
|
obj->i2c.last_stop_flag = 1;
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline int i2c_start(i2c_t *obj) {
|
2014-12-18 09:40:44 +00:00
|
|
|
int timeout = 0;
|
|
|
|
|
2015-05-13 02:00:35 +00:00
|
|
|
while ((REG(CR2.UINT32) & CR2_BBSY) != 0) {
|
2014-12-18 09:40:44 +00:00
|
|
|
timeout ++;
|
2016-03-24 07:08:43 +00:00
|
|
|
if (timeout >= obj->i2c.bbsy_wait_cnt) {
|
2015-01-29 07:40:16 +00:00
|
|
|
break;
|
2014-12-18 09:40:44 +00:00
|
|
|
}
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
2014-12-18 09:40:44 +00:00
|
|
|
/* Start Condition */
|
|
|
|
REG(CR2.UINT8[0]) |= CR2_ST;
|
2014-10-24 02:05:17 +00:00
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
return 0;
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
|
2015-02-26 07:33:01 +00:00
|
|
|
static inline int i2c_restart(i2c_t *obj) {
|
2015-01-29 07:40:16 +00:00
|
|
|
/* SR2.START = 0 */
|
|
|
|
REG(SR2.UINT32) &= ~SR2_START;
|
|
|
|
/* ReStart condition */
|
|
|
|
REG(CR2.UINT32) |= CR2_RS;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-10-24 02:05:17 +00:00
|
|
|
inline int i2c_stop(i2c_t *obj) {
|
2015-05-13 02:00:35 +00:00
|
|
|
(void)i2c_set_STOP(obj);
|
|
|
|
(void)i2c_wait_STOP(obj);
|
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
|
|
|
|
2014-10-24 02:05:17 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-07 07:46:17 +00:00
|
|
|
static void i2c_set_err_noslave(i2c_t *obj) {
|
2015-05-13 02:00:35 +00:00
|
|
|
(void)i2c_set_STOP(obj);
|
2015-04-07 07:46:17 +00:00
|
|
|
(void)i2c_wait_STOP(obj);
|
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
2016-03-24 07:08:43 +00:00
|
|
|
obj->i2c.last_stop_flag = 1;
|
2015-01-29 07:40:16 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 02:05:17 +00:00
|
|
|
static inline int i2c_do_write(i2c_t *obj, int value) {
|
2014-12-18 09:40:44 +00:00
|
|
|
int timeout = 0;
|
|
|
|
|
2015-05-13 02:00:35 +00:00
|
|
|
/* There is no timeout, but the upper limit value is set to avoid an infinite loop. */
|
|
|
|
while ((i2c_status(obj) & SR2_TDRE) == 0) {
|
|
|
|
timeout ++;
|
|
|
|
if (timeout >= WAIT_TIMEOUT) {
|
|
|
|
return -1;
|
2014-12-18 09:40:44 +00:00
|
|
|
}
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
2015-05-13 02:00:35 +00:00
|
|
|
/* write the data */
|
|
|
|
REG(DRT.UINT32) = value;
|
2014-12-18 09:40:44 +00:00
|
|
|
|
|
|
|
return 0;
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
static inline int i2c_read_address_write(i2c_t *obj, int value) {
|
|
|
|
int status;
|
2015-01-29 07:40:16 +00:00
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
status = i2c_wait_TDRE(obj);
|
|
|
|
if (status == 0) {
|
|
|
|
/* write the data */
|
|
|
|
REG(DRT.UINT32) = value;
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
2015-01-29 07:40:16 +00:00
|
|
|
|
|
|
|
return status;
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
}
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
static inline int i2c_do_read(i2c_t *obj, int last) {
|
2014-11-18 04:54:39 +00:00
|
|
|
if (last == 2) {
|
|
|
|
/* this time is befor last byte read */
|
2014-12-18 09:40:44 +00:00
|
|
|
/* Set MR3 WAIT bit is 1 */;
|
|
|
|
REG(MR3.UINT32) |= MR3_WAIT;
|
2014-11-18 04:54:39 +00:00
|
|
|
} else if (last == 1) {
|
2015-01-29 07:40:16 +00:00
|
|
|
i2c_set_MR3_NACK(obj);
|
2014-10-24 02:05:17 +00:00
|
|
|
} else {
|
2015-01-29 07:40:16 +00:00
|
|
|
i2c_set_MR3_ACK(obj);
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
/* return the data */
|
2014-10-24 02:05:17 +00:00
|
|
|
return (REG(DRR.UINT32) & 0xFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
void i2c_frequency(i2c_t *obj, int hz) {
|
2014-12-18 09:40:44 +00:00
|
|
|
float64_t pclk_val;
|
|
|
|
float64_t wait_utime;
|
|
|
|
volatile float64_t bps;
|
|
|
|
volatile float64_t L_time; /* H Width period */
|
|
|
|
volatile float64_t H_time; /* L Width period */
|
|
|
|
uint32_t tmp_L_width;
|
|
|
|
uint32_t tmp_H_width;
|
|
|
|
uint32_t remainder;
|
|
|
|
uint32_t wk_cks = 0;
|
2014-12-04 06:40:38 +00:00
|
|
|
|
2014-12-01 11:09:11 +00:00
|
|
|
/* set PCLK */
|
2014-12-04 06:40:38 +00:00
|
|
|
if (false == RZ_A1_IsClockMode0()) {
|
2014-12-18 09:40:44 +00:00
|
|
|
pclk_val = (float64_t)CM1_RENESAS_RZ_A1_P0_CLK;
|
2014-12-01 11:09:11 +00:00
|
|
|
} else {
|
2014-12-18 09:40:44 +00:00
|
|
|
pclk_val = (float64_t)CM0_RENESAS_RZ_A1_P0_CLK;
|
2014-12-01 11:09:11 +00:00
|
|
|
}
|
2014-12-04 06:40:38 +00:00
|
|
|
|
2014-11-28 01:28:45 +00:00
|
|
|
/* Min 10kHz, Max 400kHz */
|
|
|
|
if (hz < 10000) {
|
2014-12-18 09:40:44 +00:00
|
|
|
bps = 10000;
|
2014-11-28 01:28:45 +00:00
|
|
|
} else if (hz > 400000) {
|
2014-12-18 09:40:44 +00:00
|
|
|
bps = 400000;
|
2014-11-28 01:28:45 +00:00
|
|
|
} else {
|
2014-12-18 09:40:44 +00:00
|
|
|
bps = (float64_t)hz;
|
2014-11-28 01:28:45 +00:00
|
|
|
}
|
2014-12-04 06:40:38 +00:00
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
/* Calculation L width time */
|
|
|
|
L_time = (1 / (2 * bps)); /* Harf period of frequency */
|
|
|
|
H_time = L_time;
|
|
|
|
|
|
|
|
/* Check I2C mode of Speed */
|
|
|
|
if (bps > 100000) {
|
|
|
|
/* Fast-mode */
|
|
|
|
L_time -= 102E-9; /* Falling time of SCL clock. */
|
|
|
|
H_time -= 138E-9; /* Rising time of SCL clock. */
|
|
|
|
/* Check L wideth */
|
|
|
|
if (L_time < 1.3E-6) {
|
|
|
|
/* Wnen L width less than 1.3us */
|
|
|
|
/* Subtract Rise up and down time for SCL from H/L width */
|
|
|
|
L_time = 1.3E-6;
|
|
|
|
H_time = (1 / bps) - L_time - 138E-9 - 102E-9;
|
2014-11-28 01:28:45 +00:00
|
|
|
}
|
|
|
|
}
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2014-12-18 09:40:44 +00:00
|
|
|
tmp_L_width = (uint32_t)(L_time * pclk_val * 10);
|
|
|
|
tmp_L_width >>= 1;
|
|
|
|
wk_cks++;
|
|
|
|
while (tmp_L_width >= 341) {
|
|
|
|
tmp_L_width >>= 1;
|
|
|
|
wk_cks++;
|
|
|
|
}
|
|
|
|
remainder = tmp_L_width % 10;
|
|
|
|
tmp_L_width = ((tmp_L_width + 9) / 10) - 3; /* carry */
|
|
|
|
|
|
|
|
tmp_H_width = (uint32_t)(H_time * pclk_val * 10);
|
|
|
|
tmp_H_width >>= wk_cks;
|
|
|
|
if (remainder == 0) {
|
|
|
|
tmp_H_width = ((tmp_H_width + 9) / 10) - 3; /* carry */
|
2014-11-28 01:28:45 +00:00
|
|
|
} else {
|
2014-12-18 09:40:44 +00:00
|
|
|
remainder += tmp_H_width % 10;
|
|
|
|
tmp_H_width = (tmp_H_width / 10) - 3;
|
|
|
|
if (remainder > 10) {
|
|
|
|
tmp_H_width += 1; /* fine adjustment */
|
|
|
|
}
|
2014-11-28 01:28:45 +00:00
|
|
|
}
|
2014-12-18 09:40:44 +00:00
|
|
|
/* timeout of BBSY bit is minimum low width by frequency */
|
|
|
|
/* so timeout calculates "(low width) * 2" by frequency */
|
|
|
|
wait_utime = (L_time * 2) * 1000000;
|
|
|
|
/* 1 wait of BBSY bit is about 0.3us. if it's below 0.3us, wait count is set as 1. */
|
|
|
|
if (wait_utime <= 0.3) {
|
2016-03-24 07:08:43 +00:00
|
|
|
obj->i2c.bbsy_wait_cnt = 1;
|
2014-12-18 09:40:44 +00:00
|
|
|
} else {
|
2016-03-24 07:08:43 +00:00
|
|
|
obj->i2c.bbsy_wait_cnt = (int)(wait_utime / 0.3);
|
2014-12-18 09:40:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* I2C Rate */
|
2016-03-24 07:08:43 +00:00
|
|
|
obj->i2c.pclk_bit = (uint8_t)(0x10 * wk_cks); /* P_phi / xx */
|
|
|
|
obj->i2c.width_low = (uint8_t)(tmp_L_width | 0x000000E0);
|
|
|
|
obj->i2c.width_hi = (uint8_t)(tmp_H_width | 0x000000E0);
|
2014-12-18 09:40:44 +00:00
|
|
|
|
|
|
|
/* full reset */
|
|
|
|
i2c_reg_reset(obj);
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
|
2014-11-18 04:54:39 +00:00
|
|
|
int count = 0;
|
|
|
|
int status;
|
|
|
|
int value;
|
|
|
|
|
2015-01-29 07:40:16 +00:00
|
|
|
i2c_set_MR3_ACK(obj);
|
|
|
|
/* There is a STOP condition for last processing */
|
2016-03-24 07:08:43 +00:00
|
|
|
if (obj->i2c.last_stop_flag != 0) {
|
2015-01-29 07:40:16 +00:00
|
|
|
status = i2c_start(obj);
|
|
|
|
if (status != 0) {
|
2015-04-07 07:46:17 +00:00
|
|
|
i2c_set_err_noslave(obj);
|
2015-01-29 07:40:16 +00:00
|
|
|
return I2C_ERROR_BUS_BUSY;
|
|
|
|
}
|
|
|
|
}
|
2016-03-24 07:08:43 +00:00
|
|
|
obj->i2c.last_stop_flag = stop;
|
2014-12-18 09:40:44 +00:00
|
|
|
/* Send Slave address */
|
|
|
|
status = i2c_read_address_write(obj, (address | 0x01));
|
|
|
|
if (status != 0) {
|
2015-04-07 07:46:17 +00:00
|
|
|
i2c_set_err_noslave(obj);
|
2014-10-24 02:05:17 +00:00
|
|
|
return I2C_ERROR_NO_SLAVE;
|
|
|
|
}
|
2015-01-29 07:40:16 +00:00
|
|
|
/* wait RDRF */
|
2014-12-18 09:40:44 +00:00
|
|
|
status = i2c_wait_RDRF(obj);
|
2014-11-18 04:54:39 +00:00
|
|
|
/* check ACK/NACK */
|
2015-05-13 02:00:35 +00:00
|
|
|
if ((status != 0) || ((REG(SR2.UINT32) & SR2_NACKF) != 0)) {
|
2014-11-18 04:54:39 +00:00
|
|
|
/* Slave sends NACK */
|
2015-05-13 02:00:35 +00:00
|
|
|
(void)i2c_set_STOP(obj);
|
2015-04-07 07:46:17 +00:00
|
|
|
/* dummy read */
|
|
|
|
value = REG(DRR.UINT32);
|
|
|
|
(void)i2c_wait_STOP(obj);
|
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
2016-03-24 07:08:43 +00:00
|
|
|
obj->i2c.last_stop_flag = 1;
|
2014-11-18 04:54:39 +00:00
|
|
|
return I2C_ERROR_NO_SLAVE;
|
|
|
|
}
|
2017-01-10 03:44:12 +00:00
|
|
|
if (length != 0) {
|
|
|
|
/* Read in all except last byte */
|
|
|
|
if (length > 2) {
|
|
|
|
/* dummy read */
|
|
|
|
value = REG(DRR.UINT32);
|
|
|
|
for (count = 0; count < (length - 1); count++) {
|
|
|
|
/* wait for it to arrive */
|
|
|
|
status = i2c_wait_RDRF(obj);
|
|
|
|
if (status != 0) {
|
|
|
|
i2c_set_err_noslave(obj);
|
|
|
|
return I2C_ERROR_NO_SLAVE;
|
|
|
|
}
|
|
|
|
/* Recieve the data */
|
|
|
|
if (count == (length - 2)) {
|
|
|
|
value = i2c_do_read(obj, 1);
|
|
|
|
} else if ((length >= 3) && (count == (length - 3))) {
|
|
|
|
value = i2c_do_read(obj, 2);
|
|
|
|
} else {
|
|
|
|
value = i2c_do_read(obj, 0);
|
|
|
|
}
|
|
|
|
data[count] = (char)value;
|
|
|
|
}
|
|
|
|
} else if (length == 2) {
|
|
|
|
/* Set MR3 WAIT bit is 1 */
|
|
|
|
REG(MR3.UINT32) |= MR3_WAIT;
|
|
|
|
/* dummy read */
|
|
|
|
value = REG(DRR.UINT32);
|
2014-12-18 09:40:44 +00:00
|
|
|
/* wait for it to arrive */
|
|
|
|
status = i2c_wait_RDRF(obj);
|
|
|
|
if (status != 0) {
|
2015-04-07 07:46:17 +00:00
|
|
|
i2c_set_err_noslave(obj);
|
2014-12-18 09:40:44 +00:00
|
|
|
return I2C_ERROR_NO_SLAVE;
|
|
|
|
}
|
2017-01-10 03:44:12 +00:00
|
|
|
i2c_set_MR3_NACK(obj);
|
|
|
|
data[count] = (char)REG(DRR.UINT32);
|
|
|
|
count++;
|
|
|
|
} else {
|
|
|
|
/* length == 1 */
|
|
|
|
/* Set MR3 WAIT bit is 1 */;
|
|
|
|
REG(MR3.UINT32) |= MR3_WAIT;
|
|
|
|
i2c_set_MR3_NACK(obj);
|
|
|
|
/* dummy read */
|
|
|
|
value = REG(DRR.UINT32);
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
2014-12-18 09:40:44 +00:00
|
|
|
/* wait for it to arrive */
|
|
|
|
status = i2c_wait_RDRF(obj);
|
|
|
|
if (status != 0) {
|
2015-04-07 07:46:17 +00:00
|
|
|
i2c_set_err_noslave(obj);
|
2014-12-18 09:40:44 +00:00
|
|
|
return I2C_ERROR_NO_SLAVE;
|
|
|
|
}
|
2015-01-29 07:40:16 +00:00
|
|
|
|
2017-01-10 03:44:12 +00:00
|
|
|
/* If not repeated start, send stop. */
|
|
|
|
if (stop) {
|
|
|
|
(void)i2c_set_STOP(obj);
|
|
|
|
/* RIICnDRR read */
|
|
|
|
value = (REG(DRR.UINT32) & 0xFF);
|
|
|
|
data[count] = (char)value;
|
|
|
|
/* RIICnMR3.WAIT = 0 */
|
|
|
|
REG(MR3.UINT32) &= ~MR3_WAIT;
|
|
|
|
(void)i2c_wait_STOP(obj);
|
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
|
|
|
} else {
|
|
|
|
(void)i2c_restart(obj);
|
|
|
|
/* RIICnDRR read */
|
|
|
|
value = (REG(DRR.UINT32) & 0xFF);
|
|
|
|
data[count] = (char)value;
|
|
|
|
/* RIICnMR3.WAIT = 0 */
|
|
|
|
REG(MR3.UINT32) &= ~MR3_WAIT;
|
|
|
|
(void)i2c_wait_START(obj);
|
|
|
|
/* SR2.START = 0 */
|
|
|
|
REG(SR2.UINT32) &= ~SR2_START;
|
|
|
|
}
|
2015-01-07 10:10:26 +00:00
|
|
|
} else {
|
2017-01-10 03:44:12 +00:00
|
|
|
/* If not repeated start, send stop. */
|
|
|
|
if (stop) {
|
|
|
|
(void)i2c_set_STOP(obj);
|
|
|
|
(void)i2c_wait_STOP(obj);
|
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
|
|
|
} else {
|
|
|
|
(void)i2c_restart(obj);
|
|
|
|
(void)i2c_wait_START(obj);
|
|
|
|
/* SR2.START = 0 */
|
|
|
|
REG(SR2.UINT32) &= ~SR2_START;
|
|
|
|
}
|
2015-01-07 10:10:26 +00:00
|
|
|
}
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2014-10-24 02:05:17 +00:00
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
|
2014-12-18 09:40:44 +00:00
|
|
|
int cnt;
|
|
|
|
int status;
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2015-01-29 07:40:16 +00:00
|
|
|
/* There is a STOP condition for last processing */
|
2016-03-24 07:08:43 +00:00
|
|
|
if (obj->i2c.last_stop_flag != 0) {
|
2015-01-29 07:40:16 +00:00
|
|
|
status = i2c_start(obj);
|
|
|
|
if (status != 0) {
|
2015-04-07 07:46:17 +00:00
|
|
|
i2c_set_err_noslave(obj);
|
2015-01-29 07:40:16 +00:00
|
|
|
return I2C_ERROR_BUS_BUSY;
|
|
|
|
}
|
|
|
|
}
|
2016-03-24 07:08:43 +00:00
|
|
|
obj->i2c.last_stop_flag = stop;
|
2014-12-18 09:40:44 +00:00
|
|
|
/* Send Slave address */
|
2014-10-24 02:05:17 +00:00
|
|
|
status = i2c_do_write(obj, address);
|
2014-12-18 09:40:44 +00:00
|
|
|
if (status != 0) {
|
2015-04-07 07:46:17 +00:00
|
|
|
i2c_set_err_noslave(obj);
|
2014-10-24 02:05:17 +00:00
|
|
|
return I2C_ERROR_NO_SLAVE;
|
|
|
|
}
|
2015-05-13 02:00:35 +00:00
|
|
|
/* Wait send end */
|
|
|
|
status = i2c_wait_TEND(obj);
|
|
|
|
if ((status != 0) || ((REG(SR2.UINT32) & SR2_NACKF) != 0)) {
|
|
|
|
/* Slave sends NACK */
|
|
|
|
i2c_set_err_noslave(obj);
|
|
|
|
return I2C_ERROR_NO_SLAVE;
|
|
|
|
}
|
2014-12-18 09:40:44 +00:00
|
|
|
/* Send Write data */
|
|
|
|
for (cnt=0; cnt<length; cnt++) {
|
|
|
|
status = i2c_do_write(obj, data[cnt]);
|
|
|
|
if(status != 0) {
|
2015-04-07 07:46:17 +00:00
|
|
|
i2c_set_err_noslave(obj);
|
2014-12-18 09:40:44 +00:00
|
|
|
return cnt;
|
2015-05-13 02:00:35 +00:00
|
|
|
} else {
|
|
|
|
/* Wait send end */
|
|
|
|
status = i2c_wait_TEND(obj);
|
|
|
|
if ((status != 0) || ((REG(SR2.UINT32) & SR2_NACKF) != 0)) {
|
|
|
|
/* Slave sends NACK */
|
|
|
|
i2c_set_err_noslave(obj);
|
|
|
|
return I2C_ERROR_NO_SLAVE;
|
|
|
|
}
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-07 10:10:26 +00:00
|
|
|
/* If not repeated start, send stop. */
|
|
|
|
if (stop) {
|
2015-05-13 02:00:35 +00:00
|
|
|
(void)i2c_set_STOP(obj);
|
2015-01-07 10:10:26 +00:00
|
|
|
(void)i2c_wait_STOP(obj);
|
2015-01-29 07:40:16 +00:00
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
|
|
|
} else {
|
|
|
|
(void)i2c_restart(obj);
|
|
|
|
(void)i2c_wait_START(obj);
|
|
|
|
/* SR2.START = 0 */
|
|
|
|
REG(SR2.UINT32) &= ~SR2_START;
|
|
|
|
|
2015-01-07 10:10:26 +00:00
|
|
|
}
|
2014-12-18 09:40:44 +00:00
|
|
|
|
2014-10-24 02:05:17 +00:00
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
void i2c_reset(i2c_t *obj) {
|
2015-05-13 02:00:35 +00:00
|
|
|
(void)i2c_set_STOP(obj);
|
2014-12-18 09:40:44 +00:00
|
|
|
(void)i2c_wait_STOP(obj);
|
2015-01-29 07:40:16 +00:00
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int i2c_byte_read(i2c_t *obj, int last) {
|
2014-12-18 09:40:44 +00:00
|
|
|
int status;
|
2015-05-13 02:00:35 +00:00
|
|
|
int data;
|
2014-12-18 09:40:44 +00:00
|
|
|
|
2015-05-13 02:00:35 +00:00
|
|
|
data = i2c_do_read(obj, last);
|
2014-12-18 09:40:44 +00:00
|
|
|
/* wait for it to arrive */
|
|
|
|
status = i2c_wait_RDRF(obj);
|
|
|
|
if (status != 0) {
|
2015-05-13 02:00:35 +00:00
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
2014-12-18 09:40:44 +00:00
|
|
|
return I2C_ERROR_NO_SLAVE;
|
|
|
|
}
|
2014-12-08 07:47:28 +00:00
|
|
|
|
2015-05-13 02:00:35 +00:00
|
|
|
return data;
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int i2c_byte_write(i2c_t *obj, int data) {
|
2015-05-13 02:00:35 +00:00
|
|
|
int ack = 0;
|
2015-01-29 07:40:16 +00:00
|
|
|
int status;
|
2015-05-13 02:00:35 +00:00
|
|
|
int timeout = 0;
|
2015-01-29 07:40:16 +00:00
|
|
|
|
|
|
|
status = i2c_do_write(obj, (data & 0xFF));
|
2014-12-18 09:40:44 +00:00
|
|
|
if (status != 0) {
|
2015-05-13 02:00:35 +00:00
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
2014-10-24 02:05:17 +00:00
|
|
|
} else {
|
2015-05-13 02:00:35 +00:00
|
|
|
while (((i2c_status(obj) & SR2_RDRF) == 0) && ((i2c_status(obj) & SR2_TEND) == 0)) {
|
|
|
|
timeout++;
|
|
|
|
if (timeout >= WAIT_TIMEOUT) {
|
|
|
|
return ack;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* check ACK/NACK */
|
|
|
|
if ((REG(SR2.UINT32) & SR2_NACKF) != 0) {
|
|
|
|
/* NACK */
|
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
|
|
|
} else {
|
|
|
|
ack = 1;
|
|
|
|
}
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2014-10-24 02:05:17 +00:00
|
|
|
return ack;
|
|
|
|
}
|
|
|
|
|
|
|
|
void i2c_slave_mode(i2c_t *obj, int enable_slave) {
|
|
|
|
if (enable_slave != 0) {
|
2015-01-29 07:40:16 +00:00
|
|
|
REG(SER.UINT32) |= SER_SAR0E; // only slave addr 0 is enabled
|
2014-10-24 02:05:17 +00:00
|
|
|
} else {
|
2015-01-29 07:40:16 +00:00
|
|
|
REG(SER.UINT32) &= ~SER_SAR0E; // no slave addr enabled
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int i2c_slave_receive(i2c_t *obj) {
|
|
|
|
int status;
|
|
|
|
int retval;
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2015-05-13 02:00:35 +00:00
|
|
|
status = (REG(SR1.UINT8[0]) & SR1_AAS0);
|
2015-01-29 07:40:16 +00:00
|
|
|
status |= (REG(CR2.UINT8[0]) & CR2_TRS) >> 4;
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2015-01-29 07:40:16 +00:00
|
|
|
switch(status) {
|
|
|
|
case 0x01:
|
|
|
|
/* the master is writing to this slave */
|
|
|
|
retval = 3;
|
|
|
|
break;
|
|
|
|
case 0x02:
|
|
|
|
/* the master is writing to all slave */
|
|
|
|
retval = 2;
|
|
|
|
break;
|
|
|
|
case 0x03:
|
|
|
|
/* the master has requested a read from this slave */
|
|
|
|
retval = 1;
|
|
|
|
break;
|
|
|
|
default :
|
|
|
|
/* no data */
|
|
|
|
retval = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int i2c_slave_read(i2c_t *obj, char *data, int length) {
|
2015-01-29 07:40:16 +00:00
|
|
|
int timeout = 0;
|
|
|
|
int count;
|
|
|
|
int break_flg = 0;
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2015-01-29 07:40:16 +00:00
|
|
|
if(length <= 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
for (count = 0; ((count < (length + 1)) && (break_flg == 0)); count++) {
|
|
|
|
/* There is no timeout, but the upper limit value is set to avoid an infinite loop. */
|
2015-05-13 02:00:35 +00:00
|
|
|
while (((i2c_status(obj) & SR2_STOP) != 0) || ((i2c_status(obj) & SR2_RDRF) == 0)) {
|
|
|
|
if ((i2c_status(obj) & SR2_STOP) != 0) {
|
2015-01-29 07:40:16 +00:00
|
|
|
break_flg = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
timeout ++;
|
2015-04-07 07:46:17 +00:00
|
|
|
if (timeout >= WAIT_TIMEOUT) {
|
2015-01-29 07:40:16 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
2015-01-29 07:40:16 +00:00
|
|
|
if (break_flg == 0) {
|
|
|
|
if (count == 0) {
|
|
|
|
/* dummy read */
|
|
|
|
(void)REG(DRR.UINT32);
|
|
|
|
} else {
|
|
|
|
data[count - 1] = (char)(REG(DRR.UINT32) & 0xFF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (break_flg == 0) {
|
2014-12-18 09:40:44 +00:00
|
|
|
(void)i2c_wait_STOP(obj);
|
2015-01-29 07:40:16 +00:00
|
|
|
} else {
|
2015-05-13 02:00:35 +00:00
|
|
|
if ((i2c_status(obj) & SR2_RDRF) != 0) {
|
2015-01-29 07:40:16 +00:00
|
|
|
if (count <= 1) {
|
|
|
|
/* fail safe */
|
|
|
|
/* dummy read */
|
|
|
|
(void)REG(DRR.UINT32);
|
|
|
|
} else {
|
|
|
|
data[count - 2] = (char)(REG(DRR.UINT32) & 0xFF);
|
|
|
|
}
|
|
|
|
}
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
2015-01-29 07:40:16 +00:00
|
|
|
/* SR2.STOP = 0 */
|
|
|
|
REG(SR2.UINT32) &= ~SR2_STOP;
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2015-01-29 07:40:16 +00:00
|
|
|
return (count - 1);
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int i2c_slave_write(i2c_t *obj, const char *data, int length) {
|
|
|
|
int count = 0;
|
2015-01-29 07:40:16 +00:00
|
|
|
int status = 0;
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2014-10-24 02:05:17 +00:00
|
|
|
if(length <= 0) {
|
2015-01-29 07:40:16 +00:00
|
|
|
return 0;
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2015-01-29 07:40:16 +00:00
|
|
|
while ((count < length) && (status == 0)) {
|
2014-10-24 02:05:17 +00:00
|
|
|
status = i2c_do_write(obj, data[count]);
|
2015-05-13 02:00:35 +00:00
|
|
|
if(status == 0) {
|
|
|
|
/* Wait send end */
|
|
|
|
status = i2c_wait_TEND(obj);
|
|
|
|
if ((status != 0) || ((count < (length - 1)) && ((REG(SR2.UINT32) & SR2_NACKF) != 0))) {
|
|
|
|
/* NACK */
|
|
|
|
break;
|
|
|
|
}
|
2015-01-29 07:40:16 +00:00
|
|
|
}
|
2015-05-13 02:00:35 +00:00
|
|
|
count++;
|
2015-01-29 07:40:16 +00:00
|
|
|
}
|
|
|
|
/* dummy read */
|
|
|
|
(void)REG(DRR.UINT32);
|
|
|
|
(void)i2c_wait_STOP(obj);
|
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
2014-11-18 04:54:39 +00:00
|
|
|
|
2015-01-29 07:40:16 +00:00
|
|
|
return count;
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) {
|
2015-05-13 02:00:35 +00:00
|
|
|
REG(SAR0.UINT32) = (address & 0xfffffffe);
|
2014-10-24 02:05:17 +00:00
|
|
|
}
|
2016-03-24 07:08:43 +00:00
|
|
|
|
2019-01-24 04:08:11 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-03-24 07:08:43 +00:00
|
|
|
#if DEVICE_I2C_ASYNCH
|
|
|
|
|
|
|
|
#define IRQ_NUM 4
|
|
|
|
#define IRQ_TX 0
|
|
|
|
#define IRQ_RX 1
|
|
|
|
#define IRQ_ERR1 2
|
|
|
|
#define IRQ_ERR2 3
|
|
|
|
|
|
|
|
static void i2c_irqs_set(i2c_t *obj, uint32_t enable);
|
|
|
|
|
|
|
|
static void i2c0_tx_irq(void);
|
|
|
|
static void i2c1_tx_irq(void);
|
|
|
|
static void i2c2_tx_irq(void);
|
|
|
|
static void i2c3_tx_irq(void);
|
|
|
|
static void i2c0_rx_irq(void);
|
|
|
|
static void i2c1_rx_irq(void);
|
|
|
|
static void i2c2_rx_irq(void);
|
|
|
|
static void i2c3_rx_irq(void);
|
|
|
|
static void i2c0_al_irq(void);
|
|
|
|
static void i2c1_al_irq(void);
|
|
|
|
static void i2c2_al_irq(void);
|
|
|
|
static void i2c3_al_irq(void);
|
|
|
|
static void i2c0_to_irq(void);
|
|
|
|
static void i2c1_to_irq(void);
|
|
|
|
static void i2c2_to_irq(void);
|
|
|
|
static void i2c3_to_irq(void);
|
|
|
|
|
|
|
|
static const IRQn_Type irq_set_tbl[RIIC_COUNT][IRQ_NUM] = {
|
|
|
|
{INTIICTEI0_IRQn, INTIICRI0_IRQn, INTIICALI0_IRQn, INTIICTMOI0_IRQn},
|
|
|
|
{INTIICTEI1_IRQn, INTIICRI1_IRQn, INTIICALI1_IRQn, INTIICTMOI1_IRQn},
|
|
|
|
{INTIICTEI2_IRQn, INTIICRI2_IRQn, INTIICALI2_IRQn, INTIICTMOI2_IRQn},
|
|
|
|
{INTIICTEI3_IRQn, INTIICRI3_IRQn, INTIICALI3_IRQn, INTIICTMOI3_IRQn},
|
|
|
|
};
|
|
|
|
|
|
|
|
static const IRQHandler hander_set_tbl[RIIC_COUNT][IRQ_NUM] = {
|
|
|
|
{i2c0_tx_irq, i2c0_rx_irq, i2c0_al_irq, i2c0_to_irq},
|
|
|
|
{i2c1_tx_irq, i2c1_rx_irq, i2c1_al_irq, i2c1_to_irq},
|
|
|
|
{i2c2_tx_irq, i2c2_rx_irq, i2c2_al_irq, i2c2_to_irq},
|
|
|
|
{i2c3_tx_irq, i2c3_rx_irq, i2c3_al_irq, i2c3_to_irq},
|
|
|
|
};
|
|
|
|
|
|
|
|
struct i2c_global_data_s {
|
|
|
|
i2c_t *async_obj;
|
|
|
|
uint32_t async_callback, event, shouldStop, address;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct i2c_global_data_s i2c_data[RIIC_COUNT];
|
|
|
|
|
|
|
|
static void i2c_transfer_finished(i2c_t *obj)
|
|
|
|
{
|
|
|
|
i2c_irqs_set(obj, 0);
|
|
|
|
uint32_t index = obj->i2c.i2c;
|
|
|
|
i2c_data[index].event = I2C_EVENT_TRANSFER_COMPLETE;
|
|
|
|
i2c_data[index].async_obj = NULL;
|
|
|
|
((void (*)())i2c_data[index].async_callback)();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c_tx_irq(IRQn_Type irq_num, uint32_t index)
|
|
|
|
{
|
|
|
|
i2c_t *obj = i2c_data[index].async_obj;
|
|
|
|
if ((REG(SR2.UINT32) & SR2_NACKF)) {
|
|
|
|
/* Slave sends NACK */
|
|
|
|
i2c_set_err_noslave(obj);
|
|
|
|
i2c_data[index].event = I2C_EVENT_ERROR | I2C_EVENT_TRANSFER_EARLY_NACK;
|
|
|
|
i2c_abort_asynch(obj);
|
|
|
|
((void (*)())i2c_data[index].async_callback)();
|
2016-04-01 12:39:07 +00:00
|
|
|
return;
|
2016-03-24 07:08:43 +00:00
|
|
|
}
|
|
|
|
if (obj->tx_buff.pos == obj->tx_buff.length) {
|
|
|
|
/* All datas have tranferred */
|
|
|
|
|
|
|
|
/* Clear TEND */
|
|
|
|
REG(SR2.UINT32) &= ~(SR2_TEND);
|
|
|
|
|
|
|
|
/* If not repeated start, send stop. */
|
|
|
|
if (i2c_data[index].shouldStop && obj->rx_buff.length == 0) {
|
|
|
|
(void)i2c_set_STOP(obj);
|
|
|
|
(void)i2c_wait_STOP(obj);
|
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
|
|
|
i2c_transfer_finished(obj);
|
|
|
|
} else {
|
|
|
|
(void)i2c_restart(obj);
|
|
|
|
(void)i2c_wait_START(obj);
|
|
|
|
/* SR2.START = 0 */
|
|
|
|
REG(SR2.UINT32) &= ~SR2_START;
|
|
|
|
if (obj->rx_buff.length) {
|
|
|
|
/* Ready to read */
|
|
|
|
i2c_set_MR3_ACK(obj);
|
|
|
|
|
|
|
|
/* Disable INTRIICTEI */
|
|
|
|
REG(IER.UINT8[0]) &= ~(1 << 6);
|
|
|
|
|
|
|
|
/* Send Slave address */
|
|
|
|
if (i2c_read_address_write(obj, (i2c_data[index].address | 0x01)) != 0) {
|
|
|
|
i2c_set_err_noslave(obj);
|
|
|
|
i2c_data[index].event = I2C_EVENT_ERROR | I2C_EVENT_ERROR_NO_SLAVE;
|
|
|
|
i2c_abort_asynch(obj);
|
|
|
|
((void (*)())i2c_data[index].async_callback)();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
i2c_transfer_finished(obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Send next 1 byte */
|
|
|
|
if (i2c_do_write(obj, *(uint8_t *)obj->tx_buff.buffer) != 0) {
|
|
|
|
i2c_set_err_noslave(obj);
|
|
|
|
i2c_data[index].event = I2C_EVENT_ERROR | I2C_EVENT_ERROR_NO_SLAVE;
|
|
|
|
i2c_abort_asynch(obj);
|
|
|
|
((void (*)())i2c_data[index].async_callback)();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
obj->tx_buff.buffer = (uint8_t *)obj->tx_buff.buffer + 1;
|
|
|
|
++obj->tx_buff.pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c_rx_irq(IRQn_Type irq_num, uint32_t index)
|
|
|
|
{
|
|
|
|
i2c_t *obj = i2c_data[index].async_obj;
|
|
|
|
if (obj->rx_buff.pos == SIZE_MAX) {
|
|
|
|
if ((REG(SR2.UINT32) & SR2_NACKF) != 0) {
|
|
|
|
/* Slave sends NACK */
|
|
|
|
(void)i2c_set_STOP(obj);
|
|
|
|
/* dummy read */
|
|
|
|
if (REG(DRR.UINT32)) {}
|
|
|
|
(void)i2c_wait_STOP(obj);
|
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
|
|
|
obj->i2c.last_stop_flag = 1;
|
|
|
|
|
|
|
|
i2c_data[index].event = I2C_EVENT_ERROR | I2C_EVENT_TRANSFER_EARLY_NACK;
|
|
|
|
i2c_abort_asynch(obj);
|
|
|
|
((void (*)())i2c_data[index].async_callback)();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (obj->rx_buff.length == 1) {
|
|
|
|
/* length == 1 */
|
|
|
|
/* Set MR3 WAIT bit is 1 */;
|
|
|
|
REG(MR3.UINT32) |= MR3_WAIT;
|
|
|
|
i2c_set_MR3_NACK(obj);
|
|
|
|
} else if (obj->rx_buff.length == 2) {
|
|
|
|
/* Set MR3 WAIT bit is 1 */
|
|
|
|
REG(MR3.UINT32) |= MR3_WAIT;
|
|
|
|
}
|
|
|
|
/* dummy read */
|
|
|
|
if (REG(DRR.UINT32)) {}
|
|
|
|
obj->rx_buff.pos = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ((REG(SR2.UINT32) & SR2_NACKF) != 0) {
|
|
|
|
/* Slave sends NACK */
|
|
|
|
i2c_set_err_noslave(obj);
|
|
|
|
i2c_data[index].event = I2C_EVENT_ERROR | I2C_EVENT_TRANSFER_EARLY_NACK;
|
|
|
|
i2c_abort_asynch(obj);
|
|
|
|
((void (*)())i2c_data[index].async_callback)();
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
switch (obj->rx_buff.length - obj->rx_buff.pos) {
|
|
|
|
case 1:
|
|
|
|
/* Finished */
|
|
|
|
/* If not repeated start, send stop. */
|
|
|
|
if (i2c_data[index].shouldStop) {
|
|
|
|
(void)i2c_set_STOP(obj);
|
|
|
|
/* RIICnDRR read */
|
|
|
|
*(uint8_t *)obj->rx_buff.buffer = REG(DRR.UINT32) & 0xFF;
|
|
|
|
/* RIICnMR3.WAIT = 0 */
|
|
|
|
REG(MR3.UINT32) &= ~MR3_WAIT;
|
|
|
|
(void)i2c_wait_STOP(obj);
|
|
|
|
i2c_set_SR2_NACKF_STOP(obj);
|
|
|
|
} else {
|
|
|
|
(void)i2c_restart(obj);
|
|
|
|
/* RIICnDRR read */
|
|
|
|
*(uint8_t *)obj->rx_buff.buffer = REG(DRR.UINT32) & 0xFF;
|
|
|
|
/* RIICnMR3.WAIT = 0 */
|
|
|
|
REG(MR3.UINT32) &= ~MR3_WAIT;
|
|
|
|
(void)i2c_wait_START(obj);
|
|
|
|
/* SR2.START = 0 */
|
|
|
|
REG(SR2.UINT32) &= ~SR2_START;
|
|
|
|
}
|
|
|
|
|
|
|
|
i2c_transfer_finished(obj);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
i2c_set_MR3_NACK(obj);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
/* this time is befor last byte read */
|
|
|
|
/* Set MR3 WAIT bit is 1 */
|
|
|
|
REG(MR3.UINT32) |= MR3_WAIT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
i2c_set_MR3_ACK(obj);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*(uint8_t *)obj->rx_buff.buffer = REG(DRR.UINT32) & 0xFF;
|
|
|
|
obj->rx_buff.buffer = (uint8_t *)obj->rx_buff.buffer + 1;
|
|
|
|
++obj->rx_buff.pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c_err_irq(IRQn_Type irq_num, uint32_t index)
|
|
|
|
{
|
|
|
|
i2c_t *obj = i2c_data[index].async_obj;
|
|
|
|
i2c_abort_asynch(obj);
|
|
|
|
i2c_data[index].event = I2C_EVENT_ERROR;
|
|
|
|
((void (*)())i2c_data[index].async_callback)();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TX handler */
|
|
|
|
static void i2c0_tx_irq(void)
|
|
|
|
{
|
|
|
|
i2c_tx_irq(INTIICTEI0_IRQn, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c1_tx_irq(void)
|
|
|
|
{
|
|
|
|
i2c_tx_irq(INTIICTEI1_IRQn, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c2_tx_irq(void)
|
|
|
|
{
|
|
|
|
i2c_tx_irq(INTIICTEI2_IRQn, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c3_tx_irq(void)
|
|
|
|
{
|
|
|
|
i2c_tx_irq(INTIICTEI3_IRQn, 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* RX handler */
|
|
|
|
static void i2c0_rx_irq(void)
|
|
|
|
{
|
|
|
|
i2c_rx_irq(INTIICRI0_IRQn, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c1_rx_irq(void)
|
|
|
|
{
|
|
|
|
i2c_rx_irq(INTIICRI1_IRQn, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c2_rx_irq(void)
|
|
|
|
{
|
|
|
|
i2c_rx_irq(INTIICRI2_IRQn, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c3_rx_irq(void)
|
|
|
|
{
|
|
|
|
i2c_rx_irq(INTIICRI3_IRQn, 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Arbitration Lost handler */
|
|
|
|
static void i2c0_al_irq(void)
|
|
|
|
{
|
|
|
|
i2c_err_irq(INTIICALI0_IRQn, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c1_al_irq(void)
|
|
|
|
{
|
|
|
|
i2c_err_irq(INTIICALI1_IRQn, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c2_al_irq(void)
|
|
|
|
{
|
|
|
|
i2c_err_irq(INTIICALI2_IRQn, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c3_al_irq(void)
|
|
|
|
{
|
|
|
|
i2c_err_irq(INTIICALI3_IRQn, 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Timeout handler */
|
|
|
|
static void i2c0_to_irq(void)
|
|
|
|
{
|
|
|
|
i2c_err_irq(INTIICTMOI0_IRQn, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c1_to_irq(void)
|
|
|
|
{
|
|
|
|
i2c_err_irq(INTIICTMOI1_IRQn, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c2_to_irq(void)
|
|
|
|
{
|
|
|
|
i2c_err_irq(INTIICTMOI2_IRQn, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c3_to_irq(void)
|
|
|
|
{
|
|
|
|
i2c_err_irq(INTIICTMOI3_IRQn, 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c_irqs_set(i2c_t *obj, uint32_t enable)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
const IRQn_Type *irqTable = irq_set_tbl[obj->i2c.i2c];
|
|
|
|
const IRQHandler *handlerTable = hander_set_tbl[obj->i2c.i2c];
|
|
|
|
for (i = 0; i < IRQ_NUM; ++i) {
|
|
|
|
if (enable) {
|
|
|
|
InterruptHandlerRegister(irqTable[i], handlerTable[i]);
|
|
|
|
GIC_SetPriority(irqTable[i], 5);
|
2017-12-14 11:25:27 +00:00
|
|
|
if (i == 1) {
|
|
|
|
GIC_SetConfiguration(irqTable[i], 3);
|
|
|
|
} else {
|
|
|
|
GIC_SetConfiguration(irqTable[i], 1);
|
|
|
|
}
|
2016-03-24 07:08:43 +00:00
|
|
|
GIC_EnableIRQ(irqTable[i]);
|
|
|
|
} else {
|
|
|
|
GIC_DisableIRQ(irqTable[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
REG(IER.UINT8[0]) = enable ? 0x63 : 0x00;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* ASYNCHRONOUS HAL
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
MBED_ASSERT(obj);
|
|
|
|
MBED_ASSERT(tx ? tx_length : 1);
|
|
|
|
MBED_ASSERT(rx ? rx_length : 1);
|
|
|
|
MBED_ASSERT((REG(SER.UINT32) & SER_SAR0E) == 0); /* Slave mode */
|
|
|
|
|
|
|
|
obj->tx_buff.buffer = (void *)tx;
|
|
|
|
obj->tx_buff.length = tx_length;
|
|
|
|
obj->tx_buff.pos = 0;
|
|
|
|
obj->tx_buff.width = 8;
|
|
|
|
obj->rx_buff.buffer = rx;
|
|
|
|
obj->rx_buff.length = rx_length;
|
|
|
|
obj->rx_buff.pos = SIZE_MAX;
|
|
|
|
obj->rx_buff.width = 8;
|
|
|
|
i2c_data[obj->i2c.i2c].async_obj = obj;
|
|
|
|
i2c_data[obj->i2c.i2c].async_callback = handler;
|
|
|
|
i2c_data[obj->i2c.i2c].event = 0;
|
|
|
|
i2c_data[obj->i2c.i2c].shouldStop = stop;
|
|
|
|
i2c_data[obj->i2c.i2c].address = address;
|
|
|
|
i2c_irqs_set(obj, 1);
|
|
|
|
|
|
|
|
/* There is a STOP condition for last processing */
|
|
|
|
if (obj->i2c.last_stop_flag != 0) {
|
|
|
|
if (i2c_start(obj) != 0) {
|
|
|
|
i2c_set_err_noslave(obj);
|
|
|
|
i2c_data[obj->i2c.i2c].event = I2C_EVENT_ERROR | I2C_EVENT_ERROR_NO_SLAVE;
|
|
|
|
i2c_abort_asynch(obj);
|
|
|
|
((void (*)())handler)();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
obj->i2c.last_stop_flag = stop;
|
|
|
|
|
2016-04-01 12:39:07 +00:00
|
|
|
if (rx_length && tx_length == 0) {
|
2016-03-24 07:08:43 +00:00
|
|
|
/* Ready to read */
|
|
|
|
i2c_set_MR3_ACK(obj);
|
|
|
|
|
|
|
|
/* Disable INTRIICTEI */
|
|
|
|
REG(IER.UINT8[0]) &= ~(1 << 6);
|
|
|
|
|
|
|
|
address |= 0x01;
|
|
|
|
}
|
|
|
|
/* Send Slave address */
|
|
|
|
if (i2c_do_write(obj, address) != 0) {
|
|
|
|
i2c_set_err_noslave(obj);
|
|
|
|
i2c_data[obj->i2c.i2c].event = I2C_EVENT_ERROR | I2C_EVENT_ERROR_NO_SLAVE;
|
|
|
|
i2c_abort_asynch(obj);
|
|
|
|
((void (*)())handler)();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t i2c_irq_handler_asynch(i2c_t *obj)
|
|
|
|
{
|
|
|
|
return i2c_data[obj->i2c.i2c].event;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t i2c_active(i2c_t *obj)
|
|
|
|
{
|
|
|
|
return i2c_data[obj->i2c.i2c].async_obj != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void i2c_abort_asynch(i2c_t *obj)
|
|
|
|
{
|
|
|
|
i2c_data[obj->i2c.i2c].async_obj = NULL;
|
|
|
|
i2c_irqs_set(obj, 0);
|
|
|
|
i2c_reg_reset(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2019-06-19 21:08:55 +00:00
|
|
|
#endif // #if DEVICE_I2C
|