예제 #1
0
static void tx_prepare(volatile nrf_drv_twi_t const * const p_instance)
{
    volatile transfer_t * p_transfer = &(m_cb[p_instance->instance_id].transfer);

    nrf_twi_txd_set(p_instance->p_reg, p_transfer->p_data[p_transfer->count]);
    txrx_shorts_set_task_start(p_instance);
}
예제 #2
0
파일: i2c_api.c 프로젝트: Archcady/mbed-os
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)
{
    (void)hint;

    twi_info_t *twi_info = TWI_INFO(obj);
    if (twi_info->active) {
        return;
    }
    twi_info->active    = true;
    twi_info->events    = 0;
    twi_info->handler   = (void (*)(void))handler;
    twi_info->evt_mask  = event;
    twi_info->tx_length = tx_length;
    twi_info->tx        = tx;
    twi_info->rx_length = rx_length;
    twi_info->rx        = rx;
    twi_info->stop      = stop;

    NRF_TWI_Type *twi = m_twi_instances[TWI_IDX(obj)];

    nrf_twi_event_clear(twi, NRF_TWI_EVENT_TXDSENT);
    nrf_twi_event_clear(twi, NRF_TWI_EVENT_RXDREADY);
    nrf_twi_event_clear(twi, NRF_TWI_EVENT_STOPPED);
    nrf_twi_event_clear(twi, NRF_TWI_EVENT_SUSPENDED);
    nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR);
    (void)nrf_twi_errorsrc_get_and_clear(twi);

    nrf_twi_address_set(twi, twi_address(address));
    nrf_twi_task_trigger(twi, NRF_TWI_TASK_RESUME);
    // TX only, or TX + RX (after a repeated start).
    if (tx_length > 0) {
        nrf_twi_task_trigger(twi, NRF_TWI_TASK_STARTTX);
        nrf_twi_txd_set(twi, *(twi_info->tx));
        ++(twi_info->tx);
    // RX only.
    } else if (rx_length > 0) {
        start_asynch_rx(twi_info, twi);
    // Both 'tx_length' and 'rx_length' are 0 - this case may be used
    // to test if the slave is presentand ready for transfer (by just
    // sending the address and checking if it is acknowledged).
    } else {
        nrf_twi_task_trigger(twi, NRF_TWI_TASK_STARTTX);
        if (stop) {
            nrf_twi_task_trigger(twi, NRF_TWI_TASK_STOP);
        } else {
            nrf_twi_task_trigger(twi, NRF_TWI_TASK_SUSPEND);
            nrf_twi_int_enable(twi, NRF_TWI_INT_SUSPENDED_MASK);
        }
        twi_info->events |= I2C_EVENT_TRANSFER_COMPLETE;
    }

    nrf_twi_int_enable(twi, NRF_TWI_INT_TXDSENT_MASK |
                            NRF_TWI_INT_RXDREADY_MASK |
                            NRF_TWI_INT_STOPPED_MASK |
                            NRF_TWI_INT_ERROR_MASK);
}
예제 #3
0
파일: i2c_api.c 프로젝트: Archcady/mbed-os
static uint8_t twi_byte_write(NRF_TWI_Type *twi, uint8_t data)
{
    uint32_t t0;

    nrf_twi_event_clear(twi, NRF_TWI_EVENT_TXDSENT);
    nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR);

    nrf_twi_txd_set(twi, data);

    t0 = ticker_read(get_us_ticker_data());

    do {
        if (nrf_twi_event_check(twi, NRF_TWI_EVENT_TXDSENT)) {
            nrf_twi_event_clear(twi, NRF_TWI_EVENT_TXDSENT);
            return 1; // ACK received
        }
        if (nrf_twi_event_check(twi, NRF_TWI_EVENT_ERROR)) {
            nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR);
            return 0; // some error occurred
        }
    } while (((uint32_t)ticker_read(get_us_ticker_data()) - t0) < I2C_TIMEOUT_VALUE_US);

    return 2; // timeout;
}
예제 #4
0
파일: i2c_api.c 프로젝트: Archcady/mbed-os
static void twi_irq_handler(uint8_t instance_idx)
{
    twi_info_t *twi_info = &m_twi_info[instance_idx];

    NRF_TWI_Type *twi = m_twi_instances[instance_idx];
    if (nrf_twi_event_check(twi, NRF_TWI_EVENT_ERROR)) {
        nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR);

        // In case of an error, force STOP.
        // The current transfer may be suspended (if it is RX), so it must be
        // resumed before the STOP task is triggered.
        nrf_twi_task_trigger(twi, NRF_TWI_TASK_RESUME);
        nrf_twi_task_trigger(twi, NRF_TWI_TASK_STOP);

        uint32_t errorsrc = nrf_twi_errorsrc_get_and_clear(twi);
        twi_info->events |= I2C_EVENT_ERROR;
        if (errorsrc & NRF_TWI_ERROR_ADDRESS_NACK) {
            twi_info->events |= I2C_EVENT_ERROR_NO_SLAVE;
        }
        if (errorsrc & NRF_TWI_ERROR_DATA_NACK) {
            twi_info->events |= I2C_EVENT_TRANSFER_EARLY_NACK;
        }
    }

    bool finished = false;

    if (nrf_twi_event_check(twi, NRF_TWI_EVENT_TXDSENT)) {
        nrf_twi_event_clear(twi, NRF_TWI_EVENT_TXDSENT);

        MBED_ASSERT(twi_info->tx_length > 0);
        --(twi_info->tx_length);
        // Send next byte if there is still something to be sent.
        if (twi_info->tx_length > 0) {
            nrf_twi_txd_set(twi, *(twi_info->tx));
            ++(twi_info->tx);
        // It TX is done, start RX if requested.
        } else if (twi_info->rx_length > 0) {
            start_asynch_rx(twi_info, twi);
        // If there is nothing more to do, finalize the transfer.
        } else {
            if (twi_info->stop) {
                nrf_twi_task_trigger(twi, NRF_TWI_TASK_STOP);
            } else {
                nrf_twi_task_trigger(twi, NRF_TWI_TASK_SUSPEND);
                finished = true;
            }
            twi_info->events |= I2C_EVENT_TRANSFER_COMPLETE;
        }
    }

    if (nrf_twi_event_check(twi, NRF_TWI_EVENT_RXDREADY)) {
        nrf_twi_event_clear(twi, NRF_TWI_EVENT_RXDREADY);

        MBED_ASSERT(twi_info->rx_length > 0);
        *(twi_info->rx) = nrf_twi_rxd_get(twi);
        ++(twi_info->rx);
        --(twi_info->rx_length);

        if (twi_info->rx_length > 0) {
            // If more bytes should be received, resume the transfer
            // (in case the stop condition should be generated after the next
            // byte, change the shortcuts configuration first).
            if (twi_info->rx_length == 1 && twi_info->stop) {
                nrf_twi_shorts_set(twi, NRF_TWI_SHORT_BB_STOP_MASK);
            }
            nrf_twi_task_trigger(twi, NRF_TWI_TASK_RESUME);
        } else {
            // If all requested bytes were received, finalize the transfer.
            finished = true;
            twi_info->events |= I2C_EVENT_TRANSFER_COMPLETE;
        }
    }

    if (finished ||
        nrf_twi_event_check(twi, NRF_TWI_EVENT_STOPPED) ||
        (nrf_twi_int_enable_check(twi, NRF_TWI_INT_SUSPENDED_MASK) &&
         nrf_twi_event_check(twi, NRF_TWI_EVENT_SUSPENDED))) {
        // There is no need to clear the STOPPED and SUSPENDED events here,
        // they will no longer generate the interrupt - see below.

        nrf_twi_shorts_set(twi, 0);
        // Disable all interrupt sources.
        nrf_twi_int_disable(twi, UINT32_MAX);
        twi_info->active = false;

        if (twi_info->handler) {
            twi_info->handler();
        }
    }
}