/** Start i2c asynchronous transfer. * @param obj The I2C object * @param tx The buffer to send * @param tx_length The number of words to transmit * @param rx The buffer to receive * @param rx_length The number of words to receive * @param address The address to be set - 7bit or 9 bit * @param stop If true, stop will be generated after the transfer is done * @param handler The I2C IRQ handler to be set * @param hint DMA hint usage */ 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) { I2C_TransferReturn_TypeDef retval; if(i2c_active(obj)) return; if((tx_length == 0) && (rx_length == 0)) return; // For now, we are assuming a solely interrupt-driven implementation. // Store transfer config obj->i2c.xfer.addr = address; // Some combination of tx_length and rx_length will tell us what to do if((tx_length > 0) && (rx_length == 0)) { obj->i2c.xfer.flags = I2C_FLAG_WRITE; //Store buffer info obj->i2c.xfer.buf[0].data = (void *)tx; obj->i2c.xfer.buf[0].len = (uint16_t) tx_length; } else if ((tx_length == 0) && (rx_length > 0)) { obj->i2c.xfer.flags = I2C_FLAG_READ; //Store buffer info obj->i2c.xfer.buf[0].data = rx; obj->i2c.xfer.buf[0].len = (uint16_t) rx_length; } else if ((tx_length > 0) && (rx_length > 0)) { obj->i2c.xfer.flags = I2C_FLAG_WRITE_READ; //Store buffer info obj->i2c.xfer.buf[0].data = (void *)tx; obj->i2c.xfer.buf[0].len = (uint16_t) tx_length; obj->i2c.xfer.buf[1].data = rx; obj->i2c.xfer.buf[1].len = (uint16_t) rx_length; } if(address > 255) obj->i2c.xfer.flags |= I2C_FLAG_10BIT_ADDR; // Store event flags obj->i2c.events = event; // Enable interrupt i2c_enable_interrupt(obj, handler, true); // Kick off the transfer retval = I2C_TransferInit(obj->i2c.i2c, &(obj->i2c.xfer)); if(retval == i2cTransferInProgress) { blockSleepMode(EM1); } else { // something happened, and the transfer did not go through // So, we need to clean up // Disable interrupt i2c_enable_interrupt(obj, 0, false); // Block until free while(i2c_active(obj)); } }
/** Abort ongoing asynchronous transaction. * @param obj The I2C object */ void i2c_abort_asynch(i2c_t *obj) { // Do not deactivate I2C twice if (!i2c_active(obj)) return; // Disable interrupt i2c_enable_interrupt(obj, 0, false); // Abort obj->i2c.i2c->CMD = I2C_CMD_STOP | I2C_CMD_ABORT; // Block until free while(i2c_active(obj)); unblockSleepMode(EM1); }
int I2C::transfer(int address, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t& callback, int event, bool repeated) { lock(); if (i2c_active(&_i2c)) { unlock(); return -1; // transaction ongoing } aquire(); _callback = callback; int stop = (repeated) ? 0 : 1; _irq.callback(&I2C::irq_handler_asynch); i2c_transfer_asynch(&_i2c, (void *)tx_buffer, tx_length, (void *)rx_buffer, rx_length, address, stop, _irq.entry(), event, _usage); unlock(); return 0; }
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)stop; (void)hint; if (i2c_active(obj)) { return; } if ((tx_length == 0) && (rx_length == 0)) { return; } twi_info_t *twi_info = TWI_INFO(obj); twi_info->events = 0; twi_info->handler = (void (*)(void))handler; twi_info->event_mask = event; uint8_t twi_addr = twi_address(address); nrf_drv_twi_t const *twi = &m_twi_instances[TWI_IDX(obj)]; if ((tx_length > 0) && (rx_length == 0)) { nrf_drv_twi_xfer_desc_t const xfer = NRF_DRV_TWI_XFER_DESC_TX(twi_addr, (uint8_t *)tx, tx_length); nrf_drv_twi_xfer(twi, &xfer, stop ? 0 : NRF_DRV_TWI_FLAG_TX_NO_STOP); } else if ((tx_length == 0) && (rx_length > 0)) { nrf_drv_twi_xfer_desc_t const xfer = NRF_DRV_TWI_XFER_DESC_RX(twi_addr, rx, rx_length); nrf_drv_twi_xfer(twi, &xfer, 0); } else if ((tx_length > 0) && (rx_length > 0)) { nrf_drv_twi_xfer_desc_t const xfer = NRF_DRV_TWI_XFER_DESC_TXRX(twi_addr, (uint8_t *)tx, tx_length, rx, rx_length); nrf_drv_twi_xfer(twi, &xfer, 0); } }