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

📄 lh79524_ssp_driver.c

📁 SHARP_ARM720T_LH79524/5软件开发包_支持TFT_LCD_NAND_FLASH_ETH_USB
💻 C
📖 第 1 页 / 共 4 页
字号:
/***********************************************************************
 * $Workfile:   lh79524_ssp_driver.c  $
 * $Revision:   1.0  $
 * $Author:   ZhangJ  $
 * $Date:   Oct 20 2004 09:48:56  $
 *
 * Project: LH79520 SSP driver
 *
 * Description:
 *     This file contains driver support for the SSP module on the
 *     LH79520
 *
 * Revision History:
 * $Log:   //smaicnt2/pvcs/VM/sharpmcu/archives/sharpmcu/software/csps/lh79524/source/lh79524_ssp_driver.c-arc  $
 * 
 *    Rev 1.0   Oct 20 2004 09:48:56   ZhangJ
 * Initial revision.
 * 
 *    Rev 1.0   Jul 07 2003 16:40:00   LiJ
 * 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 "lh79524_rcpc.h"
#include "lh79524_iocon.h"
#include "lh79524_dmac.h"
#include "lh79524_vic.h"
#include "lh79524_gpio.h"
#include "lh79524_ssp_driver.h"

#include "sdk79524_board.h"

/***********************************************************************
 * SSP driver private data
 **********************************************************************/

STATIC INT_32 ssp_set_speed(UNS_32 requested_bits_per_second);
STATIC INT_32 ssp_get_speed(void);

STATIC INT_32 hclk_freq;

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

#define SSPFRM_GPIO_BIT _BIT(2)


/**********************************************************************
*
* Function: ssp_set_speed
*
* Purpose:
*  return the SSP receive timeout in microseconds
*
* Processing:
*  If the requested_bits_per_second is too fast, set the bit rate
*  as fast as possible.
*  If the requested_bits_per_second is too slow, set the bit rate as
*  slow as possible.
*  If the requested_bits_per_second is in range, set the RCPC
*  SSP clock prescaler register, SSP prescaler, and SSP divider
*  to obtain the clock as close as possible.
*
* Parameters: 
*  requested_bits_per_second: The desired bits per second
*
* Outputs: None
*
* Returns: 
*  the actual bits per second obtained or 0 if the requested bits
*  per second is not obtainable.
*
* Notes: 
*  The ssp_init_spi_mode, ssp_init_uwire_mode, or ssp_init_ti_mode
*  must be called first in order for this function to work.
*  RCPC write lock bit need to be cleared using
*   rcpc_reg_write_unlock() function call before using this function
*
*   set serial ssp serial clock rate. The bit rate is 
*   fSSPCLK + (CPSDVSR * (1+SCR)), where CPSDVSR is an
*   even value from 2 to 254 and SCR is a value from 0-255) 
*
**********************************************************************/
STATIC INT_32 ssp_set_speed(UNS_32 requested_bits_per_second)
{
    INT_32 ssp_prescale;
    INT_32 ssp_divider;
    INT_32 rcpc_prescale;
    INT_32 new_prescale;
    INT_32 new_divider;
    INT_32 quotient;
    INT_32 delta1;
    INT_32 delta2;  
    INT_32 min_error;
    INT_32 new_error;

    /* get the dividers as close to the requested freq as possible */
    if (requested_bits_per_second >= MAX_SSP_FREQ)
    {
        /* requested clock frequency is too fast. Set to max freq */
        ssp_prescale = SSP_PRESCALE_MIN;
        ssp_divider = 1;
        rcpc_prescale = 1;
    }
    else
    {
        /* compute the required divider as close as possible */
        quotient = hclk_freq / requested_bits_per_second;
        //assert(quotient > 0); 

        /* round the quotient */
        delta1 = requested_bits_per_second - (hclk_freq / quotient );
        if (delta1 < 0)
            delta1 = - delta1;
        delta2 = requested_bits_per_second 
                 - (hclk_freq / (quotient + 1) );
        if (delta2 < 0)
            delta2 = - delta2;
        if (delta1 > delta2)
            quotient++;

        if (quotient >= (SSP_PRESCALE_MAX 
                         * RCPC_SSP_PRESCALE_MAX 
                         * SSP_DIVIDER_MAX) )
        {
            /* 
            Then requested clock frequency is <= minimum possible.
            Make it as slow as possible.
            */
            rcpc_prescale = RCPC_SSP_PRESCALE_MAX;
            ssp_prescale = SSP_PRESCALE_MAX;
            ssp_divider = SSP_DIVIDER_MAX;
        }
        else
        {
            /* 
            The computed quotient is in range.
            quotient is the target clock divide frequency; 
            get as close as possible 
            */

            rcpc_prescale = 1;
            /* 
            try to reduce power by using RCPC prescaler
            Note that the ssp prescaler minimum is two
            so can only prescale and maintain accuracy
            if quotient is divisble by 4.
            */           
            while ( ((quotient & 0x3) == 0) 
                    && (rcpc_prescale < RCPC_SSP_PRESCALE_MAX) )
            {
                quotient >>= 1;
                rcpc_prescale <<= 1;
            }

            /* 
            Make sure the requested frequency is within range
            of the SPP's prescaler and divider.
            Hopefully, this loop never executes. If it does,
            accuracy suffers.
            */
            while (quotient > (SSP_PRESCALE_MAX * SSP_DIVIDER_MAX) )
            {
                rcpc_prescale <<= 1;
                quotient >>= 1;
            }

            /* 
            factor the quotient into the divider and prescaler combo
            that minimizes the error in the quotient by exhaustively
            searching all legal ssp prescaler values.
            */
            ssp_prescale = SSP_PRESCALE_MIN;
            ssp_divider = (quotient / ssp_prescale);
            ssp_divider = (ssp_divider > SSP_DIVIDER_MAX) ? 
                                        SSP_DIVIDER_MAX : 
                                        ssp_divider;
            min_error = quotient - (ssp_divider * ssp_prescale);
            min_error = (min_error < 0) ? -min_error : min_error;
            for (new_prescale = SSP_PRESCALE_MIN + 2; 
                 new_prescale < SSP_PRESCALE_MAX;
                 new_prescale += 2)
            {
                new_divider = (quotient / new_prescale);
                new_divider = (new_divider > SSP_DIVIDER_MAX) ? 
                                        SSP_DIVIDER_MAX : 
                                        new_divider;
                new_error = quotient - (new_divider * new_prescale);
                new_error = (new_error < 0) ? -new_error : new_error;
                if (new_error < min_error)
                {
                    min_error = new_error;
                    ssp_prescale = new_prescale;
                    ssp_divider = new_divider;
                }
            }

        } /* end if quotient is greater than max */

    } /* end if requested frequency is too large */

    /* set up registers */
    RCPC->sspclkprescale = rcpc_prescale >> 1;

    SSP->cpsr = ssp_prescale;

    SSP->ctrl0 &= 0xff; /* clear old divider value */
    SSP->ctrl0 |= SSP_CR0_SCR(ssp_divider - 1);
    return ssp_get_speed();
}

/**********************************************************************
*
* Function: ssp_get_speed
*
* Purpose:
*  return the SSP speed in bits per second.
*
* Processing:
*  
*
* Parameters: 
*  time_in_us: The timeout interval in microseconds.
*
* Outputs: None
*
* Returns: 
*  Return the SSP bits per second
*
* Notes: None
*
**********************************************************************/
STATIC INT_32 ssp_get_speed(void)
{
    INT_32 rcpc_prescale;
    INT_32 ssp_prescale=1;
    INT_32 ssp_divider;
    
   
    if (ssp_prescale == 0)
       return 0;

    rcpc_prescale = RCPC->sspclkprescale;
    if (rcpc_prescale == 0)
       rcpc_prescale = 1;
    else
       rcpc_prescale <<= 1;
    ssp_prescale = SSP->cpsr;
    ssp_divider = (SSP->ctrl0 & _SBF(8,_BITMASK(8) ) ) >> 8;

    return hclk_freq / (rcpc_prescale 
                        * (ssp_prescale) 
                        * (ssp_divider + 1) );
}

/***********************************************************************
 * SSP driver public functions
 **********************************************************************/
/***********************************************************************
 *
 * Function: ssp_open
 *
 * Purpose: Open the SSP controller
 *
 * Processing:
 *     If init is not FALSE, return 0x00000000 to the caller. Otherwise,
 *      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;
    INT_32 temp1;

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

        /* Save and return address of peripheral block */
        sspcfg.regptr = (SSP_REGS_T *) ipbase;

        /* Return pointer to SSP configuration structure */
        status = (INT_32) &sspcfg;
        

⌨️ 快捷键说明

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