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 + -
显示快捷键?