示例#1
0
static void eeprom_poll_ack(HW_I2C_ID id)
{
        /*
         * Writing to 24LC256 EEPROM fills internal buffer with data and starts actual write cycle
         * once it received STOP condition for a write command. Another read or write can be handled
         * by EEPROM only after it completes write cycle and this can be checked by ACK pooling
         * (described in datasheet) which basically is sending write command to EEPROM as long as it
         * does not return ACK - once ACK is received, it means write cycle has completed.
         */
        do {
                /*
                 * Make sure TX abort is reset, this is because at the beginning EEPROM will not ACK
                 * address byte so we'll have a TX abort set in controller.
                 */
                hw_i2c_reset_int_tx_abort(id);
                /*
                 * We only need to check if EEPROM returns ACK for address byte, however we cannot
                 * simply send address byte since it's controller who takes care of this once TX FIFO
                 * is filled with data. A simple solution is to send 'dummy' byte which will be
                 * ignored by EEPROM but will make I2C controller to generate START condition and
                 * send address byte.
                 */
                hw_i2c_write_byte(id, 0xAA);
                /*
                 * Before transmission status can be checked, we have to be sure that controller
                 * finished sending 'dummy' byte and received ACK (or not).
                 */
                while (hw_i2c_is_master_busy(id)) {
                }
                /*
                 * No check it transmission was successful - if EEPROM did not ACK address byte,
                 * appropriate abort source will be set.
                 */
        } while (hw_i2c_get_abort_source(id) & HW_I2C_ABORT_7B_ADDR_NO_ACK);
}
示例#2
0
BOOL hw_i2c_master_tx(const uint8_t *buf, uint8_t buf_len)
{
    BOOL error = FALSE;

    cpu_disable_int();

#if USE_HARDWARE_I2C
    while ((buf_len > 0) && !error) {
        TWDR = *buf++;
        TWCR = TWICR_TWEN | TWICR_TWINT;
        while ((TWCR & TWICR_TWINT) == 0);
        error = (TWSR & TW_STATUS_MASK) != TW_MT_DATA_ACK;
        buf_len--;
    }
#else
    while ((buf_len > 0) && !error) {
        hw_i2c_write_byte(*buf++);
        error = hw_i2c_read_bit() != 0;
        buf_len--;
    }
#endif
    cpu_enable_int();

    return !error;
}
示例#3
0
static void fm75_write_reg(uint8_t reg, const uint8_t *val, uint8_t len)
{
        size_t wr_status = 0;
        HW_I2C_ABORT_SOURCE abrt_src = HW_I2C_ABORT_NONE;

        /*
         * The first writing byte informs to which register rest data will be written.
         */
        hw_i2c_write_byte(HW_I2C1, reg);
        wr_status = hw_i2c_write_buffer_sync(HW_I2C1, val, len, &abrt_src, HW_I2C_F_WAIT_FOR_STOP);
        if ((wr_status < (ssize_t)len) || (abrt_src != HW_I2C_ABORT_NONE)) {
                printf("fm75 write failure: %u" NEWLINE, abrt_src);
        }
}
示例#4
0
static void fm75_read_reg(uint8_t reg, uint8_t *val, uint8_t len)
{
        size_t rd_status = 0;
        HW_I2C_ABORT_SOURCE abrt_src = HW_I2C_ABORT_NONE;

        /*
         * Before reading values from sensor registers we need to send one byte information to it
         * to inform which sensor register will be read now.
         */
        hw_i2c_write_byte(HW_I2C1, reg);
        rd_status = hw_i2c_read_buffer_sync(HW_I2C1, val, len, &abrt_src, HW_I2C_F_NONE);
        if ((rd_status < (size_t)len) || (abrt_src != HW_I2C_ABORT_NONE)) {
                printf("fm75 read failure: %u" NEWLINE, abrt_src);
        }
}
示例#5
0
bool hw_i2c_write_buffer(HW_I2C_ID id, const uint8_t *data, uint16_t len,
                hw_i2c_complete_cb cb, void *cb_data, bool wait_for_stop)
{
        if (!data) {
                return false;
        }

        if (!cb) {
                while (len--) {
                        while (!hw_i2c_is_tx_fifo_not_full(id));
                        hw_i2c_write_byte(id, *data);
                        data++;
                        if (hw_i2c_get_abort_source(id)) {
                                return false;
                        }
                }

                while (!hw_i2c_is_tx_fifo_empty(id));
                while (hw_i2c_is_master_busy(id));

                if (hw_i2c_get_abort_source(id)) {
                        return false;
                }
        } 
        else {
                struct i2c *i2c = get_i2c(id);

                i2c->tx_state.data = data;
                i2c->tx_state.len = len;
                i2c->tx_state.num = 0;
                i2c->tx_state.cb = cb;
                i2c->tx_state.cb_data = cb_data;
                i2c->tx_state.flags = wait_for_stop? HW_I2C_F_WAIT_FOR_STOP : HW_I2C_F_NONE;

                hw_i2c_reset_int_tx_abort(id);
                if (wait_for_stop) {
                        hw_i2c_reset_int_stop_detected(id);
                }

                hw_i2c_register_int(id, intr_write_buffer_handler, HW_I2C_INT_TX_EMPTY |
                        (wait_for_stop ? HW_I2C_INT_STOP_DETECTED : 0) | HW_I2C_INT_TX_ABORT);

                /* we want TX_EMPTY as soon as FIFO is not completely full */
                hw_i2c_set_tx_fifo_threshold(id, I2C_FIFO_DEPTH - 1);
        }

        return true;
}
示例#6
0
BOOL hw_i2c_master_start(uint8_t address, hw_i2c_rdwr_t hw_i2c_rd_wr)
{
#if USE_HARDWARE_I2C
    BOOL error = FALSE;
    uint8_t twsr;

    cpu_disable_int();

    TWCR = TWICR_TWEN | TWICR_TWINT | TWICR_TWSTA;
    while ((TWCR & TWICR_TWINT) == 0);

    twsr = TWSR & TW_STATUS_MASK;
    if ((twsr != TW_START) && (twsr != TW_REP_START)) {
        error = TRUE;
    } else {
        TWDR = (address & 0xfe) | hw_i2c_rd_wr;
        TWCR = TWICR_TWEN | TWICR_TWINT;
        while ((TWCR & TWICR_TWINT) == 0);

        twsr = TWSR & TW_STATUS_MASK;
        if (hw_i2c_rd_wr == hw_i2c_rd) {
            error = twsr != TW_MR_SLA_ACK;
        } else {
            error = twsr != TW_MT_SLA_ACK;
        }
    }

    cpu_enable_int();
    return !error;
#else
    cpu_disable_int();

    delay_T2();
    if (hold_bus) {
        sda_hi();
        delay_T2();
        scl_hi();
        delay_T2();
    }
    sda_low();
    delay_T2();
    scl_low();

    hold_bus = TRUE;
    hw_i2c_write_byte((address & 0xfe) | hw_i2c_rd_wr);
    return hw_i2c_read_bit() == 0;  // will call cpu_enable_int()
#endif
}
示例#7
0
static void intr_write_buffer_handler(HW_I2C_ID id, uint16_t mask)
{
        struct i2c *i2c = get_i2c(id);
        struct tx_state *txs = &i2c->tx_state;

        if (!txs->data || mask == 0) {
                return;
        }

        if (mask & HW_I2C_INT_TX_ABORT) {
                tx_reply(id, false);

                /* clear abort */
                hw_i2c_reset_int_tx_abort(id);

                return;
        }

        if (mask & HW_I2C_INT_STOP_DETECTED) {
                tx_reply(id, txs->num == txs->len);
                hw_i2c_reset_int_stop_detected(id);
                return;
        }

        if (!(mask & HW_I2C_INT_TX_EMPTY)) {
                tx_reply(id, false);
                return;
        }

        while (txs->num < txs->len && hw_i2c_is_tx_fifo_not_full(id)) {
                hw_i2c_write_byte(id, txs->data[txs->num]);
                txs->num++;
        }

        /*
         * trigger reply when all data were written to TX FIFO and either TX FIFO is empty
         * (controller will generate STOP condition on bus) or caller requested immediate callback
         * (caller can continue with another transfer immediately).
         */
        if (txs->num == txs->len) {
                if (txs->flags & HW_I2C_F_WAIT_FOR_STOP) {
                        hw_i2c_set_int_mask(id, hw_i2c_get_int_mask(id) & ~HW_I2C_INT_TX_EMPTY);
                } else {
                        tx_reply(id, true);
                }
        }
}
示例#8
0
size_t hw_i2c_write_buffer_sync(HW_I2C_ID id, const uint8_t *data, uint16_t len, 
                                HW_I2C_ABORT_SOURCE *abrt_code, uint32_t flags)
{
        HW_I2C_ABORT_SOURCE ret = HW_I2C_ABORT_NONE;
        size_t offst = 0;

        if (!data || len == 0) {
                ret = HW_I2C_ABORT_SW_ERROR;
        }
        else {
                while (len--) {
                        while (!hw_i2c_is_tx_fifo_not_full(id));

                        hw_i2c_write_byte(id, data[offst++]);
                        ret = hw_i2c_get_abort_source(id);
                        if (ret) {
                                break;
                        }
                }

                if (!ret && (flags & HW_I2C_F_WAIT_FOR_STOP)) {
                        while (!hw_i2c_is_tx_fifo_empty(id));
                        while (hw_i2c_is_master_busy(id));
                        ret = hw_i2c_get_abort_source(id);
                }
        }

        if (abrt_code) {
                *abrt_code = ret;
        }

        if (ret) {
                hw_i2c_reset_int_tx_abort(id);
        }

        return offst;
}