Esempio n. 1
0
/** Configure I2C as slave or master.
 *  @param obj The I2C object
 *  @param data    The buffer for sending
 *  @param length  Number of bytes to write
 *  @return non-zero if a value is available
 */
int i2c_slave_write(i2c_t *obj, const char *data, int length)
{
    struct i2c_s *obj_s = I2C_S(obj);
    int count = 0;
    int timeout = 0;

    i2c_ack_config(obj_s->i2c, I2C_ACK_ENABLE);
    /* wait until ADDSEND bit is set */
    while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_ADDSEND)) {
        timeout++;
        if (timeout > 100000) {
            return -1;
        }
    }
    /* clear ADDSEND bit */
    i2c_flag_clear(obj_s->i2c, I2C_FLAG_ADDSEND);
    while (length > 0) {
        /* wait until the TBE bit is set */
        timeout = 0;
        while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_TBE)) {
            timeout++;
            if (timeout > 100000) {
                return -1;
            }
        }
        i2c_data_transmit(obj_s->i2c, *data);
        data++;
        length--;
        count++;
    }
    /* the master doesn't acknowledge for the last byte */
    timeout = 0;
    while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_AERR)) {
        timeout++;
        if (timeout > 100000) {
            return -1;
        }
    }
    /* clear the bit of AERR */
    i2c_flag_clear(obj_s->i2c, I2C_FLAG_AERR);
    /* disable acknowledge */
    i2c_ack_config(obj_s->i2c, I2C_ACK_DISABLE);

    return count;
}
Esempio n. 2
0
/** Configure I2C as slave or master.
 *  @param obj The I2C object
 *  @param data    The buffer for receiving
 *  @param length  Number of bytes to read
 *  @return non-zero if a value is available
 */
int i2c_slave_read(i2c_t *obj, char *data, int length)
{
    struct i2c_s *obj_s = I2C_S(obj);
    int count = 0;
    int timeout = 0;

    i2c_ack_config(obj_s->i2c, I2C_ACK_ENABLE);

    /* wait until ADDSEND bit is set */
    while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_ADDSEND)) {
        timeout++;
        if (timeout > 100000) {
            return -1;
        }
    }
    /* clear ADDSEND bit */
    i2c_flag_clear(obj_s->i2c, I2C_FLAG_ADDSEND);

    while (0 < length) {
        /* wait until the RBNE bit is set */
        timeout = 0;
        while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_RBNE)) {
            timeout++;
            if (timeout > 100000) {
                return -1;
            }
        }
        *data = i2c_data_receive(obj_s->i2c);
        data++;
        length--;
        count++;
    }
    /* wait until the STPDET bit is set */
    timeout = 0;
    while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_STPDET)) {
        timeout++;
        if (timeout > 100) {
            return count;
        }
    }
    /* clear the STPDET bit */
    i2c_enable(obj_s->i2c);

    i2c_ack_config(obj_s->i2c, I2C_ACK_DISABLE);

    return count;
}
Esempio n. 3
0
/*!
    \brief      handle I2C1 error interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/
void I2C1_ErrorIRQ_Handler(void)
{
    /* no acknowledge received */
    if(i2c_flag_get(I2C1, I2C_AERR)){
        i2c_flag_clear(I2C1, I2C_AERR);
    }

    /* SMBus alert */
    if(i2c_flag_get(I2C1, I2C_SMBALTS)){
        i2c_flag_clear(I2C1, I2C_SMBALTS);
    }

    /* bus timeout in SMBus mode */
    if(i2c_flag_get(I2C1, I2C_SMBTO)){
        i2c_flag_clear(I2C1, I2C_SMBTO);
    }

    /* over-run or under-run when SCL stretch is disabled */
    if(i2c_flag_get(I2C1, I2C_OUERR)){
       i2c_flag_clear(I2C1, I2C_OUERR);
    }

    /* arbitration lost */
    if(i2c_flag_get(I2C1, I2C_LOSTARB)){
        i2c_flag_clear(I2C1, I2C_LOSTARB);
    }

    /* bus error */
    if(i2c_flag_get(I2C1, I2C_BERR)){
        i2c_flag_clear(I2C1, I2C_BERR);
    }

    /* CRC value doesn't match */
    if(i2c_flag_get(I2C1, I2C_PECERR)){
        i2c_flag_clear(I2C1, I2C_PECERR);
    }

    /* disable the error interrupt */
    i2c_interrupt_disable(I2C1,I2C_CTL1_ERRIE | I2C_CTL1_BUFIE | I2C_CTL1_EVIE);
}
Esempio n. 4
0
/** Send START command
 *
 *  @param obj The I2C object
 */
int i2c_start(i2c_t *obj)
{
    int timeout;
    struct i2c_s *obj_s = I2C_S(obj);

    /* clear I2C_FLAG_AERR Flag */
    i2c_flag_clear(obj_s->i2c, I2C_FLAG_AERR);

    /* wait until I2C_FLAG_I2CBSY flag is reset */
    timeout = FLAG_TIMEOUT;
    while ((i2c_flag_get(obj_s->i2c, I2C_FLAG_I2CBSY)) == SET) {
        if ((timeout--) == 0) {
            return (int)GD_BUSY;
        }
    }

    /* ensure the i2c has been stopped */
    timeout = FLAG_TIMEOUT;
    while ((I2C_CTL0(obj_s->i2c) & I2C_CTL0_STOP) == I2C_CTL0_STOP) {
        if ((timeout--) == 0) {
            return (int)GD_ERROR;
        }
    }

    /* generate a START condition */
    i2c_start_on_bus(obj_s->i2c);

    /* ensure the i2c has been started successfully */
    timeout = FLAG_TIMEOUT;
    while ((i2c_flag_get(obj_s->i2c, I2C_FLAG_SBSEND)) == RESET) {
        if ((timeout--) == 0) {
            return (int)GD_ERROR;
        }
    }

    return (int)GD_OK;
}
Esempio n. 5
0
/** Blocking sending data
 *
 *  @param obj     The I2C object
 *  @param address 7-bit address (last bit is 0)
 *  @param data    The buffer for sending
 *  @param length  Number of bytes to write
 *  @param stop    Stop to be generated after the transfer is done
 *  @return
 *      zero or non-zero - Number of written bytes
 *      negative - I2C_ERROR_XXX status
 */
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
{
    struct i2c_s *obj_s = I2C_S(obj);
    gd_status_enum status = GD_OK;
    uint32_t count = 0;
    int timeout = 0;

    if (obj_s->global_trans_option == I2C_FIRST_AND_LAST_FRAME ||
            obj_s->global_trans_option == I2C_LAST_FRAME) {
        if (stop) {
            obj_s->global_trans_option = I2C_FIRST_AND_LAST_FRAME;
        } else {
            obj_s->global_trans_option = I2C_FIRST_FRAME;
        }
    } else if (obj_s->global_trans_option == I2C_FIRST_FRAME ||
               obj_s->global_trans_option == I2C_NEXT_FRAME) {
        if (stop) {
            obj_s->global_trans_option = I2C_LAST_FRAME;
        } else {
            obj_s->global_trans_option = I2C_NEXT_FRAME;
        }
    }

    if (obj_s->global_trans_option == I2C_FIRST_AND_LAST_FRAME || obj_s->global_trans_option == I2C_FIRST_FRAME) {
        /* wait until I2C_FLAG_I2CBSY flag is reset */
        timeout = FLAG_TIMEOUT;
        while ((i2c_flag_get(obj_s->i2c, I2C_FLAG_I2CBSY)) == SET) {
            if ((timeout--) == 0) {
                i2c_stop(obj);
                return I2C_ERROR_BUS_BUSY;
            }
        }
    }

    if (obj_s->global_trans_option == I2C_FIRST_AND_LAST_FRAME || obj_s->global_trans_option == I2C_FIRST_FRAME ||
            obj_s->previous_state_mode != I2C_STATE_MASTER_BUSY_TX) {
        /* generate a START condition */
        i2c_start_on_bus(obj_s->i2c);

        /* ensure the i2c has been started successfully */
        timeout = FLAG_TIMEOUT;
        while ((i2c_flag_get(obj_s->i2c, I2C_FLAG_SBSEND)) == RESET) {
            if ((timeout--) == 0) {
                i2c_stop(obj);
                return I2C_ERROR_BUS_BUSY;
            }
        }

        /* send slave address */
        i2c_master_addressing(obj_s->i2c, address, I2C_TRANSMITTER);

        /* wait until I2C_FLAG_ADDSEND flag is set */
        while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_ADDSEND)) {
            timeout++;
            if (timeout > 100000) {
                i2c_stop(obj);
                return I2C_ERROR_NO_SLAVE;
            }
        }

        /* clear ADDSEND */
        i2c_flag_clear(obj_s->i2c, I2C_FLAG_ADDSEND);
    }

    obj_s->state = (operation_state_enum)I2C_STATE_MASTER_BUSY_TX;

    for (count = 0; count < length; count++) {
        status = (gd_status_enum)i2c_byte_write(obj, data[count]);
        if (status != 1) {
            i2c_stop(obj);
            return count;
        }
    }

    obj_s->previous_state_mode = obj_s->state;

    /* if not sequential write, then send stop */
    if (stop) {
        i2c_stop(obj);
    }

    return count;
}
Esempio n. 6
0
/** Blocking reading data
 *
 *  @param obj     The I2C object
 *  @param address 7-bit address (last bit is 1)
 *  @param data    The buffer for receiving
 *  @param length  Number of bytes to read
 *  @param stop    Stop to be generated after the transfer is done
 *  @return Number of read bytes
 */
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
{
    struct i2c_s *obj_s = I2C_S(obj);
    uint32_t count = 0U;
    int timeout = 0;

    if (obj_s->global_trans_option == I2C_FIRST_AND_LAST_FRAME ||
            obj_s->global_trans_option == I2C_LAST_FRAME) {
        if (stop) {
            obj_s->global_trans_option = I2C_FIRST_AND_LAST_FRAME;
        } else {
            obj_s->global_trans_option = I2C_FIRST_FRAME;
        }
    } else if (obj_s->global_trans_option == I2C_FIRST_FRAME ||
               obj_s->global_trans_option == I2C_NEXT_FRAME) {
        if (stop) {
            obj_s->global_trans_option = I2C_LAST_FRAME;
        } else {
            obj_s->global_trans_option = I2C_NEXT_FRAME;
        }
    }

    if (obj_s->global_trans_option == I2C_FIRST_AND_LAST_FRAME || obj_s->global_trans_option == I2C_FIRST_FRAME) {
        /* wait until I2C_FLAG_I2CBSY flag is reset */
        timeout = FLAG_TIMEOUT;
        while ((i2c_flag_get(obj_s->i2c, I2C_FLAG_I2CBSY)) == SET) {
            if ((timeout--) == 0) {
                i2c_stop(obj);
                return I2C_ERROR_BUS_BUSY;
            }
        }
    }

    if (obj_s->global_trans_option == I2C_FIRST_AND_LAST_FRAME || obj_s->global_trans_option == I2C_FIRST_FRAME ||
            obj_s->previous_state_mode != I2C_STATE_MASTER_BUSY_RX) {
        /* generate a START condition */
        i2c_start_on_bus(obj_s->i2c);

        /* ensure the i2c has been started successfully */
        timeout = FLAG_TIMEOUT;
        while ((i2c_flag_get(obj_s->i2c, I2C_FLAG_SBSEND)) == RESET) {
            if ((timeout--) == 0) {
                i2c_stop(obj);
                return I2C_ERROR_BUS_BUSY;
            }
        }

        /* send slave address */
        i2c_master_addressing(obj_s->i2c, address, I2C_RECEIVER);

        if (1 == length) {
            /* disable acknowledge */
            i2c_ack_config(obj_s->i2c, I2C_ACK_DISABLE);
            /* send a stop condition to I2C bus*/
        } else if (2 == length) {
            /* send a NACK for the next data byte which will be received into the shift register */
            i2c_ackpos_config(obj_s->i2c, I2C_ACKPOS_NEXT);
            /* disable acknowledge */
            i2c_ack_config(obj_s->i2c, I2C_ACK_DISABLE);
        } else {
            /* enable acknowledge */
            i2c_ack_config(obj_s->i2c, I2C_ACK_ENABLE);
        }

        /* wait until I2C_FLAG_ADDSEND flag is set */
        while (!i2c_flag_get(obj_s->i2c, I2C_FLAG_ADDSEND)) {
            timeout++;
            if (timeout > 100000) {
                i2c_stop(obj);
                return I2C_ERROR_NO_SLAVE;
            }
        }

        /* clear ADDSEND */
        i2c_flag_clear(obj_s->i2c, I2C_FLAG_ADDSEND);
    }

    obj_s->state = (operation_state_enum)I2C_STATE_MASTER_BUSY_RX;

    for (count = 0; count < length; count++) {
        if (length > 2 && count == length - 3) {
            while (RESET == i2c_flag_get(obj_s->i2c, I2C_FLAG_BTC));
            i2c_ack_config(obj_s->i2c, I2C_ACK_DISABLE);
        } else if (2 == length && count == 0) {
            while (RESET == i2c_flag_get(obj_s->i2c, I2C_FLAG_BTC));
        }

        while (RESET == i2c_flag_get(obj_s->i2c, I2C_FLAG_RBNE));
        data[count] = i2c_data_receive(obj_s->i2c);
    }

    obj_s->previous_state_mode = obj_s->state;

    /* if not sequential read, then send stop */
    if (stop) {
        i2c_stop(obj);
    }

    return count;
}