/******************************************************************************* | |
* (c) Copyright 2007-2015 Microsemi SoC Products Group. All rights reserved. | |
* | |
* Core16550 driver implementation. See file "core_16550.h" for a | |
* description of the functions implemented in this file. | |
* | |
* SVN $Revision: 7963 $ | |
* SVN $Date: 2015-10-09 17:58:21 +0530 (Fri, 09 Oct 2015) $ | |
*/ | |
#include "hal.h" | |
#include "core_16550.h" | |
#include "core16550_regs.h" | |
#include "hal_assert.h" | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
/******************************************************************************* | |
* Definitions for transmitter states | |
*/ | |
#define TX_COMPLETE 0x00U | |
/******************************************************************************* | |
* Definition for transmitter FIFO size | |
*/ | |
#define TX_FIFO_SIZE 16U | |
/******************************************************************************* | |
* Default receive interrupt trigger level | |
*/ | |
#define DEFAULT_RX_TRIG_LEVEL ((uint8_t)UART_16550_FIFO_SINGLE_BYTE) | |
/******************************************************************************* | |
* Receiver error status mask and shift offset | |
*/ | |
#define STATUS_ERROR_MASK ( LSR_OE_MASK | LSR_PE_MASK | \ | |
LSR_FE_MASK | LSR_BI_MASK | LSR_FIER_MASK) | |
/******************************************************************************* | |
* Definitions for invalid parameters with proper type | |
*/ | |
#define INVALID_INTERRUPT 0U | |
#define INVALID_IRQ_HANDLER ( (uart_16550_irq_handler_t) 0 ) | |
/******************************************************************************* | |
* Possible values for Interrupt Identification Register Field. | |
*/ | |
#define IIRF_MODEM_STATUS 0x00U | |
#define IIRF_THRE 0x02U | |
#define IIRF_RX_DATA 0x04U | |
#define IIRF_RX_LINE_STATUS 0x06U | |
#define IIRF_DATA_TIMEOUT 0x0CU | |
/******************************************************************************* | |
* Null parameters with appropriate type definitions | |
*/ | |
#define NULL_ADDR ( ( addr_t ) 0 ) | |
#define NULL_INSTANCE ( ( uart_16550_instance_t * ) 0 ) | |
#define NULL_BUFF ( ( uint8_t * ) 0 ) | |
/******************************************************************************* | |
* Possible states for different register bit fields | |
*/ | |
enum { | |
DISABLE = 0U, | |
ENABLE = 1U | |
}; | |
/******************************************************************************* | |
* Static function declarations | |
*/ | |
static void default_tx_handler(uart_16550_instance_t * this_uart); | |
/******************************************************************************* | |
* Public function definitions | |
*/ | |
/***************************************************************************//** | |
* UART_16550_init. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
void | |
UART_16550_init | |
( | |
uart_16550_instance_t* this_uart, | |
addr_t base_addr, | |
uint16_t baud_value, | |
uint8_t line_config | |
) | |
{ | |
#ifndef NDEBUG | |
uint8_t dbg1; | |
uint8_t dbg2; | |
#endif | |
uint8_t fifo_config; | |
uint8_t temp; | |
HAL_ASSERT( base_addr != NULL_ADDR ); | |
HAL_ASSERT( this_uart != NULL_INSTANCE ); | |
if( ( base_addr != NULL_ADDR ) && ( this_uart != NULL_INSTANCE ) ) | |
{ | |
/* disable interrupts */ | |
HAL_set_8bit_reg(base_addr, IER, DISABLE); | |
/* reset divisor latch */ | |
HAL_set_8bit_reg_field(base_addr, LCR_DLAB, ENABLE); | |
#ifndef NDEBUG | |
dbg1 = HAL_get_8bit_reg_field(base_addr, LCR_DLAB ); | |
HAL_ASSERT( dbg1 == ENABLE ); | |
#endif | |
/* MSB of baud value */ | |
temp = (uint8_t)(baud_value >> 8); | |
HAL_set_8bit_reg(base_addr, DMR, temp ); | |
/* LSB of baud value */ | |
HAL_set_8bit_reg(base_addr, DLR, ( (uint8_t)baud_value ) ); | |
#ifndef NDEBUG | |
dbg1 = HAL_get_8bit_reg(base_addr, DMR ); | |
dbg2 = HAL_get_8bit_reg(base_addr, DLR ); | |
HAL_ASSERT( ( ( ( (uint16_t) dbg1 ) << 8 ) | dbg2 ) == baud_value ); | |
#endif | |
/* reset divisor latch */ | |
HAL_set_8bit_reg_field(base_addr, LCR_DLAB, DISABLE); | |
#ifndef NDEBUG | |
dbg1 = HAL_get_8bit_reg_field(base_addr, LCR_DLAB ); | |
HAL_ASSERT( dbg1 == DISABLE ); | |
#endif | |
/* set the line control register (bit length, stop bits, parity) */ | |
HAL_set_8bit_reg( base_addr, LCR, line_config ); | |
#ifndef NDEBUG | |
dbg1 = HAL_get_8bit_reg(base_addr, LCR ); | |
HAL_ASSERT( dbg1 == line_config) | |
#endif | |
/* Enable and configure the RX and TX FIFOs. */ | |
fifo_config = ((uint8_t)(DEFAULT_RX_TRIG_LEVEL << FCR_TRIG_LEVEL_SHIFT) | | |
FCR_RDYN_EN_MASK | FCR_CLEAR_RX_MASK | | |
FCR_CLEAR_TX_MASK | FCR_ENABLE_MASK ); | |
HAL_set_8bit_reg( base_addr, FCR, fifo_config ); | |
/* disable loopback */ | |
HAL_set_8bit_reg_field( base_addr, MCR_LOOP, DISABLE ); | |
#ifndef NDEBUG | |
dbg1 = HAL_get_8bit_reg_field(base_addr, MCR_LOOP); | |
HAL_ASSERT( dbg1 == DISABLE ); | |
#endif | |
/* Instance setup */ | |
this_uart->base_address = base_addr; | |
this_uart->tx_buffer = NULL_BUFF; | |
this_uart->tx_buff_size = TX_COMPLETE; | |
this_uart->tx_idx = 0U; | |
this_uart->tx_handler = default_tx_handler; | |
this_uart->rx_handler = ( (uart_16550_irq_handler_t) 0 ); | |
this_uart->linests_handler = ( (uart_16550_irq_handler_t) 0 ); | |
this_uart->modemsts_handler = ( (uart_16550_irq_handler_t) 0 ); | |
this_uart->status = 0U; | |
} | |
} | |
/***************************************************************************//** | |
* UART_16550_polled_tx. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
void | |
UART_16550_polled_tx | |
( | |
uart_16550_instance_t * this_uart, | |
const uint8_t * pbuff, | |
uint32_t tx_size | |
) | |
{ | |
uint32_t char_idx = 0U; | |
uint32_t size_sent; | |
uint8_t status; | |
HAL_ASSERT( this_uart != NULL_INSTANCE ); | |
HAL_ASSERT( pbuff != NULL_BUFF ); | |
HAL_ASSERT( tx_size > 0U ); | |
if( ( this_uart != NULL_INSTANCE ) && | |
( pbuff != NULL_BUFF ) && | |
( tx_size > 0U ) ) | |
{ | |
/* Remain in this loop until the entire input buffer | |
* has been transferred to the UART. | |
*/ | |
do { | |
/* Read the Line Status Register and update the sticky record */ | |
status = HAL_get_8bit_reg( this_uart->base_address, LSR ); | |
this_uart->status |= status; | |
/* Check if TX FIFO is empty. */ | |
if( status & LSR_THRE_MASK ) | |
{ | |
uint32_t fill_size = TX_FIFO_SIZE; | |
/* Calculate the number of bytes to transmit. */ | |
if ( tx_size < TX_FIFO_SIZE ) | |
{ | |
fill_size = 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. */ | |
HAL_set_8bit_reg( this_uart->base_address, THR, | |
(uint_fast8_t)pbuff[char_idx++]); | |
} | |
/* Calculate the number of untransmitted bytes remaining. */ | |
tx_size -= size_sent; | |
} | |
} while ( tx_size ); | |
} | |
} | |
/***************************************************************************//** | |
* UART_16550_polled_tx_string. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
void | |
UART_16550_polled_tx_string | |
( | |
uart_16550_instance_t * this_uart, | |
const uint8_t * p_sz_string | |
) | |
{ | |
uint32_t char_idx = 0U; | |
uint32_t fill_size; | |
uint_fast8_t data_byte; | |
uint8_t status; | |
HAL_ASSERT( this_uart != NULL_INSTANCE ); | |
HAL_ASSERT( p_sz_string != NULL_BUFF ); | |
if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFF ) ) | |
{ | |
char_idx = 0U; | |
/* Get the first data byte from the input buffer */ | |
data_byte = (uint_fast8_t)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 = HAL_get_8bit_reg( this_uart->base_address,LSR); | |
this_uart->status |= status; | |
} while ( !( status & LSR_THRE_MASK ) ); | |
/* 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 */ | |
HAL_set_8bit_reg( this_uart->base_address, THR, data_byte ); | |
++fill_size; | |
char_idx++; | |
/* Get the next data byte from the input buffer */ | |
data_byte = (uint_fast8_t)p_sz_string[char_idx]; | |
} | |
} | |
} | |
} | |
/***************************************************************************//** | |
* UART_16550_irq_tx. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
void | |
UART_16550_irq_tx | |
( | |
uart_16550_instance_t * this_uart, | |
const uint8_t * pbuff, | |
uint32_t tx_size | |
) | |
{ | |
HAL_ASSERT( this_uart != NULL_INSTANCE ) | |
HAL_ASSERT( pbuff != NULL_BUFF ) | |
HAL_ASSERT( tx_size > 0U ) | |
if( ( this_uart != NULL_INSTANCE ) && | |
( pbuff != NULL_BUFF ) && | |
( tx_size > 0U ) ) | |
{ | |
/*Initialize the UART instance with | |
parameters required for transmission.*/ | |
this_uart->tx_buffer = pbuff; | |
this_uart->tx_buff_size = tx_size; | |
/* char_idx; */ | |
this_uart->tx_idx = 0U; | |
/* assign handler for default data transmission */ | |
this_uart->tx_handler = default_tx_handler; | |
/* enables TX interrupt */ | |
HAL_set_8bit_reg_field(this_uart->base_address, IER_ETBEI, ENABLE); | |
} | |
} | |
/***************************************************************************//** | |
* UART_16550_tx_complete. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
int8_t | |
UART_16550_tx_complete | |
( | |
uart_16550_instance_t * this_uart | |
) | |
{ | |
int8_t returnvalue = 0; | |
uint8_t status = 0U; | |
HAL_ASSERT( this_uart != NULL_INSTANCE ) | |
if( this_uart != NULL_INSTANCE ) | |
{ | |
status = HAL_get_8bit_reg(this_uart->base_address,LSR); | |
this_uart->status |= status; | |
if( ( this_uart->tx_buff_size == TX_COMPLETE ) && | |
( status & LSR_TEMT_MASK ) ) | |
{ | |
returnvalue = (int8_t)1; | |
} | |
} | |
return returnvalue; | |
} | |
/***************************************************************************//** | |
* UART_16550_get_rx. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
size_t | |
UART_16550_get_rx | |
( | |
uart_16550_instance_t * this_uart, | |
uint8_t * rx_buff, | |
size_t buff_size | |
) | |
{ | |
uint8_t status; | |
size_t rx_size = 0U; | |
HAL_ASSERT( this_uart != NULL_INSTANCE ) | |
HAL_ASSERT( rx_buff != (uint8_t *)0 ) | |
HAL_ASSERT( buff_size > 0U ) | |
if( ( this_uart != NULL_INSTANCE ) && | |
( rx_buff != (uint8_t *)0 ) && | |
( buff_size > 0U ) ) | |
{ | |
status = HAL_get_8bit_reg( this_uart->base_address, LSR ); | |
this_uart->status |= status; | |
while ( ((status & LSR_DR_MASK) != 0U) && ( rx_size < buff_size ) ) | |
{ | |
rx_buff[rx_size] = HAL_get_8bit_reg( this_uart->base_address, RBR ); | |
rx_size++; | |
status = HAL_get_8bit_reg( this_uart->base_address, LSR ); | |
this_uart->status |= status; | |
} | |
} | |
return rx_size; | |
} | |
/***************************************************************************//** | |
* UART_16550_isr. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
void | |
UART_16550_isr | |
( | |
uart_16550_instance_t * this_uart | |
) | |
{ | |
uint8_t iirf; | |
HAL_ASSERT( this_uart != NULL_INSTANCE ) | |
if(this_uart != NULL_INSTANCE ) | |
{ | |
iirf = HAL_get_8bit_reg_field( this_uart->base_address, IIR_IIR ); | |
switch ( iirf ) | |
{ | |
/* Modem status interrupt */ | |
case IIRF_MODEM_STATUS: | |
{ | |
if( INVALID_IRQ_HANDLER != this_uart->modemsts_handler ) | |
{ | |
HAL_ASSERT( INVALID_IRQ_HANDLER != this_uart->modemsts_handler ); | |
if( INVALID_IRQ_HANDLER != this_uart->modemsts_handler ) | |
{ | |
(*(this_uart->modemsts_handler))(this_uart); | |
} | |
} | |
} | |
break; | |
/* Transmitter Holding Register Empty interrupt */ | |
case IIRF_THRE: | |
{ | |
HAL_ASSERT( INVALID_IRQ_HANDLER != this_uart->tx_handler ); | |
if ( INVALID_IRQ_HANDLER != this_uart->tx_handler ) | |
{ | |
(*(this_uart->tx_handler))(this_uart); | |
} | |
} | |
break; | |
/* Received Data Available interrupt */ | |
case IIRF_RX_DATA: | |
case IIRF_DATA_TIMEOUT: | |
{ | |
HAL_ASSERT( INVALID_IRQ_HANDLER != this_uart->rx_handler ); | |
if ( INVALID_IRQ_HANDLER != this_uart->rx_handler ) | |
{ | |
(*(this_uart->rx_handler))(this_uart); | |
} | |
} | |
break; | |
/* Line status interrupt */ | |
case IIRF_RX_LINE_STATUS: | |
{ | |
HAL_ASSERT( INVALID_IRQ_HANDLER != this_uart->linests_handler ); | |
if ( INVALID_IRQ_HANDLER != this_uart->linests_handler ) | |
{ | |
(*(this_uart->linests_handler))(this_uart); | |
} | |
} | |
break; | |
/* Unidentified interrupt */ | |
default: | |
{ | |
HAL_ASSERT( INVALID_INTERRUPT ) | |
} | |
} | |
} | |
} | |
/***************************************************************************//** | |
* UART_16550_set_rx_handler. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
void | |
UART_16550_set_rx_handler | |
( | |
uart_16550_instance_t * this_uart, | |
uart_16550_irq_handler_t handler, | |
uart_16550_rx_trig_level_t trigger_level | |
) | |
{ | |
HAL_ASSERT( this_uart != NULL_INSTANCE ) | |
HAL_ASSERT( handler != INVALID_IRQ_HANDLER) | |
HAL_ASSERT( trigger_level < UART_16550_FIFO_INVALID_TRIG_LEVEL) | |
if( ( this_uart != NULL_INSTANCE ) && | |
( handler != INVALID_IRQ_HANDLER) && | |
( trigger_level < UART_16550_FIFO_INVALID_TRIG_LEVEL) ) | |
{ | |
this_uart->rx_handler = handler; | |
/* Set the receive interrupt trigger level. */ | |
HAL_set_8bit_reg_field( this_uart->base_address, | |
FCR_TRIG_LEVEL, trigger_level ); | |
/* Enable receive interrupt. */ | |
HAL_set_8bit_reg_field( this_uart->base_address, IER_ERBFI, ENABLE ); | |
} | |
} | |
/***************************************************************************//** | |
* UART_16550_set_loopback. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
void | |
UART_16550_set_loopback | |
( | |
uart_16550_instance_t * this_uart, | |
uart_16550_loopback_t loopback | |
) | |
{ | |
HAL_ASSERT( this_uart != NULL_INSTANCE ); | |
HAL_ASSERT( loopback < UART_16550_INVALID_LOOPBACK ); | |
if( ( this_uart != NULL_INSTANCE ) && | |
( loopback < UART_16550_INVALID_LOOPBACK ) ) | |
{ | |
if ( loopback == UART_16550_LOOPBACK_OFF ) | |
{ | |
HAL_set_8bit_reg_field( this_uart->base_address, | |
MCR_LOOP, | |
DISABLE ); | |
} | |
else | |
{ | |
HAL_set_8bit_reg_field( this_uart->base_address, | |
MCR_LOOP, | |
ENABLE ); | |
} | |
} | |
} | |
/***************************************************************************//** | |
* UART_16550_get_rx_status. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
uint8_t | |
UART_16550_get_rx_status | |
( | |
uart_16550_instance_t * this_uart | |
) | |
{ | |
uint8_t status = UART_16550_INVALID_PARAM; | |
HAL_ASSERT( this_uart != NULL_INSTANCE ); | |
if( ( this_uart != NULL_INSTANCE ) ) | |
{ | |
/* | |
* 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 |= HAL_get_8bit_reg( this_uart->base_address, LSR ); | |
status = ( this_uart->status & STATUS_ERROR_MASK ); | |
/* | |
* Clear the sticky status for this instance. | |
*/ | |
this_uart->status = (uint8_t)0; | |
} | |
return status; | |
} | |
/***************************************************************************//** | |
* UART_16550_get_modem_status. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
uint8_t | |
UART_16550_get_modem_status | |
( | |
uart_16550_instance_t * this_uart | |
) | |
{ | |
uint8_t status = UART_16550_NO_ERROR; | |
HAL_ASSERT( this_uart != NULL_INSTANCE ) | |
if( ( this_uart != NULL_INSTANCE ) ) | |
{ | |
/* | |
* Extract UART error 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 = HAL_get_8bit_reg( this_uart->base_address, MSR ); | |
} | |
return status; | |
} | |
/***************************************************************************//** | |
* Default TX interrupt handler to automatically transmit data from | |
* user assgined TX buffer. | |
*/ | |
static void | |
default_tx_handler | |
( | |
uart_16550_instance_t * this_uart | |
) | |
{ | |
uint8_t status; | |
HAL_ASSERT( NULL_INSTANCE != this_uart ) | |
if ( this_uart != NULL_INSTANCE ) | |
{ | |
HAL_ASSERT( NULL_BUFF != this_uart->tx_buffer ) | |
HAL_ASSERT( 0U != this_uart->tx_buff_size ) | |
if ( ( this_uart->tx_buffer != NULL_BUFF ) && | |
( 0U != this_uart->tx_buff_size ) ) | |
{ | |
/* Read the Line Status Register and update the sticky record. */ | |
status = HAL_get_8bit_reg( this_uart->base_address,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 & LSR_THRE_MASK ) | |
{ | |
uint32_t size_sent = 0U; | |
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 ( size_sent = 0U; size_sent < fill_size; ++size_sent ) | |
{ | |
/* Send next character in the buffer. */ | |
HAL_set_8bit_reg( this_uart->base_address, THR, | |
(uint_fast8_t)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 */ | |
HAL_set_8bit_reg_field( this_uart->base_address, | |
IER_ETBEI, DISABLE); | |
} | |
} | |
} | |
} | |
/***************************************************************************//** | |
* UART_16550_enable_irq. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
void | |
UART_16550_enable_irq | |
( | |
uart_16550_instance_t * this_uart, | |
uint8_t irq_mask | |
) | |
{ | |
HAL_ASSERT( this_uart != NULL_INSTANCE ) | |
if( this_uart != NULL_INSTANCE ) | |
{ | |
/* 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 | |
*/ | |
/* read present interrupts for enabled ones*/ | |
irq_mask |= HAL_get_8bit_reg( this_uart->base_address, IER ); | |
/* Enable interrupts */ | |
HAL_set_8bit_reg( this_uart->base_address, IER, irq_mask ); | |
} | |
} | |
/***************************************************************************//** | |
* UART_16550_disable_irq. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
void | |
UART_16550_disable_irq | |
( | |
uart_16550_instance_t * this_uart, | |
uint8_t irq_mask | |
) | |
{ | |
HAL_ASSERT( this_uart != NULL_INSTANCE ) | |
if( this_uart != NULL_INSTANCE ) | |
{ | |
/* irq_mask encoding: 1 - disable | |
* bit 0 - Receive Data Available Interrupt | |
* bit 1 - Transmitter Holding Register Empty Interrupt | |
* bit 2 - Receiver Line Status Interrupt | |
* bit 3 - Modem Status Interrupt | |
*/ | |
/* read present interrupts for enabled ones */ | |
irq_mask = (( (uint8_t)~irq_mask ) & | |
HAL_get_8bit_reg( this_uart->base_address, IER )); | |
/* Disable interrupts */ | |
HAL_set_8bit_reg( this_uart->base_address, IER, irq_mask ); | |
} | |
} | |
/***************************************************************************//** | |
* UART_16550_set_rxstatus_handler. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
void | |
UART_16550_set_rxstatus_handler | |
( | |
uart_16550_instance_t * this_uart, | |
uart_16550_irq_handler_t handler | |
) | |
{ | |
HAL_ASSERT( this_uart != NULL_INSTANCE ) | |
HAL_ASSERT( handler != INVALID_IRQ_HANDLER) | |
if( ( this_uart != NULL_INSTANCE ) && | |
( handler != INVALID_IRQ_HANDLER) ) | |
{ | |
this_uart->linests_handler = handler; | |
/* Enable receiver line status interrupt. */ | |
HAL_set_8bit_reg_field( this_uart->base_address, IER_ELSI, ENABLE ); | |
} | |
} | |
/***************************************************************************//** | |
* UART_16550_set_tx_handler. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
void | |
UART_16550_set_tx_handler | |
( | |
uart_16550_instance_t * this_uart, | |
uart_16550_irq_handler_t handler | |
) | |
{ | |
HAL_ASSERT( this_uart != NULL_INSTANCE ) | |
HAL_ASSERT( handler != INVALID_IRQ_HANDLER) | |
if( ( this_uart != NULL_INSTANCE ) && | |
( handler != INVALID_IRQ_HANDLER) ) | |
{ | |
this_uart->tx_handler = handler; | |
/* Make TX buffer info invalid */ | |
this_uart->tx_buffer = NULL_BUFF; | |
this_uart->tx_buff_size = 0U; | |
/* Enable transmitter holding register Empty interrupt. */ | |
HAL_set_8bit_reg_field( this_uart->base_address, IER_ETBEI, ENABLE ); | |
} | |
} | |
/***************************************************************************//** | |
* UART_16550_set_modemstatus_handler. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
void | |
UART_16550_set_modemstatus_handler | |
( | |
uart_16550_instance_t * this_uart, | |
uart_16550_irq_handler_t handler | |
) | |
{ | |
HAL_ASSERT( this_uart != NULL_INSTANCE ) | |
HAL_ASSERT( handler != INVALID_IRQ_HANDLER) | |
if( ( this_uart != NULL_INSTANCE ) && | |
( handler != INVALID_IRQ_HANDLER) ) | |
{ | |
this_uart->modemsts_handler = handler; | |
/* Enable modem status interrupt. */ | |
HAL_set_8bit_reg_field( this_uart->base_address, IER_EDSSI, ENABLE ); | |
} | |
} | |
/***************************************************************************//** | |
* UART_16550_fill_tx_fifo. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
size_t | |
UART_16550_fill_tx_fifo | |
( | |
uart_16550_instance_t * this_uart, | |
const uint8_t * tx_buffer, | |
size_t tx_size | |
) | |
{ | |
uint8_t status; | |
size_t size_sent = 0U; | |
HAL_ASSERT( this_uart != NULL_INSTANCE ) | |
HAL_ASSERT( tx_buffer != NULL_BUFF ) | |
HAL_ASSERT( tx_size > 0U ) | |
/* Fill the UART's Tx FIFO until the FIFO is full or the complete input | |
* buffer has been written. */ | |
if( (this_uart != NULL_INSTANCE) && | |
(tx_buffer != NULL_BUFF) && | |
(tx_size > 0U) ) | |
{ | |
/* Read the Line Status Register and update the sticky record. */ | |
status = HAL_get_8bit_reg( this_uart->base_address, LSR ); | |
this_uart->status |= status; | |
/* Check if TX FIFO is empty. */ | |
if( status & LSR_THRE_MASK ) | |
{ | |
uint32_t fill_size = TX_FIFO_SIZE; | |
/* Calculate the number of bytes to transmit. */ | |
if ( tx_size < TX_FIFO_SIZE ) | |
{ | |
fill_size = 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. */ | |
HAL_set_8bit_reg( this_uart->base_address, THR, | |
(uint_fast8_t)tx_buffer[size_sent]); | |
} | |
} | |
} | |
return size_sent; | |
} | |
/***************************************************************************//** | |
* UART_16550_get_tx_status. | |
* See core_16550.h for details of how to use this function. | |
*/ | |
uint8_t | |
UART_16550_get_tx_status | |
( | |
uart_16550_instance_t * this_uart | |
) | |
{ | |
uint8_t status = UART_16550_TX_BUSY; | |
HAL_ASSERT( this_uart != NULL_INSTANCE ); | |
if( ( this_uart != NULL_INSTANCE ) ) | |
{ | |
/* Read the Line Status Register and update the sticky record. */ | |
status = HAL_get_8bit_reg( this_uart->base_address, 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 &= ( LSR_THRE_MASK | LSR_TEMT_MASK ); | |
} | |
return status; | |
} | |
#ifdef __cplusplus | |
} | |
#endif | |