in IndustrialDeviceController/Software/MT3620_IDC_RTApp/lib/UART.c [243:328]
int32_t UART_Write(UART *handle, const void *data, uintptr_t size)
{
if (!handle) {
return ERROR_PARAMETER;
}
if (!handle->open) {
return ERROR_HANDLE_CLOSED;
}
if (!data || (size == 0)) {
return ERROR_PARAMETER;
}
if (handle->dma) {
volatile mt3620_dma_t * const tx_dma = &mt3620_dma[MT3620_UART_DMA_TX(handle->id)];
while (size > 0) {
// We can't send any bytes until TX fifo is not full.
while (MT3620_DMA_FIELD_READ(MT3620_UART_DMA_TX(handle->id), ffsta, full));
MT3620_DMA_FIELD_WRITE(MT3620_UART_DMA_TX(handle->id), start, str, false);
uintptr_t remain = (tx_dma->ffsize - tx_dma->ffcnt);
uintptr_t chunk = (remain >= size ? size : remain);
uintptr_t i;
for (i = 0; i < chunk; i++) {
UART_BuffTX[handle->id][tx_dma->swptr++] = ((const uint8_t *)data)[i];
#if (TX_BUFFER_SIZE < 65536)
// When the buffer isn't exactly 16-bits we need to handle the wrap bit.
if ((tx_dma->swptr & 0xFFFF) > TX_BUFFER_SIZE) {
tx_dma->swptr &= 0xFFFF0000;
tx_dma->swptr ^= 0x00010000;
}
#endif
}
MT3620_DMA_FIELD_WRITE(MT3620_UART_DMA_TX(handle->id), start, str, true);
data = (const void *)((uintptr_t)data + chunk);
size -= chunk;
}
} else {
// If nothing is queued in hardware, queue that first.
if ((handle->txRemain == TX_BUFFER_SIZE)
&& MT3620_UART_FIELD_READ(handle->id, lsr, thre)) {
uint32_t offset = MT3620_UART_FIELD_READ(handle->id, tx_offset, tx_offset);
uint32_t remain = MT3620_UART_TX_FIFO_DEPTH - offset;
uint32_t chunk = (remain > size ? size : remain);
uint32_t i;
for (i = 0; i < chunk; i++) {
mt3620_uart[handle->id]->thr = ((const uint8_t *)data)[i];
}
data = (const void *)((uintptr_t)data + chunk);
size -= chunk;
}
// Queue remaining bytes in buffer to be handled by interrupt.
while (size > 0) {
while (handle->txRemain == 0) {
__asm__("wfi");
}
uint32_t chunk = (handle->txRemain >= size ? size : handle->txRemain);
// We can't use memcpy here because the buffer wraps.
uint32_t i;
for (i = 0; i < chunk; i++) {
UART_BuffTX[handle->id][handle->txWrite++] = ((const uint8_t *)data)[i];
handle->txWrite %= TX_BUFFER_SIZE;
}
handle->txRemain -= chunk;
// Enable interrupt so queued data is processed.
MT3620_UART_FIELD_WRITE(handle->id, ier, etbei, true);
data = (const void *)((uintptr_t)data + chunk);
size -= chunk;
}
}
return ERROR_NONE;
}