ser_mcf5272_uart.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 947 行 · 第 1/3 页

C
947
字号
                       UART driver.

 INPUT:
    Pointer to the the device table.

 RETURN:
    Returns true if the initialization is successful. Otherwise, it retuns false
*/
static bool MCF5272_uart_init(struct cyg_devtab_entry * tab)
{
    serial_channel *chan = (serial_channel *)tab->priv;
    MCF5272_uart_info_t *MCF5272_uart_chan = (MCF5272_uart_info_t *)chan->dev_priv;

    #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL0

    /*   Instantiation of the  UART channel  0 data  strucutre.  This  data */
    /* structure contains channel information.                              */

    if (strcmp(tab->name, CYGDAT_IO_SERIAL_MCF5272_UART_CHANNEL0_NAME) == 0)
    {

        /*   Initiliaze the UART information data to all zeros.             */

        memset(MCF5272_uart_chan, sizeof(MCF5272_uart_info_t), 0);

        /*   Set the base  address of the  UART registers to  differentiate */
        /* itself from the different regusters for the other UART port.     */

        MCF5272_uart_chan->base = (mcf5272_sim_uart_t*)&MCF5272_SIM->uart[0];

        /*   Set the UART interrupt vector number.                          */

        MCF5272_uart_chan->uart_vector = CYGNUM_HAL_VECTOR_UART1;

        /*   Set the autobaud state to idle.                                */

        MCF5272_uart_chan->autobaud_state = AB_IDLE;

        /* Initilize the UART 0 output pins */

        MCF5272_SIM->gpio.pbcnt =  MCF5272_GPIO_PBCNT_URT0_EN |
            ((MCF5272_SIM->gpio.pbcnt) & ~MCF5272_GPIO_PBCNT_URT0_MSK);
    }
    #endif

    #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL1

    /* Instantiation of the UART channel 1 data strucutre. This data structure contains
       channel information.
     */
    if (strcmp(tab->name, CYGDAT_IO_SERIAL_MCF5272_UART_CHANNEL1_NAME) == 0)
    {

        /*   Initiliaze the UART information data to all zeros.             */

        memset(MCF5272_uart_chan, sizeof(MCF5272_uart_info_t), 0);

        /*   Set the base  address of the  UART registers to  differentiate */
        /* itself from the different regusters for the other UART port.     */

        MCF5272_uart_chan->base = (mcf5272_sim_uart_t*)&MCF5272_SIM->uart[1];

         /*   Set the UART interrupt vector number.                          */

        MCF5272_uart_chan->uart_vector = CYGNUM_HAL_VECTOR_UART2;

        /*   Set the autobaud state to idle.                                */

        MCF5272_uart_chan->autobaud_state = AB_IDLE;

        /* Initilize the UART 1 output pins */

        MCF5272_SIM->gpio.pdcnt =  MCF5272_GPIO_PDCNT_URT1_EN |
            ((MCF5272_SIM->gpio.pdcnt) & ~MCF5272_GPIO_PDCNT_URT1_MSK);

    }
    #endif


    if (chan->out_cbuf.len > 0) {

        /*   If the the buffer is greater  than zero, then the driver  will */
        /* use  interrupt  driven  I/O.   Hence,  the  driver  creates   an */
        /* interrupt context for the UART device.                           */

        cyg_drv_interrupt_create(MCF5272_uart_chan->uart_vector,
                                 MCF5272_UART_PRIORITY_LEVEL,           // Priority - Level 2
                                 (cyg_addrword_t)chan,                  //  Data item passed to interrupt handler
                                 MCF5272_uart_ISR,
                                 MCF5272_uart_DSR,
                                 &MCF5272_uart_chan->serial_interrupt_handle,
                                 &MCF5272_uart_chan->serial_interrupt);

        cyg_drv_interrupt_attach(MCF5272_uart_chan->serial_interrupt_handle);

        (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
    }

    // Configure Serial device.
    return(MCF5272_uart_config_port(chan, &chan->config));
}

/******************************************************************************************************
 MCF5272_uart_config_port() - Configure the UART port.

 Internal function to actually configure the hardware to desired baud rate, etc.

 INPUT:
    chan        - The channel information
    new_confg   - The port configuration which include the desired baud rate, etc.

 RETURN:
    Returns true if the port configuration is successful. Otherwise, it retuns false

 */
static bool MCF5272_uart_config_port(serial_channel *chan,
                                     cyg_serial_info_t *new_config)
{
    MCF5272_uart_info_t * port = (MCF5272_uart_info_t *) chan->dev_priv;
    uint8 mode_reg = 0;
    uint32 ubgs;
    unsigned int baud_divisor;


    /*   Get the  divisor  from  the  baudrate  table  which  will  use  to */
    /* configure the port's baud rate.                                      */

    baud_divisor = baud_rates_table[new_config->baud];

    /*   If the divisor is zeor, we dont' configure the port.               */

    if (baud_divisor == 0) return false;

    /*   Save the configuration value for later use.                        */

    port->config = *new_config;

    /*   We first write the reset values into the device and then configure */
    /* the device the we way we want to use it.                             */
	
	/* Reset Transmitter */

    MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_RESET_TX);

	/* Reset Receiver */
	
    MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_RESET_RX);

	/* Reset Mode Register */
	
    MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_RESET_MR);

    /* Translate the parity configuration to UART mode bits. */

    switch(port->config.parity)
    {
    default:
    case CYGNUM_SERIAL_PARITY_NONE:
        mode_reg = 0 | MCF5272_UART_UMR1_PM_NONE;
        break;
    case CYGNUM_SERIAL_PARITY_EVEN:
        mode_reg = 0 | MCF5272_UART_UMR1_PM_EVEN;
        break;
    case CYGNUM_SERIAL_PARITY_ODD:
        mode_reg = 0 | MCF5272_UART_UMR1_PM_ODD;
        break;
    case CYGNUM_SERIAL_PARITY_MARK:
        mode_reg = 0 | MCF5272_UART_UMR1_PM_FORCE_HI;
        break;
    case CYGNUM_SERIAL_PARITY_SPACE:
        mode_reg = 0 | MCF5272_UART_UMR1_PM_FORCE_LO;
        break;
    }

    /* Translate the number of bits per character configuration to UART mode bits. */

    switch(port->config.word_length)
    {

    case CYGNUM_SERIAL_WORD_LENGTH_5:
        mode_reg |= MCF5272_UART_UMR1_BC_5;
        break;
    case CYGNUM_SERIAL_WORD_LENGTH_6:
        mode_reg |= MCF5272_UART_UMR1_BC_6;
        break;
    case CYGNUM_SERIAL_WORD_LENGTH_7:
        mode_reg |= MCF5272_UART_UMR1_BC_7;
        break;
    default:
    case CYGNUM_SERIAL_WORD_LENGTH_8:
        mode_reg |= MCF5272_UART_UMR1_BC_8;
        break;
    }

   	/* Configure the parity and the bits per character */
	
    MCF5272_UART_WRITE(port->base->umr, mode_reg);

    /* Translate the stop bit length to UART mode bits. */

    switch(port->config.stop)
    {
    default:
    case CYGNUM_SERIAL_STOP_1:
        mode_reg = MCF5272_UART_UMR2_STOP_BITS_1;
        break;
    case CYGNUM_SERIAL_STOP_1_5:
        mode_reg = MCF5272_UART_UMR2_STOP_BITS_15;
        break;
    case CYGNUM_SERIAL_STOP_2:
        mode_reg = MCF5272_UART_UMR2_STOP_BITS_2;
        break;
    }

	/* No echo or loopback */
	
    MCF5272_UART_WRITE(port->base->umr, 0 | MCF5272_UART_UMR2_CM_NORMAL | mode_reg);

	/* Set Rx and Tx baud by timer */
	
    MCF5272_UART_WRITE(port->base->ucr, 0 | MCF5272_UART_UCSR_RCS(0xD) |
                       MCF5272_UART_UCSR_TCS(0xD));

	/* Mask all USART interrupts */
	
    MCF5272_UART_WRITE(port->base->uisr_uimr, 0);

	/* Calculate baud settings */
	
    ubgs = (uint16)((CYGHWR_HAL_SYSTEM_CLOCK_MHZ*1000000)/
                    (baud_divisor * 32));

    /*   Program the baud settings to the device.                           */

	MCF5272_UART_WRITE(port->base->udu, (uint8)((ubgs & 0xFF00) >> 8));
	MCF5272_UART_WRITE(port->base->udl, (uint8)(ubgs & 0x00FF));

	/* Enable receiver and transmitter */

    MCF5272_UART_WRITE(port->base->ucr, 0 | MCF5272_UART_UCR_TXRXEN);

    /* Enable both transmit and receive interrupt. */

    port->imr_mirror = MCF5272_UART_UIMR_TXRDY | MCF5272_UART_UIMR_FFULL |
                       MCF5272_UART_UIMR_DB;
    MCF5272_UART_WRITE(port->base->uisr_uimr, port->imr_mirror);

    return true; /* Returns true to indicate a successful configuration */

}

/*******************************************************************************
 MCF5272_uart_lookup() - This routine is called when the device is "looked" up
                        (i.e. attached)

 INPUT:
    tab - pointer to a pointer of the device table
    sub_tab - Pointer to the sub device table.
    name - name of the device

 RETURN:
    always return ENOERR

*/
static Cyg_ErrNo MCF5272_uart_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;
}

/*******************************************************************************
 MCF5272_uart_putc() - Send a character to the device output buffer.

 INPUT:
    chan - pointer to the serial private data.
    c    - the character to output

 RETURN:
    'true' if character is sent to device, return 'false' when we've
    ran out of buffer space in the device itself.

*/

static bool MCF5272_uart_putc(serial_channel *chan, unsigned char c)
{
    CYG_INTERRUPT_STATE int_state;
    MCF5272_uart_info_t *port = (MCF5272_uart_info_t *)chan->dev_priv;

    /* Make sure the transmitter is not full. If it is full, return false. */
    if  (!(MCF5272_UART_READ(port->base->usr_ucsr) & MCF5272_UART_USR_TXRDY))
        return false;

    /* Enable transmit interrupt. */
    HAL_DISABLE_INTERRUPTS(int_state);
    port->imr_mirror |= MCF5272_UART_UIMR_TXRDY;
    MCF5272_UART_WRITE(port->base->uisr_uimr, port->imr_mirror);
    HAL_RESTORE_INTERRUPTS(int_state);

    /* Enable the UART transmit. */
    MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_TXRXEN);

	/* Send the character */
    MCF5272_UART_WRITE(port->base->urb_utb, c);

	return true ;
}


/******************************************************************************************************
 MCF5272_uart_getc() - Fetch a character from the device input bufferand return it to the alling
                       routine. Wait until there is a character ready.

 INPUT:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?