rt-thread/bsp/smartfusion2/libraries/mss_uart/mss_uart.c

1763 lines
54 KiB
C

/*******************************************************************************
* (c) Copyright 2011-2013 Microsemi SoC Products Group. All rights reserved.
*
* SmartFusion2 Microcontroller Subsystem MMUART bare metal software driver
* implementation.
*
* SVN $Revision: 5610 $
* SVN $Date: 2013-04-05 18:49:30 +0530 (Fri, 05 Apr 2013) $
*/
#include "mss_uart.h"
#include "mss_uart_regs.h"
#include "../../CMSIS/mss_assert.h"
#include "../../CMSIS/hw_reg_io.h"
#include "../../CMSIS/system_m2sxxx.h"
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
* 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 ((mss_uart_irq_handler_t) 0)
#define NULL_HANDLER ((mss_uart_irq_handler_t) 0)
#define MSS_UART_DATA_READY ((uint8_t) 0x01)
#define SYNC_ASYNC_MODE_MASK (0x7u)
/*******************************************************************************
* 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
/*******************************************************************************
* Receiver error status mask.
*/
#define STATUS_ERROR_MASK ( MSS_UART_OVERUN_ERROR | MSS_UART_PARITY_ERROR | \
MSS_UART_FRAMING_ERROR | MSS_UART_BREAK_ERROR | \
MSS_UART_FIFO_ERROR)
/*******************************************************************************
* Cortex-M3 interrupt handler functions implemented as part of the MSS UART
* driver.
*/
#if defined(__GNUC__)
__attribute__((__interrupt__)) void UART0_IRQHandler(void);
#else
void UART0_IRQHandler(void);
#endif
#if defined(__GNUC__)
__attribute__((__interrupt__)) void UART1_IRQHandler(void);
#else
void UART1_IRQHandler(void);
#endif
/*******************************************************************************
* Local functions.
*/
static void global_init(mss_uart_instance_t * this_uart, uint32_t baud_rate,
uint8_t line_config);
static void MSS_UART_isr(mss_uart_instance_t * this_uart);
static void default_tx_handler(mss_uart_instance_t * this_uart);
static void config_baud_divisors
(
mss_uart_instance_t * this_uart,
uint32_t baudrate
);
/*******************************************************************************
* Instance definitions
*/
mss_uart_instance_t g_mss_uart0;
mss_uart_instance_t g_mss_uart1;
/*******************************************************************************
* Public Functions
*******************************************************************************/
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_init
(
mss_uart_instance_t* this_uart,
uint32_t baud_rate,
uint8_t line_config
)
{
/* The driver expects g_mss_uart0 and g_mss_uart1 to be the only
* mss_uart_instance_t instances used to identify UART0 and UART1. */
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
/* Perform generic initialization */
global_init(this_uart, baud_rate, line_config);
/* Disable LIN mode */
clear_bit_reg8(&this_uart->hw_reg->MM0, ELIN);
/* Disable IrDA mode */
clear_bit_reg8(&this_uart->hw_reg->MM1, EIRD);
/* Disable SmartCard Mode */
clear_bit_reg8(&this_uart->hw_reg->MM2, EERR);
/* set default tx handler for automated TX using interrupt in USART mode */
this_uart->tx_handler = default_tx_handler;
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void MSS_UART_lin_init
(
mss_uart_instance_t* this_uart,
uint32_t baud_rate,
uint8_t line_config
)
{
/* The driver expects g_mss_uart0 and g_mss_uart1 to be the only
* mss_uart_instance_t instances used to identify UART0 and UART1. */
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
/* Perform generic initialization */
global_init(this_uart, baud_rate, line_config);
/* Enable LIN mode */
set_bit_reg8(&this_uart->hw_reg->MM0, ELIN);
/* Disable IrDA mode */
clear_bit_reg8(&this_uart->hw_reg->MM1, EIRD);
/* Disable SmartCard Mode */
clear_bit_reg8(&this_uart->hw_reg->MM2, EERR);
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_irda_init
(
mss_uart_instance_t* this_uart,
uint32_t baud_rate,
uint8_t line_config,
mss_uart_rzi_polarity_t rxpol,
mss_uart_rzi_polarity_t txpol,
mss_uart_rzi_pulsewidth_t pw
)
{
/* The driver expects g_mss_uart0 and g_mss_uart1 to be the only
* mss_uart_instance_t instances used to identify UART0 and UART1. */
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
/* Perform generic initialization */
global_init(this_uart, baud_rate, line_config);
/* Enable LIN mode */
clear_bit_reg8(&this_uart->hw_reg->MM0, ELIN);
/* Disable IrDA mode */
set_bit_reg8(&this_uart->hw_reg->MM1, EIRD);
((rxpol == MSS_UART_ACTIVE_LOW) ? clear_bit_reg8(&this_uart->hw_reg->MM1,EIRX) :
set_bit_reg8(&this_uart->hw_reg->MM1,EIRX));
((txpol == MSS_UART_ACTIVE_LOW) ? clear_bit_reg8(&this_uart->hw_reg->MM1,EITX) :
set_bit_reg8(&this_uart->hw_reg->MM1,EITX));
((pw == MSS_UART_3_BY_16) ? clear_bit_reg8(&this_uart->hw_reg->MM1,EITP) :
set_bit_reg8(&this_uart->hw_reg->MM1,EITP));
/* Disable SmartCard Mode */
clear_bit_reg8(&this_uart->hw_reg->MM2, EERR);
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_smartcard_init
(
mss_uart_instance_t* this_uart,
uint32_t baud_rate,
uint8_t line_config
)
{
/* The driver expects g_mss_uart0 and g_mss_uart1 to be the only
* mss_uart_instance_t instances used to identify UART0 and UART1. */
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
/* Perform generic initialization */
global_init(this_uart, baud_rate, line_config);
/* Disable LIN mode */
clear_bit_reg8(&this_uart->hw_reg->MM0, ELIN);
/* Disable IrDA mode */
clear_bit_reg8(&this_uart->hw_reg->MM1, EIRD);
/* Enable SmartCard Mode : Only when data is 8-bit and 2 stop bits*/
if( ( MSS_UART_DATA_8_BITS | MSS_UART_TWO_STOP_BITS) ==
(line_config & (MSS_UART_DATA_8_BITS | MSS_UART_TWO_STOP_BITS)))
{
set_bit_reg8(&this_uart->hw_reg->MM2, EERR);
/* Enable single wire half-duplex mode */
set_bit_reg8(&this_uart->hw_reg->MM2,ESWM);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_polled_tx
(
mss_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;
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(pbuff != ( (uint8_t *)0));
ASSERT(tx_size > 0u);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(pbuff != ((uint8_t *)0)) && (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 = this_uart->hw_reg->LSR;
this_uart->status |= status;
/* Check if TX FIFO is empty. */
if(status & MSS_UART_THRE)
{
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. */
this_uart->hw_reg->THR = pbuff[char_idx];
char_idx++;
}
/* Calculate the number of untransmitted bytes remaining. */
tx_size -= size_sent;
}
} while(tx_size);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_polled_tx_string
(
mss_uart_instance_t * this_uart,
const uint8_t * p_sz_string
)
{
uint32_t char_idx = 0u;
uint32_t fill_size;
uint8_t data_byte;
uint8_t status;
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(p_sz_string != ((uint8_t *)0));
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(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 & MSS_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 mss_uart.h for details of how to use this function.
*/
void
MSS_UART_irq_tx
(
mss_uart_instance_t * this_uart,
const uint8_t * pbuff,
uint32_t tx_size
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(pbuff != ((uint8_t *)0));
ASSERT(tx_size > 0u);
if((tx_size > 0u) && ( pbuff != ((uint8_t *)0)) &&
((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)))
{
/*Initialise 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 = (uint16_t)0;
/* Clear any previously pended interrupts */
NVIC_ClearPendingIRQ(this_uart->irqn);
/* assign default handler for data transfer */
this_uart->tx_handler = default_tx_handler;
/* enables TX interrupt */
set_bit_reg8(&this_uart->hw_reg->IER,ETBEI);
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
NVIC_EnableIRQ(this_uart->irqn);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
int8_t
MSS_UART_tx_complete
(
mss_uart_instance_t * this_uart
)
{
int8_t ret_value = 0;
uint8_t status = 0u;
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/* 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 & MSS_UART_TEMT) != 0u))
{
ret_value = (int8_t)1;
}
}
return ret_value;
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
size_t
MSS_UART_get_rx
(
mss_uart_instance_t * this_uart,
uint8_t * rx_buff,
size_t buff_size
)
{
size_t rx_size = 0u;
uint8_t status = 0u;
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(rx_buff != ((uint8_t *)0));
ASSERT(buff_size > 0u);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(rx_buff != ((uint8_t *)0)) && (buff_size > 0u))
{
status = this_uart->hw_reg->LSR;
this_uart->status |= status;
while(((status & MSS_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 mss_uart.h for details of how to use this function.
*/
void
MSS_UART_enable_irq
(
mss_uart_instance_t * this_uart,
mss_uart_irq_t irq_mask
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(MSS_UART_INVALID_IRQ > irq_mask);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(MSS_UART_INVALID_IRQ > irq_mask))
{
/* Clear any previously pended interrupts */
NVIC_ClearPendingIRQ(this_uart->irqn);
/* 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)irq_mask & IIRF_MASK;
/*
* bit 4 - Receiver time-out interrupt
* bit 5 - NACK / ERR signal interrupt
* bit 6 - PID parity error interrupt
* bit 7 - LIN break detection interrupt
* bit 8 - LIN Sync detection interrupt
*/
this_uart->hw_reg->IEM |= (uint8_t)(((uint32_t)irq_mask & ~((uint32_t)IIRF_MASK)) >> 4u);
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
NVIC_EnableIRQ(this_uart->irqn);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_disable_irq
(
mss_uart_instance_t * this_uart,
mss_uart_irq_t irq_mask
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/* 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
*/
this_uart->hw_reg->IER &= ((uint8_t)(~((uint32_t)irq_mask & (uint32_t)IIRF_MASK)));
/*
* bit 4 - Receiver time-out interrupt
* bit 5 - NACK / ERR signal interrupt
* bit 6 - PID parity error interrupt
* bit 7 - LIN break detection interrupt
* bit 8 - LIN Sync detection interrupt
*/
this_uart->hw_reg->IEM |= (uint8_t)(~(((uint32_t)irq_mask & ~((uint32_t)IIRF_MASK)) >> 8u));
/* Clear any previously pended interrupts */
NVIC_ClearPendingIRQ(this_uart->irqn);
if(irq_mask == IIRF_MASK)
{
/* Disable UART instance interrupt in Cortex-M3 NVIC. */
NVIC_DisableIRQ(this_uart->irqn);
}
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_rx_handler
(
mss_uart_instance_t * this_uart,
mss_uart_irq_handler_t handler,
mss_uart_rx_trig_level_t trigger_level
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(handler != INVALID_IRQ_HANDLER );
ASSERT(trigger_level < MSS_UART_FIFO_INVALID_TRIG_LEVEL);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(handler != INVALID_IRQ_HANDLER) &&
(trigger_level < MSS_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;
/* Clear any previously pended interrupts */
NVIC_ClearPendingIRQ(this_uart->irqn);
/* Enable receive interrupt. */
set_bit_reg8(&this_uart->hw_reg->IER,ERBFI);
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
NVIC_EnableIRQ(this_uart->irqn);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_loopback
(
mss_uart_instance_t * this_uart,
mss_uart_loopback_t loopback
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(MSS_UART_INVALID_LOOPBACK > loopback);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) ||
(MSS_UART_INVALID_LOOPBACK > loopback))
{
switch(loopback)
{
case MSS_UART_LOCAL_LOOPBACK_OFF:
/* Disable local loopback */
clear_bit_reg8(&this_uart->hw_reg->MCR,LOOP);
break;
case MSS_UART_LOCAL_LOOPBACK_ON:
/* Enable local loopback */
set_bit_reg8(&this_uart->hw_reg->MCR,LOOP);
break;
case MSS_UART_REMOTE_LOOPBACK_OFF:
case MSS_UART_AUTO_ECHO_OFF:
/* Disable remote loopback & automatic echo*/
this_uart->hw_reg->MCR &= ~RLOOP_MASK;
break;
case MSS_UART_REMOTE_LOOPBACK_ON:
/* Enable remote loopback */
this_uart->hw_reg->MCR |= (1u << RLOOP);
break;
case MSS_UART_AUTO_ECHO_ON:
/* Enable automatic echo */
this_uart->hw_reg->MCR |= (1u << ECHO);
break;
case MSS_UART_INVALID_LOOPBACK:
/* Fall through to default. */
default:
ASSERT(0);
break;
}
}
}
/***************************************************************************//**
* UART0 interrupt service routine.
* UART0_IRQHandler is included within the Cortex-M3 vector table as part of the
* Fusion 2 CMSIS.
*/
#if defined(__GNUC__)
__attribute__((__interrupt__)) void UART0_IRQHandler(void)
#else
void UART0_IRQHandler(void)
#endif
{
MSS_UART_isr(&g_mss_uart0);
}
/***************************************************************************//**
* UART1 interrupt service routine.
* UART2_IRQHandler is included within the Cortex-M3 vector table as part of the
* Fusion 2 CMSIS.
*/
#if defined(__GNUC__)
__attribute__((__interrupt__)) void UART1_IRQHandler(void)
#else
void UART1_IRQHandler(void)
#endif
{
MSS_UART_isr(&g_mss_uart1);
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_rxstatus_handler
(
mss_uart_instance_t * this_uart,
mss_uart_irq_handler_t handler
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(handler != INVALID_IRQ_HANDLER);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(handler != INVALID_IRQ_HANDLER))
{
this_uart->linests_handler = handler;
/* Clear any previously pended interrupts */
NVIC_ClearPendingIRQ(this_uart->irqn);
/* Enable receiver line status interrupt. */
set_bit_reg8(&this_uart->hw_reg->IER,ELSI);
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
NVIC_EnableIRQ(this_uart->irqn);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_tx_handler
(
mss_uart_instance_t * this_uart,
mss_uart_irq_handler_t handler
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(handler != INVALID_IRQ_HANDLER);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(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;
/* Clear any previously pended interrupts */
NVIC_ClearPendingIRQ(this_uart->irqn);
/* Enable transmitter holding register Empty interrupt. */
set_bit_reg8(&this_uart->hw_reg->IER,ETBEI);
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
NVIC_EnableIRQ(this_uart->irqn);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_modemstatus_handler
(
mss_uart_instance_t * this_uart,
mss_uart_irq_handler_t handler
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(handler != INVALID_IRQ_HANDLER);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(handler != INVALID_IRQ_HANDLER))
{
this_uart->modemsts_handler = handler;
/* Clear any previously pended interrupts */
NVIC_ClearPendingIRQ(this_uart->irqn);
/* Enable modem status interrupt. */
set_bit_reg8(&this_uart->hw_reg->IER,EDSSI);
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
NVIC_EnableIRQ(this_uart->irqn);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
size_t
MSS_UART_fill_tx_fifo
(
mss_uart_instance_t * this_uart,
const uint8_t * tx_buffer,
size_t tx_size
)
{
uint8_t status = 0u;
size_t size_sent = 0u;
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
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(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(tx_buffer != ((uint8_t *)0)) &&
(tx_size > 0u))
{
status = this_uart->hw_reg->LSR;
this_uart->status |= status;
if(status & MSS_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 mss_uart.h for details of how to use this function.
*/
uint8_t
MSS_UART_get_rx_status
(
mss_uart_instance_t * this_uart
)
{
uint8_t status = MSS_UART_INVALID_PARAM;
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/*
* 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 mss_uart.h for details of how to use this function.
*/
uint8_t
MSS_UART_get_modem_status
(
mss_uart_instance_t * this_uart
)
{
uint8_t status = MSS_UART_INVALID_PARAM;
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/*
* 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;
}
/***************************************************************************//**
* MSS_UART_get_tx_status.
* See mss_uart.h for details of how to use this function.
*/
uint8_t
MSS_UART_get_tx_status
(
mss_uart_instance_t * this_uart
)
{
uint8_t status = MSS_UART_TX_BUSY;
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/* 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 &= (MSS_UART_THRE | MSS_UART_TEMT);
}
return status;
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_break
(
mss_uart_instance_t * this_uart
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/* set break charecter on Tx line */
set_bit_reg8(&this_uart->hw_reg->LCR,SB);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_clear_break
(
mss_uart_instance_t * this_uart
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/* remove break charecter from Tx line */
clear_bit_reg8(&this_uart->hw_reg->LCR,SB);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_pidpei_handler
(
mss_uart_instance_t * this_uart,
mss_uart_irq_handler_t handler
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(handler != INVALID_IRQ_HANDLER);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(handler != INVALID_IRQ_HANDLER))
{
this_uart->pid_pei_handler = handler;
/* Clear any previously pended interrupts */
NVIC_ClearPendingIRQ( this_uart->irqn );
/* Enable PID parity error interrupt. */
set_bit_reg8(&this_uart->hw_reg->IEM,EPID_PEI);
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
NVIC_EnableIRQ(this_uart->irqn);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_linbreak_handler
(
mss_uart_instance_t * this_uart,
mss_uart_irq_handler_t handler
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(handler != INVALID_IRQ_HANDLER);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(handler != INVALID_IRQ_HANDLER))
{
this_uart->break_handler = handler;
/* Clear any previously pended interrupts */
NVIC_ClearPendingIRQ( this_uart->irqn );
/* Enable LIN break detection interrupt. */
set_bit_reg8(&this_uart->hw_reg->IEM,ELINBI);
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
NVIC_EnableIRQ(this_uart->irqn);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_linsync_handler
(
mss_uart_instance_t * this_uart,
mss_uart_irq_handler_t handler
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(handler != INVALID_IRQ_HANDLER);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(handler != INVALID_IRQ_HANDLER))
{
this_uart->sync_handler = handler;
/* Clear any previously pended interrupts */
NVIC_ClearPendingIRQ( this_uart->irqn );
/* Enable LIN sync detection interrupt. */
set_bit_reg8(&this_uart->hw_reg->IEM,ELINSI);
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
NVIC_EnableIRQ(this_uart->irqn);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_nack_handler
(
mss_uart_instance_t * this_uart,
mss_uart_irq_handler_t handler
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(handler != INVALID_IRQ_HANDLER);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(handler != INVALID_IRQ_HANDLER))
{
this_uart->nack_handler = handler;
/* Clear any previously pended interrupts */
NVIC_ClearPendingIRQ( this_uart->irqn );
/* Enable LIN sync detection interrupt. */
set_bit_reg8(&this_uart->hw_reg->IEM,ENACKI);
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
NVIC_EnableIRQ(this_uart->irqn);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_rx_timeout_handler
(
mss_uart_instance_t * this_uart,
mss_uart_irq_handler_t handler
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(handler != INVALID_IRQ_HANDLER);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(handler != INVALID_IRQ_HANDLER))
{
this_uart->rto_handler = handler;
/* Clear any previously pended interrupts */
NVIC_ClearPendingIRQ( this_uart->irqn );
/* Enable receiver timeout interrupt. */
set_bit_reg8(&this_uart->hw_reg->IEM,ERTOI);
/* Enable UART instance interrupt in Cortex-M3 NVIC. */
NVIC_EnableIRQ(this_uart->irqn);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_enable_half_duplex
(
mss_uart_instance_t * this_uart
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/* enable single wire half-duplex mode */
set_bit_reg8(&this_uart->hw_reg->MM2,ESWM);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_disable_half_duplex
(
mss_uart_instance_t * this_uart
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/* enable single wire half-duplex mode */
clear_bit_reg8(&this_uart->hw_reg->MM2,ESWM);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_rx_endian
(
mss_uart_instance_t * this_uart,
mss_uart_endian_t endian
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(MSS_UART_INVALID_ENDIAN > endian);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(MSS_UART_INVALID_ENDIAN > endian))
{
/* Configure MSB first / LSB first for receiver */
((MSS_UART_LITTLEEND == endian) ? (clear_bit_reg8(&this_uart->hw_reg->MM1,E_MSB_RX)) :
(set_bit_reg8(&this_uart->hw_reg->MM1,E_MSB_RX)));
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_tx_endian
(
mss_uart_instance_t * this_uart,
mss_uart_endian_t endian
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(MSS_UART_INVALID_ENDIAN > endian);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(MSS_UART_INVALID_ENDIAN > endian))
{
/* Configure MSB first / LSB first for transmitter */
((MSS_UART_LITTLEEND == endian) ? (clear_bit_reg8(&this_uart->hw_reg->MM1,E_MSB_TX)) :
(set_bit_reg8(&this_uart->hw_reg->MM1,E_MSB_TX)) ) ;
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_filter_length
(
mss_uart_instance_t * this_uart,
mss_uart_filter_length_t length
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(MSS_UART_INVALID_FILTER_LENGTH > length);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(MSS_UART_INVALID_FILTER_LENGTH > length))
{
/* Configure glitch filter length */
this_uart->hw_reg->GFR = (uint8_t)length;
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_enable_afm
(
mss_uart_instance_t * this_uart
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/* Disable RX FIFO till address flag with correct address is received */
set_bit_reg8(&this_uart->hw_reg->MM2,EAFM);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_disable_afm
(
mss_uart_instance_t * this_uart
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/* Enable RX FIFO irrespective of address flag and
correct address is received */
clear_bit_reg8(&this_uart->hw_reg->MM2,EAFM);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_enable_afclear
(
mss_uart_instance_t * this_uart
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/* Enable address flag clearing */
/* Disable RX FIFO till another address flag with
correct address is received */
set_bit_reg8(&this_uart->hw_reg->MM2,EAFC);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_disable_afclear
(
mss_uart_instance_t * this_uart
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/* Disable address flag clearing */
clear_bit_reg8(&this_uart->hw_reg->MM2,EAFC);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_enable_rx_timeout
(
mss_uart_instance_t * this_uart,
uint8_t timeout
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/* Load the receive timeout value */
this_uart->hw_reg->RTO = timeout;
/*Enable receiver time-out */
set_bit_reg8(&this_uart->hw_reg->MM0,ERTO);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_disable_rx_timeout
(
mss_uart_instance_t * this_uart
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/*Disable receiver time-out */
clear_bit_reg8(&this_uart->hw_reg->MM0,ERTO);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_enable_tx_time_guard
(
mss_uart_instance_t * this_uart,
uint8_t timeguard
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/* Load the transmitter time guard value */
this_uart->hw_reg->TTG = timeguard;
/*Enable transmitter time guard */
set_bit_reg8(&this_uart->hw_reg->MM0,ETTG);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_disable_tx_time_guard
(
mss_uart_instance_t * this_uart
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
/*Disable transmitter time guard */
clear_bit_reg8(&this_uart->hw_reg->MM0,ETTG);
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_address
(
mss_uart_instance_t * this_uart,
uint8_t address
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
this_uart->hw_reg->ADR = address;
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_ready_mode
(
mss_uart_instance_t * this_uart,
mss_uart_ready_mode_t mode
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(MSS_UART_INVALID_READY_MODE > mode);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(MSS_UART_INVALID_READY_MODE > mode ) )
{
/* Configure mode 0 or mode 1 for TXRDY and RXRDY */
((MSS_UART_READY_MODE0 == mode) ? clear_bit_reg8(&this_uart->hw_reg->FCR,RDYMODE) :
set_bit_reg8(&this_uart->hw_reg->FCR,RDYMODE) );
}
}
/***************************************************************************//**
* Configure baud divisors using fractional baud rate if possible.
*/
static void
config_baud_divisors
(
mss_uart_instance_t * this_uart,
uint32_t baudrate
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
uint32_t baud_value;
uint32_t baud_value_by_64;
uint32_t baud_value_by_128;
uint32_t fractional_baud_value;
uint32_t pclk_freq;
this_uart->baudrate = baudrate;
/* Force the value of the CMSIS global variables holding the various system
* clock frequencies to be updated. */
SystemCoreClockUpdate();
if(this_uart == &g_mss_uart0)
{
pclk_freq = g_FrequencyPCLK0;
}
else
{
pclk_freq = g_FrequencyPCLK1;
}
/*
* 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 = (8u * 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)
{
if(baud_value > 1u)
{
/*
* Use Frational baud rate divisors
*/
/* set divisor latch */
set_bit_reg8(&this_uart->hw_reg->LCR,DLAB);
/* msb of baud value */
this_uart->hw_reg->DMR = (uint8_t)(baud_value >> 8);
/* lsb of baud value */
this_uart->hw_reg->DLR = (uint8_t)baud_value;
/* reset divisor latch */
clear_bit_reg8(&this_uart->hw_reg->LCR,DLAB);
/* Enable Fractional baud rate */
set_bit_reg8(&this_uart->hw_reg->MM0,EFBR);
/* Load the fractional baud rate register */
ASSERT(fractional_baud_value <= (uint32_t)UINT8_MAX);
this_uart->hw_reg->DFR = (uint8_t)fractional_baud_value;
}
else
{
/*
* Do NOT use Frational baud rate divisors.
*/
/* set divisor latch */
set_bit_reg8(&this_uart->hw_reg->LCR,DLAB);
/* msb of baud value */
this_uart->hw_reg->DMR = (uint8_t)(baud_value >> 8u);
/* lsb of baud value */
this_uart->hw_reg->DLR = (uint8_t)baud_value;
/* reset divisor latch */
clear_bit_reg8(&this_uart->hw_reg->LCR,DLAB);
/* Disable Fractional baud rate */
clear_bit_reg8(&this_uart->hw_reg->MM0,EFBR);
}
}
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
void
MSS_UART_set_usart_mode
(
mss_uart_instance_t * this_uart,
mss_uart_usart_mode_t mode
)
{
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(MSS_UART_INVALID_SYNC_MODE > mode);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(MSS_UART_INVALID_SYNC_MODE > mode))
{
/* Nothing to do for the baudrate: operates at PCLK / 2 + glitch filter length */
/* Clear the ESYN bits 2:0 */
this_uart->hw_reg->MM0 &= ~SYNC_ASYNC_MODE_MASK;
this_uart->hw_reg->MM0 |= (uint8_t)mode;
}
}
/*******************************************************************************
* Local Functions
*******************************************************************************/
/*******************************************************************************
* Global initialization for all modes
*/
static void global_init
(
mss_uart_instance_t * this_uart,
uint32_t baud_rate,
uint8_t line_config
)
{
/* The driver expects g_mss_uart0 and g_mss_uart1 to be the only
* mss_uart_instance_t instances used to identify UART0 and UART1. */
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if(this_uart == &g_mss_uart0)
{
this_uart->hw_reg = UART0;
this_uart->irqn = UART0_IRQn;
/* reset UART0 */
SYSREG->SOFT_RST_CR |= SYSREG_MMUART0_SOFTRESET_MASK;
/* Clear any previously pended UART0 interrupt */
NVIC_ClearPendingIRQ(UART0_IRQn);
/* Take UART0 out of reset. */
SYSREG->SOFT_RST_CR &= ~SYSREG_MMUART0_SOFTRESET_MASK;
}
else
{
this_uart->hw_reg = UART1;
this_uart->irqn = UART1_IRQn;
/* Reset UART1 */
SYSREG->SOFT_RST_CR |= SYSREG_MMUART1_SOFTRESET_MASK;
/* Clear any previously pended UART1 interrupt */
NVIC_ClearPendingIRQ(UART1_IRQn);
/* Take UART1 out of reset. */
SYSREG->SOFT_RST_CR &= ~SYSREG_MMUART1_SOFTRESET_MASK;
}
/* disable interrupts */
this_uart->hw_reg->IER = 0u;
/* FIFO configuration */
this_uart->hw_reg->FCR = (uint8_t)MSS_UART_FIFO_SINGLE_BYTE;
/* clear receiver FIFO */
set_bit_reg8(&this_uart->hw_reg->FCR,CLEAR_RX_FIFO);
/* clear transmitter FIFO */
set_bit_reg8(&this_uart->hw_reg->FCR,CLEAR_TX_FIFO);
/* 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. */
set_bit_reg8(&this_uart->hw_reg->FCR,RXRDY_TXRDYN_EN);
/* disable loopback : local * remote */
clear_bit_reg8(&this_uart->hw_reg->MCR,LOOP);
clear_bit_reg8(&this_uart->hw_reg->MCR,RLOOP);
/* set default TX endian */
clear_bit_reg8(&this_uart->hw_reg->MM1,E_MSB_TX);
/* set default RX endian */
clear_bit_reg8(&this_uart->hw_reg->MM1,E_MSB_RX);
/* default AFM : disabled */
clear_bit_reg8(&this_uart->hw_reg->MM2,EAFM);
/* disable TX time gaurd */
clear_bit_reg8(&this_uart->hw_reg->MM0,ETTG);
/* set default RX timeout */
clear_bit_reg8(&this_uart->hw_reg->MM0,ERTO);
/* disable fractional baud-rate */
clear_bit_reg8(&this_uart->hw_reg->MM0,EFBR);
/* disable single wire mode */
clear_bit_reg8(&this_uart->hw_reg->MM2,ESWM);
/* set filter to minimum value */
this_uart->hw_reg->GFR = 0u;
/* set default TX time gaurd */
this_uart->hw_reg->TTG = 0u;
/* set default RX timeout */
this_uart->hw_reg->RTO = 0u;
/*
* Configure baud rate divisors. This uses the frational 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;
this_uart->rto_handler = NULL_HANDLER;
this_uart->nack_handler = NULL_HANDLER;
this_uart->pid_pei_handler = NULL_HANDLER;
this_uart->break_handler = NULL_HANDLER;
this_uart->sync_handler = NULL_HANDLER;
/* Initialize the sticky status */
this_uart->status = 0u;
}
/***************************************************************************//**
* 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
* MSS_UART_set_*_handler() functions, or it will call the default_tx_handler()
* function in response to transmit interrupts if MSS_UART_irq_tx() is used to
* transmit data.
*/
static void
MSS_UART_isr
(
mss_uart_instance_t * this_uart
)
{
uint8_t iirf;
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))
{
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);
}
}
break;
case IIRF_MMI:
{
/* Identify multimode interrupts and handle */
/* Receiver time-out interrupt */
if(read_bit_reg8(&this_uart->hw_reg->IIM,ERTOI))
{
ASSERT(NULL_HANDLER != this_uart->rto_handler);
if(NULL_HANDLER != this_uart->rto_handler)
{
(*(this_uart->rto_handler))(this_uart);
}
}
/* NACK interrupt */
if(read_bit_reg8(&this_uart->hw_reg->IIM,ENACKI))
{
ASSERT(NULL_HANDLER != this_uart->nack_handler);
if(NULL_HANDLER != this_uart->nack_handler)
{
(*(this_uart->nack_handler))(this_uart);
}
}
/* PID parity error interrupt */
if(read_bit_reg8(&this_uart->hw_reg->IIM,EPID_PEI))
{
ASSERT(NULL_HANDLER != this_uart->pid_pei_handler);
if(NULL_HANDLER != this_uart->pid_pei_handler)
{
(*(this_uart->pid_pei_handler))(this_uart);
}
}
/* LIN break detection interrupt */
if(read_bit_reg8(&this_uart->hw_reg->IIM,ELINBI))
{
ASSERT(NULL_HANDLER != this_uart->break_handler);
if(NULL_HANDLER != this_uart->break_handler)
{
(*(this_uart->break_handler))(this_uart);
}
}
/* LIN Sync detection interrupt */
if(read_bit_reg8(&this_uart->hw_reg->IIM,ELINSI))
{
ASSERT(NULL_HANDLER != this_uart->sync_handler);
if(NULL_HANDLER != this_uart->sync_handler)
{
(*(this_uart->sync_handler))(this_uart);
}
}
break;
}
default:
{
ASSERT(INVALID_INTERRUPT);
}
break;
}
}
}
/***************************************************************************//**
* See mss_uart.h for details of how to use this function.
*/
static void
default_tx_handler
(
mss_uart_instance_t * this_uart
)
{
uint8_t status;
ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1));
ASSERT(( (uint8_t *)0 ) != this_uart->tx_buffer);
ASSERT(0u < this_uart->tx_buff_size);
if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) &&
(((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 & MSS_UART_THRE)
{
uint32_t i;
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(i = 0u; i < fill_size; ++i)
{
/* 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 */
clear_bit_reg8(&this_uart->hw_reg->IER,ETBEI);
}
}
}
#ifdef __cplusplus
}
#endif