diff --git a/bench/bsp/drivers/uart/uart.c b/bench/bsp/drivers/uart/uart.c new file mode 100644 index 0000000000000000000000000000000000000000..09421f4f12c4e8931858a898687dd9e7cbfd6558 --- /dev/null +++ b/bench/bsp/drivers/uart/uart.c @@ -0,0 +1,834 @@ +/******************************************************************************* + * Copyright (c) 2020 Thales. + * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + */ +// Additional contributions by: +// Sebastien Jacq - sjthales on github.com +// +// Description: Driver for UART Ip of the CVA6 platform +// +// =========================================================================== // +// Revisions : +// Date Version Author Description +// 2020-10-06 0.1 S.Jacq modification of the Test for CVA6 softcore +// =========================================================================== // + + + +#include "uart.h" + +#include "plic.h" +#include "fpga_platform_config.h" + + +/******************************************************************************* + * Defines + */ +#define TX_COMPLETE 0u +#define TX_FIFO_SIZE 16u + +#define FCR_TRIG_LEVEL_MASK 0xC0u + +#define IIRF_MASK 0x0Fu + +#define INVALID_INTERRUPT 0u +#define INVALID_IRQ_HANDLER ((uart_irq_handler_t) 0) +#define NULL_HANDLER ((uart_irq_handler_t) 0) + +#define UART_DATA_READY ((uint8_t) 0x01) + + +/******************************************************************************* + * Possible values for Interrupt Identification Register Field. + */ +#define IIRF_MODEM_STATUS 0x00u +#define IIRF_THRE 0x02u +//#define IIRF_MMI 0x03u +#define IIRF_RX_DATA 0x04u +#define IIRF_RX_LINE_STATUS 0x06u +#define IIRF_DATA_TIMEOUT 0x0Cu + + +uart_instance_t g_uart_0 = { .hw_reg = FPGA_UART_0_BASE }; + +/******************************************************************************* + * Global initialization for all modes + */ +static void global_init +( + uart_instance_t * this_uart, + uint32_t baud_rate, + uint8_t line_config +) +{ + + /* disable interrupts */ + this_uart->hw_reg->IER = 0u; + + /* FIFO configuration */ + this_uart->hw_reg->FCR = 0u; + + /* clear receiver FIFO */ + this_uart->hw_reg->FCR = FIFO_RX_TRIGGER_LEVEL_14_MASK | CLEAR_RX_FIFO_MASK | CLEAR_TX_FIFO_MASK | RXRDY_TXRDYN_EN_MASK; + + /* clear transmitter FIFO */ + //this_uart->hw_reg->FCR |= CLEAR_TX_FIFO_MASK; + + /* set default READY mode : Mode 0*/ + /* enable RXRDYN and TXRDYN pins. The earlier FCR write to set the TX FIFO + * trigger level inadvertently disabled the FCR_RXRDY_TXRDYN_EN bit. */ + // this_uart->hw_reg->FCR |= RXRDY_TXRDYN_EN_MASK; + + this_uart->hw_reg->MCR = 0u; + + + + /* + * Configure baud rate divisors. This uses the fractional baud rate divisor + * where possible to provide the most accurate baud rat possible. + */ + config_baud_divisors(this_uart, baud_rate); + + /* set the line control register (bit length, stop bits, parity) */ + this_uart->hw_reg->LCR = line_config; + + /* Instance setup */ + this_uart->baudrate = baud_rate; + this_uart->lineconfig = line_config; + this_uart->tx_buff_size = TX_COMPLETE; + this_uart->tx_buffer = (const uint8_t*)0; + this_uart->tx_idx = 0u; + + /* Default handlers for MSS UART interrupts */ + this_uart->rx_handler = NULL_HANDLER; + this_uart->tx_handler = NULL_HANDLER; + this_uart->linests_handler = NULL_HANDLER; + this_uart->modemsts_handler = NULL_HANDLER; + + /* Initialize the sticky status */ + this_uart->status = 0u; +} + +/******************************************************************************* + * Public Functions + *******************************************************************************/ +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_init +( + uart_instance_t* this_uart, + uint32_t baud_rate, + uint8_t line_config +) +{ + /* Perform generic initialization */ + global_init(this_uart, baud_rate, line_config); + + + /* set default tx handler for automated TX using interrupt in USART mode */ + this_uart->tx_handler = default_tx_handler; +} + + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_polled_tx +( + uart_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +) +{ + uint32_t char_idx = 0u; + // uint32_t size_sent; + uint8_t status; + //uint32_t temp_tx_size = tx_size; + + //ASSERT(pbuff != ( (uint8_t*)0)); + //ASSERT(tx_size > 0u); + + if ((pbuff != ((uint8_t*)0)) && (tx_size > 0u)) + { + /* Remain in this loop until the entire input buffer + * has been transferred to the UART. + */ + do + { + /* Wait until TX FIFO is empty. */ + do + { + status = this_uart->hw_reg->LSR; + // this_uart->status |= status; + }while (0u == (status & UART_THRE)); + + + /* Check if TX FIFO is empty. */ + // if (status & UART_THRE) + //{ + // uint32_t fill_size = TX_FIFO_SIZE; + + /* Calculate the number of bytes to transmit. */ + //if (temp_tx_size < TX_FIFO_SIZE) + //{ + // fill_size = temp_tx_size; + //} + + /* Fill the TX FIFO with the calculated the number of bytes. */ + //for (size_sent = 0u; size_sent < fill_size; ++size_sent) + //{ + /* Send next character in the buffer. */ + this_uart->hw_reg->THR = pbuff[char_idx]; + char_idx++; + //} + + /* Calculate the number of bytes remaining(not transmitted yet)*/ + //temp_tx_size -= size_sent; + //} + }while (char_idx < tx_size); + } +} + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_polled_tx_string +( + uart_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx = 0u; + uint32_t fill_size; + uint8_t data_byte; + volatile uint8_t status; + + //ASSERT(p_sz_string != ((uint8_t*)0)); + + if (p_sz_string != ((uint8_t*)0)) + { + /* Get the first data byte from the input buffer */ + data_byte = p_sz_string[char_idx]; + + /* First check for the NULL terminator byte. + * Then remain in this loop until the entire string in the input buffer + * has been transferred to the UART. + */ + while (0u != data_byte) + { + /* Wait until TX FIFO is empty. */ + do + { + status = this_uart->hw_reg->LSR; + // this_uart->status |= status; + }while (0u == (status & UART_THRE)); + + + /* Send bytes from the input buffer until the TX FIFO is full + * or we reach the NULL terminator byte. + */ + //fill_size = 0u; + + // while ((0u != data_byte) && (fill_size < TX_FIFO_SIZE)) + //{ + /* Send the data byte */ + this_uart->hw_reg->THR = data_byte; + //++fill_size; + char_idx++; + /* Get the next data byte from the input buffer */ + data_byte = p_sz_string[char_idx]; + //} + } + } +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_irq_tx +( + uart_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +) +{ + //ASSERT(pbuff != ((uint8_t*)0)); + //ASSERT(tx_size > 0u); + + if ((tx_size > 0u) && (pbuff != ((uint8_t*)0))) + { + /*Initialize the transmit info for the UART instance with the arguments*/ + this_uart->tx_buffer = pbuff; + this_uart->tx_buff_size = tx_size; + this_uart->tx_idx = 0u; + + /* assign default handler for data transfer */ + this_uart->tx_handler = default_tx_handler; + + /* enables TX interrupt */ + this_uart->hw_reg->IER |= ETBEI_MASK; + enable_irq(this_uart); + } +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +int8_t +UART_tx_complete +( + uart_instance_t * this_uart +) +{ + int8_t ret_value = 0; + uint8_t status = 0u; + + /* Read the Line Status Register and update the sticky record. */ + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + if ((TX_COMPLETE == this_uart->tx_buff_size) && + ((status & UART_TEMT) != 0u)) + { + ret_value = (int8_t)1; + } + + return ret_value; +} + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +size_t +UART_get_rx +( + uart_instance_t * this_uart, + uint8_t * rx_buff, + size_t buff_size +) +{ + size_t rx_size = 0u; + uint8_t status = 0u; + + //ASSERT(rx_buff != ((uint8_t*)0)); + //ASSERT(buff_size > 0u); + + if ((rx_buff != (uint8_t*)0) && (buff_size > 0u)) + { + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + while (((status & UART_DATA_READY) != 0u) && (rx_size < buff_size)) + { + rx_buff[rx_size] = this_uart->hw_reg->RBR; + ++rx_size; + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + } + } + + return rx_size; +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_enable_irq +( + uart_instance_t * this_uart, + uart_irq_t irq_mask +) +{ + //ASSERT(UART_INVALID_IRQ > irq_mask); + + enable_irq(this_uart); + + if (UART_INVALID_IRQ > irq_mask) + { + /* irq_mask encoding: 1- enable + * bit 0 - Receive Data Available Interrupt + * bit 1 - Transmitter Holding Register Empty Interrupt + * bit 2 - Receiver Line Status Interrupt + * bit 3 - Modem Status Interrupt + */ + this_uart->hw_reg->IER |= ((uint8_t)(((uint32_t)irq_mask & + (uint32_t)IIRF_MASK))); + + } +} + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_set_rx_handler +( + uart_instance_t * this_uart, + uart_irq_handler_t handler, + uart_rx_trig_level_t trigger_level +) +{ + //ASSERT(handler != INVALID_IRQ_HANDLER ); + //ASSERT(trigger_level < UART_FIFO_INVALID_TRIG_LEVEL); + + if ((handler != INVALID_IRQ_HANDLER) && + (trigger_level < UART_FIFO_INVALID_TRIG_LEVEL)) + { + this_uart->rx_handler = handler; + + /* Set the receive interrupt trigger level. */ + this_uart->hw_reg->FCR = (this_uart->hw_reg->FCR & + (uint8_t)(~((uint8_t)FCR_TRIG_LEVEL_MASK))) | + (uint8_t)trigger_level; + + /* Enable receive interrupt. */ + this_uart->hw_reg->IER |= ERBFI_MASK; + + enable_irq(this_uart); + } +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_set_tx_handler +( + uart_instance_t * this_uart, + uart_irq_handler_t handler +) +{ + //ASSERT(handler != INVALID_IRQ_HANDLER); + + if (handler != INVALID_IRQ_HANDLER) + { + this_uart->tx_handler = handler; + + /* Make TX buffer info invalid */ + this_uart->tx_buffer = (const uint8_t*)0; + this_uart->tx_buff_size = 0u; + + /* Enable transmitter holding register Empty interrupt. */ + this_uart->hw_reg->IER |= ETBEI_MASK; + enable_irq(this_uart); + } +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_set_modemstatus_handler +( + uart_instance_t * this_uart, + uart_irq_handler_t handler +) +{ + //ASSERT(handler != INVALID_IRQ_HANDLER); + + if (handler != INVALID_IRQ_HANDLER) + { + this_uart->modemsts_handler = handler; + + /* Enable modem status interrupt. */ + this_uart->hw_reg->IER |= EDSSI_MASK; + enable_irq(this_uart); + } +} + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + uart_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t status = 0u; + uint32_t size_sent = 0u; + + //ASSERT(tx_buffer != ( (uint8_t*)0)); + //ASSERT(tx_size > 0); + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if ((tx_buffer != ((uint8_t*)0)) && (tx_size > 0u)) + { + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + if (status & UART_THRE) + { + uint32_t fill_size = TX_FIFO_SIZE; + + if (tx_size < TX_FIFO_SIZE) + { + fill_size = tx_size; + } + + /* Fill up FIFO */ + for (size_sent = 0u; size_sent < fill_size; size_sent++) + { + /* Send next character in the buffer. */ + this_uart->hw_reg->THR = tx_buffer[size_sent]; + } + } + } + + return size_sent; +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + uart_instance_t * this_uart +) +{ + uint8_t status = UART_INVALID_PARAM; + + /* + * Extract UART receive error status. + * Bit 1 - Overflow error status + * Bit 2 - Parity error status + * Bit 3 - Frame error status + * Bit 4 - Break interrupt indicator + * Bit 7 - FIFO data error status + */ + this_uart->status |= (this_uart->hw_reg->LSR); + status = (this_uart->status & STATUS_ERROR_MASK); + /* Clear the sticky status after reading */ + this_uart->status = 0u; + + return status; +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +uint8_t +UART_get_modem_status +( + const uart_instance_t * this_uart +) +{ + uint8_t status = UART_INVALID_PARAM; + + /* + * Extract UART modem status and place in lower bits of "status". + * Bit 0 - Delta Clear to Send Indicator + * Bit 1 - Delta Clear to Receive Indicator + * Bit 2 - Trailing edge of Ring Indicator detector + * Bit 3 - Delta Data Carrier Detect indicator + * Bit 4 - Clear To Send + * Bit 5 - Data Set Ready + * Bit 6 - Ring Indicator + * Bit 7 - Data Carrier Detect + */ + status = this_uart->hw_reg->MSR; + + return status; +} + + +/***************************************************************************//** + * UART_get_tx_status. + * See uart.h for details of how to use this function. + */ +uint8_t +UART_get_tx_status +( + uart_instance_t * this_uart +) +{ + uint8_t status = UART_TX_BUSY; + + /* Read the Line Status Register and update the sticky record. */ + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + /* + * Extract the transmit status bits from the UART's Line Status Register. + * Bit 5 - Transmitter Holding Register/FIFO Empty (THRE) status. + (If = 1, TX FIFO is empty) + * Bit 6 - Transmitter Empty (TEMT) status. + (If = 1, both TX FIFO and shift register are empty) + */ + status &= (UART_THRE | UART_TEMT); + + return status; +} + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_set_break +( + uart_instance_t * this_uart +) +{ + /* set break character on Tx line */ + this_uart->hw_reg->LCR |= SB_MASK; +} + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +void +UART_clear_break +( + uart_instance_t * this_uart +) +{ + /* remove break character from Tx line */ + this_uart->hw_reg->LCR &= ~SB_MASK; +} + +/***************************************************************************//** + * Configure baud divisors using fractional baud rate if possible. + */ +static void +config_baud_divisors +( + uart_instance_t * this_uart, + uint32_t baudrate +) +{ + uint32_t baud_value; + uint32_t baud_value_by_64; + uint32_t baud_value_by_128; +// uint32_t fractional_baud_value; + uint64_t pclk_freq; + + this_uart->baudrate = baudrate; + + /* Use the system clock value from hw_platform.h */ + pclk_freq = FPGA_UART_0_FREQUENCY; + + /* + * Compute baud value based on requested baud rate and PCLK frequency. + * The baud value is computed using the following equation: + * baud_value = PCLK_Frequency / (baud_rate * 16) + */ + baud_value_by_128 = (uint32_t)((8UL * pclk_freq) / baudrate); + baud_value_by_64 = baud_value_by_128 / 2u; + baud_value = baud_value_by_64 / 64u; +// fractional_baud_value = baud_value_by_64 - (baud_value * 64u); +// fractional_baud_value += (baud_value_by_128 - (baud_value * 128u)) + // - (fractional_baud_value * 2u); + + /* //ASSERT if integer baud value fits in 16-bit. */ + //ASSERT(baud_value <= UINT16_MAX); + + if (baud_value <= (uint32_t)UINT16_MAX) + { + + /* + * Use Fractional baud rate divisors + */ + /* set divisor latch */ + this_uart->hw_reg->LCR = DLAB_MASK; + + /* msb of baud value */ + this_uart->hw_reg->DLM = (uint8_t)(baud_value >> 8); + /* lsb of baud value */ + this_uart->hw_reg->DLL = (uint8_t)baud_value; + + /* reset divisor latch */ + this_uart->hw_reg->LCR = 0; + } +} + +/***************************************************************************//** + * Interrupt service routine triggered by any MSS UART interrupt. This routine + * will call the handler function appropriate to the interrupt from the + * handlers previously registered with the driver through calls to the + * UART_set_*_handler() functions, or it will call the default_tx_handler() + * function in response to transmit interrupts if UART_irq_tx() is used to + * transmit data. + */ +static void +uart_isr +( + uart_instance_t * this_uart +) +{ + uint8_t iirf; + + iirf = this_uart->hw_reg->IIR & IIRF_MASK; + + switch (iirf) + { + case IIRF_MODEM_STATUS: /* Modem status interrupt */ + { + //ASSERT(NULL_HANDLER != this_uart->modemsts_handler); + if (NULL_HANDLER != this_uart->modemsts_handler) + { + (*(this_uart->modemsts_handler))(this_uart); + } + } + break; + + case IIRF_THRE: /* Transmitter Holding Register Empty */ + { + //ASSERT(NULL_HANDLER != this_uart->tx_handler); + if (NULL_HANDLER != this_uart->tx_handler) + { + (*(this_uart->tx_handler))(this_uart); + } + } + break; + + case IIRF_RX_DATA: /* Received Data Available */ + case IIRF_DATA_TIMEOUT: /* Received Data Timed-out */ + { + //ASSERT(NULL_HANDLER != this_uart->rx_handler); + if (NULL_HANDLER != this_uart->rx_handler) + { + (*(this_uart->rx_handler))(this_uart); + } + } + break; + + case IIRF_RX_LINE_STATUS: /* Line Status Interrupt */ + { + //ASSERT(NULL_HANDLER != this_uart->linests_handler); + if (NULL_HANDLER != this_uart->linests_handler) + { + (*(this_uart->linests_handler))(this_uart); + } + } + + default: + { + //ASSERT(INVALID_INTERRUPT); /*Alternative case has been considered*/ + } + break; + } +} + + + +/***************************************************************************//** + * See uart.h for details of how to use this function. + */ +static void +default_tx_handler +( + uart_instance_t * this_uart +) +{ + uint8_t status; + + //ASSERT(( (uint8_t*)0 ) != this_uart->tx_buffer); + //ASSERT(0u < this_uart->tx_buff_size); + + if ((((uint8_t*)0 ) != this_uart->tx_buffer) && + (0u < this_uart->tx_buff_size)) + { + /* Read the Line Status Register and update the sticky record. */ + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + /* + * This function should only be called as a result of a THRE interrupt. + * Verify that this is true before proceeding to transmit data. + */ + if (status & UART_THRE) + { + uint32_t cnt; + uint32_t fill_size = TX_FIFO_SIZE; + uint32_t tx_remain = this_uart->tx_buff_size - this_uart->tx_idx; + + /* Calculate the number of bytes to transmit. */ + if (tx_remain < TX_FIFO_SIZE) + { + fill_size = tx_remain; + } + + /* Fill the TX FIFO with the calculated the number of bytes. */ + for (cnt = 0u; cnt < fill_size; ++cnt) + { + /* Send next character in the buffer. */ + this_uart->hw_reg->THR = this_uart->tx_buffer[this_uart->tx_idx]; + ++this_uart->tx_idx; + } + } + + /* Flag Tx as complete if all data has been pushed into the Tx FIFO. */ + if (this_uart->tx_idx == this_uart->tx_buff_size) + { + this_uart->tx_buff_size = TX_COMPLETE; + + /* disables TX interrupt */ + this_uart->hw_reg->IER &= ~ETBEI_MASK; + } + } +} + + +static void +enable_irq +( + const uart_instance_t * this_uart +) +{ + + + PLIC_IRQn_Type plic_num = 0; + + if (&g_uart_0 == this_uart ) + { + plic_num = UART_0_PLIC_IRQHandler; + } + else + { + ASSERT(0); /*Alternative case has been considered*/ + } + + /* Enable UART instance interrupt in PLIC. */ + PLIC_EnableIRQ(plic_num); +} + +static void +disable_irq +( + const uart_instance_t * this_uart +) +{ + PLIC_IRQn_Type plic_num = 0; + + if (&g_uart_0 == this_uart ) + { + plic_num = UART_0_PLIC_IRQHandler; + } + else + { + ASSERT(0); /*Alternative case has been considered*/ + } + + /* Disable UART instance interrupt in PLIC. */ + PLIC_DisableIRQ(plic_num); +} + diff --git a/bench/bsp/drivers/uart/uart.h b/bench/bsp/drivers/uart/uart.h new file mode 100644 index 0000000000000000000000000000000000000000..433d0653a67880febe245d00e34e9cb9bf5afd2e --- /dev/null +++ b/bench/bsp/drivers/uart/uart.h @@ -0,0 +1,935 @@ +/******************************************************************************* + * Copyright (c) 2020 Thales. + * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * + */ +// Additional contributions by: +// Sebastien Jacq - sjthales on github.com +// +// Description: Driver header for UART Ip of the CVA6 platform +// +// =========================================================================== // +// Revisions : +// Date Version Author Description +// 2020-10-06 0.1 S.Jacq modification of the Test for CVA6 softcore +// =========================================================================== // + +#ifndef __UART_H_ +#define __UART_H_ 1 + +#include <stddef.h> +#include <stdint.h> + + + +/***************************************************************************//** + Baud rates + ========== + The following definitions are used to specify standard baud rates as a + parameter to the UART_init() function. + + | Constant | Description | + |----------------------|------------------| + | UART_110_BAUD | 110 baud rate | + | UART_300_BAUD | 300 baud rate | + | UART_600_BAUD | 600 baud rate | + | UART_1200_BAUD | 1200 baud rate | + | UART_2400_BAUD | 2400 baud rate | + | UART_4800_BAUD | 4800 baud rate | + | UART_9600_BAUD | 9600 baud rate | + | UART_19200_BAUD | 19200 baud rate | + | UART_38400_BAUD | 38400 baud rate | + | UART_57600_BAUD | 57600 baud rate | + | UART_115200_BAUD | 115200 baud rate | + | UART_230400_BAUD | 230400 baud rate | + | UART_460800_BAUD | 460800 baud rate | + | UART_921600_BAUD | 921600 baud rate | + + */ +#define UART_110_BAUD 110U +#define UART_300_BAUD 300U +#define UART_600_BAUD 600U +#define UART_1200_BAUD 1200U +#define UART_2400_BAUD 2400U +#define UART_4800_BAUD 4800U +#define UART_9600_BAUD 9600U +#define UART_19200_BAUD 19200U +#define UART_38400_BAUD 38400U +#define UART_57600_BAUD 57600U +#define UART_115200_BAUD 115200U +#define UART_230400_BAUD 230400U +#define UART_460800_BAUD 460800U +#define UART_921600_BAUD 921600U + +/***************************************************************************//** + Data Bits Length + ================ + The following defines are used to build the value of the UART_init() + function line_config parameter. + + | Constant | Description | + |----------------------|----------------------------| + | UART_DATA_5_BITS | 5 bits of data transmitted | + | UART_DATA_6_BITS | 6 bits of data transmitted | + | UART_DATA_7_BITS | 7 bits of data transmitted | + | UART_DATA_8_BITS | 8 bits of data transmitted | + + */ +#define UART_DATA_5_BITS ((uint8_t) 0x00) +#define UART_DATA_6_BITS ((uint8_t) 0x01) +#define UART_DATA_7_BITS ((uint8_t) 0x02) +#define UART_DATA_8_BITS ((uint8_t) 0x03) + +/***************************************************************************//** + Parity + ====== + The following defines are used to build the value of the UART_init() + function line_config parameter. + + | Constant | Description | + |-------------------------|--------------------------| + | UART_NO_PARITY | No parity | + | UART_ODD_PARITY | Odd Parity | + | UART_EVEN_PARITY | Even parity | + | UART_STICK_PARITY_0 | Stick parity bit to zero | + | UART_STICK_PARITY_1 | Stick parity bit to one | + */ +#define UART_NO_PARITY ((uint8_t) 0x00) +#define UART_ODD_PARITY ((uint8_t) 0x08) +#define UART_EVEN_PARITY ((uint8_t) 0x18) +#define UART_STICK_PARITY_0 ((uint8_t) 0x38) +#define UART_STICK_PARITY_1 ((uint8_t) 0x28) + +/***************************************************************************//** + Number of Stop Bits + =================== + The following defines are used to build the value of the UART_init() + function line_config parameter. + + | Constant | Description | + |---------------------------|--------------------------| + | UART_ONE_STOP_BIT | One stop bit | + | UART_ONEHALF_STOP_BIT | One and a half stop bits | + | UART_TWO_STOP_BITS | Two stop bits | + + */ +#define UART_ONE_STOP_BIT ((uint8_t) 0x00) +#define UART_ONEHALF_STOP_BIT ((uint8_t) 0x04) +#define UART_TWO_STOP_BITS ((uint8_t) 0x04) + +/***************************************************************************//** + Receiver Error Status + ===================== + The following defines are used to determine the UART receiver error type. + These bit mask constants are used with the return value of the + UART_get_rx_status() function to find out if any errors occurred while + receiving data. + + + | Constant | Description | + |------------------------|--------------------------------------------| + | UART_NO_ERROR | No error bit mask (0x00) | + | UART_OVERUN_ERROR | Overrun error bit mask (0x02) | + | UART_PARITY_ERROR | Parity error bit mask (0x04) | + | UART_FRAMING_ERROR | Framing error bit mask (0x08) | + | UART_BREAK_ERROR | Break error bit mask (0x10) | + | UART_FIFO_ERROR | FIFO error bit mask (0x80) | + | UART_INVALID_PARAM | Invalid function parameter bit mask (0xFF) | + */ +#define UART_INVALID_PARAM ((uint8_t)0xFF) +#define UART_NO_ERROR ((uint8_t)0x00 ) +#define UART_OVERUN_ERROR ((uint8_t)0x02) +#define UART_PARITY_ERROR ((uint8_t)0x04) +#define UART_FRAMING_ERROR ((uint8_t)0x08) +#define UART_BREAK_ERROR ((uint8_t)0x10) +#define UART_FIFO_ERROR ((uint8_t)0x80) + + +/******************************************************************************* + * Receiver error status mask. + */ +#define STATUS_ERROR_MASK ( UART_OVERUN_ERROR | UART_PARITY_ERROR | \ + UART_FRAMING_ERROR | UART_BREAK_ERROR | \ + UART_FIFO_ERROR) + +/***************************************************************************//** + Transmitter Status + ================== + The following definitions are used to determine the UART transmitter status. + These bit mask constants are used with the return value of the + UART_get_tx_status() function to find out the status of the transmitter. + + | Constant | Description | + |------------------|----------------------------------------------------| + | UART_TX_BUSY | Transmitter busy (0x00) | + | UART_THRE | Transmitter holding register empty bit mask (0x20) | + | UART_TEMT | Transmitter empty bit mask (0x40) | + + */ +#define UART_TX_BUSY ((uint8_t) 0x00) +#define UART_THRE ((uint8_t) 0x20) +#define UART_TEMT ((uint8_t) 0x40) + +/***************************************************************************//** + Modem Status + ============ + The following defines are used to determine the modem status. These bit + mask constants are used with the return value of the + UART_get_modem_status() function to find out the modem status of + the UART. + + | Constant | Description | + |---------------|-------------------------------------------------| + | UART_DCTS | Delta clear to send bit mask (0x01) | + | UART_DDSR | Delta data set ready bit mask (0x02) | + | UART_TERI | Trailing edge of ring indicator bit mask (0x04) | + | UART_DDCD | Delta data carrier detect bit mask (0x08) | + | UART_CTS | Clear to send bit mask (0x10) | + | UART_DSR | Data set ready bit mask (0x20) | + | UART_RI | Ring indicator bit mask (0x40) | + | UART_DCD | Data carrier detect bit mask (0x80) | + */ +#define UART_DCTS ((uint8_t) 0x01) +#define UART_DDSR ((uint8_t) 0x02) +#define UART_TERI ((uint8_t) 0x04) +#define UART_DDCD ((uint8_t) 0x08) +#define UART_CTS ((uint8_t) 0x10) +#define UART_DSR ((uint8_t) 0x20) +#define UART_RI ((uint8_t) 0x40) +#define UART_DCD ((uint8_t) 0x80) + +/***************************************************************************//** + This typedef specifies the irq_mask parameter for the UART_enable_irq() + and UART_disable_irq() functions. The driver defines a set of bit masks + that are used to build the value of the irq_mask parameter. A bitwise OR of + these bit masks is used to enable or disable multipleUART interrupts. + */ +typedef uint16_t uart_irq_t; + +/***************************************************************************//** + UART Interrupts + ===================== + The following defines specify the interrupt masks to enable and disable + UART interrupts. They are used to build the value of the irq_mask parameter + for the UART_enable_irq() and UART_disable_irq() functions. A bitwise + OR of these constants is used to enable or disable multiple interrupts. + + + | Constant | Description | + |--------------------|---------------------------------------------------------------| + | UART_RBF_IRQ | Receive Data Available Interrupt bit mask (0x001) | + | UART_TBE_IRQ | Transmitter Holding Register Empty interrupt bit mask (0x002) | + | UART_LS_IRQ | Receiver Line Status interrupt bit mask (0x004) | + | UART_MS_IRQ | Modem Status interrupt bit mask (0x008) | + + */ +#define UART_RBF_IRQ 0x001 +#define UART_TBE_IRQ 0x002 +#define UART_LS_IRQ 0x004 +#define UART_MS_IRQ 0x008 +//#define UART_RTO_IRQ 0x010 +//#define UART_NACK_IRQ 0x020 +//#define UART_PIDPE_IRQ 0x040 +//#define UART_LINB_IRQ 0x080 +//#define UART_LINS_IRQ 0x100 +#define UART_INVALID_IRQ UINT16_MAX + +/***************************************************************************//** + This enumeration specifies the receiver FIFO trigger level. This is the number + of bytes that must be received before the UART generates a receive data + available interrupt. It provides the allowed values for the + UART_set_rx_handler() function trigger_level parameter. + */ +typedef enum { + UART_FIFO_SINGLE_BYTE = 0x00, + UART_FIFO_FOUR_BYTES = 0x40, + UART_FIFO_EIGHT_BYTES = 0x80, + UART_FIFO_FOURTEEN_BYTES = 0xC0, + UART_FIFO_INVALID_TRIG_LEVEL + +} uart_rx_trig_level_t; + + + + +/***************************************************************************//** + UART instance type. + This is type definition for UART instance. You need to create and + maintain a record of this type. This holds all data regarding the UART + instance + */ +typedef struct uart_instance uart_instance_t; + +/***************************************************************************//** + Interrupt handler prototype. + This typedef specifies the function prototype for UART interrupt handlers. + All interrupt handlers registered with the UART driver must be of this type. + The interrupt handlers are registered with the driver through the + UART_set_rx_handler(), UART_set_tx_handler(), + UART_set_rxstatus_handler(), and UART_set_modemstatus_handler() + functions. + The this_uart parameter is a pointer to either g_uart0 or g_uart1 to + identify the UART to associate with the handler function. + */ +typedef void (*uart_irq_handler_t)( uart_instance_t * this_uart ); + + +/******************************************************************************* + Register Bit definitions + */ + +/* Line Control register bit definitions */ +#define SB 6u /* Set break */ +#define DLAB 7u /* Divisor latch access bit */ + +/* Line Control register bit masks */ +#define SB_MASK (0x01u << SB) /* Set break */ +#define DLAB_MASK (0x01u << DLAB) /* Divisor latch access bit */ + +/* FIFO Control register bit definitions */ +#define ENABLE_FIFO 0u /* Enable FIFO */ +#define CLEAR_RX_FIFO 1u /* Clear receiver FIFO */ +#define CLEAR_TX_FIFO 2u /* Clear transmitter FIFO */ +#define DMA_MODE 3u /* DMA mode */ +#define FIFO64_ENABLE 5u /* FIFO64 enable */ +//#define RDYMODE 3u /* Mode 0 or Mode 1 for TXRDY and RXRDY */ +#define FIFO_RX_TRIGGER 6u /* FIFO RX trigger */ + +/* FIFO Control register bit MASKS */ +#define RXRDY_TXRDYN_EN_MASK (0x01u << 0u) /* Enable TXRDY and RXRDY signals */ +#define CLEAR_RX_FIFO_MASK (0x01u << 1u) /* Clear receiver FIFO */ +#define CLEAR_TX_FIFO_MASK (0x01u << 2u) /* Clear transmitter FIFO */ +#define DMA_MODE_MASK (0x01u << 3u) /* DMA mode */ +#define FIFO64_ENABLE_MASK (0x01u << 5u) /* FIFO64 enable */ +//#define RDYMODE_MASK (0x01u << 3u) /* Mode 0 or Mode 1 for TXRDY and RXRDY */ + +#define FIFO_RX_TRIGGER_LEVEL_4_MASK (0x01u << 6u) +#define FIFO_RX_TRIGGER_LEVEL_8_MASK (0x02u << 6u) +#define FIFO_RX_TRIGGER_LEVEL_14_MASK (0x03u << 6u) + +#define FIFO64_RX_TRIGGER_LEVEL_16_MASK (0x01u << 6u) +#define FIFO64_RX_TRIGGER_LEVEL_32_MASK (0x02u << 6u) +#define FIFO64_RX_TRIGGER_LEVEL_56_MASK (0x03u << 6u) + +/* Modem Control register bit definitions */ +//#define LOOP 4u /* Local loopback */ +//#define RLOOP 5u /* Remote loopback */ +//#define ECHO 6u /* Automatic echo */ + +/* Modem Control register bit MASKS */ +//#define LOOP_MASK (0x01u << 4u) /* Local loopback */ +//#define RLOOP_MASK (0x01u << 5u) /* Remote loopback & Automatic echo*/ +//#define ECHO_MASK (0x01u << 6u) /* Automatic echo */ + +/* Line Status register bit definitions */ +#define DR 0u /* Data ready */ +#define THRE 5u /* Transmitter holding register empty */ +#define TEMT 6u /* Transmitter empty */ + +/* Line Status register bit MASKS */ +#define DR_MASK (0x01u << 0u) /* Data ready */ +#define THRE_MASK (0x01u << 5u) /* Transmitter holding register empty */ +#define TEMT_MASK (0x01u << 6u) /* Transmitter empty */ + +/* Interrupt Enable register bit definitions */ +#define ERBFI 0u /* Enable receiver buffer full interrupt */ +#define ETBEI 1u /* Enable transmitter buffer empty interrupt */ +#define ELSI 2u /* Enable line status interrupt */ +#define EDSSI 3u /* Enable modem status interrupt */ + +/* Interrupt Enable register bit MASKS */ +#define ERBFI_MASK (0x01u << 0u) /* Enable receiver buffer full interrupt */ +#define ETBEI_MASK (0x01u << 1u) /* Enable transmitter buffer empty interrupt */ +#define ELSI_MASK (0x01u << 2u) /* Enable line status interrupt */ +#define EDSSI_MASK (0x01u << 3u) /* Enable modem status interrupt */ + +/* Multimode register 0 bit definitions */ +#define ELIN 3u /* Enable LIN header detection */ +#define ETTG 5u /* Enable transmitter time guard */ +#define ERTO 6u /* Enable receiver time-out */ +#define EFBR 7u /* Enable fractional baud rate mode */ + +/* Multimode register 0 bit MASKS */ +#define ELIN_MASK (0x01u << 3u) /* Enable LIN header detection */ +#define ETTG_MASK (0x01u << 5u) /* Enable transmitter time guard */ +#define ERTO_MASK (0x01u << 6u) /* Enable receiver time-out */ +#define EFBR_MASK (0x01u << 7u) /* Enable fractional baud rate mode */ + +/* Multimode register 1 bit definitions */ +#define E_MSB_RX 0u /* MSB / LSB first for receiver */ +#define E_MSB_TX 1u /* MSB / LSB first for transmitter */ +#define EIRD 2u /* Enable IrDA modem */ +#define EIRX 3u /* Input polarity for IrDA modem */ +#define EITX 4u /* Output polarity for IrDA modem */ +#define EITP 5u /* Output pulse width for IrDA modem */ + +/* Multimode register 1 bit MASKS */ +#define E_MSB_RX_MASK (0x01u << 0u) /* MSB / LSB first for receiver */ +#define E_MSB_TX_MASK (0x01u << 1u) /* MSB / LSB first for transmitter */ +#define EIRD_MASK (0x01u << 2u) /* Enable IrDA modem */ +#define EIRX_MASK (0x01u << 3u) /* Input polarity for IrDA modem */ +#define EITX_MASK (0x01u << 4u) /* Output polarity for IrDA modem */ +#define EITP_MASK (0x01u << 5u) /* Output pulse width for IrDA modem */ + +/* Multimode register 2 bit definitions */ +//#define EERR 0u /* Enable ERR / NACK during stop time */ +//#define EAFM 1u /* Enable 9-bit address flag mode */ +//#define EAFC 2u /* Enable address flag clear */ +//#define ESWM 3u /* Enable single wire half-duplex mode */ + +/* Multimode register 2 bit MASKS */ +//#define EERR_MASK (0x01u << 0u) /* Enable ERR / NACK during stop time */ +//#define EAFM_MASK (0x01u << 1u) /* Enable 9-bit address flag mode */ +//#define EAFC_MASK (0x01u << 2u) /* Enable address flag clear */ +//#define ESWM_MASK (0x01u << 3u) /* Enable single wire half-duplex mode */ + +/* Multimode Interrupt Enable register and + Multimode Interrupt Identification register definitions */ +//#define ERTOI 0u /* Enable receiver timeout interrupt */ +//#define ENACKI 1u /* Enable NACK / ERR interrupt */ +//#define EPID_PEI 2u /* Enable PID parity error interrupt */ +//#define ELINBI 3u /* Enable LIN break interrupt */ +//#define ELINSI 4u /* Enable LIN sync detection interrupt */ + +/* Multimode Interrupt Enable register and + Multimode Interrupt Identification register MASKS */ +//#define ERTOI_MASK (0x01u << 0u) /* Enable receiver timeout interrupt */ +//#define ENACKI_MASK (0x01u << 1u) /* Enable NACK / ERR interrupt */ +//#define EPID_PEI_MASK (0x01u << 2u) /* Enable PID parity error interrupt */ +//#define ELINBI_MASK (0x01u << 3u) /* Enable LIN break interrupt */ +//#define ELINSI_MASK (0x01u << 4u) /* Enable LIN sync detection interrupt */ + +typedef struct +{ + union + { + volatile const uint8_t RBR; + volatile uint8_t THR; + volatile uint8_t DLL; + uint32_t RESERVED0; + }; + + union + { + volatile uint8_t DLM; + volatile uint8_t IER; + uint32_t RESERVED1; + }; + + union + { + volatile uint8_t IIR; + volatile uint8_t FCR; + uint32_t RESERVED2; + }; + + volatile uint8_t LCR; + uint8_t RESERVED3[3]; + + volatile uint8_t MCR; + uint8_t RESERVED4[3]; + + volatile const uint8_t LSR; + uint8_t RESERVED5[3]; + + volatile const uint8_t MSR; + uint8_t RESERVED6[3]; + + volatile uint8_t SR; + uint8_t RESERVED7[7]; + +} UART_TypeDef; + + +/***************************************************************************//** + uart_instance. + There is one instance of this structure for each instance of the + microprocessor subsystem's UARTs. Instances of this structure are used to + identify a specific UART. A pointer to an initialized instance of the + uart_instance_t structure is passed as the first parameter to + UART driver functions to identify which UART should perform the + requested operation. + */ +struct uart_instance{ + /* CMSIS related defines identifying the UART hardware. */ + UART_TypeDef * hw_reg; /*!< Pointer to UART registers. */ + uint32_t baudrate; /*!< Operating baud rate. */ + uint8_t lineconfig; /*!< Line configuration parameters. */ + uint8_t status; /*!< Sticky line status. */ + + /* transmit related info (used with interrupt driven transmit): */ + const uint8_t * tx_buffer; /*!< Pointer to transmit buffer. */ + uint32_t tx_buff_size; /*!< Transmit buffer size. */ + uint32_t tx_idx; /*!< Index within transmit buffer of next byte to transmit.*/ + + /* line status interrupt handler:*/ + uart_irq_handler_t linests_handler; /*!< Pointer to user registered line status handler. */ + /* receive interrupt handler:*/ + uart_irq_handler_t rx_handler; /*!< Pointer to user registered receiver handler. */ + /* transmit interrupt handler:*/ + uart_irq_handler_t tx_handler; /*!< Pointer to user registered transmit handler. */ + /* modem status interrupt handler:*/ + uart_irq_handler_t modemsts_handler; /*!< Pointer to user registered modem status handler. */ + + + +}; + +extern uart_instance_t g_uart_0; + +static void default_tx_handler(uart_instance_t * this_uart); +static void enable_irq(const uart_instance_t * this_uart); +static void disable_irq(const uart_instance_t * this_uart); + +static void config_baud_divisors +( + uart_instance_t * this_uart, + uint32_t baudrate +); + +/***************************************************************************//** + The UART_init() function initializes and configures the + UART with the configuration passed as a parameter. The configuration + parameters are the baud_rate which is used to generate the baud value and the + line_config which is used to specify the line configuration (bit length, + stop bits and parity). + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @param baud_rate + The baud_rate parameter specifies the baud rate. It can be specified for + common baud rates using the following defines: + - UART_110_BAUD + - UART_300_BAUD + - UART_600_BAUD + - UART_1200_BAUD + - UART_2400_BAUD + - UART_4800_BAUD + - UART_9600_BAUD + - UART_19200_BAUD + - UART_38400_BAUD + - UART_57600_BAUD + - UART_115200_BAUD + - UART_230400_BAUD + - UART_460800_BAUD + - UART_921600_BAUD + + Alternatively, any nonstandard baud rate can be specified by simply passing + the actual required baud rate as the value for this parameter. + @param line_config + The line_config parameter is the line configuration specifying the bit length, + number of stop bits and parity settings. + + This is a bitwise OR of one value from each of the following groups of + allowed values: + + One of the following to specify the transmit/receive data bit length: + - UART_DATA_5_BITS + - UART_DATA_6_BITS, + - UART_DATA_7_BITS + - UART_DATA_8_BITS + + One of the following to specify the parity setting: + - UART_NO_PARITY + - UART_EVEN_PARITY + - UART_ODD_PARITY + - UART_STICK_PARITY_0 + - UART_STICK_PARITY_1 + + One of the following to specify the number of stop bits: + - UART_ONE_STOP_BIT + - UART_ONEHALF_STOP_BIT + - UART_TWO_STOP_BITS + @return + This function does not return a value. + Example: + @code + #include "uart.h" + int main(void) + { + UART_init(&g_uart0_lo, + UART_57600_BAUD, + UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + + return(0); + } + @endcode + */ +void +UART_init +( + uart_instance_t* this_uart, + uint32_t baud_rate, + uint8_t line_config +); + +/***************************************************************************//** + The function UART_polled_tx() is used to transmit data. It transfers the + contents of the transmitter data buffer, passed as a function parameter, into + the UART's hardware transmitter FIFO. It returns when the full content of the + transmit data buffer has been transferred to the UART's transmit FIFO. It is + safe to release or reuse the memory used as the transmitter data buffer once + this function returns. + Note: This function reads the UART's line status register (LSR) to poll + for the active state of the transmitter holding register empty (THRE) bit + before transferring data from the data buffer to the transmitter FIFO. It + transfers data to the transmitter FIFO in blocks of 16 bytes or less and + allows the FIFO to empty before transferring the next block of data. + Note: The actual transmission over the serial connection will still be + in progress when this function returns. Use the UART_get_tx_status() + function if you need to know when the transmitter is empty. + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @param pbuff + The pbuff parameter is a pointer to a buffer containing the data to + be transmitted. + @param tx_size + The tx_size parameter specifies the size, in bytes, of the data to + be transmitted. + @return + This function does not return a value. + Example: + @code + #include "uart.h" + int main(void) + { + uint8_t message[12] = "Hello World"; + UART_init(&g_uart0_lo, + UART_57600_BAUD, + SS_UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + UART_polled_tx(&g_uart0_lo, message, sizeof(message)); + + return(0); + } + @endcode + */ +void +UART_polled_tx +( + uart_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +); + +/***************************************************************************//** + The function UART_polled_tx_string() is used to transmit a NULL ('\0') + terminated string. It transfers the text string, from the buffer starting at + the address pointed to by p_sz_string into the UART's hardware transmitter + FIFO. It returns when the complete string has been transferred to the UART's + transmit FIFO. It is safe to release or reuse the memory used as the string + buffer once this function returns. + Note: This function reads the UART's line status register (LSR) to poll + for the active state of the transmitter holding register empty (THRE) bit + before transferring data from the data buffer to the transmitter FIFO. It + transfers data to the transmitter FIFO in blocks of 16 bytes or less and + allows the FIFO to empty before transferring the next block of data. + Note: The actual transmission over the serial connection will still be + in progress when this function returns. Use the UART_get_tx_status() + function if you need to know when the transmitter is empty. + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @param p_sz_string + The p_sz_string parameter is a pointer to a buffer containing the NULL + ('\0') terminated string to be transmitted. + @return + This function does not return a value. + Example: + @code + #include "uart.h" + int main(void) + { + uint8_t message[12] = "Hello World"; + UART_init(&g_uart0_lo, + UART_57600_BAUD, + UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + + UART_polled_tx_string(&g_uart0_lo, message); + + return(0); + } + @endcode + */ +void +UART_polled_tx_string +( + uart_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + The function UART_irq_tx() is used to initiate an interrupt-driven + transmit. It returns immediately after making a note of the transmit buffer + location and enabling transmit interrupts both at the UART and the PolarFire + SoC Core Complex PLIC level. This function takes a pointer via the pbuff + parameter to a memory buffer containing the data to transmit. The memory + buffer specified through this pointer must remain allocated and contain the + data to transmit until the transmit completion has been detected through calls + to function UART_tx_complete(). The actual transmission over the serial + connection is still in progress until calls to the UART_tx_complete() + function indicate transmit completion. + Note: The UART_irq_tx() function enables both the transmit holding + register empty (THRE) interrupt in the UART and the UART instance + interrupt in the PolarFire SoC Core Complex PLIC as part of its implementation. + Note: The UART_irq_tx() function assigns an internal default transmit + interrupt handler function to the UART's THRE interrupt. This interrupt + handler overrides any custom interrupt handler that you may have previously + registered using the UART_set_tx_handler() function. + Note: The UART_irq_tx() function's default transmit interrupt + handler disables the UART's THRE interrupt when all of the data has + been transferred to the UART's transmit FIFO. + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @param pbuff + The pbuff parameter is a pointer to a buffer containing the data + to be transmitted. + @param tx_size + The tx_size parameter specifies the size, in bytes, of the data + to be transmitted. + @return + This function does not return a value. + Example: + @code + #include "uart.h" + int main(void) + { + uint8_t tx_buff[10] = "abcdefghi"; + + UART_init(&g_uart0_lo, + UART_57600_BAUD, + UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + + UART_irq_tx(&g_uart0_lo, tx_buff, sizeof(tx_buff)); + + while(0 == UART_tx_complete(&g_uart0_lo)) + { + ; + } + return(0); + } + @endcode + */ +void +UART_irq_tx +( + uart_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +); + +/***************************************************************************//** + The UART_tx_complete() function is used to find out if the + interrupt-driven transmit previously initiated through a call to + UART_irq_tx() is complete. This is typically used to find out when it is + safe to reuse or release the memory buffer holding transmit data. + Note: The transfer of all of the data from the memory buffer to the UART's + transmit FIFO and the actual transmission over the serial connection are both + complete when a call to the UART_tx_complete() function indicates transmit + completion. + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @return + This function return a non-zero value if transmit has completed, otherwise + it returns zero. + Example: + See the UART_irq_tx() function for an example that uses the + UART_tx_complete() function. + */ +int8_t +UART_tx_complete +( + uart_instance_t * this_uart +); + +/***************************************************************************//** + The UART_get_rx() function reads the content of the UART receiver's FIFO + and stores it in the receive buffer that is passed via the rx_buff function + parameter. It copies either the full contents of the FIFO into the receive + buffer, or just enough data from the FIFO to fill the receive buffer, + dependent upon the size of the receive buffer passed by the buff_size + parameter. The UART_get_rx() function returns the number of bytes copied + into the receive buffer .This function is non-blocking and will return 0 + immediately if no data has been received. + Note: The UART_get_rx() function reads and accumulates the receiver + status of the UART instance before reading each byte from the receiver's + data register/FIFO. This allows the driver to maintain a sticky record of any + receiver errors that occur as the UART receives each data byte; receiver + errors would otherwise be lost after each read from the receiver's data + register. A call to the UART_get_rx_status() function returns any receiver + errors accumulated during the execution of the UART_get_rx() function. + Note: If you need to read the error status for each byte received, set + the buff_size to 1 and read the receive line error status for each byte + using the UART_get_rx_status() function. + The UART_get_rx() function can be used in polled mode, where it is called + at regular intervals to find out if any data has been received, or in + interrupt driven-mode, where it is called as part of a receive handler that is + called by the driver as a result of data being received. + Note: In interrupt driven mode you should call the UART_get_rx() + function as part of the receive handler function that you register with + the UART driver through a call to UART_set_rx_handler(). + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @param rx_buff + The rx_buff parameter is a pointer to a buffer where the received + data is copied. + @param buff_size + The buff_size parameter specifies the size of the receive buffer in bytes. + @return + This function returns the number of bytes that were copied into the + rx_buff buffer. It returns 0 if no data has been received. + Polled mode example: + @code + int main( void ) + { + uint8_t rx_buff[RX_BUFF_SIZE]; + uint32_t rx_idx = 0; + UART_init(&g_uart0_lo, + UART_57600_BAUD, + UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + + while(1) + { + rx_size = UART_get_rx(&g_uart0_lo, rx_buff, sizeof(rx_buff)); + if(rx_size > 0) + { + process_rx_data(rx_buff, rx_size); + } + task_a(); + task_b(); + } + return 0; + } + @endcode + Interrupt driven example: + @code + int main( void ) + { + UART_init(&g_uart1, + UART_57600_BAUD, + UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + + UART_set_rx_handler(&g_uart1, + uart1_rx_handler, + UART_FIFO_SINGLE_BYTE); + + while(1) + { + task_a(); + task_b(); + } + return 0; + } + void uart1_rx_handler(uart_instance_t * this_uart) + { + uint8_t rx_buff[RX_BUFF_SIZE]; + uint32_t rx_idx = 0; + rx_size = UART_get_rx(this_uart, rx_buff, sizeof(rx_buff)); + process_rx_data(rx_buff, rx_size); + } + @endcode + */ +size_t +UART_get_rx +( + uart_instance_t * this_uart, + uint8_t * rx_buff, + size_t buff_size +); + +/***************************************************************************//** + The UART_set_rx_handler() function is used to register a receive handler + function that is called by the driver when a UART receive data available (RDA) + interrupt occurs. You must create and register the receive handler function + to suit your application and it must include a call to the UART_get_rx() + function to actually read the received data. + Note: The UART_set_rx_handler() function enables both the RDA + interrupt in the UART instance. It also enables the corresponding + UART instance interrupt in the PolarFire SoC Core Complex PLIC as part + of its implementation. + Note: You can disable the RDA interrupt when required by calling the + UART_disable_irq() function. This is your choice and is dependent upon + your application. + + @param this_uart + The this_uart parameter is a pointer to an uart_instance_t + structure identifying the UART hardware block that will perform + the requested function. + @param handler + The handler parameter is a pointer to a receive interrupt handler function + provided by your application that will be called as a result of a UART RDA + interrupt. This handler function must be of type uart_irq_handler_t. + @param trigger_level + The trigger_level parameter is the receive FIFO trigger level. This + specifies the number of bytes that must be received before the UART + triggers an RDA interrupt. + @return + This function does not return a value. + Example: + @code + #include "uart.h" + #define RX_BUFF_SIZE 64 + uint8_t g_rx_buff[RX_BUFF_SIZE]; + void uart0_rx_handler(uart_instance_t * this_uart) + { + UART_get_rx(this_uart, &g_rx_buff[g_rx_idx], sizeof(g_rx_buff)); + } + int main(void) + { + UART_init(&g_uart0_lo, + UART_57600_BAUD, + UART_DATA_8_BITS | UART_NO_PARITY | UART_ONE_STOP_BIT); + + UART_set_rx_handler(&g_uart0_lo, + uart0_rx_handler, + UART_FIFO_SINGLE_BYTE); + + while(1) + { + ; + } + return(0); + } + @endcode + */ +void +UART_set_rx_handler +( + uart_instance_t * this_uart, + uart_irq_handler_t handler, + uart_rx_trig_level_t trigger_level +); + + +#endif /*__UART_H_*/ +