mcf5272_serial.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,138 行 · 第 1/3 页
C
1,138 行
if (chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_RX)
umr1_mask |= MCF5272_UART_UMR1_RXRTS;
else umr1_mask &= ~MCF5272_UART_UMR1_RXRTS;
if (chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_TX)
umr2_mask |= MCF5272_UART_UMR2_TXCTS;
else umr2_mask &= ~MCF5272_UART_UMR2_TXCTS;
// Reset mode register pointer
HAL_WRITE_UINT8(&port->base->ucr, MCF5272_UART_UCR_RESET_MR);
// Write mode register 1
HAL_WRITE_UINT8(&port->base->umr, umr1_mask);
// Write mode register 2
HAL_WRITE_UINT8(&port->base->umr, umr2_mask);
// Unmask UART interrupt
cyg_drv_interrupt_unmask(port->uart_vector);
}
break;
#endif // CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
default:
return EINVAL;
}
return ENOERR;
}
// ***************************************************************************
// MCF5272_uart_start_xmit() - Enable the transmitter on the device.
//
// INPUT:
// chan - pointer to the serial private data.
static void MCF5272_uart_start_xmit(serial_channel *chan)
{
MCF5272_uart_info_t *port = (MCF5272_uart_info_t *) chan->dev_priv;
// Mask UART interrupt to prevent race conditions
cyg_drv_interrupt_mask(port->uart_vector);
// Enable the UART transmitter.
// Eventually, preserve the ongoing autobaud calculation.
#ifdef REQUESTED_AUTOBAUD
if(port->autobaud_state == AB_BEGIN)
HAL_WRITE_UINT8(&port->base->ucr, (MCF5272_UART_UCR_TX_ENABLED |
MCF5272_UART_UCR_ENAB));
else
#endif
{
HAL_WRITE_UINT8(&port->base->ucr, MCF5272_UART_UCR_TX_ENABLED);
}
// Enable transmitter interrupt
port->imr_mirror |= MCF5272_UART_UIMR_TXRDY;
HAL_WRITE_UINT8(&port->base->uisr_uimr, port->imr_mirror);
// Unmask UART interrupt
cyg_drv_interrupt_unmask(port->uart_vector);
}
// ***************************************************************************
// MCF5272_uart_stop_xmit() - Disable the transmitter on the device
//
// INPUT:
// chan - pointer to the serial private data.
static void MCF5272_uart_stop_xmit(serial_channel * chan)
{
MCF5272_uart_info_t *port = (MCF5272_uart_info_t *) chan->dev_priv;
// Mask UART interrupt to prevent race conditions
cyg_drv_interrupt_mask(port->uart_vector);
// Disable transmitter interrupt
port->imr_mirror &= ~MCF5272_UART_UIMR_TXRDY;
HAL_WRITE_UINT8(&port->base->uisr_uimr, port->imr_mirror);
// Disable the UART transmitter.
// Eventually, preserve the ongoing autobaud calculation.
// !!!!!!!!!!!!!
// !!!WARNING!!!
// !!!!!!!!!!!!!
// If the transmitter is disabled
// the diag_printf routines will poll forever to transmit the
// a character. Hence, don't ever disable the transmitter if
// you want it to work with diag_printf.
#ifdef REQUESTED_AUTOBAUD
if(port->autobaud_state == AB_BEGIN)
HAL_WRITE_UINT8(&port->base->ucr, (MCF5272_UART_UCR_TX_DISABLED |
MCF5272_UART_UCR_ENAB));
else
#endif
{
HAL_WRITE_UINT8(&port->base->ucr, MCF5272_UART_UCR_TX_DISABLED);
}
// Unmask UART interrupt
cyg_drv_interrupt_unmask(port->uart_vector);
}
// ***************************************************************************
// MCF5272_uart_ISR() - UART I/O interrupt interrupt service routine (ISR).
//
// INPUT:
// vector - the interrupt vector number.
// data - user parameter.
//
// RETURN:
// returns CYG_ISR_CALL_DSR to call the DSR.
static cyg_uint32 MCF5272_uart_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *) data;
MCF5272_uart_info_t *port = (MCF5272_uart_info_t *) chan->dev_priv;
// Write the value in the interrupt status register back
// to the mask register to disable the interrupt temporarily.
HAL_WRITE_UINT8(&port->base->uisr_uimr, 0);
// Cause DSR to run
return CYG_ISR_CALL_DSR;
}
// ***************************************************************************
// MCF5272_uart_DSR() - Defered Service Routine (DSR) - This routine processes
// the interrupt from the device.
//
// INPUT:
// vector - The interrupt vector number.
// count - The nunber of DSR requests.
// data - Device specific information.
//
// The autobaud feature is implemented by means of a simple finite state
// machine which can take the following states:
// AB_DISABLED: autobaud is disabled.
// AB_IDLE: no autobaud calculation is in progress. If autobaud calculation
// has completed, retrieve the new baud rate.
// AB_BEGIN_BREAK: the start of a break character was detected.
// AB_BEGIN: the end of a break character was detected. Start autobaud
// calculation.
//
// The state diagram is the following:
// AB_IDLE --> AB_BEGIN_BREAK --> AB_BEGIN --> Back to AB_IDLE
// The state AB_DISABLED is isolated and means that the autobaud feature is
// not active for that port.
static void MCF5272_uart_DSR(cyg_vector_t vector, cyg_ucount32 count,
cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *) data;
MCF5272_uart_info_t *port = (MCF5272_uart_info_t *) chan->dev_priv;
volatile cyg_uint8 isr;
cyg_uint8 uisr_uimr;
while (1)
{
// First of all, the exit condition
// Retrieve the interrupt status bits. We use these status bits to
// figure out what process should we perform: read from the UART or
// inform of a completion of a data transmission.
HAL_READ_UINT8(&port->base->uisr_uimr, uisr_uimr);
isr = uisr_uimr & port->imr_mirror;
// If there are no more events pending, exit the loop
if (!isr) break;
#ifdef REQUESTED_AUTOBAUD
switch (port->autobaud_state)
{
case AB_DISABLED:
// Nothing to check for
break;
case AB_BEGIN_BREAK:
if (isr & MCF5272_UART_UISR_DB)
{
// Detected the end of a break, set the state to
// AB_BEGIN, and setup autobaud detection.
port->autobaud_state = AB_BEGIN;
// Initialize divider
HAL_WRITE_UINT8(&port->base->udu, 0);
HAL_WRITE_UINT8(&port->base->udl, 0);
// Reset the Delta Break bit in the UISR and
//Enable autobaud
HAL_WRITE_UINT8(&port->base->ucr,
MCF5272_UART_UCR_RESET_BKCHGINT);
HAL_WRITE_UINT8(&port->base->ucr, MCF5272_UART_UCR_ENAB);
// Enable autobaud completion interrupt
port->imr_mirror |= MCF5272_UART_UIMR_ABC;
// Disable the delta break interrupt so we can't receive
// anymore break interrupt.
port->imr_mirror &= ~MCF5272_UART_UIMR_DB;
}
break;
case AB_BEGIN:
if (isr & MCF5272_UART_UISR_ABC)
{
int count;
unsigned int threshold;
cyg_uint8 uabu, uabl;
// Retrieve the detected baud rate
HAL_READ_UINT8(&port->base->uabu, uabu);
HAL_READ_UINT8(&port->base->uabl, uabl);
cyg_uint16 divider = (uabu << 8) + uabl;
// Search in the list to find a match
for (count = sizeof(dividers_table)/
sizeof(unsigned long) - 1;
count > 1; count--)
{
if (divider < dividers_table[count - 1]) break;
}
// Modify baud rate only if it is in range
if (count > 1)
{
// Set the baud rate to the nearest standard rate
threshold = (dividers_table[count] +
dividers_table[count - 1]) / 2;
port->config.baud = (divider < threshold) ? count :
count - 1;
}
divider = dividers_table[port->config.baud];
// Program the baud settings to the device
HAL_WRITE_UINT8(&port->base->udu,
(cyg_uint8)((divider & 0xFF00) >> 8));
HAL_WRITE_UINT8(&port->base->udl,
(cyg_uint8)(divider & 0x00FF));
// Autobaud completion
port->autobaud_state = AB_IDLE;
// Disable autobaud
HAL_WRITE_UINT8(&port->base->ucr, MCF5272_UART_UCR_NONE);
#if 0
// In case patch submitted July 11, 2005 gets committed
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
// Inform upper layers of the new baud rate
{
cyg_serial_line_status_t stat;
stat.which = CYGNUM_SERIAL_STATUS_NEWBAUDRATE;
stat.value = port->config.baud;
(chan->callbacks->indicate_status)(chan, &stat);
}
#endif
#endif
// Ignore autobaud completion interrupt
port->imr_mirror &= ~MCF5272_UART_UIMR_ABC;
// Reenable delta break interrupt
port->imr_mirror |= MCF5272_UART_UIMR_DB;
}
break;
default:
case AB_IDLE:
if (isr & MCF5272_UART_UISR_DB)
{
// Detected the begin of a break, set the state to
// AB_BEGIN_BREAK
port->autobaud_state = AB_BEGIN_BREAK;
// Reset the delta break bit in the UISR
HAL_WRITE_UINT8(&port->base->ucr,
MCF5272_UART_UCR_RESET_BKCHGINT);
}
break;
}
#endif // REQUESTED_AUTOBAUD
// Receive character interrupt
if ((isr & MCF5272_UART_UISR_RXRDY))
{
char c;
cyg_uint8 usr_ucsr;
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
cyg_serial_line_status_t stat;
#endif
// Read all the characters in the fifo
while (1)
{
// First of all, the exit condition
// If there are no more characters waiting, exit the loop
HAL_READ_UINT8(&port->base->uisr_uimr, uisr_uimr);
if (!(uisr_uimr & MCF5272_UART_UISR_RXRDY)) break;
// Read port status
HAL_READ_UINT8(&port->base->usr_ucsr, usr_ucsr);
// Received break
if (usr_ucsr & MCF5272_UART_USR_RB)
{
// Ignore break character
HAL_READ_UINT8(&port->base->urb_utb, c);
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
stat.which = CYGNUM_SERIAL_STATUS_BREAK;
(chan->callbacks->indicate_status)(chan, &stat);
#endif
continue;
}
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
// Overrun error
if (usr_ucsr & MCF5272_UART_USR_OE)
{
stat.which = CYGNUM_SERIAL_STATUS_OVERRUNERR;
(chan->callbacks->indicate_status)(chan, &stat);
}
#endif
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
// Framing error
if (usr_ucsr & MCF5272_UART_USR_FE)
{
stat.which = CYGNUM_SERIAL_STATUS_FRAMEERR;
(chan->callbacks->indicate_status)(chan, &stat);
}
#endif
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
// Parity error
if (usr_ucsr & MCF5272_UART_USR_PE)
{
stat.which = CYGNUM_SERIAL_STATUS_PARITYERR;
(chan->callbacks->indicate_status)(chan, &stat);
}
#endif
// Read the character from the UART
HAL_READ_UINT8(&port->base->urb_utb, c);
// Pass the read character to the upper layer
(chan->callbacks->rcv_char)(chan, c);
}
}
// Transmit complete interrupt
if ((isr & MCF5272_UART_UISR_TXRDY))
{
// Transmit holding register is empty
(chan->callbacks->xmt_char)(chan);
}
}
// Unmask all the UART interrupts that were masked in the ISR, so
// that we can receive the next interrupt.
HAL_WRITE_UINT8(&port->base->uisr_uimr, port->imr_mirror);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?