444 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			444 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**********************************************************************
 | |
| * $Id$		lpc17xx_spi.c				2010-05-21
 | |
| *//**
 | |
| * @file		lpc17xx_spi.c
 | |
| * @brief	Contains all functions support for SPI firmware library on LPC17xx
 | |
| * @version	2.0
 | |
| * @date		21. May. 2010
 | |
| * @author	NXP MCU SW Application Team
 | |
| *
 | |
| * Copyright(C) 2010, NXP Semiconductor
 | |
| * All rights reserved.
 | |
| *
 | |
| ***********************************************************************
 | |
| * 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.
 | |
| * Permission to use, copy, modify, and distribute this software and its
 | |
| * documentation is hereby granted, under NXP Semiconductors'
 | |
| * relevant copyright in the software, without fee, provided that it
 | |
| * is used in conjunction with NXP Semiconductors microcontrollers.  This
 | |
| * copyright, permission, and disclaimer notice must appear in all copies of
 | |
| * this code.
 | |
| **********************************************************************/
 | |
| 
 | |
| /* 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
 | |
| 
 | |
| 
 | |
| /* Public Functions ----------------------------------------------------------- */
 | |
| /** @addtogroup SPI_Public_Functions
 | |
|  * @{
 | |
|  */
 | |
| 
 | |
| /*********************************************************************//**
 | |
|  * @brief 		Setup clock rate for SPI device
 | |
|  * @param[in] 	SPIx	SPI peripheral definition, should be LPC_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 LPC_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		Get data bit size per transfer
 | |
|  * @param[in]	SPIx	SPI peripheral selected, should be LPC_SPI
 | |
|  * @return 		number of bit per transfer, could be 8-16
 | |
|  **********************************************************************/
 | |
| uint8_t SPI_GetDataSize (LPC_SPI_TypeDef *SPIx)
 | |
| {
 | |
| 	CHECK_PARAM(PARAM_SPIx(SPIx));
 | |
| 	return ((SPIx->SPCR)>>8 & 0xF);
 | |
| }
 | |
| 
 | |
| /********************************************************************//**
 | |
|  * @brief		Initializes the SPIx peripheral according to the specified
 | |
| *               parameters in the UART_ConfigStruct.
 | |
|  * @param[in]	SPIx	SPI peripheral selected, should be LPC_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;
 | |
| 
 | |
| 	// 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 LPC_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 LPC_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 LPC_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;
 | |
|     uint8_t dataword;
 | |
| 
 | |
| 	//read for empty buffer
 | |
| 	temp = SPIx->SPDR;
 | |
| 	//dummy to clear status
 | |
| 	temp = SPIx->SPSR;
 | |
| 	dataCfg->counter = 0;
 | |
| 	dataCfg->status = 0;
 | |
| 
 | |
| 	if(SPI_GetDataSize (SPIx) == 8)
 | |
| 		dataword = 0;
 | |
| 	else dataword = 1;
 | |
| 	if (xfType == SPI_TRANSFER_POLLING){
 | |
| 
 | |
| 		if (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 (dataword == 0){
 | |
| 					SPI_SendData(SPIx, 0xFF);
 | |
| 				} else {
 | |
| 					SPI_SendData(SPIx, 0xFFFF);
 | |
| 				}
 | |
| 			} else {
 | |
| 				if (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 (dataword == 0){
 | |
| 					*(rdata8) = (uint8_t) temp;
 | |
| 					rdata8++;
 | |
| 				} else {
 | |
| 					*(rdata16) = (uint16_t) temp;
 | |
| 					rdata16++;
 | |
| 				}
 | |
| 			}
 | |
| 			// Increase counter
 | |
| 			if (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 {
 | |
| 
 | |
| 		// 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 (dataword == 0){
 | |
| 					SPI_SendData(SPIx, 0xFF);
 | |
| 				} else {
 | |
| 					SPI_SendData(SPIx, 0xFFFF);
 | |
| 				}
 | |
| 			} else {
 | |
| 				if (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);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| /********************************************************************//**
 | |
|  * @brief 		Enable or disable SPIx interrupt.
 | |
|  * @param[in]	SPIx	SPI peripheral selected, should be LPC_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 LPC_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 LPC_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 LPC_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);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * @}
 | |
|  */
 | |
| 
 | |
| #endif /* _SPI */
 | |
| 
 | |
| /**
 | |
|  * @}
 | |
|  */
 | |
| 
 | |
| /* --------------------------------- End Of File ------------------------------ */
 |