in IndustrialDeviceController/Software/MT3620_IDC_RTApp/lib/I2CMaster.c [241:414]
int32_t I2CMaster_TransferSequentialAsync_UserData(
I2CMaster *handle, uint16_t address,
const I2C_Transfer *transfer, uint32_t count,
void (*callback)(int32_t status, uintptr_t count, void* userData),
void *userData)
{
if (!handle) {
return ERROR_PARAMETER;
}
if (!handle->open) {
return ERROR_HANDLE_CLOSED;
}
if (handle->transfer) {
return ERROR_BUSY;
}
// We don't support more than 7-bit addressing.
if ((address >> 7) != 0) {
return ERROR_UNSUPPORTED;
}
if (!transfer || (count == 0)) {
return ERROR_PARAMETER;
}
// It's up to the user to group transfers of the same type
if (count > MT3620_I2C_QUEUE_DEPTH) {
return ERROR_UNSUPPORTED;
}
bool onBus = true;
unsigned wcnt = 0, rcnt = 0;
unsigned wdata = 0, rdata = 0;
unsigned i;
for (i = 0; i < count; i++) {
if (transfer[i].length > MT3620_I2C_PACKET_SIZE_MAX) {
return ERROR_UNSUPPORTED;
}
// Transfer must be a read or a write.
if (!transfer[i].writeData && !transfer[i].readData) {
return ERROR_PARAMETER;
}
// I2C doesn't support duplex transfers.
if (transfer[i].writeData && transfer[i].readData) {
return ERROR_UNSUPPORTED;
}
if (transfer[i].writeData) {
if (!addrOnBus(transfer[i].writeData)) {
onBus = false;
}
wcnt++;
wdata += transfer[i].length;
}
if (transfer[i].readData) {
if (!addrOnBus(transfer[i].readData)) {
onBus = false;
}
rcnt++;
rdata += transfer[i].length;
}
}
if (MT3620_I2C_FIELD_READ(handle->id, mm_status, bus_busy)) {
return ERROR_BUSY;
}
bool useDMA = false;
if ((wdata > MT3620_I2C_TX_FIFO_DEPTH)
|| (rdata > MT3620_I2C_RX_FIFO_DEPTH)) {
// DMA can only access data on the bus (i.e. not TCM).
if (!onBus) {
return ERROR_DMA_SOURCE;
}
// DMA can queue a maximum of two transactions in each direction.
if ((wcnt > 2) || (rcnt > 2)) {
return ERROR_UNSUPPORTED;
}
useDMA = true;
}
handle->callbackUser = callback;
handle->userData = userData;
handle->useDMA = useDMA;
handle->txQueued = wdata;
handle->rxQueued = rdata;
handle->transfer = transfer;
handle->count = count;
mt3620_i2c[handle->id]->mm_slave_id = address;
for (i = 0; i < count; i++) {
mt3620_i2c[handle->id]->mm_cnt_byte_val_pk[i] = transfer[i].length;
}
mt3620_i2c_mm_pack_con0_t mm_pack_con0 = { .mask = mt3620_i2c[handle->id]->mm_pack_con0 };
mm_pack_con0.mm_pack_rw0 = (transfer[0].readData != NULL);
if (count >= 2) mm_pack_con0.mm_pack_rw1 = (transfer[1].readData != NULL);
if (count >= 3) mm_pack_con0.mm_pack_rw2 = (transfer[2].readData != NULL);
mm_pack_con0.mm_pack_val = (count - 1);
mt3620_i2c[handle->id]->mm_pack_con0 = mm_pack_con0.mask;
if (useDMA) {
volatile mt3620_dma_t * const tx_dma = &mt3620_dma[MT3620_I2C_DMA_TX(handle->id)];
volatile mt3620_dma_t * const rx_dma = &mt3620_dma[MT3620_I2C_DMA_RX(handle->id)];
unsigned w = 0, r = 0;
for (i = 0; i < count; i++) {
if (transfer[i].writeData) {
if (w++ == 0) {
tx_dma->pgmaddr = (uint32_t *)transfer[i].writeData;
tx_dma->wppt = transfer[i].length;
tx_dma->count = transfer[i].length;
} else {
tx_dma->wpto = (uint32_t *)transfer[i].writeData;
tx_dma->count += transfer[i].length;
}
} else {
if (r++ == 0) {
rx_dma->pgmaddr = transfer[i].readData;
rx_dma->wppt = transfer[i].length;
rx_dma->count = transfer[i].length;
} else {
rx_dma->wpto = transfer[i].readData;
rx_dma->count += transfer[i].length;
}
}
}
if (wcnt > 0) {
MT3620_DMA_FIELD_WRITE(MT3620_I2C_DMA_TX(handle->id), con, wpen, (wcnt > 1));
// Start DMA TX transfer.
MT3620_DMA_FIELD_WRITE(MT3620_I2C_DMA_TX(handle->id), start, str, true);
}
if (rcnt > 0) {
MT3620_DMA_FIELD_WRITE(MT3620_I2C_DMA_RX(handle->id), con, wpen, (rcnt > 1));
// Start DMA RX transfer.
MT3620_DMA_FIELD_WRITE(MT3620_I2C_DMA_RX(handle->id), start, str, true);
}
} else {
// Pre-fill TX buffer with data.
for (i = 0; i < count; i++) {
const uint8_t *writeData = transfer[i].writeData;
if (writeData) {
unsigned j;
for (j = 0; j < transfer[i].length; j++) {
mt3620_i2c[handle->id]->mm_fifo_data = writeData[j];
}
}
}
}
// Wait until I2C is ready after setting config
while (!MT3620_I2C_FIELD_READ(handle->id, mm_status, mm_start_ready)) {
// Do nothing.
}
mt3620_i2c_mm_con0_t mm_con0 = { .mask = mt3620_i2c[handle->id]->mm_con0 };
mm_con0.mm_gmode = true;
mm_con0.mm_start_en = true;
mt3620_i2c[handle->id]->mm_con0 = mm_con0.mask;
return ERROR_NONE;
}