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

📄 lh7a400_ssp_driver.c

📁 sharp的arm920t 7A400的评估板附带光盘Sharp KEVLH7A400 v0.3b Welcome to the SHARP KEV7A400 Evaluation board
💻 C
📖 第 1 页 / 共 3 页
字号:
/**********************************************************************
 *	$Workfile:   lh7a400_ssp_driver.c  $
 *	$Revision:   1.5  $
 *	$Author:   KovitzP  $
 *	$Date:   Nov 21 2001 09:39:34  $
 *
 *	Project: LH79520 and eval board test
 *
 *	Description:
 *  This file contains driver support for the Synchronous
 *  Serial Port (SSP) on the LH7A400. Functions are described below
 *   ssp_init_spi_mode()--Put the SSP into SPI mode with FIFOs off, 
 *                        interrupts off, default word length, default
 *                        divider, SSP enabled, SPH==SPO==0
 *   ssp_init_uwire_mode()--Put the SSP into MICROWIRE mode with FIFOs 
 *                          off, interrupts off, default word length, 
 *                          default divider, SSP enabled
 *   ssp_init_ti_mode()--Put the SSP into TI mode with FIFOs off, 
 *                       interrupts off, default word length, default
 *                       divider, SSP enabled, SPH==SPO==0
 *   ssp_disable()--Put the SSP into its default state with receiver
 *                  overrun interrupts disabled.
 *   ssp_enable()--Gate on the SSP clock to enable to SSP.
 *   ssp_set_bits_per_word()--Set the bits per SSP word (5-16)
 *   ssp_get_bits_per_word()--return the number of bits per SSP word
 *   ssp_loopback_on()--put the SSP in loopback mode
 *   ssp_loopback_off()--take the SSP out of loopback mode.
 *   ssp_set_speed()--set the SSPCLK frequency as close to the requested
 *                    bits per second as possible and return the actual
 *                    bits per second.
 *   ssp_get_speed()--return the SSPCLK speed in bits per second.
 *   ssp_spi_set_spo()--For SPI mode, SSPCLK is normally high
 *   ssp_spi_clr_spo()--For SPI mode, SSPCLK is normally low
 *   ssp_spi_set_sph()--For SPI mode, data are sampled 1/2 SSPCLK cycle
 *                      after the first SSPCLK transition in a frame
 *   ssp_spi_clr_sph()--For SPI mode, data are sampled on the first
 *                      SSPCLK transition in a frame
 *   ssp_int_enable_receive_overflow()--enable SSP receiver overrun 
 *                                      interrupts
 *   ssp_int_disable_receive_overflow()--disable SSP receiver overrun 
 *                                       interrupts
 *   ssp_int_enable_receive()--enable SSP receiver interrupt
 *   ssp_int_disable_receive()--disable SSP receiver interrupt
 *   ssp_int_enable_transmit()--enable SSP transmitter interrupt
 *   ssp_int_disable_transmit()--disable SSP transmitter interrupt
 *   ssp_int_enable_transmit_idle()--enable SSP transmit idle interrupt
 *   ssp_int_disable_transmit_idle()--disable SSP transmit idle interrupt
 *   ssp_int_disable_all()--disable all SSP interrupts
 *   ssp_disable_fifos()--disable SSP transmitter and receiver FIFOs
 *   ssp_enable_fifos()--enable SSP transmitter and receiver FIFOs
 *   ssp_flush_fifos()--empty SSP transmitter and receiver FIFOs
 *   ssp_transmit()--write a single word to the transmitter FIFO (if
 *                   FIFOs are enabled) or to the transmit register (if
 *                   FIFOs are disabled). If the FIFO or transmit
 *                   register are full, wait until the FIFO or
 *                   register is available.
 *   ssp_transmit_block()--transmit an array of words by repeated calls
 *                         to ssp_transmit()
 *   ssp_receive()--wait for a word to become available in the SSP
 *                  receiver. Read the word and return it.
 *   ssp_receive_block()--Fill an array with all the words in the receive
 *                        FIFO
 *   ssp_transceive()--Send a word and wait for the data return. Return
 *                     the received data.
 *   ssp_transceive_block()--Send an array of data and record an array
 *                           of returned data by multiple calls to 
 *                           ssp_transceive()
 *   ssp_fifos_enabled()--Return 1 if FIFOs are enabled.
 *   ssp_busy()--Return 1 if the SSP is transmitting a word
 *   ssp_receive_fifo_full()--Return 1 if the SSP receive FIFO is full
 *   ssp_receive_fifo_not_empty()--Return 1 if the SSP receive FIFO
 *                                 contains data
 *   ssp_transmit_fifo_not_full()--Return 1 if the SSP transmit FIFO is
 *                                 not full.
 *   ssp_transmit_fifo_empty()--Return 1 if the SSP transmit FIFO is empty
 *   ssp_loopback_is_on()--Return 1 if the SSP is in loopback mode.
 *   ssp_int_transmit_idle_enabled()--Return 1 if the SSP transmit idle
 *                                    interrupt is enabled
 *   ssp_int_receive_overflow_enabled()--Return 1 if the SSP receive
 *                                       overflow is enabled.
 *   ssp_int_receive_enabled()--Return 1 if the SSP receiver interrupt is
 *                              enabled
 *   ssp_int_transmit_enabled()--Return 1 if the SSP transmitter interrupt
 *                               is enabled
 *   ssp_spi_spo_is_set()--Return 1 if the SSP SPO bit is set
 *   ssp_spi_sph_is_set()--Return 1 if the SSP SPH bit is set
 *   ssp_clr_receive_overflow()--Clear any pending SSP receiver overflow
 *                               interrupts
 *   ssp_int_transmit_idle()--Return 1 if the SSP transmitter idle 
 *                            interrupt is pending.
 *   ssp_int_transmit()--Return 1 if the SSP transmitter interrupt is
 *                       pending.
 *   ssp_int_receive()--Return 1 if the SSP receiver interrupt is pending
 *   ssp_int_receive_overflow()--Return 1 if the SSP receiver overflow
 *                               interrupt is pending.
 *
 *	Revision History:
 *	$Log:   P:/PVCS6_6/archives/LH7A400 (Aruba)/SSP/lh7a400_ssp_driver.c-arc  $
 * 
 *    Rev 1.5   Nov 21 2001 09:39:34   KovitzP
 * All block comments added.
 * 
 *    Rev 1.4   Nov 20 2001 18:37:14   KovitzP
 * Added block comment headers to all functions. All fields
 * of block headers are not filled in yet.
 * 
 *    Rev 1.3   Nov 19 2001 10:25:22   KovitzP
 * Corrected bugs in interrupt enable/disable functions. Removed
 * some dead code for installing interrupt handlers.
 * 
 *    Rev 1.2   Nov 14 2001 09:01:46   KovitzP
 * Modified include hierarchy
 * 
 *    Rev 1.1   Nov 12 2001 17:47:52   KovitzP
 * Used derived clock symbol from clock and state controller include file instead of a hard number.
 * 
 *    Rev 1.0   Nov 12 2001 13:32:10   KovitzP
 * Initial revision.
 * 
 * 
 *	COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
 *		CAMAS, WA
 *********************************************************************/
#include "LH7A400_ssp_driver.h"

/* sspclk is the ssp state machine clock */
static const UNS_32 sspclk=CLKSC_SSP_CLK;

/**********************************************************************
*
* Function: init_ssp
*
* Purpose:
*  Put the SSP in the default state with the clock gated on.
*
* Processing:
*  Clear the control registers with the enable bit set. This disables
*  the FIFOs and the interrupts
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
*  This function is called by the three initialize functions
*
**********************************************************************/
static void init_ssp(void)
{
   /* gate on the SSP clock */
   SSP->cr0 = SSP_CR0_SSE;
	/* flush the FIFOs. disable all interrupts */
	SSP->cr1 = 0;
}

/**********************************************************************
*
* Function: ssp_init_spi_mode
*
* Purpose:
*  Put the SSP into SPI mode with FIFOs off, interrupts off,
*  default word length, default divider, SSP enabled, SPH==SPO==0
*
* Processing:
*  Call init_ssp() and then change to SPI mode.
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
*
**********************************************************************/
void ssp_init_spi_mode(void)
{
	init_ssp();
	SSP->cr0 |= SSP_CR0_FRF_MOT;
}

/**********************************************************************
*
* Function: ssp_init_uwire_mode
*
* Purpose:
*  Put the SSP into MICROWIRE mode with FIFOs off, interrupts off,
*  default word length, default divider, SSP enabled
*
* Processing:
*  Call init_ssp() and then change to MICROWIRE mode.
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
*
**********************************************************************/
void ssp_init_uwire_mode(void)
{
	init_ssp();
	SSP->cr0 |= SSP_CR0_FRF_NS;
}

/**********************************************************************
*
* Function: ssp_init_ti_mode
*
* Purpose:
*  Put the SSP into TI mode with FIFOs off, interrupts off,
*  default word length, default divider, SSP enabled
*
* Processing:
*  Call init_ssp() and then change to TI mode.
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
*
**********************************************************************/
void ssp_init_ti_mode(void)
{
	init_ssp();
	SSP->cr0 |= SSP_CR0_FRF_TI;
}

/**********************************************************************
*
* Function: ssp_enable
*
* Purpose:
*  Gate the SSP clock on
*
* Processing:
*  set the enable bit
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
*
**********************************************************************/
void ssp_enable(void)
{
	SSP->cr0 |= SSP_CR0_SSE;
}


/**********************************************************************
*
* Function: ssp_disable
*
* Purpose:
*  Gate the SSP clock off; disable interrupts and clear any pending
*  receiver overrun interrupts.
*
* Processing:
*  Clear the control registers and write to the interrupt control
*  register.
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
*
**********************************************************************/
void ssp_disable(void)
{

   /* set control registers to their reset defaults */
   SSP->cr1 = 0; 
   SSP->cr0 = 0;

   /* clear any receive overruns */
   SSP->u.icr = SSP_IIR_RORIS;
}

/* control functions */

/**********************************************************************
*
* Function: ssp_set_bits_per_word
*
* Purpose:
*  Set the number of bits per word to nbits. Return
*  the previous bits per word session.
*
* Processing:
*  Read the current bits per word. 
*
* Parameters:
*  nbits: number of bits per word (4-16)
*
* Outputs: None
*
* Returns: 
*  previously set number of bits per word.
*
* Notes:
*  If the requested bits per word is out of range, the function
*  returns the curent setting and has no effect on the word length.
*
**********************************************************************/
INT_32 ssp_set_bits_per_word(INT_32 nbits)
{
	INT_32 saved_nbits = ssp_get_bits_per_word();

	if (nbits > 16 || nbits < 4)
		return saved_nbits;
	SSP->cr0 &= ~ SSP_CR0_DSS(16); /* clear all bits */
	SSP->cr0 |= SSP_CR0_DSS(nbits);
	return saved_nbits;
}

/**********************************************************************
*
* Function: ssp_get_bits_per_word
*
* Purpose:
*  return the number of bits per SSP word
*
* Processing:
*  AND off all non-word size bits in Control Register 0. Shift
*  the result right to the bit position of the the LSB of the
*  word size bit field, and add 1. Return the result.
*
* Parameters: None
*
* Outputs: None
*
* Returns:
*  The number of bits per word.
*
* Notes:
*  If the number of bits per word set is less than 4, the results
*  of this function are not predictable.
*
**********************************************************************/
/* Return the number of bits per word */
INT_32 ssp_get_bits_per_word(void)
{
	return ( (SSP->cr0 & SSP_CR0_DSS(16)) / SSP_CR0_DSS(2) ) + 1;
}

/**********************************************************************
*
* Function: ssp_loopback_on
*
* Purpose:
*  put the SSP in loopback mode
*
* Processing:
*  Set the LBM bit in control register 1
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
*
**********************************************************************/
/* turn SSP loopback on */
void ssp_loopback_on(void)
{
	SSP->cr1 |= SSP_CR1_LBM;
}

/**********************************************************************
*
* Function: ssp_loopback_off
*
* Purpose:
*  take the SSP out of loopback mode.
*
* Processing:
*  Clear the LBM bit in control register 1
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
*
**********************************************************************/
/* turn SSP loopback off */
void ssp_loopback_off(void)
{
	SSP->cr1 &= ~ SSP_CR1_LBM;
}

/**********************************************************************
*
* Function: ssp_set_speed
*
* Purpose:
*  set the SSPCLK frequency as close to the requested bits per second
*  as possible and return the actual bits per second.
*
* Processing:
*  If the requested bits per second is greater than or equal to
*  the maximum possible SSPCLK frequency, set the divider and
*  the prescaler to the minimum values. 
*
*  If not too fast, compute the closest integer result of dividing the
*  base sspclk frequency (approximately 7.4 MHz) by the requested
*  bits per second. If this quotient is larger than the result
*  of multiplying the maximum possible prescaler by the maximum
*  possible divider, then the requested clock is too slow. Use
*  the maximum possible divider and prescaler to get the slowest
*  SSPCLK speed.
*
*  If the clock frequency is neither too fast nor too slow, then
*  step through all possible prescaler values to determine which
*  combination of prescaler and divider values give the SSPCLK
*  value closest to the requested bits per second.
*
*  Set the SSP clock prescaler register to the prescaler value
*  determined above. Clear out the old divider value from SSP
*  control register 0 and OR in the new divider value - 1. Return
*  the value returned by ssp_get_speed().
*
* Parameters:
*  requested_bits_per_second: the desired frequency of the SSPCLK 
*                             pin in bits per second.
*
* Outputs: None
*
* Returns:
*  0 if the requested frequency is illegal. Otherwise, return
*  the actual clock speed.
*
* Notes:
*
**********************************************************************/
INT_32 ssp_set_speed(INT_32 requested_bits_per_second)
{
	INT_32 ssp_prescale;
	INT_32 ssp_divider;
	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;

	if (requested_bits_per_second <= 0)
		/* requested frequency is illegal. Return 0 */
		return 0;

	/* 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;
	}
	else
	{
		/* compute the required divider as close as possible */
		quotient = sspclk / requested_bits_per_second;

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

		if (quotient >= (SSP_PRESCALE_MAX * SSP_DIVIDER_MAX) )
		{
			/* 
			Then requested clock frequency is <= minimum possible.
			Make it as slow as possible.
			*/
			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 
			*/

			/* 
			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 */

	SSP->cpsr = ssp_prescale;

	SSP->cr0 &= ~SSP_CR0_SCR(SSP_DIVIDER_MAX - 1); /* clear old divider value */
	SSP->cr0 |= SSP_CR0_SCR(ssp_divider - 1);
	return ssp_get_speed();
}

/**********************************************************************

⌨️ 快捷键说明

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