/*****************************************************************************
* spi.c: SPI C file for NXP LPC29xx Family Microprocessors
*
* Copyright(C) 2007, NXP Semiconductor
* All rights reserved.
*
* History
* 2007.07.19 ver 1.00 Prelimnary version, first Release
*
****************************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
*****************************************************************************/
#include "LPC29xx.h" /* LPC29xx Peripheral Registers */
#include "type.h"
#include "irq.h"
#include "spi.h"
volatile DWORD RxFlag = 0;
volatile DWORD TxFlag = 0;
volatile DWORD OverrunFlag = 0;
volatile DWORD TimeoutFlag = 0;
volatile DWORD RxCounter = 0;
volatile DWORD TxCounter = 0;
volatile DWORD RxInterruptCounter = 0;
extern BYTE SPICmd[PAGE_SIZE];
extern BYTE SPIWRData[PAGE_SIZE];
extern BYTE SPIRDData[PAGE_SIZE];
DWORD FIFOCount, FIFO_Debug[FIFO_SIZE];
/*****************************************************************************
** Function name: SPI2_Handler
**
** Descriptions: SPI2 interrupt handler
**
** parameters: None
** Returned value: None
**
*****************************************************************************/
void SPI2_Handler (void)
{
DWORD regValue;
regValue = SPI2_INT_STATUS; /* check interrupt flag */
if ( regValue & SPI_OV )
{
SPI2_INT_CLR_STATUS = SPI_OV;
OverrunFlag++;
}
if ( regValue & SPI_TO )
{
SPI2_INT_CLR_STATUS = SPI_TO;
TimeoutFlag++;
}
if ( regValue & SPI_RX )
{
SPIRDData[RxCounter++] = SPI2_FIFO_DATA;
RxInterruptCounter++;
SPI2_INT_CLR_STATUS = SPI_RX;
RxFlag++;
}
if ( regValue & SPI_TX )
{
SPI2_INT_CLR_STATUS = SPI_TX;
TxFlag++;
}
return;
}
/*****************************************************************************
** Function name: SPIInit
**
** Descriptions: SPI port initialization routine
**
** parameters: None
** Returned value: None
**
*****************************************************************************/
void SPIInit( void )
{
DWORD regVal;
TxCounter = RxCounter = 0;
TxFlag = RxFlag = TimeoutFlag = OverrunFlag = 0;
/* Setup the SPI BASE Clock */
SPI_CLK_CONF = CLK_SEL_PLL | AUTOBLK | DIV2; /* BASE_SPI_CLK */
/* P2.19 is SPI2 SCS0, P2.22 is SPI2 SCLK, P2.21 is SPI2 SDI,
P2.20 is SPI2 SDO */
#if USE_GPIO_CS
SFSP2_19 = (0x01<<2)|(0x00<<0);
GPIO2_OR |= (0x1<<19);
GPIO2_DR |= (0x1<<19);
#else
SFSP2_19 = (0x03<<2)|(0x01<<0); /* Digital no PU and PD, func. 1. */
#endif
SFSP2_20 = (0x03<<2)|(0x01<<0); /* Digital no PU and PD, func. 1. */
SFSP2_21 = (0x03<<2)|(0x01<<0); /* Digital no PU and PD, func. 1. */
SFSP2_22 = (0x03<<2)|(0x01<<0); /* Digital no PU and PD, func. 1. */
/* Reset SPI2 */
SPI2_CONFIG |= (0x1<<6);
while ( SPI2_CONFIG & (0x1<<6) ); /* Self clear when reset is done. */
SPI2_TX_FIFO_FLUSH = 1; /* Flush TX FIFO */
/* Default value, set to master mode, no loop back, normal mode, slave
can drive its transmit-data output */
regVal = SPI2_CONFIG;
regVal &= ~(SPI_MS_MODE| SPI_LOOPBACK_MODE | SPI_TRANSMIT_MODE|SPI_SLAVE_DISABLE);
SPI2_CONFIG = regVal;
/* Set slave of the SPI module */
SPI2_SLV0_SET1 = 240 << 8; /* SPI_CLK is 120 MHz, serial clock is 1Mhz. */
SPI2_SLV0_SET2 = /*(0x1<<9)|*/(0x1<<8)|0x0F; /* Motorola 8 bits, the rest is default */
/* Slave 0 is enabled */
SPI2_SLV_ENABLE |= (0x01<<0);
/* Set SPI Update Enable bit */
SPI2_CONFIG |= (0x1<<7);
// SPI2_RD_FIFO_RDMODE = 0x01;
// /* Setting SPI2 clock, for Atmel SEEPROM, SPI clock should be no more
// than 3Mhz on 4.5V~5.5V, no more than 2.1Mhz on 2.7V~5.5V */
#if INTERRUPT_MODE
/* Disable interrupts, clear interrupt status */
SPI2_INT_CLR_STATUS = 0x1F;
SPI2_INT_CLR_ENABLE = 0x1F;
/* Threshold for both TX and RX is 1 */
SPI2_INT_THRESHOLD = (0x0<<0)|(0x0<<8);
SPI2_INT_SET_ENABLE = 0x1F;
install_irq( SPI2_INT, (void *)SPI2_Handler, HIGHEST_PRIORITY );
EnableIntReq_IRQ( SPI2_INT, ACTIVE_HIGH, HIGHEST_PRIORITY );
#endif
SPI2_CONFIG |= SPI_ENABLE; /* Enable SPI */
return;
}
/*****************************************************************************
** Function name: SPI_RX_Flush
**
** Descriptions: Flush RX FIFO until is empty.
**
** parameters: None
** Returned value: None
**
*****************************************************************************/
void SPI_RX_Flush( void )
{
FIFOCount = 0;
if (SPI2_RD_FIFO_RDMODE & 0x01)
{
while ( !(SPI2_STAT & (SPI_RX_FIFO_EMPTY|SPI_BUSY)) )
{
SPI2_FIFO_POP = 0x01;
}
}
else
{
while ( !(SPI2_STAT & (SPI_RX_FIFO_EMPTY|SPI_BUSY)) )
{
FIFO_Debug[FIFOCount++] = SPI2_FIFO_DATA;
}
}
return;
}
/*****************************************************************************
** Function name: SPISend
**
** Descriptions: Send a block of data to the SPI port, the first
** parameter is the buffer pointer, the 2nd
** parameter is the block length.
**
** parameters: buffer pointer, and the block length
** Returned value: None
**
*****************************************************************************/
void SPISend( WORD *buf, DWORD Length )
{
DWORD i;
/* If no data is passed, return */
if ( Length == 0 )
return;
for ( i = 0; i < Length; i++ )
{
/* Wait untill SPI TX is done */
while ( SPI2_STAT & SPI_BUSY );
/* If TX FIFO full, flush FIFO */
if ( SPI2_STAT & SPI_TX_FIFO_FULL )
{
SPI2_TX_FIFO_FLUSH = 1;
/* Wait until flush is done */
while ( SPI2_STAT & SPI_BUSY );
}
/* Shift data to buffer */
SPI2_FIFO_DATA = *buf;
buf++;
}
/* Wait untill data is transmitted */
while ( SPI2_STAT & SPI_BUSY );
return;
}
/*****************************************************************************
** Function name: SPIReceive
** Descriptions: the module will receive a block of data from
** the SPI, the 2nd parameter is the block length.
** parameters: buffer pointer, and block length
** Returned value: None
**
*****************************************************************************/
void SPIReceive( WORD *buf, DWORD Length )
{
DWORD i;
for ( i = 0; i < Length; i++ )
{
/* */
SPI_RX_Flush();
/* wrtie dummy half-word out to generate clock, then read data from MISO */
SPI2_FIFO_DATA = *buf;
/* Wait for transfer complete, SPIF bit set */
while ( SPI2_STAT & (SPI_BUSY | SPI_RX_FIFO_FULL) ){NOP;}
*buf = SPI2_FIFO_DATA;
while ( SPI2_STAT & SPI_BUSY );
buf++;
}
return;
}
/*****************************************************************************
** Function name: SPIInterruptReceive
** Descriptions: This module is used when Rx interrupt is enabled
** RX Buffer pointer is updated in the ISR
** parameters: block length
** Returned value: None
**
*****************************************************************************/
void SPIInterruptReceive( DWORD Length )
{
DWORD i;
for ( i = 0; i < Length; i++ )
{
/* write dummy half-word out to generate clock, then read data from MISO */
SPI2_FIFO_DA