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

📄 lpc_spi.c

📁 给大家提供一个在inram/exram中调试的示例,在周公的lpc2200上调试过.
💻 C
字号:
/*************************************************************************
 *         BU MMS China, Philips Semiconductor Software Support
 *         Embest info&Tech Co. Software Support
 *---------------------------------------------------------------------------
 * The software is delivered "AS IS" without warranty or condition of any
 * kind, either express, implied or statutory.  Everybody can use it as 
 * it is opened and without copyright. We will not take any law responsibility
 * for any problem produced by using this software.
 *---------------------------------------------------------------------------                                                        
 *    File name:	LPC_SPI.c                                                            
 *    Description:	Define API for SPI
 *                                                                                      
 *    History:                                                                     
 *    1. Date: 		Nov 11, 2004                                              
 *       Author:		Shawn Zhang                                                    
 *       Description: Create 
 *
 *	$Revision: 1.0 $
 **************************************************************************/

#include "LPC_SPI.h"

// Define globe variable
LPC_SPI_Config_t SPI0Config, SPI1Config;

/*************************************************************************
 * Function Name: SPI_InitSPIBuf
 * Parameters: LPC_SPI_Buffer_t *pSPIBuf
 * Return: void
 *
 * Description: Initialize Rx & Tx buffer
 *  
 *************************************************************************/
static void SPI_InitSPIBuf (LPC_SPI_Buffer_t *pSPIBuf)
{
	int i;

	for(i=0; i<SPI_RXBUFSIZE; i++)
		pSPIBuf->RxBuf[i] = 0;
	pSPIBuf->pTxBuf = NULL;
	
	pSPIBuf->RxHeadPoint=0;
	pSPIBuf->RxTailPoint=0;

	pSPIBuf->RxCount=0;
	pSPIBuf->TxCount=0;

	pSPIBuf->status=0;
}

/*************************************************************************
 * Function Name: SPI_Init
 * Parameters:	LPC_SPI_Channel_t DevNum -- SPI0 | SPI1
 *				LPC_SPI_Mode_t Mode -- SPI_SLAVE | SPI_MASTER
 *				lpc_uint32 BusSpeed -- 0 ~ SPI_MAXSPEED
 *									(if Slave mode, it's inefficacy)
 *				LPC_SPI_CPHA_t  CPHA -- SCK_FIRSTEDGE | SCK_SECONDEDGE
 *				LPC_SPI_CPOL_t  CPOL -- SCK_HIGH | SCK_LOW
 *				LPC_SPI_LSBF_t  LSBF -- MSB | LSB
 *				bool IntEnable -- Whether be enable to use interrupt method 
 * 							for transfering data
 *				void (* Fnpr)(void *) -- Corresponding function pointer which will be
 *								called if enable interrupt method
 *				void * FnprArg
 * Return: int 
 *             	0: sucess
 *			1: fail
 * Description: Initialize SPI, configure SPI bus speed, mode etc.
 *  
 *************************************************************************/
int SPI_Init (LPC_SPI_Channel_t DevNum, LPC_SPI_Mode_t Mode, lpc_uint32 BusSpeed,
	LPC_SPI_CPHA_t  CPHA, LPC_SPI_CPOL_t  CPOL, LPC_SPI_LSBF_t  LSBF,
	bool IntEnable, void (* Fnpr)(void *), void * FnprArg)
{
	unsigned long SPCCR_value;
	LPC_SPI_Config_t *pConfig;

	// Check parameter valid
	if (BusSpeed > SPI_MAXSPEED)
		return 1;
	SPCCR_value = SYS_GetFpclk() / BusSpeed;
	if (SPCCR_value < SPCCR_MINVALUE)
		return 1;

	// Copy paratmeters to goble variable
	if (DevNum == SPI0)
		pConfig = &SPI0Config;
	else
		pConfig = &SPI1Config;
	
	pConfig->Mode = Mode;
	pConfig->BusSpeed = BusSpeed;
	pConfig->CPHA = CPHA;
	pConfig->CPOL = CPOL;
	pConfig->LSBF = LSBF;
	pConfig->IntEnable = IntEnable;
	if (IntEnable)
	{
		pConfig->Fnpr = Fnpr;
		pConfig->FnprArg = FnprArg;
	}
	else
	{
		pConfig->Fnpr = NULL;
		pConfig->FnprArg = NULL;
	}
	SPI_InitSPIBuf(&pConfig->SPIBuffer);
	
	// Configure the registers
	if (DevNum == SPI0)
	{
		/* Enable SCK, MISO, MOSI and SSEL, bit 8~15=0101 0101 */
		PINSEL0 &= ~0xFF00;
		PINSEL0 |= 0x5500;
		
		// b0 must aways 0 and value must also great than or equal to 8
		SPI0_SPCCR = SPCCR_value & 0xFE;
		SPI0_SPCR = (CPHA << 3) | (CPOL << 4) | (Mode << 5) |(LSBF<< 6);

		if (IntEnable)
			SPI0_SPCR |= (1<<7);
		else
			SPI0_SPCR &= ~(1<<7);
	}
	else
	{
		/* Enable SCK, MISO, MOSI and SSEL, bit 2~9=1010 1010 */
		PINSEL1 &= ~0x3FA;
		PINSEL1 |= 0x2A8;
		
		SPI1_SPCCR = SPCCR_value & 0xFE;
		SPI1_SPCR = (CPHA << 3) | (CPOL << 4) | (Mode << 5) |(LSBF<< 6);

		if (IntEnable)
			SPI1_SPCR |= (1<<7);
		else
			SPI1_SPCR &= ~(1<<7);
	}
	return 0;
}

/*************************************************************************
 * Function Name: SPI_WriteRxBuf
 * Parameters: LPC_SPI_Buffer_t *pSPIBuf
 *			  char ch
 * Return: int : 1 overflow
 *			 0 
 *
 * Description: Write a character to SPI Rx Buffer
 *  
 *************************************************************************/
__inline static int SPI_WriteRxBuf (LPC_SPI_Buffer_t *pSPIBuf, char ch)
{
	pSPIBuf->RxBuf[pSPIBuf->RxTailPoint] = ch;
	pSPIBuf->RxTailPoint = (pSPIBuf->RxTailPoint+1)%SPI_RXBUFSIZE;
	
	// overflow
	if (++pSPIBuf->RxCount >= SPI_RXBUFSIZE)
		return 1;

	return 0;
}

/*************************************************************************
 * Function Name: SPI_WriteCharByPolling
 * Parameters: 	LPC_SPI_Channel_t DevNum
 * 			 	char ch	
 * Return: int 
 *             	0: sucess
 *			1: fail
 * Description: Write a character to SPI Port by polling SPSR register. After writing, receive
 *			SPSR register to Rxbuf (goble variable)
 *  
 *************************************************************************/
int SPI_WriteCharByPolling (LPC_SPI_Channel_t DevNum, char ch)
{
	unsigned long status;

	if ( DevNum == SPI0 )
	{	
		SPI0_SPDR = ch;
		do
		{
			status = SPI0_SPSR;
			if ( status & (SPSR_ABRT | SPSR_MODF | SPSR_ROVR | SPSR_WCOL))
			{
				SPI0Config.SPIBuffer.status = status & 0xFF;
				//return 1;
				//Embest w.h.xie modify
			}
		}
		while(!(status & SPSR_SPIF));
		/*
		if (SPI_WriteRxBuf(&SPI0Config.SPIBuffer, SPI0_SPDR))
		{
			SPI0Config.SPIBuffer.status = SPI_BUF_OVERFLOW_ERR;
			return 1;
		}*/
	}
	else // SPI1
	{
		SPI1_SPDR = ch;
		do
		{
			status = SPI1_SPSR;
			if ( status & (SPSR_ABRT | SPSR_MODF | SPSR_ROVR | SPSR_WCOL))
			{
				SPI1Config.SPIBuffer.status = status & 0xFF;
				return 1;
			}
		}
		while(!(status & SPSR_SPIF));
		/*
		if (SPI_WriteRxBuf(&SPI1Config.SPIBuffer, SPI1_SPDR))
		{
			SPI0Config.SPIBuffer.status = SPI_BUF_OVERFLOW_ERR;
			return 1;
		}
		*/
	}
	
	return 0;
} 

/*************************************************************************
 * Function Name: SPI_WriteBlockByPolling
 * Parameters: 	LPC_SPI_Channel_t DevNum
 * 			 	char *Buf
 *				int size
 * Return: int 
 *             	>0: send character count
 *			0: fail
 * Description: Send a block by using polling method. After writing, receive
 *			SPSR register to Rxbuf (goble variable)
 *  
 *************************************************************************/
int SPI_WriteBlockByPolling(LPC_SPI_Channel_t DevNum, char *Buf, int size)
{
	char *pBuf = Buf;
	int count;//, i;

	for (count=0; count < size; count++, pBuf++)
	{
		if (SPI_WriteCharByPolling(DevNum, *pBuf))
			break;
	}
	return count;
}

/*************************************************************************
 * Function Name: SPI_WriteBlockByInterrupt
 * Parameters: LPC_SPI_Channel_t DevNum
 *			  char *Buf
 * Return: int -- send character count
 *
 * Description: Send a string by interrupt method
 *  
 *************************************************************************/
static int SPI_WriteBlockByInterrupt (LPC_SPI_Channel_t DevNum, char *Buf, int size)
{
	LPC_SPI_Config_t *pConfig;
	char ch = *Buf;
//	unsigned long IntFlagsHold;	

	if (size < 1 || Buf == NULL)
		return 0;

	if ( DevNum == SPI0 )
		pConfig = &SPI0Config;
	else
		pConfig = &SPI1Config;

//	IntFlagsHold = disable_IRQ();
	pConfig->SPIBuffer.TxCount = size -1;
	pConfig->SPIBuffer.status = 0;
	pConfig->SPIBuffer.pTxBuf = ++Buf;
//	restore_IRQ(IntFlagsHold);

	// Must send the first character
	if ( DevNum == SPI0 )
		SPI0_SPDR = ch;
	else
		SPI1_SPDR = ch;
	while(pConfig->SPIBuffer.TxCount && (pConfig->SPIBuffer.status == 0));

	return(size - pConfig->SPIBuffer.TxCount);
}

/*************************************************************************
 * Function Name: SPI_Write
 * Parameters:	LPC_SPI_Channel_t DevNum
 *				char *Buf
 * 	        		int Size
 * Return: int --send character count
 *		
 * Description: Write a block of character by using method depends of setting
 *  
 *************************************************************************/
int SPI_Write(LPC_SPI_Channel_t DevNum, char* Buf, int Size)
{
	LPC_SPI_Config_t *pConfig;
	if ( DevNum == SPI0 )
		pConfig = &SPI0Config;
	else
		pConfig = &SPI1Config;

	if (pConfig->IntEnable)
		return SPI_WriteBlockByInterrupt(DevNum, Buf, Size);
	else
		return SPI_WriteBlockByPolling(DevNum, Buf,Size);
}

/*************************************************************************
 * Function Name: SPI_ReadCharByPolling
 * Parameters: 	LPC_SPI_Channel_t DevNum
 * 			 	char ch	
 * Return: char 
 *             	0: fail
 * Description: Read a character to SPI Port by polling SPSR register. 
 *  
 *************************************************************************/
char SPI_ReadCharByPolling (LPC_SPI_Channel_t DevNum)
{
	unsigned long status;

	if ( DevNum == SPI0 )
	{	
		do
		{
			status = SPI0_SPSR;
			if ( status & (SPSR_ABRT | SPSR_MODF | SPSR_ROVR | SPSR_WCOL))
			{
				SPI0Config.SPIBuffer.status = status & 0x3A;
				return 0;
			}
		}
		while(!(status & SPSR_SPIF));
		return (SPI0_SPDR);
	}
	else // SPI1
	{
		do
		{
			status = SPI1_SPSR;
			if ( status & (SPSR_ABRT | SPSR_MODF | SPSR_ROVR | SPSR_WCOL))
			{
				SPI1Config.SPIBuffer.status = status & 0x3A;
				return 0;
			}
		}
		while(!(status & SPSR_SPIF));
		return (SPI1_SPDR);
	}

} 

/*************************************************************************
 * Function Name: SPI_ReadCharByInterrupt
 * Parameters:  	LPC_SPI_Channel_t DevNum
 *				char * ch
 * Return: int 	0 - Rx FIFO is empty
 *          		1 - valid char
 *			2 - status is wrong, and return the current status through "char* ch"
 *
 * Description: Get character from SPI Port by making use of interrupt. At same time,
 *			the received data will be stored into its buffer.
 *  
 *************************************************************************/
static int SPI_ReadCharByInterrupt (LPC_SPI_Channel_t DevNum, char* ch)
{
	LPC_SPI_Buffer_t *pSPIBuf;
//	unsigned long IntFlagsHold;
	
	if (DevNum == SPI0)
		pSPIBuf = &SPI0Config.SPIBuffer;
	else
		pSPIBuf = &SPI1Config.SPIBuffer;

	if (pSPIBuf->RxCount == 0)
		return 0;

	if (pSPIBuf->status)
	{
		*ch = pSPIBuf->status;
		return 2;
	}
 
	*ch = pSPIBuf->RxBuf[pSPIBuf->RxHeadPoint];
	pSPIBuf->RxHeadPoint = (pSPIBuf->RxHeadPoint+1)%SPI_RXBUFSIZE;

//	IntFlagsHold = disable_IRQ();
	pSPIBuf->RxCount--;
//	restore_IRQ(IntFlagsHold);

	return 1;
}

/*************************************************************************
 * Function Name: SPI_Read
 * Parameters: LPC_SPI_Channel_t DevNum
 * Return: char 
 *
 * Description: Receive a character from SPI interface.
 *  
 *************************************************************************/
char SPI_Read (LPC_SPI_Channel_t DevNum)
{
	bool IntEnable;
	int cnt;
	char ch;

	if ( DevNum == SPI0 )
		IntEnable = SPI0Config.IntEnable;
	else // SPI1
		IntEnable = SPI1Config.IntEnable;

	if (IntEnable)
	{
		cnt = SPI_ReadCharByInterrupt(DevNum,&ch);
		switch(cnt)
		{
			case 0:
				break;
			case 1:
				return ch;
			case 2:	// error
				break;
		}
	}
	else // Polling method
		return SPI_ReadCharByPolling(DevNum);
	
	return 0;
}

/*************************************************************************
 * Function Name: SPI_GetStatus
 * Parameters:	LPC_SPI_Channel_t DevNum
 * Return: char -- status
 *		
 * Description:  Return current status
 *  
 *************************************************************************/
char SPI_GetStatus(LPC_SPI_Channel_t DevNum)
{
	if ( DevNum == SPI0 )
		return SPI0Config.SPIBuffer.status;
	else
		return SPI1Config.SPIBuffer.status;

}

/*************************************************************************
 * Function Name: SPI0_ISR
 * Parameters: void
 * Return: void
 *
 * Description: SPI0 interrupt subroutine
 *  
 *************************************************************************/
void SPI0_ISR (void)
{
	unsigned long status;
	LPC_SPI_Buffer_t *pSPIBuf = &SPI0Config.SPIBuffer;
	char ch;

	status = SPI0_SPSR;
	// Clear Interrupt
	SPI0_SPINT = 0x01;

	if (pSPIBuf->status & (SPSR_ABRT | SPSR_MODF | SPSR_ROVR | SPSR_WCOL)) // Error
	{
		pSPIBuf->status = status & 0x3A;
	}
	else		// Correct status, transfer complete
	{
		// 1. Receive data 
		ch = SPI0_SPDR;

		if (SPI_WriteRxBuf(pSPIBuf, ch))
		{
			pSPIBuf->status = SPI_BUF_OVERFLOW_ERR;
		}
		else
		{
			if (pSPIBuf->TxCount > 0) // 2. Transfer data
			{
				SPI0_SPDR = *pSPIBuf->pTxBuf++;
				pSPIBuf->TxCount--;
			}

			// 3. Call user function
			if (SPI0Config.Fnpr != NULL)
				SPI0Config.Fnpr((void *)SPI0Config.FnprArg);
		}

	}
		
	VICVectAddr = 0;
}

/*************************************************************************
 * Function Name: SPI1_ISR
 * Parameters: void
 * Return: void
 *
 * Description: SPI1 interrupt subroutine
 *  
 *************************************************************************/
void SPI1_ISR (void)
{
	unsigned long status;
	LPC_SPI_Buffer_t *pSPIBuf = &SPI1Config.SPIBuffer;
	char ch;

	status = SPI1_SPSR;
	// Clear Interrupt
	SPI1_SPINT = 0x01;

	if (pSPIBuf->status & (SPSR_ABRT | SPSR_MODF | SPSR_ROVR | SPSR_WCOL)) // Error
		pSPIBuf->status = status & 0x3A;
	else		// Correct status, transfer complete
	{
		// 1. Receive data 
		ch = SPI1_SPDR;

		if (SPI_WriteRxBuf(pSPIBuf, ch))
			pSPIBuf->status = SPI_BUF_OVERFLOW_ERR;
		else
		{
			if (pSPIBuf->TxCount > 0) // 2. Transfer data
			{
				SPI1_SPDR = *pSPIBuf->pTxBuf++;
				pSPIBuf->TxCount--;
			}

			// 3. Call user function
			if (SPI1Config.Fnpr != NULL)
				SPI1Config.Fnpr((void *)SPI1Config.FnprArg);
		}

	}
		
	VICVectAddr = 0;
}

⌨️ 快捷键说明

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