##// END OF EJS Templates
Now uses qmake to compile an Qt-creator compatible!
Now uses qmake to compile an Qt-creator compatible!

File last commit:

r18:bd9ab647f70a default
r18:bd9ab647f70a default
Show More
lpc17xx_spi.c
562 lines | 16.9 KiB | text/x-c | CLexer
/**
* @file : lpc17xx_spi.c
* @brief : Contains all functions support for SPI firmware library on LPC17xx
* @version : 1.0
* @date : 3. April. 2009
* @author : HieuNguyen
**************************************************************************
* 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.
**********************************************************************/
/* Peripheral group ----------------------------------------------------------- */
/** @addtogroup SPI
* @{
*/
/* Includes ------------------------------------------------------------------- */
#include "lpc17xx_spi.h"
#include "lpc17xx_clkpwr.h"
/* If this source file built with example, the LPC17xx FW library configuration
* file in each example directory ("lpc17xx_libcfg.h") must be included,
* otherwise the default FW library configuration file must be included instead
*/
#ifdef __BUILD_WITH_EXAMPLE__
#include "lpc17xx_libcfg.h"
#else
#include "lpc17xx_libcfg_default.h"
#endif /* __BUILD_WITH_EXAMPLE__ */
#ifdef _SPI
/* Private Types -------------------------------------------------------------- */
/** @defgroup SPI_Private_Types
* @{
*/
/** @brief SPI device configuration structure type */
typedef struct
{
int32_t dataword; /* Current data word: 0 - 8 bit; 1 - 16 bit */
uint32_t txrx_setup; /* Transmission setup */
void (*inthandler)(void); /* Transmission interrupt handler */
} SPI_CFG_T;
/**
* @}
*/
/* Private Variables ---------------------------------------------------------- */
/* SPI configuration data */
static SPI_CFG_T spidat;
/* Private Functions ---------------------------------------------------------- */
/** @defgroup SPI_Private_Functions
* @{
*/
/*********************************************************************//**
* @brief Standard Private SPI Interrupt handler
* @param[in] None
* @return None
***********************************************************************/
void SPI_IntHandler(void)
{
SPI_DATA_SETUP_Type *xf_setup;
uint16_t tmp;
xf_setup = (SPI_DATA_SETUP_Type *)spidat.txrx_setup;
/* Dummy read to clear SPI interrupt flag */
if (LPC_SPI->SPINT & SPI_SPINT_INTFLAG){
LPC_SPI->SPINT = SPI_SPINT_INTFLAG;
}
// save status
tmp = LPC_SPI->SPSR;
xf_setup->status = tmp;
// Check for error
if (tmp & (SPI_SPSR_ABRT | SPI_SPSR_MODF | SPI_SPSR_ROVR | SPI_SPSR_WCOL)){
xf_setup->status |= SPI_STAT_ERROR;
// Disable Interrupt and call call-back
SPI_IntCmd(LPC_SPI, DISABLE);
if (xf_setup->callback != NULL){
xf_setup->callback();
}
return;
}
/* Check SPI complete flag */
if (tmp & SPI_SPSR_SPIF){
// Read data from SPI data
tmp = SPI_ReceiveData(LPC_SPI);
if (xf_setup->rx_data != NULL)
{
// if (spidat.dataword == 0){
// *(uint8_t *)(xf_setup->rx_data + xf_setup->counter) = (uint8_t) tmp;
// } else {
// *(uint16_t *)(xf_setup->rx_data + xf_setup->counter) = (uint8_t) tmp;
// }
if (spidat.dataword == 0){
*(uint8_t *)((uint8_t *)(xf_setup->rx_data) + xf_setup->counter) = (uint8_t) tmp;
} else {
*(uint16_t *)((uint8_t *)(xf_setup->rx_data) + xf_setup->counter) = (uint8_t) tmp;
}
}
// Increase counter
if (spidat.dataword == 0){
xf_setup->counter++;
} else {
xf_setup->counter += 2;
}
}
if (xf_setup->counter < xf_setup->length){
// Write data to buffer
if(xf_setup->tx_data == NULL){
if (spidat.dataword == 0){
SPI_SendData(LPC_SPI, 0xFF);
} else {
SPI_SendData(LPC_SPI, 0xFFFF);
}
} else {
// if (spidat.dataword == 0){
// SPI_SendData(SPI, (*(uint8_t *)(xf_setup->tx_data + xf_setup->counter)));
// } else {
// SPI_SendData(SPI, (*(uint16_t *)(xf_setup->tx_data + xf_setup->counter)));
// }
if (spidat.dataword == 0){
SPI_SendData(LPC_SPI, (*(uint8_t *)((uint8_t *)(xf_setup->tx_data) + xf_setup->counter)));
} else {
SPI_SendData(LPC_SPI, (*(uint16_t *)((uint8_t *)(xf_setup->tx_data) + xf_setup->counter)));
}
}
}
// No more data to send
else {
xf_setup->status |= SPI_STAT_DONE;
// Disable Interrupt and call call-back
SPI_IntCmd(LPC_SPI, DISABLE);
if (xf_setup->callback != NULL){
xf_setup->callback();
}
}
}
/**
* @}
*/
/* Public Functions ----------------------------------------------------------- */
/** @addtogroup SPI_Public_Functions
* @{
*/
/*********************************************************************//**
* @brief Setup clock rate for SPI device
* @param[in] SPIx SPI peripheral definition, should be SPI
* @param[in] target_clock : clock of SPI (Hz)
* @return None
***********************************************************************/
void SPI_SetClock (LPC_SPI_TypeDef *SPIx, uint32_t target_clock)
{
uint32_t spi_pclk;
uint32_t prescale, temp;
CHECK_PARAM(PARAM_SPIx(SPIx));
if (SPIx == LPC_SPI){
spi_pclk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_SPI);
} else {
return;
}
prescale = 8;
// Find closest clock to target clock
while (1){
temp = target_clock * prescale;
if (temp >= spi_pclk){
break;
}
prescale += 2;
if(prescale >= 254){
break;
}
}
// Write to register
SPIx->SPCCR = SPI_SPCCR_COUNTER(prescale);
}
/*********************************************************************//**
* @brief De-initializes the SPIx peripheral registers to their
* default reset values.
* @param[in] SPIx SPI peripheral selected, should be SPI
* @return None
**********************************************************************/
void SPI_DeInit(LPC_SPI_TypeDef *SPIx)
{
CHECK_PARAM(PARAM_SPIx(SPIx));
if (SPIx == LPC_SPI){
/* Set up clock and power for SPI module */
CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSPI, DISABLE);
}
}
/********************************************************************//**
* @brief Initializes the SPIx peripheral according to the specified
* parameters in the UART_ConfigStruct.
* @param[in] SPIx SPI peripheral selected, should be SPI
* @param[in] SPI_ConfigStruct Pointer to a SPI_CFG_Type structure
* that contains the configuration information for the
* specified SPI peripheral.
* @return None
*********************************************************************/
void SPI_Init(LPC_SPI_TypeDef *SPIx, SPI_CFG_Type *SPI_ConfigStruct)
{
uint32_t tmp;
CHECK_PARAM(PARAM_SPIx(SPIx));
if(SPIx == LPC_SPI){
/* Set up clock and power for UART module */
CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSPI, ENABLE);
} else {
return;
}
// Configure SPI, interrupt is disable as default
tmp = ((SPI_ConfigStruct->CPHA) | (SPI_ConfigStruct->CPOL) \
| (SPI_ConfigStruct->DataOrder) | (SPI_ConfigStruct->Databit) \
| (SPI_ConfigStruct->Mode) | SPI_SPCR_BIT_EN) & SPI_SPCR_BITMASK;
// write back to SPI control register
SPIx->SPCR = tmp;
if (SPI_ConfigStruct->Databit > SPI_DATABIT_8){
spidat.dataword = 1;
} else {
spidat.dataword = 0;
}
// Set clock rate for SPI peripheral
SPI_SetClock(SPIx, SPI_ConfigStruct->ClockRate);
// If interrupt flag is set, Write '1' to Clear interrupt flag
if (SPIx->SPINT & SPI_SPINT_INTFLAG){
SPIx->SPINT = SPI_SPINT_INTFLAG;
}
}
/*****************************************************************************//**
* @brief Fills each SPI_InitStruct member with its default value:
* - CPHA = SPI_CPHA_FIRST
* - CPOL = SPI_CPOL_HI
* - ClockRate = 1000000
* - DataOrder = SPI_DATA_MSB_FIRST
* - Databit = SPI_DATABIT_8
* - Mode = SPI_MASTER_MODE
* @param[in] SPI_InitStruct Pointer to a SPI_CFG_Type structure
* which will be initialized.
* @return None
*******************************************************************************/
void SPI_ConfigStructInit(SPI_CFG_Type *SPI_InitStruct)
{
SPI_InitStruct->CPHA = SPI_CPHA_FIRST;
SPI_InitStruct->CPOL = SPI_CPOL_HI;
SPI_InitStruct->ClockRate = 1000000;
SPI_InitStruct->DataOrder = SPI_DATA_MSB_FIRST;
SPI_InitStruct->Databit = SPI_DATABIT_8;
SPI_InitStruct->Mode = SPI_MASTER_MODE;
}
/*********************************************************************//**
* @brief Transmit a single data through SPIx peripheral
* @param[in] SPIx SPI peripheral selected, should be SPI
* @param[in] Data Data to transmit (must be 16 or 8-bit long,
* this depend on SPI data bit number configured)
* @return none
**********************************************************************/
void SPI_SendData(LPC_SPI_TypeDef* SPIx, uint16_t Data)
{
CHECK_PARAM(PARAM_SPIx(SPIx));
SPIx->SPDR = Data & SPI_SPDR_BITMASK;
}
/*********************************************************************//**
* @brief Receive a single data from SPIx peripheral
* @param[in] SPIx SPI peripheral selected, should be SPI
* @return Data received (16-bit long)
**********************************************************************/
uint16_t SPI_ReceiveData(LPC_SPI_TypeDef* SPIx)
{
CHECK_PARAM(PARAM_SPIx(SPIx));
return ((uint16_t) (SPIx->SPDR & SPI_SPDR_BITMASK));
}
/*********************************************************************//**
* @brief SPI Read write data function
* @param[in] SPIx Pointer to SPI peripheral, should be SPI
* @param[in] dataCfg Pointer to a SPI_DATA_SETUP_Type structure that
* contains specified information about transmit
* data configuration.
* @param[in] xfType Transfer type, should be:
* - SPI_TRANSFER_POLLING: Polling mode
* - SPI_TRANSFER_INTERRUPT: Interrupt mode
* @return Actual Data length has been transferred in polling mode.
* In interrupt mode, always return (0)
* Return (-1) if error.
* Note: This function can be used in both master and slave mode.
***********************************************************************/
int32_t SPI_ReadWrite (LPC_SPI_TypeDef *SPIx, SPI_DATA_SETUP_Type *dataCfg, \
SPI_TRANSFER_Type xfType)
{
uint8_t *rdata8;
uint8_t *wdata8;
uint16_t *rdata16;
uint16_t *wdata16;
uint32_t stat;
uint32_t temp;
//read for empty buffer
temp = SPIx->SPDR;
//dummy to clear status
temp = SPIx->SPSR;
dataCfg->counter = 0;
dataCfg->status = 0;
if (xfType == SPI_TRANSFER_POLLING){
if (spidat.dataword == 0){
rdata8 = (uint8_t *)dataCfg->rx_data;
wdata8 = (uint8_t *)dataCfg->tx_data;
} else {
rdata16 = (uint16_t *)dataCfg->rx_data;
wdata16 = (uint16_t *)dataCfg->tx_data;
}
while(dataCfg->counter < dataCfg->length)
{
// Write data to buffer
if(dataCfg->tx_data == NULL){
if (spidat.dataword == 0){
SPI_SendData(SPIx, 0xFF);
} else {
SPI_SendData(SPIx, 0xFFFF);
}
} else {
if (spidat.dataword == 0){
SPI_SendData(SPIx, *wdata8);
wdata8++;
} else {
SPI_SendData(SPIx, *wdata16);
wdata16++;
}
}
// Wait for transfer complete
while (!((stat = SPIx->SPSR) & SPI_SPSR_SPIF));
// Check for error
if (stat & (SPI_SPSR_ABRT | SPI_SPSR_MODF | SPI_SPSR_ROVR | SPI_SPSR_WCOL)){
// save status
dataCfg->status = stat | SPI_STAT_ERROR;
return (dataCfg->counter);
}
// Read data from SPI dat
temp = (uint32_t) SPI_ReceiveData(SPIx);
// Store data to destination
if (dataCfg->rx_data != NULL)
{
if (spidat.dataword == 0){
*(rdata8) = (uint8_t) temp;
rdata8++;
} else {
*(rdata16) = (uint16_t) temp;
rdata16++;
}
}
// Increase counter
if (spidat.dataword == 0){
dataCfg->counter++;
} else {
dataCfg->counter += 2;
}
}
// Return length of actual data transferred
// save status
dataCfg->status = stat | SPI_STAT_DONE;
return (dataCfg->counter);
}
// Interrupt mode
else {
spidat.txrx_setup = (uint32_t)dataCfg;
spidat.inthandler = SPI_IntHandler;
// Check if interrupt flag is already set
if(SPIx->SPINT & SPI_SPINT_INTFLAG){
SPIx->SPINT = SPI_SPINT_INTFLAG;
}
if (dataCfg->counter < dataCfg->length){
// Write data to buffer
if(dataCfg->tx_data == NULL){
if (spidat.dataword == 0){
SPI_SendData(SPIx, 0xFF);
} else {
SPI_SendData(SPIx, 0xFFFF);
}
} else {
if (spidat.dataword == 0){
SPI_SendData(SPIx, (*(uint8_t *)dataCfg->tx_data));
} else {
SPI_SendData(SPIx, (*(uint16_t *)dataCfg->tx_data));
}
}
SPI_IntCmd(SPIx, ENABLE);
} else {
// Save status
dataCfg->status = SPI_STAT_DONE;
}
return (0);
}
return (0);
}
/********************************************************************//**
* @brief Enable or disable SPIx interrupt.
* @param[in] SPIx SPI peripheral selected, should be SPI
* @param[in] NewState New state of specified UART interrupt type,
* should be:
* - ENALBE: Enable this SPI interrupt.
* - DISALBE: Disable this SPI interrupt.
* @return None
*********************************************************************/
void SPI_IntCmd(LPC_SPI_TypeDef *SPIx, FunctionalState NewState)
{
CHECK_PARAM(PARAM_SPIx(SPIx));
CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));
if (NewState == ENABLE)
{
SPIx->SPCR |= SPI_SPCR_SPIE;
}
else
{
SPIx->SPCR &= (~SPI_SPCR_SPIE) & SPI_SPCR_BITMASK;
}
}
/********************************************************************//**
* @brief Checks whether the SPI interrupt flag is set or not.
* @param[in] SPIx SPI peripheral selected, should be SPI
* @return The new state of SPI Interrupt Flag (SET or RESET)
*********************************************************************/
IntStatus SPI_GetIntStatus (LPC_SPI_TypeDef *SPIx)
{
CHECK_PARAM(PARAM_SPIx(SPIx));
return ((SPIx->SPINT & SPI_SPINT_INTFLAG) ? SET : RESET);
}
/********************************************************************//**
* @brief Clear SPI interrupt flag.
* @param[in] SPIx SPI peripheral selected, should be SPI
* @return None
*********************************************************************/
void SPI_ClearIntPending(LPC_SPI_TypeDef *SPIx)
{
CHECK_PARAM(PARAM_SPIx(SPIx));
SPIx->SPINT = SPI_SPINT_INTFLAG;
}
/********************************************************************//**
* @brief Get current value of SPI Status register in SPIx peripheral.
* @param[in] SPIx SPI peripheral selected, should be SPI
* @return Current value of SPI Status register in SPI peripheral.
* Note: The return value of this function must be used with
* SPI_CheckStatus() to determine current flag status
* corresponding to each SPI status type. Because some flags in
* SPI Status register will be cleared after reading, the next reading
* SPI Status register could not be correct. So this function used to
* read SPI status register in one time only, then the return value
* used to check all flags.
*********************************************************************/
uint32_t SPI_GetStatus(LPC_SPI_TypeDef* SPIx)
{
CHECK_PARAM(PARAM_SPIx(SPIx));
return (SPIx->SPSR & SPI_SPSR_BITMASK);
}
/********************************************************************//**
* @brief Checks whether the specified SPI Status flag is set or not
* via inputSPIStatus parameter.
* @param[in] inputSPIStatus Value to check status of each flag type.
* This value is the return value from SPI_GetStatus().
* @param[in] SPIStatus Specifies the SPI status flag to check,
* should be one of the following:
- SPI_STAT_ABRT: Slave abort.
- SPI_STAT_MODF: Mode fault.
- SPI_STAT_ROVR: Read overrun.
- SPI_STAT_WCOL: Write collision.
- SPI_STAT_SPIF: SPI transfer complete.
* @return The new state of SPIStatus (SET or RESET)
*********************************************************************/
FlagStatus SPI_CheckStatus (uint32_t inputSPIStatus, uint8_t SPIStatus)
{
CHECK_PARAM(PARAM_SPI_STAT(SPIStatus));
return ((inputSPIStatus & SPIStatus) ? SET : RESET);
}
/**
* @brief Standard SPI Interrupt handler
* @param[in] None
* @return None
*/
void SPI_StdIntHandler(void)
{
// Call relevant handler
spidat.inthandler();
}
/**
* @}
*/
#endif /* _SPI */
/**
* @}
*/
/* --------------------------------- End Of File ------------------------------ */