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

📄 lh7a404_ssp_driver.c

📁 在sharp 404开发板的串口测试代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/***********************************************************************
 * $Workfile:   lh7a404_ssp_driver.c  $
 * $Revision:   1.2  $
 * $Author:   KovitzP  $
 * $Date:   Apr 07 2004 09:59:54  $
 *
 * Project: LH7A404 SSP driver
 *
 * Description:
 *     This file contains driver support for the SSP module on the
 *     LH7A404
 *
 * Revision History:
 * $Log:   //smaicnt2/pvcs/VM/sharpmcu/archives/sharpmcu/software/csps/lh7a404/source/lh7a404_ssp_driver.c-arc  $
 * 
 *    Rev 1.2   Apr 07 2004 09:59:54   KovitzP
 * Fixed bug in SSP_SET_DATA_BITS IOCTL.
 * 
 *    Rev 1.1   Mar 15 2004 08:35:54   WellsK
 * Corrected default clock speed when device is opened.
 * 
 *    Rev 1.0   Jul 01 2003 11:06:02   WellsK
 * Initial revision.
 * 
 *
 ***********************************************************************
 * SHARP MICROELECTRONICS OF THE AMERICAS MAKES NO REPRESENTATION
 * OR WARRANTIES WITH RESPECT TO THE PERFORMANCE OF THIS SOFTWARE,
 * AND SPECIFICALLY DISCLAIMS ANY RESPONSIBILITY FOR ANY DAMAGES, 
 * SPECIAL OR CONSEQUENTIAL, CONNECTED WITH THE USE OF THIS SOFTWARE.
 *
 * SHARP MICROELECTRONICS OF THE AMERICAS PROVIDES THIS SOFTWARE SOLELY 
 * FOR THE PURPOSE OF SOFTWARE DEVELOPMENT INCORPORATING THE USE OF A 
 * SHARP MICROCONTROLLER OR SYSTEM-ON-CHIP PRODUCT. USE OF THIS SOURCE
 * FILE IMPLIES ACCEPTANCE OF THESE CONDITIONS.
 *
 * COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
 *     CAMAS, WA
 **********************************************************************/

#include "lh7a404_csc_driver.h"
#include "lh7a404_ssp_driver.h"

/***********************************************************************
 * SSP driver private data and types
 **********************************************************************/

/* Speed of SSP peripheral clock */
#define SSP_CLOCK (CLOCK_MAINOSC / 2)

/* Size of SSP transmit and receive queues (ring buffers) */
#ifndef SSP_R_SIZE
#define SSP_R_SIZE 64
#endif

/* SSP device configuration structure type */
typedef struct
{
    BOOL_32 init;          /* Device initialized flag */
    UNS_16 tx[SSP_R_SIZE]; /* SSP TX data */
    UNS_16 rx[SSP_R_SIZE]; /* SSP RX data */
    INT_32 tx_head;        /* SSP TX 'put' entry index */
    INT_32 tx_tail;        /* SSP TX 'get' entry index */
    INT_32 rx_head;        /* SSP RX 'put' entry index */
    INT_32 rx_tail;        /* SSP RX 'get' entry index */
    SSP_REGS_T *regptr;    /* Pointer to SSP registers */
} SSP_CFG_T;

/* SSP device configuration structure */
STATIC SSP_CFG_T sspcfg;

/* SSP default clock rate when initialized */
#define DEFAULT_SSP_CLOCK (CLOCK_MAINOSC / 16)

/***********************************************************************
 * SSP driver private functions
 **********************************************************************/

/***********************************************************************
 *
 * Function: ssp_set_clock
 *
 * Purpose: Sets or resets the serial clock rate of the SSP interface
 *          (in Hz)
 *
 * Processing:
 *     Set the default divider and prescaler divider values to 1. Read
 *     the existing control 0 word and mask off the clock rate bits.
 *     Compute the optimum divider valye with a call to
 *     csc_compute_divider with the target_clock frequency and the
 *     default SSP peripheral clock. If the divider is 1, update the
 *     SSP control 0 register and SSP prescaler register with values
 *     to generate the fastest SSP clock available and exit. If the
 *     computed main divider is over 254, then limit the computed
 *     main divider to 254 and compute the prescaler divider by
 *     increment the prescaler divider and testing it against the
 *     computed frequency with the main SSP divider. Before exiting,
 *     write the computed main clock divider and prescaler divider
 *     values to the SSP control 0 and prescaler registers.
 *
 * Parameters:
 *     ssp_ptr      : Pointer to SSP registers
 *     target_clock : The value in Hz for the new SSP serial clock
 *
 * Outputs: None
 *
 * Returns: Nothing
 *
 * Notes: None
 *
 **********************************************************************/
void ssp_set_clock(SSP_REGS_T *ssp_ptr, UNS_32 target_clock) /// CLOCK_MAINOSC / 16
{
    UNS_32 control, prescale, ssp_div;

    /* Always a minimum divider and prescaler value of 1 */
    ssp_div = 1;
    prescale = 1;

    /* Get existing control word with clock data and clear prescale */
    control = ssp_ptr->cr0 &= ~(SSP_CR0_SCR(255));

    /* The SSP clock is derived from the (main system oscillator / 2),
       so compute the best divider from that clock */
    ///ssp_div = csc_compute_divider(SSP_CLOCK, target_clock);

	ssp_div = SSP_CLOCK / target_clock;  ///8

    /* If divider is above 254, then the prescaler is needed also */
    if (ssp_div >= 255)
    {
        /* Limit SSP main divider to 254 (which corresponds to a 255
           divider) */
        ssp_div = 254;

        /* Find the closest target clock frequency with the prescaler */
        while ((prescale < 254) &&
            (target_clock < (SSP_CLOCK / (prescale + ssp_div + 1))))
        {
            /* Try next prescale value */
            prescale++;
        }
    }

    /* Write computed prescaler and divider back to register */
    ssp_ptr->cr0  = control | SSP_CR0_SCR(ssp_div - 1);
    ssp_ptr->cpsr = prescale;
}

/***********************************************************************
 *
 * Function: ssp_get_free_tx_count
 *
 * Purpose: Returns the number of free spaces left in the TX queue
 *
 * Processing:
 *     Compute count by subtracting the tx_tail value from the tx_head
 *     value for the transmit queue. If the value is less than 0, then
 *     compute count by subtracting tx_tail from the queue size and
 *     adding in the tx_head index. Computed the 'used' value by
 *     subtracting the (count value + 1) from the queue size and return
 *     this value to the caller.
 *
 * Parameters:
 *     sspcfgptr : Pointer to an SSP config structure
 *
 * Outputs: None
 *
 * Returns: The number of free data entries in the TX ring buffer
 *
 * Notes: None
 *
 **********************************************************************/
INT_32 ssp_get_free_tx_count(SSP_CFG_T *sspcfgptr)
{
    INT_32 count;

    count = sspcfgptr->tx_head - sspcfgptr->tx_tail;
    if (count < 0)
    {
        /* Head pointer has flipped to start of ring */
        count = (SSP_R_SIZE - sspcfgptr->tx_tail) +
            sspcfgptr->tx_head;
    }

   return (SSP_R_SIZE - count - 1);
}

/***********************************************************************
 *
 * Function: ssp_standard_receive
 *
 * Purpose: SSP data receive function
 *
 * Processing:
 *     While the receive FIFO is not empty, read the data from the FIFO
 *     and place it into the receive queue indexed by the rx_head index.
 *     Increment the rx_head index. If the rx_head_index goes past the
 *     size of the queue end index (SSP_R_SIZE), reset the rx_head_index
 *     to 0. Continue reading until the FIFO is empty.
 *
 * Parameters:
 *     sspcfgptr : Pointer to an SSP config structure
 *
 * Outputs: None
 *
 * Returns: Nothing
 *
 * Notes: None
 *
 **********************************************************************/
void ssp_standard_receive(SSP_CFG_T *sspcfgptr)
{
    SSP_REGS_T *sspregs = sspcfgptr->regptr;

    /* Is there data in the RX FIFO? */
    while ((sspregs->sr & SSP_SR_RNE) != 0)
    {
        /* Read data from SSP and put in queue */
        sspcfgptr->rx[sspcfgptr->rx_head] = (UNS_16) sspregs->dr;

        /* Increment and limit rx queue head pointer */
        sspcfgptr->rx_head++;

        /* Reindex queue to start if needed */
        if (sspcfgptr->rx_head >= SSP_R_SIZE)
        {
            sspcfgptr->rx_head = 0;
        }
    }
}

/***********************************************************************
 *
 * Function: ssp_standard_transmit
 *
 * Purpose: SSP data transmit function
 *
 * Processing:
 *     While the transmit queue is not empty and the SSP transmit FIFO
 *     has space in it, place the data value from the transmit queue
 *     indexed by tx_tail into the SSP transmit FIFO. Increment tx_tail.
 *     If tx_tail goes past the size of the queue end index
 *     (SSP_R_SIZE), reset the rx_head_index to 0. If the transmit FIFO
 *     is empty, disable the transmit FIFO service interrupt, otherwise
 *     enable it.
 *
 * Parameters:
 *     sspcfgptr : Pointer to an SSP config structure
 *
 * Outputs: None
 *
 * Returns: Nothing
 *
 * Notes: None
 *
 **********************************************************************/
void ssp_standard_transmit(SSP_CFG_T *sspcfgptr)
{
    SSP_REGS_T *sspregs = sspcfgptr->regptr;

    /* Continue until all data is sent or until TX FIFO is full */
    while ((sspcfgptr->tx_head != sspcfgptr->tx_tail) &&
        ((sspregs->sr & SSP_SR_TNF) != 0))
    {
        /* Put entry in FIFO */
        sspregs->dr = (UNS_32) sspcfgptr->tx[sspcfgptr->tx_tail];
            
        /* Index to next transmit FIFO entry */
        sspcfgptr->tx_tail++;

        /* Re-index queue to start if needed */
        if (sspcfgptr->tx_tail >= SSP_R_SIZE)
        {
            sspcfgptr->tx_tail = 0;
        }
    }

    /* If the transmit queue is empty, disable the transmit interrupt,
       otherwise enable it */
    if (sspcfgptr->tx_head == sspcfgptr->tx_tail)
    {
        /* Empty queue, no more transmit interrupts */
        sspregs->cr1 &= ~SSP_CR1_TIE;
    }
    else
    {
        /* Enable or keep transmit interrupts enabled */
        sspregs->cr1 |= SSP_CR1_TIE;
    }
}

/***********************************************************************
 *
 * Function: ssp_standard_interrupt
 *
 * Purpose: SSP standard interrupt function
 *
 * Processing:
 *     If the receive FIFO interrupt is pending, call the
 *     ssp_standard_receive function. If the transmit FIFO empty
 *     interrupt is pending, call the ssp_standard_transmit function.
 *     If the receive FIFO overrun interrupt is pending, disable and
 *     clear the receive overrun interrupt. If the transmitter idle
 *     interrupt is pending, disable the transmitter idle interrupt.
 *
 * Parameters:
 *     sspcfgptr : Pointer to an SSP config structure
 *
 * Outputs: None
 *
 * Returns: Nothing
 *
 * Notes: None
 *
 **********************************************************************/
void ssp_standard_interrupt(SSP_CFG_T *sspcfgptr)
{
    SSP_REGS_T *sspregs = sspcfgptr->regptr;

    /* Interrupt was due to a receive data FIFO service request */
    if ((sspregs->iir_icr & SSP_IIR_RIS) != 0)
    {
        /* Receive interrupt */
        ssp_standard_receive(sspcfgptr);
    }

    /* Interrupt was due to a transmit data FIFO service request */
    if ((sspregs->iir_icr & SSP_IIR_TIS) != 0)
    {
        /* Transmit interrupt */
        ssp_standard_transmit(sspcfgptr);
    }

    /* Interrupt was due to a receive FIFO overrun service request */
    if ((sspregs->iir_icr & SSP_IIR_RORIS) != 0)
    {
        /* RX FIFO overrun, just clear interrupt and disable it */
        sspregs->iir_icr = 0;
        sspregs->cr1 &= ~SSP_CR1_RORIE;
    }

    /* Interrupt was due to a transmitter idle service request */
    if ((sspregs->iir_icr & SSP_IIR_TXIDLE) != 0)
    {
        /* Disable this interrupt, not used */
        sspregs->cr1 &= ~SSP_CR1_TXIDLE;
    }
}

/***********************************************************************
 * SSP driver public functions
 **********************************************************************/

/***********************************************************************
 *
 * Function: ssp_open
 *
 * Purpose: Open the SSP
 *
 * Processing:
 *     If init is not FALSE, return NULL to the caller. Otherwise,
 *     set init to TRUE, save the SSP peripheral register set address,
 *     set the default states of the SSP device (SSP disabled, SSP clock
 *     is divide by 8, SPI mode, FIFOs enabled), and return a pointer to
 *     the SSP config structure to the caller.
 *
 * Parameters:
 *     ipbase: SSP descriptor device address
 *
 * Outputs: None
 *
 * Returns: The pointer to a SSP config structure or 0
 *
 * Notes: None
 *
 **********************************************************************/
INT_32 ssp_open(void *ipbase, INT_32 arg)
{
    INT_32 status = 0;

    if ((sspcfg.init == FALSE) && ((SSP_REGS_T *) ipbase == SSP))
    {
        /* Device is valid and not previously initialized */

⌨️ 快捷键说明

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