mbed library sources

Dependents:   Encrypted my_mbed lklk CyaSSL_DTLS_Cellular ... more

Superseded

This library was superseded by mbed-dev - https://os.mbed.com/users/mbed_official/code/mbed-dev/.

Development branch of the mbed library sources. This library is kept in synch with the latest changes from the mbed SDK and it is not guaranteed to work.

If you are looking for a stable and tested release, please import one of the official mbed library releases:

Import librarymbed

The official Mbed 2 C/C++ SDK provides the software platform and libraries to build your applications.

targets/hal/TARGET_RENESAS/TARGET_RZ_A1H/i2c_api.c

Committer:
mbed_official
Date:
2015-09-11
Revision:
621:9c82b0f79f3d
Parent:
541:7f313a59e20c

File content as of revision 621:9c82b0f79f3d:

/* 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"
#include "cmsis.h"
#include "pinmap.h"
#include "r_typedefs.h"

#include "riic_iodefine.h"
#include "RZ_A1_Init.h"
#include "MBRZA1H.h"

volatile struct st_riic *RIIC[] = RIIC_ADDRESS_LIST;

#define REG(N) \
    RIIC[obj->i2c]->RIICn##N

/* RIICnCR1 */
#define CR1_RST   (1 << 6)
#define CR1_ICE   (1 << 7)

/* RIICnCR2 */
#define CR2_ST    (1 << 1)
#define CR2_RS    (1 << 2)
#define CR2_SP    (1 << 3)
#define CR2_TRS   (1 << 5)
#define CR2_BBSY  (1 << 7)

/* RIICnMR3 */
#define MR3_ACKBT (1 << 3)
#define MR3_ACKWP (1 << 4)
#define MR3_WAIT  (1 << 6)

/* RIICnSER */
#define SER_SAR0E (1 << 0)

/* RIICnSR1 */
#define SR1_AAS0  (1 << 0)

/* RIICnSR2 */
#define SR2_START (1 << 2)
#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)

#define WAIT_TIMEOUT    (3600000)  /* Loop counter : Time-out is about 1s. By 3600000 loops, measured value is 969ms. */

static const PinMap PinMap_I2C_SDA[] = {
    {P1_1 , I2C_0, 1},
    {P1_3 , I2C_1, 1},
    {P1_7 , I2C_3, 1},
    {NC   , NC   , 0}
};

static const PinMap PinMap_I2C_SCL[] = {
    {P1_0 , I2C_0, 1},
    {P1_2 , I2C_1, 1},
    {P1_6 , I2C_3, 1},
    {NC   , NC,    0}
};


static inline int i2c_status(i2c_t *obj) {
    return REG(SR2.UINT8[0]);
}

static void i2c_reg_reset(i2c_t *obj) {
    /* 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

    REG(MR1.UINT8[0])  =  0x08;    // P_phi /x  9bit (including Ack)
    REG(SER.UINT8[0])  =  0x00;    // no slave addr enabled

    /* set frequency */
    REG(MR1.UINT8[0]) |=  obj->pclk_bit;
    REG(BRL.UINT8[0])  =  obj->width_low;
    REG(BRH.UINT8[0])  =  obj->width_hi;

    REG(MR2.UINT8[0])  =  0x07;
    REG(MR3.UINT8[0])  =  0x00;

    REG(FER.UINT8[0])  =  0x72;    // SCLE, NFE enabled, TMOT
    REG(IER.UINT8[0])  =  0x00;    // no interrupt

    REG(CR1.UINT32) &= ~CR1_RST;   // CR1.IICRST negate reset
}

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. */
    while ((i2c_status(obj) & SR2_RDRF) == 0) {
        timeout ++;
        if (timeout >= WAIT_TIMEOUT) {
            return -1;
        }
    }

    return 0;
}

static int i2c_wait_TDRE(i2c_t *obj) {
    int timeout = 0;

    /* 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;
        }
    }

    return 0;
}

static int i2c_wait_TEND(i2c_t *obj) {
    int timeout = 0;
    
    /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */
    while ((i2c_status(obj) & SR2_TEND) == 0) {
        timeout ++;
        if (timeout >= WAIT_TIMEOUT) {
            return -1;
        }
    }

    return 0;
}


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. */
    while ((i2c_status(obj) & SR2_START) == 0) {
        timeout ++;
        if (timeout >= WAIT_TIMEOUT) {
            return -1;
        }
    }

    return 0;
}

static int i2c_wait_STOP(i2c_t *obj) {
    int timeout = 0;
    
    /* There is no timeout, but the upper limit value is set to avoid an infinite loop. */
    while ((i2c_status(obj) & SR2_STOP) == 0) {
        timeout ++;
        if (timeout >= WAIT_TIMEOUT) {
            return -1;
        }
    }

    return 0;
}

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;
}

static void i2c_set_SR2_NACKF_STOP(i2c_t *obj) {
    /* SR2.NACKF = 0 */
    REG(SR2.UINT32) &= ~SR2_NACKF;
    /* SR2.STOP = 0 */
    REG(SR2.UINT32) &= ~SR2_STOP;
}

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;
}

static inline void i2c_power_enable(i2c_t *obj) {
    volatile uint8_t dummy;
    switch ((int)obj->i2c) {
        case I2C_0:
            CPGSTBCR9 &= ~(0x80);
            break;
        case I2C_1:
            CPGSTBCR9 &= ~(0x40);
            break;
        case I2C_2:
            CPGSTBCR9 &= ~(0x20);
            break;
        case I2C_3:
            CPGSTBCR9 &= ~(0x10);
            break;
    }
    dummy = CPGSTBCR9;
}

void i2c_init(i2c_t *obj, PinName sda, PinName scl) {
    /* determine the I2C to use */
    I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA);
    I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL);
    obj->i2c = pinmap_merge(i2c_sda, i2c_scl);
    MBED_ASSERT((int)obj->i2c != NC);

    /* enable power */
    i2c_power_enable(obj);

    /* set default frequency at 100k */
    i2c_frequency(obj, 100000);

    pinmap_pinout(sda, PinMap_I2C_SDA);
    pinmap_pinout(scl, PinMap_I2C_SCL);
    
    obj->last_stop_flag = 1;
}

inline int i2c_start(i2c_t *obj) {
    int timeout = 0;

    while ((REG(CR2.UINT32) & CR2_BBSY) != 0) {
        timeout ++;
        if (timeout >= obj->bbsy_wait_cnt) {
            break;
        }
    }
    /* Start Condition */
    REG(CR2.UINT8[0]) |= CR2_ST;

    return 0;
}

static inline int i2c_restart(i2c_t *obj) {
    /* SR2.START = 0 */
    REG(SR2.UINT32) &= ~SR2_START;
    /* ReStart condition */
    REG(CR2.UINT32) |= CR2_RS;

    return 0;
}

inline int i2c_stop(i2c_t *obj) {
    (void)i2c_set_STOP(obj);
    (void)i2c_wait_STOP(obj);
    i2c_set_SR2_NACKF_STOP(obj);
    
    return 0;
}

static void i2c_set_err_noslave(i2c_t *obj) {
    (void)i2c_set_STOP(obj);
    (void)i2c_wait_STOP(obj);
    i2c_set_SR2_NACKF_STOP(obj);
    obj->last_stop_flag = 1;
}

static inline int i2c_do_write(i2c_t *obj, int value) {
    int timeout = 0;

    /* 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;
        }
    }
    /* write the data */
    REG(DRT.UINT32) = value;

    return 0;
}

static inline int i2c_read_address_write(i2c_t *obj, int value) {
    int status;
    
    status = i2c_wait_TDRE(obj);
    if (status == 0) {
        /* write the data */
        REG(DRT.UINT32) = value;
    }
    
    return status;

}

static inline int i2c_do_read(i2c_t *obj, int last) {
    if (last == 2) {
        /* this time is befor last byte read */
        /* Set MR3 WAIT bit is 1 */;
        REG(MR3.UINT32) |= MR3_WAIT;
    } else if (last == 1) {
        i2c_set_MR3_NACK(obj);
    } else {
        i2c_set_MR3_ACK(obj);
    }

    /* return the data */
    return (REG(DRR.UINT32) & 0xFF);
}

void i2c_frequency(i2c_t *obj, int hz) {
    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;

    /* set PCLK */
    if (false == RZ_A1_IsClockMode0()) {
        pclk_val = (float64_t)CM1_RENESAS_RZ_A1_P0_CLK;
    } else {
        pclk_val = (float64_t)CM0_RENESAS_RZ_A1_P0_CLK;
    }

    /* Min 10kHz, Max 400kHz */
    if (hz < 10000) {
        bps = 10000;
    } else if (hz > 400000) {
        bps = 400000;
    } else {
        bps = (float64_t)hz;
    }

    /* 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;
        }
    }

    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 */
    } else {
        remainder    += tmp_H_width % 10;
        tmp_H_width   = (tmp_H_width / 10) - 3;
        if (remainder > 10) {
            tmp_H_width += 1;                         /* fine adjustment */
        }
    }
    /* 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) {
        obj->bbsy_wait_cnt = 1;
    } else {
        obj->bbsy_wait_cnt = (int)(wait_utime / 0.3);
    }


    /* I2C Rate */
    obj->pclk_bit  = (uint8_t)(0x10 * wk_cks);        /* P_phi / xx */
    obj->width_low = (uint8_t)(tmp_L_width | 0x000000E0);
    obj->width_hi  = (uint8_t)(tmp_H_width | 0x000000E0);

    /* full reset */
    i2c_reg_reset(obj);
}

int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
    int count = 0;
    int status;
    int value;
    volatile uint32_t work_reg = 0;

    if(length <= 0) {
        return 0;
    }
    i2c_set_MR3_ACK(obj);
    /* There is a STOP condition for last processing */
    if (obj->last_stop_flag != 0) {
        status = i2c_start(obj);
        if (status != 0) {
            i2c_set_err_noslave(obj);
            return I2C_ERROR_BUS_BUSY;
        }
    }
    obj->last_stop_flag = stop;
    /*  Send Slave address */
    status = i2c_read_address_write(obj, (address | 0x01));
    if (status != 0) {
        i2c_set_err_noslave(obj);
        return I2C_ERROR_NO_SLAVE;
    }
    /* wait RDRF */
    status = i2c_wait_RDRF(obj);
    /* check ACK/NACK */
    if ((status != 0) || ((REG(SR2.UINT32) & SR2_NACKF) != 0)) {
        /* Slave sends NACK */
        (void)i2c_set_STOP(obj);
        /* dummy read */
        value = REG(DRR.UINT32);
        (void)i2c_wait_STOP(obj);
        i2c_set_SR2_NACKF_STOP(obj);
        obj->last_stop_flag = 1;
        return I2C_ERROR_NO_SLAVE;
    }
    /* 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 WATI bit is 1 */
        REG(MR3.UINT32) |= MR3_WAIT;
        /* dummy read */
        value = REG(DRR.UINT32);
        /* wait for it to arrive */
        status = i2c_wait_RDRF(obj);
        if (status != 0) {
            i2c_set_err_noslave(obj);
            return I2C_ERROR_NO_SLAVE;
        }
        i2c_set_MR3_NACK(obj);
        data[count] = (char)REG(DRR.UINT32);
        count++;
    } else {
        /* length == 1 */
        /* Set MR3 WATI bit is 1 */;
        REG(MR3.UINT32) |=  MR3_WAIT;
        i2c_set_MR3_NACK(obj);
        /* dummy read */
        value = REG(DRR.UINT32);
    }
    /* wait for it to arrive */
    status = i2c_wait_RDRF(obj);
    if (status != 0) {
        i2c_set_err_noslave(obj);
        return I2C_ERROR_NO_SLAVE;
    }

    /* 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;
    }

    return length;
}

int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
    int cnt;
    int status;

    if(length <= 0) {
        return 0;
    }

    /* There is a STOP condition for last processing */
    if (obj->last_stop_flag != 0) {
        status = i2c_start(obj);
        if (status != 0) {
            i2c_set_err_noslave(obj);
            return I2C_ERROR_BUS_BUSY;
        }
    }
    obj->last_stop_flag = stop;
    /*  Send Slave address */
    status = i2c_do_write(obj, address);
    if (status != 0) {
        i2c_set_err_noslave(obj);
        return I2C_ERROR_NO_SLAVE;
    }
    /* 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;
    }
    /* Send Write data */
    for (cnt=0; cnt<length; cnt++) {
        status = i2c_do_write(obj, data[cnt]);
        if(status != 0) {
            i2c_set_err_noslave(obj);
            return cnt;
        } 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;
            }
        }
    }
    /* 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;

    }
    
    return length;
}

void i2c_reset(i2c_t *obj) {
    (void)i2c_set_STOP(obj);
    (void)i2c_wait_STOP(obj);
    i2c_set_SR2_NACKF_STOP(obj);
}

int i2c_byte_read(i2c_t *obj, int last) {
    int status;
    int data;

    data = i2c_do_read(obj, last);
    /* wait for it to arrive */
    status = i2c_wait_RDRF(obj);
    if (status != 0) {
        i2c_set_SR2_NACKF_STOP(obj);
        return I2C_ERROR_NO_SLAVE;
    }
    
    return data;
}

int i2c_byte_write(i2c_t *obj, int data) {
    int ack = 0;
    int status;
    int timeout = 0;
    
    status = i2c_do_write(obj, (data & 0xFF));
    if (status != 0) {
        i2c_set_SR2_NACKF_STOP(obj);
    } else {
        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;
        }
    }

    return ack;
}

void i2c_slave_mode(i2c_t *obj, int enable_slave) {
    if (enable_slave != 0) {
        REG(SER.UINT32) |= SER_SAR0E;   // only slave addr 0 is enabled
    } else {
        REG(SER.UINT32) &= ~SER_SAR0E;  // no slave addr enabled
    }
}

int i2c_slave_receive(i2c_t *obj) {
    int status;
    int retval;

    status = (REG(SR1.UINT8[0]) & SR1_AAS0);
    status |= (REG(CR2.UINT8[0]) & CR2_TRS) >> 4;

    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;
}

int i2c_slave_read(i2c_t *obj, char *data, int length) {
    int timeout = 0;
    int count;
    int break_flg = 0;

    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. */
        while (((i2c_status(obj) & SR2_STOP) != 0) || ((i2c_status(obj) & SR2_RDRF) == 0)) {
            if ((i2c_status(obj) & SR2_STOP) != 0) {
                break_flg = 1;
                break;
            }
            timeout ++;
            if (timeout >= WAIT_TIMEOUT) {
                return -1;
            }
        }
        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) {
        (void)i2c_wait_STOP(obj);
    } else {
        if ((i2c_status(obj) & SR2_RDRF) != 0) {
            if (count <= 1) {
                /* fail safe */
                /* dummy read */
                (void)REG(DRR.UINT32);
            } else {
                data[count - 2] = (char)(REG(DRR.UINT32) & 0xFF);
            }
        }
    }
    /* SR2.STOP = 0 */
    REG(SR2.UINT32) &= ~SR2_STOP;

    return (count - 1);
}

int i2c_slave_write(i2c_t *obj, const char *data, int length) {
    int count = 0;
    int status = 0;

    if(length <= 0) {
        return 0;
    }

    while ((count < length) && (status == 0)) {
        status = i2c_do_write(obj, data[count]);
        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;
            }
        }
        count++;
    }
    /* dummy read */
    (void)REG(DRR.UINT32);
    (void)i2c_wait_STOP(obj);
    i2c_set_SR2_NACKF_STOP(obj);

    return count;
}

void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) {
    REG(SAR0.UINT32) = (address & 0xfffffffe);
}