mn10300_serial.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,037 行 · 第 1/3 页
C
1,037 行
{ 0, 0 }, // 1800
{ 0, 0 }, // 2400
{ 0, 0 }, // 3600
{ 110, 56 }, // 4800
{ 0, 0 }, // 7200
{ 110, 28 }, // 9600
{ 0, 0 }, // 14400
{ 71, 21 }, // 19200
{ 102, 7 }, // 38400
{ 0, 0 }, // 57600
{ 9, 26 }, // 115200
{ 0, 0 }, // 230400
};
#else
#error Unsupported MN10300 variant
#endif
//-------------------------------------------------------------------------
// Info for each serial device controlled
typedef struct mn10300_serial_info {
CYG_ADDRWORD base;
CYG_ADDRWORD timer_base;
CYG_WORD timer_select;
CYG_WORD rx_int;
CYG_WORD tx_int;
cyg_bool is_serial2;
cyg_interrupt rx_interrupt;
cyg_interrupt tx_interrupt;
cyg_handle_t rx_interrupt_handle;
cyg_handle_t tx_interrupt_handle;
#ifdef CYG_HAL_MN10300_SERIAL_RX_FIFO
volatile cyg_int32 fifo_head;
volatile cyg_int32 fifo_tail;
volatile cyg_uint8 fifo[16];
#endif
} mn10300_serial_info;
//-------------------------------------------------------------------------
// Callback functions exported by this driver
static SERIAL_FUNS(mn10300_serial_funs,
mn10300_serial_putc,
mn10300_serial_getc,
mn10300_serial_set_config,
mn10300_serial_start_xmit,
mn10300_serial_stop_xmit
);
//-------------------------------------------------------------------------
// Hardware info for each serial line
#ifndef CYGPKG_HAL_MN10300_AM31_STDEVAL1
#ifdef CYGPKG_IO_SERIAL_MN10300_SERIAL0
static mn10300_serial_info mn10300_serial_info0 = {
SERIAL0_BASE,
TIMER0_BASE,
SERIAL0_TIMER_SELECT,
CYGNUM_HAL_INTERRUPT_SERIAL_0_RX,
CYGNUM_HAL_INTERRUPT_SERIAL_0_TX,
false
};
#if CYGNUM_IO_SERIAL_MN10300_SERIAL0_BUFSIZE > 0
static unsigned char mn10300_serial_out_buf0[CYGNUM_IO_SERIAL_MN10300_SERIAL0_BUFSIZE];
static unsigned char mn10300_serial_in_buf0[CYGNUM_IO_SERIAL_MN10300_SERIAL0_BUFSIZE];
#endif
#endif // CYGPKG_IO_SERIAL_MN10300_SERIAL0
#endif
#ifdef CYGPKG_IO_SERIAL_MN10300_SERIAL1
static mn10300_serial_info mn10300_serial_info1 = {
SERIAL1_BASE,
TIMER1_BASE,
SERIAL1_TIMER_SELECT,
CYGNUM_HAL_INTERRUPT_SERIAL_1_RX,
CYGNUM_HAL_INTERRUPT_SERIAL_1_TX,
false
};
#if CYGNUM_IO_SERIAL_MN10300_SERIAL1_BUFSIZE > 0
static unsigned char mn10300_serial_out_buf1[CYGNUM_IO_SERIAL_MN10300_SERIAL1_BUFSIZE];
static unsigned char mn10300_serial_in_buf1[CYGNUM_IO_SERIAL_MN10300_SERIAL1_BUFSIZE];
#endif
#endif // CYGPKG_IO_SERIAL_MN10300_SERIAL1
#ifdef CYGPKG_IO_SERIAL_MN10300_SERIAL2
static mn10300_serial_info mn10300_serial_info2 = {
SERIAL2_BASE,
TIMER2_BASE,
SERIAL2_TIMER_SELECT,
CYGNUM_HAL_INTERRUPT_SERIAL_2_RX,
CYGNUM_HAL_INTERRUPT_SERIAL_2_TX,
true
};
#if CYGNUM_IO_SERIAL_MN10300_SERIAL2_BUFSIZE > 0
static unsigned char mn10300_serial_out_buf2[CYGNUM_IO_SERIAL_MN10300_SERIAL2_BUFSIZE];
static unsigned char mn10300_serial_in_buf2[CYGNUM_IO_SERIAL_MN10300_SERIAL2_BUFSIZE];
#endif
#endif // CYGPKG_IO_SERIAL_MN10300_SERIAL2
//-------------------------------------------------------------------------
// Channel descriptions:
#ifdef CYGPKG_IO_SERIAL_MN10300_POLLED_MODE
#define SIZEOF_BUF(_x_) 0
#else
#define SIZEOF_BUF(_x_) sizeof(_x_)
#endif
#ifndef CYGPKG_HAL_MN10300_AM31_STDEVAL1
#ifdef CYGPKG_IO_SERIAL_MN10300_SERIAL0
#if CYGNUM_IO_SERIAL_MN10300_SERIAL0_BUFSIZE > 0
static SERIAL_CHANNEL_USING_INTERRUPTS(mn10300_serial_channel0,
mn10300_serial_funs,
mn10300_serial_info0,
CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MN10300_SERIAL0_BAUD),
CYG_SERIAL_STOP_DEFAULT,
CYG_SERIAL_PARITY_DEFAULT,
CYG_SERIAL_WORD_LENGTH_DEFAULT,
CYG_SERIAL_FLAGS_DEFAULT,
&mn10300_serial_out_buf0[0],
SIZEOF_BUF(mn10300_serial_out_buf0),
&mn10300_serial_in_buf0[0],
SIZEOF_BUF(mn10300_serial_in_buf0)
);
#else
static SERIAL_CHANNEL(mn10300_serial_channel0,
mn10300_serial_funs,
mn10300_serial_info0,
CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MN10300_SERIAL0_BAUD),
CYG_SERIAL_STOP_DEFAULT,
CYG_SERIAL_PARITY_DEFAULT,
CYG_SERIAL_WORD_LENGTH_DEFAULT,
CYG_SERIAL_FLAGS_DEFAULT
);
#endif
#endif // CYGPKG_IO_SERIAL_MN10300_SERIAL0
#endif
#ifdef CYGPKG_IO_SERIAL_MN10300_SERIAL1
#if CYGNUM_IO_SERIAL_MN10300_SERIAL1_BUFSIZE > 0
static SERIAL_CHANNEL_USING_INTERRUPTS(mn10300_serial_channel1,
mn10300_serial_funs,
mn10300_serial_info1,
CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MN10300_SERIAL1_BAUD),
CYG_SERIAL_STOP_DEFAULT,
CYG_SERIAL_PARITY_DEFAULT,
CYG_SERIAL_WORD_LENGTH_DEFAULT,
CYG_SERIAL_FLAGS_DEFAULT,
&mn10300_serial_out_buf1[0],
SIZEOF_BUF(mn10300_serial_out_buf1),
&mn10300_serial_in_buf1[0],
SIZEOF_BUF(mn10300_serial_in_buf1)
);
#else
static SERIAL_CHANNEL(mn10300_serial_channel1,
mn10300_serial_funs,
mn10300_serial_info1,
CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MN10300_SERIAL1_BAUD),
CYG_SERIAL_STOP_DEFAULT,
CYG_SERIAL_PARITY_DEFAULT,
CYG_SERIAL_WORD_LENGTH_DEFAULT,
CYG_SERIAL_FLAGS_DEFAULT
);
#endif
#endif // CYGPKG_IO_SERIAL_MN10300_SERIAL1
#ifdef CYGPKG_IO_SERIAL_MN10300_SERIAL2
#if CYGNUM_IO_SERIAL_MN10300_SERIAL2_BUFSIZE > 0
static SERIAL_CHANNEL_USING_INTERRUPTS(mn10300_serial_channel2,
mn10300_serial_funs,
mn10300_serial_info2,
CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MN10300_SERIAL2_BAUD),
CYG_SERIAL_STOP_DEFAULT,
CYG_SERIAL_PARITY_DEFAULT,
CYG_SERIAL_WORD_LENGTH_DEFAULT,
CYG_SERIAL_FLAGS_DEFAULT,
&mn10300_serial_out_buf2[0],
SIZEOF_BUF(mn10300_serial_out_buf2),
&mn10300_serial_in_buf2[0],
SIZEOF_BUF(mn10300_serial_in_buf2)
);
#else
static SERIAL_CHANNEL(mn10300_serial_channel2,
mn10300_serial_funs,
mn10300_serial_info2,
CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MN10300_SERIAL2_BAUD),
CYG_SERIAL_STOP_DEFAULT,
CYG_SERIAL_PARITY_DEFAULT,
CYG_SERIAL_WORD_LENGTH_DEFAULT,
CYG_SERIAL_FLAGS_DEFAULT
);
#endif
#endif // CYGPKG_IO_SERIAL_MN10300_SERIAL2
//-------------------------------------------------------------------------
// And finally, the device table entries:
#ifndef CYGPKG_HAL_MN10300_AM31_STDEVAL1
#ifdef CYGPKG_IO_SERIAL_MN10300_SERIAL0
// On the standard eval board serial0 is not connected. If enabled, it
// generates continuous frame error and overrun interrupts. Hence we do
// not touch it.
DEVTAB_ENTRY(mn10300_serial_io0,
CYGDAT_IO_SERIAL_MN10300_SERIAL0_NAME,
0, // Does not depend on a lower level interface
&cyg_io_serial_devio,
mn10300_serial_init,
mn10300_serial_lookup, // Serial driver may need initializing
&mn10300_serial_channel0
);
#endif // CYGPKG_IO_SERIAL_MN10300_SERIAL0
#endif
#ifdef CYGPKG_IO_SERIAL_MN10300_SERIAL1
DEVTAB_ENTRY(mn10300_serial_io1,
CYGDAT_IO_SERIAL_MN10300_SERIAL1_NAME,
0, // Does not depend on a lower level interface
&cyg_io_serial_devio,
mn10300_serial_init,
mn10300_serial_lookup, // Serial driver may need initializing
&mn10300_serial_channel1
);
#endif // CYGPKG_IO_SERIAL_MN10300_SERIAL1
#ifdef CYGPKG_IO_SERIAL_MN10300_SERIAL2
DEVTAB_ENTRY(mn10300_serial_io2,
CYGDAT_IO_SERIAL_MN10300_SERIAL2_NAME,
0, // Does not depend on a lower level interface
&cyg_io_serial_devio,
mn10300_serial_init,
mn10300_serial_lookup, // Serial driver may need initializing
&mn10300_serial_channel2
);
#endif // CYGPKG_IO_SERIAL_MN10300_SERIAL2
//-------------------------------------------------------------------------
// Read the serial line's status register. Serial 2 has an 8 bit status
// register while serials 0 and 1 have 16 bit registers. This function
// uses the correct size access, but passes back a 16 bit quantity for
// both.
static cyg_uint16 mn10300_read_sr( mn10300_serial_info *mn10300_chan )
{
cyg_uint16 sr = 0;
if( mn10300_chan->is_serial2 )
{
cyg_uint8 sr8;
HAL_READ_UINT8(mn10300_chan->base+SERIAL_STR, sr8);
sr = sr8;
}
else
{
HAL_READ_UINT16(mn10300_chan->base+SERIAL_STR, sr);
}
return sr;
}
//-------------------------------------------------------------------------
static bool
mn10300_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
{
mn10300_serial_info *mn10300_chan = (mn10300_serial_info *)chan->dev_priv;
cyg_uint16 cr = 0;
cyg_uint16 sr;
// wait for the device to become quiescent. This could take some time
// if the device had been transmitting at a low baud rate.
do {
sr = mn10300_read_sr(mn10300_chan);
} while (sr & (SR_RXF|SR_TXF));
// Disable device entirely.
HAL_WRITE_UINT16(mn10300_chan->base+SERIAL_CTR, 0);
// Set up the Interrupt Mode Register
HAL_WRITE_UINT8(mn10300_chan->base+SERIAL_ICR, 0);
// Set up baud rate
if( mn10300_chan->is_serial2 )
{
// Serial 2 is a bit different from 0 and 1 in the way that the
// baud rate is controlled.
cyg_uint8 baud_divisor = select_baud_2[new_config->baud].timer2_val;
if (baud_divisor == 0)
return false; // Invalid baud rate selected
HAL_WRITE_UINT8(mn10300_chan->timer_base+TIMER_BR, baud_divisor);
HAL_WRITE_UINT8(mn10300_chan->timer_base+TIMER_MD, 0x80 );
baud_divisor = select_baud_2[new_config->baud].serial2_val;
HAL_WRITE_UINT8(mn10300_chan->base+SERIAL_TIM, baud_divisor);
cr |= mn10300_chan->timer_select;
}
else
{
cyg_uint16 baud_divisor = select_baud_01[new_config->baud];
cyg_uint8 timer_mode = 0x80;
if (baud_divisor == 0)
return false; // Invalid baud rate selected
#if defined(CYGPKG_HAL_MN10300_AM33)
if( baud_divisor > 255 )
{
// The AM33 runs at a higher clock rate than the AM31 and
// needs a bigger divisor for low baud rates. We do this by
// using timer 0 as a prescaler. We set it to 198 so we can then
// use it to prescale for both serial0 and serial1 if they need
// it.
static int timer0_initialized = 0;
baud_divisor /= 198;
baud_divisor--;
timer_mode = 0x84;
if( !timer0_initialized )
{
timer0_initialized = 1;
HAL_WRITE_UINT8(HW_TIMER0+TIMER_BR, 198 );
HAL_WRITE_UINT8(HW_TIMER0+TIMER_MD, 0x80 );
}
}
#endif
HAL_WRITE_UINT8(mn10300_chan->timer_base+TIMER_BR, baud_divisor);
HAL_WRITE_UINT8(mn10300_chan->timer_base+TIMER_MD, timer_mode );
cr |= mn10300_chan->timer_select;
}
#ifdef PORT3_MD
HAL_WRITE_UINT8( PORT3_MD, 0x01 );
#endif
// set up other config values:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?