⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial.c

📁 ARM入门的好帮手.包含了从简单到相对较复杂的程序.
💻 C
📖 第 1 页 / 共 2 页
字号:
    if ( ! Angel_FindParam( AP_BAUD_RATE, conf, &speed ) )
    {
        LogWarning(LOG_SERIAL, ("serial_set_params: Speed parameter not found in config\n"));
        return DE_OKAY;
    }

    switch (speed)
    {
        case 1200:
            baud_word = BAUD_DEB;
            break;

        case 9600:
            baud_word = BAUD_009;
            break;

        case 19200:
            baud_word = BAUD_019;
            break;

        case 38400:
            baud_word = BAUD_038;
            break;

        case 57600:
            baud_word = BAUD_057;
            break;

        case 115200:
            baud_word = BAUD_115;
            break;

        default:     return DE_BAD_OP;
    }

    LogInfo(LOG_SERIAL, ("serial_set_params: Speed %d (csr: 0x%x, acr: 0x%x)\n",
                         speed, baud_value, acr));

    /* Enable the transmitter to enable the TXEMPTY to be set */
    /* Has no effect if the transmitter is already enabled */
    usart_pt->US_CR = ENABLETX ;
    if ( usart_pt->US_BRGR == 0 )
    {
        usart_pt->US_BRGR = baud_word;
    }

    /* Wait for the end of transmission (interrupts must be enabled) */
    while (( usart_pt->US_CSR & TXEMPTY ) == 0 ) ;

    /* Reset the queue tx deferred flag */
    queue_tx_deferred = FALSE ;

    angel_DeviceStatus[DI_SERIAL] |= SER_TX_KICKSTART;

    /* Disable receiver and transmitter */
    usart_pt->US_CR = DISABLERX|DISABLERX  ;
    /* Check that the PDC System isn't interfering */
    usart_pt->US_RPR = 0;
    usart_pt->US_RCR = 0;
    usart_pt->US_TPR = 0;
    usart_pt->US_TPR = 0;

    /* Disable all interrupts on the USART */
    usart_pt->US_IDR = 0x3FF;
    /* Disable the USART0 interrupt */
    /* aic_pt->AIC_IDCR = 1<<IRQ_ANGEL ; */

    /* Reset the receiver and the transmitter */
    usart_pt->US_CR = RESETRX | RESETTX ;

    /* Wait for the resets to be effective : at least one bit period */
    for ( i = (usart_pt->US_BRGR*16) ; i > 0 ; i -- ) ;

    /* Enable pads as peripheral */
    *PIO_PDR_USART = PIO_USART_ANGEL ;

    usart_pt->US_MR = INTCLK   | /* Internal Clock */
                     CHAR8BIT | /* 8 bit Chars    */
                     ASYNC    | /* Asynch clock mode */
                     NOPARITY | /* No Parity */
                     STOP1BIT | /* 1 Stop Bit */
                     NORMAL;    /* Channel Mode */

    /* Disable the Reception Timeout */
    usart_pt->US_RTOR = 0 ;

    usart_pt->US_BRGR = baud_word;
    usart_pt->US_IER = OVRE | FRAME | PARE | RXRDY ;

    /* Setup the USART0 interrupt in the AIC */
    aic_pt->AIC_SMR[IRQ_ANGEL] = 0x07;
    aic_pt->AIC_SVR[IRQ_ANGEL] = (int) angel_DeviceInterruptHandler ;

    /* Re-enable the USART 0 interrupt */
    aic_pt->AIC_IECR = 1<<IRQ_ANGEL ;

    /* Enable receiver and transmitter */
    usart_pt->US_CR = ENABLETX | ENABLERX ;

    return DE_OKAY;
}


/*
 * Set the LED on the PIE board - uses serial chip controller (!!!)
 */
void set_led( char state)
{

  *PIO_PER = ( LED2BIT | LED1BIT );

  if ( state & LED1)
    *PIO_SODR = LED1BIT;


  if ( state & LED2)
    *PIO_SODR = LED2BIT;

}

/*
 * Set the LED on the PIE board - uses serial chip controller (!!!)
 */
void clear_led( char state)
{

  *PIO_PER = ( LED2BIT | LED1BIT );

  if ( state & LED1)
    *PIO_CODR = LED1BIT;


  if ( state & LED2)
    *PIO_CODR = LED2BIT;

}


/*
 * implementation of device control for serial driver
 *
 * devid is guaranteed to be in range but op is not checked as
 * individual devices can extend the range of operations
 */
static DevError serial_Control(DeviceID devid,
                               DeviceControl op, void *arg)
{
    DevError ret_code;

    LogInfo(LOG_SERIAL, ("serial_Control: op %d arg %x\n", op, arg ));

    /* we only implement the standard ones here */
    switch( op )
    {
       case DC_INIT:
           ret_code = serial_init(devid);
           break;

       case DC_RESET:
           ret_code = serial_reset(devid);
           break;

       case DC_RECEIVE_MODE:
           ret_code = serial_recv_mode(devid, (DevRecvMode)((int)arg));
           break;

       case DC_SET_PARAMS:
           ret_code = serial_set_params(devid, (const ParameterConfig *)arg);
           break;

       case DC_SET_LED:
           break;

       default:
           ret_code = DE_BAD_OP;
           break;
    }

    return ret_code;
}



/* Loop Number for a Wait of a character */
#define SR_POLL_TIMEOUT_COUNT 100

static char rx_preread_char;

/*
 *  Function: serial_rx_processing
 *   Purpose: Read a stream of characters from the unbuffered
 *            serial port
 *
 *    Params: (via args)
 *       Input: device ident of the serial device
 *
 *   Returns: Nothing
 */
static void serial_rx_processing(void *args)
{
    StructUSART *usart_pt = USART_ANGEL_BASE ;
    DeviceID    devid = (DeviceID)args;
    bool            done = FALSE ;
    bool            timeout = FALSE ;
    unsigned int i ;


    while (( timeout == FALSE ) && ( done == FALSE ))
    {
        if ( ringBufFull( &serial_rx_ring ))
        {
            LogError(LOG_SERIAL, ("rx ring buffer overflow\n" ));
            done = TRUE ;
        }
        else
        {
            /* Put the new character in the ring buffer */
            ringBufPutChar( &serial_rx_ring, rx_preread_char ) ;

            /* If character is end of packet or ring buffer is nearly full */
            if (( rx_preread_char == serial_ETX ) ||
                 (ringBufCount( &serial_rx_ring ) >= RING_HIGH_WATER_MARK ))
            {
                /* Start RX processing */
                serial_ctrl.rx_processing((void *)devid);
                /* Exit */
                done = TRUE ;
            }
            else
            {
                i = 0 ;
                /* Wait for a new character */
                while ((( usart_pt->US_CSR & RXRDY ) == 0 ) && ( i++ < SR_POLL_TIMEOUT_COUNT )) ;

                /* If timeout has occured */
                if ( i >= SR_POLL_TIMEOUT_COUNT )
                {
                    /* Exit */
                    timeout = TRUE ;
                }
                else
                {
                    /* Read received character */
                    rx_preread_char = usart_pt->US_RHR ;
                }
            }
        }
    }

    /* Reenable Receiver Interrupt */
    usart_pt->US_IER = RXRDY | FRAME | OVRE | PARE ;
}




/*
 * interrupt handler for serial driver
 */
#pragma no_check_stack

void angel_SerialIntHandler( unsigned ident, unsigned data,
                             unsigned empty_stack )
{
    StructUSART     *usart_pt = USART_ANGEL_BASE ;
    StructAIC       *aic_pt = AIC_BASE ;
    word            ser_status ;
    bool            serialize_rx = FALSE ;


    IGNORE( data );

    // Add IVR Writting for Protect Mode support
    aic_pt->AIC_IVR = (u_int) aic_pt ;

    ser_status = ( usart_pt->US_CSR & usart_pt->US_IMR ) ;

    if (( ser_status & NASTYERR ) != 0 )
    {
        LogWarning(LOG_SERIAL, ( "Nasty serial chip error %02x\n", ser_status ));
        usart_pt->US_CR =  RESETSTAT;
        if (( ser_status & (FRAME|PARE)) != 0 )
        {
            /* Remove the wrong character */
            rx_preread_char = usart_pt->US_RHR ;
            ser_status &= ~RXRDY ;
        }
    }

    if (( ser_status & RXRDY ) != 0 )
    {
        rx_preread_char = usart_pt->US_RHR ;
        serialize_rx = TRUE ;
        /* Disable Receiver Interrupt */
        usart_pt->US_IDR = RXRDY | FRAME | OVRE | PARE ;
    }

    if (( ser_status & TXRDY ) != 0 )
    {

        if ( ringBufNotEmpty( &serial_tx_ring ) )
        {
            /* send a packet char to UART */
            usart_pt->US_THR = ringBufGetChar( &serial_tx_ring ) ;

        }

#ifdef NEVER
        /*
        * if we have reached to low-water mark in the
        * ring buffer then it is time to ask for a refill,
        * as long as there is more of the packet to come
        */

        if ( ringBufCount ( &serial_tx_ring ) < 5 /*RING_LOW_WATER_MARK */)
        {
            queue_tx_deferred = TRUE;
        }
#endif

        /* is it time to give up yet? */
        if ( ringBufEmpty( &serial_tx_ring ) )
        {
            usart_pt->US_IDR = TXRDY ;
            queue_tx_deferred = TRUE;
        }

    }

    /* Signify End of Interrupt to the Interrupt Controller */
    aic_pt->AIC_EOICR = (int) aic_pt ;

    /* If receive serialization requested and receiver interrupt enabled */
    if ( serialize_rx == TRUE )
    {
        /* serialise to polled serial rx */
        Angel_SerialiseTask( 0, serial_rx_processing, (void *)DI_SERIAL, empty_stack );
    }

    /* If we got here then we may need to queue deferred tx processing */
    if ( queue_tx_deferred == TRUE )
    {
        queue_tx_deferred = FALSE ;
        Angel_SerialiseTask( 0, serial_ctrl.tx_processing, DI_SERIAL, empty_stack );
    }
}

#if PROFILE_SUPPORTED

void Angel_ProfileTimerStart(int interval)
{

  /* interval is the desired interrupt interval (in microseconds) */
  /* (we assume r0 < 2^16, and measure interval in units of 2^-20 */
  /* seconds for ease of calculation).                            */

  unsigned t1 = interval * (TimerFreq % 0x10000),
           t2 = interval * (TimerFreq / 0x10000);
  t1 = (t1 >> 20) + (t2 >> 4);
  if (t1 == 0) t1 = 1;

  AT91Serial->CTUR = t1 >> 8;
  AT91Serial->CTLR = t1 & 255;

  AT91Serial->CR = StartTimer;

  /* This needs to be atomic wrt serial driver activity */
  Angel_EnterSVC();
  IMR_set(IMRTimer);
  Angel_ExitToUSR();
}

void Angel_ProfileTimerStop(void)
{
  /* This needs to be atomic wrt serial driver activity */
  Angel_EnterSVC();
  IMR_clr(IMRTimer);
  Angel_ExitToUSR();
}

void Angel_TimerIntHandler(unsigned ident, unsigned data, unsigned empty_stack)
{
  unsigned pc = Angel_MutexSharedTempRegBlocks[0].r[15];
  IGNORE(ident);
  IGNORE(data);
  IGNORE(empty_stack);
  if (angel_profilestate.enabled) {
    unsigned *map = angel_profilestate.map;
    int size = angel_profilestate.numentries;
    int low = 0,
        high = size-1;
    if (map[low] <= pc && pc < map[high]) {
      int i;
      for (;;) {
        i = (high + low) / 2;
        if (pc >= map[i]) {
          if (pc < map[i+1]) {
            i++; break;
          } else
            low = i;
        } else if (pc >= map[i-1])
          break;
        else
          high = i;
      }
      angel_profilestate.counts[i-1]++;
    }
  }
  AT91Serial->CR = ResetTimer;  /* clear the interrupt */
}

#endif /* PROFILE_SUPPORTED */

#pragma check_stack


/* EOF serial.c */

⌨️ 快捷键说明

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