int32_t UART_Write()

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;
}