tx3904_serial.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 758 行 · 第 1/2 页
C
758 行
{
cyg_count32 i,j,k;
for( i = 0; i < clock_loop; i++ )
for( j = 0; j < div_loop; j++ )
for( k = 0; k < bit_time; k++ )
continue;
}
}
//-------------------------------------------------------------------------
static bool
tx3904_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
{
tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
cyg_uint16 cr = 0;
cyg_uint16 icr = 0;
cyg_uint16 baud_divisor = select_baud[new_config->baud];
if (baud_divisor == 0)
return false; // Invalid baud rate selected
// set up other config values:
cr |= select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5];
cr |= select_stop_bits[new_config->stop];
cr |= select_parity[new_config->parity];
// Source transfer clock from BRG
cr |= LCR_BRG;
#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
// Enable RX interrupts only at present
#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
if ((chan->out_cbuf.len != 0) || (chan == &tx3904_serial_channel0)) {
#else
if (chan->out_cbuf.len != 0) {
#endif
icr |= ICR_RXE;
}
#endif
// Avoid any interrupts while we are fiddling with the line parameters.
cyg_drv_interrupt_mask(tx3904_chan->int_num);
// In theory we should wait here for the transmitter to drain the
// FIFO so we dont change the line parameters with characters
// unsent. Unfortunately the TX39 serial devices do not allow us
// to discover when the FIFO is empty.
delay_char_time(tx3904_chan, 8);
// Disable device entirely.
// HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_CR, 0);
// HAL_WRITE_UINT8(tx3904_chan->base+SERIAL_ICR, 0);
// Reset the FIFOs
HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_FCR, 7);
HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_FCR, 0);
// Set up baud rate
HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_BRG, baud_divisor );
// Write CR into hardware
HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_CR, cr);
// Write ICR into hardware
HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_ICR, icr);
// Re-enable interrupts.
cyg_drv_interrupt_unmask(tx3904_chan->int_num);
// Save current baud rate
tx3904_chan->cur_baud = new_config->baud;
if (new_config != &chan->config) {
chan->config = *new_config;
}
return true;
}
//-------------------------------------------------------------------------
// Function to initialize the device. Called at bootstrap time.
bool tx3904_serial_init(struct cyg_devtab_entry *tab)
{
serial_channel *chan = (serial_channel *)tab->priv;
tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
(chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
tx3904_chan->cur_baud = CYGNUM_SERIAL_BAUD_38400;
#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
if (chan->out_cbuf.len != 0) {
// Install and enable the interrupt
cyg_drv_interrupt_create(tx3904_chan->int_num,
4, // Priority
(cyg_addrword_t)chan, // Data item passed to interrupt handler
(cyg_ISR_t *)tx3904_serial_ISR,
tx3904_serial_DSR,
&tx3904_chan->interrupt_handle,
&tx3904_chan->interrupt);
cyg_drv_interrupt_attach(tx3904_chan->interrupt_handle);
cyg_drv_interrupt_unmask(tx3904_chan->int_num);
}
#endif
tx3904_serial_config_port(chan, &chan->config, true);
return true;
}
//-------------------------------------------------------------------------
// This routine is called when the device is "looked" up (i.e. attached)
static Cyg_ErrNo
tx3904_serial_lookup(struct cyg_devtab_entry **tab,
struct cyg_devtab_entry *sub_tab,
const char *name)
{
serial_channel *chan = (serial_channel *)(*tab)->priv;
(chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
return ENOERR;
}
//-------------------------------------------------------------------------
// Return 'true' if character is sent to device
bool
tx3904_serial_putc(serial_channel *chan, unsigned char c)
{
tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
cyg_uint16 isr;
HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
if( isr & ISR_TXRDY )
{
HAL_WRITE_UINT8( tx3904_chan->base+SERIAL_TXB, c );
isr &= ~ISR_TXRDY;
HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
return true;
}
else return false;
}
//-------------------------------------------------------------------------
unsigned char
tx3904_serial_getc(serial_channel *chan)
{
unsigned char c;
tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
cyg_uint16 isr;
do
{
HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
// Eliminate any RX errors
if( isr & ISR_ERROR )
{
cyg_uint16 sr = 0;
isr &= ISR_ERROR;
// HAL_READ_UINT16( tx3904_chan->base+SERIAL_SR, sr );
HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_SR, sr );
HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
}
} while( (isr & ISR_RXRDY) != ISR_RXRDY );
HAL_READ_UINT8( tx3904_chan->base+SERIAL_RXB, c );
isr &= ~ISR_RXRDY;
HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
return c;
}
//-------------------------------------------------------------------------
static Cyg_ErrNo
tx3904_serial_set_config(serial_channel *chan, cyg_uint32 key,
const void *xbuf, cyg_uint32 *len)
{
switch (key) {
case CYG_IO_SET_CONFIG_SERIAL_INFO:
{
cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
if ( *len < sizeof(cyg_serial_info_t) ) {
return -EINVAL;
}
*len = sizeof(cyg_serial_info_t);
if ( true != tx3904_serial_config_port(chan, config, false) )
return -EINVAL;
}
break;
default:
return -EINVAL;
}
return ENOERR;
}
//-------------------------------------------------------------------------
// Enable the transmitter on the device
static void
tx3904_serial_start_xmit(serial_channel *chan)
{
#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
cyg_uint16 icr;
HAL_READ_UINT16( tx3904_chan->base+SERIAL_ICR, icr );
icr |= ICR_TXE;
HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ICR, icr );
#endif
}
//-------------------------------------------------------------------------
// Disable the transmitter on the device
static void
tx3904_serial_stop_xmit(serial_channel *chan)
{
#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
cyg_uint16 icr;
HAL_READ_UINT16( tx3904_chan->base+SERIAL_ICR, icr );
icr &= ~ICR_TXE;
HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ICR, icr );
#endif
}
//-------------------------------------------------------------------------
// Serial I/O - low level interrupt handlers (ISR)
#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
static cyg_uint32
tx3904_serial_ISR(cyg_vector_t vector, cyg_addrword_t data, cyg_addrword_t *regs)
{
serial_channel *chan = (serial_channel *)data;
tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
cyg_uint8 isr;
cyg_uint32 result = 0;
cyg_drv_interrupt_mask(tx3904_chan->int_num);
cyg_drv_interrupt_acknowledge(tx3904_chan->int_num);
HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
// Eliminate any RX errors
if( isr & ISR_ERROR )
{
cyg_uint16 sr = 0;
isr &= ~ISR_ERROR;
HAL_READ_UINT16( tx3904_chan->base+SERIAL_SR, sr );
HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_SR, 0 );
}
// Check for a TX interrupt and set the flag if so.
if( isr & ISR_TXRDY )
{
isr &= ~ISR_TXRDY;
tx3904_chan->output_ready = true;
result |= CYG_ISR_CALL_DSR; // Cause DSR to be run
}
// Check here for an RX interrupt and fetch the character. If it
// is a ^C then call into GDB stub to handle it.
if( isr & ISR_RXRDY )
{
cyg_uint8 rxb;
HAL_READ_UINT8( tx3904_chan->base+SERIAL_RXB, rxb );
isr &= ~ISR_RXRDY;
if( cyg_hal_is_break( &rxb , 1 ) )
cyg_hal_user_break( regs );
else
{
tx3904_chan->input_char = rxb;
tx3904_chan->input_char_valid = true;
result |= CYG_ISR_CALL_DSR; // Cause DSR to be run
}
}
HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
return result;
}
#endif
//-------------------------------------------------------------------------
// Serial I/O - high level interrupt handler (DSR)
#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
static void
tx3904_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *)data;
tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
cyg_uint8 isr;
HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
if( tx3904_chan->input_char_valid )
{
(chan->callbacks->rcv_char)(chan, tx3904_chan->input_char);
tx3904_chan->input_char_valid = false;
#if 0
// And while we are here, pull any further characters out of the
// FIFO. This should help to reduce the interrupt rate.
HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
while( isr & ISR_RXRDY )
{
cyg_uint8 rxb;
HAL_READ_UINT8( tx3904_chan->base+SERIAL_RXB, rxb );
(chan->callbacks->rcv_char)(chan, rxb);
isr &= ~ISR_RXRDY;
HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
}
#endif
}
if( tx3904_chan->output_ready )
{
(chan->callbacks->xmt_char)(chan);
tx3904_chan->output_ready = false;
}
cyg_drv_interrupt_unmask(tx3904_chan->int_num);
}
#endif
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904
//-------------------------------------------------------------------------
// EOF tx3904_serial.c
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?