📄 lpc_spi.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 + -