lpc-field

Template project for programming NXP's LPC1768 MCUs
git clone git://git.mdnr.space/lpc-field
Log | Files | Refs | README | LICENSE

lpc17xx_spi.c (14158B)


      1 /**********************************************************************
      2 * $Id$		lpc17xx_spi.c				2010-05-21
      3 *//**
      4 * @file		lpc17xx_spi.c
      5 * @brief	Contains all functions support for SPI firmware library on LPC17xx
      6 * @version	2.0
      7 * @date		21. May. 2010
      8 * @author	NXP MCU SW Application Team
      9 *
     10 * Copyright(C) 2010, NXP Semiconductor
     11 * All rights reserved.
     12 *
     13 ***********************************************************************
     14 * Software that is described herein is for illustrative purposes only
     15 * which provides customers with programming information regarding the
     16 * products. This software is supplied "AS IS" without any warranties.
     17 * NXP Semiconductors assumes no responsibility or liability for the
     18 * use of the software, conveys no license or title under any patent,
     19 * copyright, or mask work right to the product. NXP Semiconductors
     20 * reserves the right to make changes in the software without
     21 * notification. NXP Semiconductors also make no representation or
     22 * warranty that such application will be suitable for the specified
     23 * use without further testing or modification.
     24 * Permission to use, copy, modify, and distribute this software and its
     25 * documentation is hereby granted, under NXP Semiconductors'
     26 * relevant copyright in the software, without fee, provided that it
     27 * is used in conjunction with NXP Semiconductors microcontrollers.  This
     28 * copyright, permission, and disclaimer notice must appear in all copies of
     29 * this code.
     30 **********************************************************************/
     31 
     32 /* Peripheral group ----------------------------------------------------------- */
     33 /** @addtogroup SPI
     34  * @{
     35  */
     36 
     37 /* Includes ------------------------------------------------------------------- */
     38 #include "lpc17xx_spi.h"
     39 #include "lpc17xx_clkpwr.h"
     40 
     41 /* If this source file built with example, the LPC17xx FW library configuration
     42  * file in each example directory ("lpc17xx_libcfg.h") must be included,
     43  * otherwise the default FW library configuration file must be included instead
     44  */
     45 #ifdef __BUILD_WITH_EXAMPLE__
     46 #include "lpc17xx_libcfg.h"
     47 #else
     48 #include "lpc17xx_libcfg_default.h"
     49 #endif /* __BUILD_WITH_EXAMPLE__ */
     50 
     51 #ifdef _SPI
     52 
     53 
     54 /* Public Functions ----------------------------------------------------------- */
     55 /** @addtogroup SPI_Public_Functions
     56  * @{
     57  */
     58 
     59 /*********************************************************************//**
     60  * @brief 		Setup clock rate for SPI device
     61  * @param[in] 	SPIx	SPI peripheral definition, should be LPC_SPI
     62  * @param[in]	target_clock : clock of SPI (Hz)
     63  * @return 		None
     64  ***********************************************************************/
     65 void SPI_SetClock (LPC_SPI_TypeDef *SPIx, uint32_t target_clock)
     66 {
     67 	uint32_t spi_pclk;
     68 	uint32_t prescale, temp;
     69 
     70 	CHECK_PARAM(PARAM_SPIx(SPIx));
     71 
     72 	if (SPIx == LPC_SPI){
     73 		spi_pclk =  CLKPWR_GetPCLK (CLKPWR_PCLKSEL_SPI);
     74 	} else {
     75 		return;
     76 	}
     77 
     78 	prescale = 8;
     79 	// Find closest clock to target clock
     80 	while (1){
     81 		temp = target_clock * prescale;
     82 		if (temp >= spi_pclk){
     83 			break;
     84 		}
     85 		prescale += 2;
     86 		if(prescale >= 254){
     87 			break;
     88 		}
     89 	}
     90 
     91 	// Write to register
     92 	SPIx->SPCCR = SPI_SPCCR_COUNTER(prescale);
     93 }
     94 
     95 
     96 /*********************************************************************//**
     97  * @brief		De-initializes the SPIx peripheral registers to their
     98 *                  default reset values.
     99  * @param[in]	SPIx	SPI peripheral selected, should be LPC_SPI
    100  * @return 		None
    101  **********************************************************************/
    102 void SPI_DeInit(LPC_SPI_TypeDef *SPIx)
    103 {
    104 	CHECK_PARAM(PARAM_SPIx(SPIx));
    105 
    106 	if (SPIx == LPC_SPI){
    107 		/* Set up clock and power for SPI module */
    108 		CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSPI, DISABLE);
    109 	}
    110 }
    111 
    112 /*********************************************************************//**
    113  * @brief		Get data bit size per transfer
    114  * @param[in]	SPIx	SPI peripheral selected, should be LPC_SPI
    115  * @return 		number of bit per transfer, could be 8-16
    116  **********************************************************************/
    117 uint8_t SPI_GetDataSize (LPC_SPI_TypeDef *SPIx)
    118 {
    119 	CHECK_PARAM(PARAM_SPIx(SPIx));
    120 	return ((SPIx->SPCR)>>8 & 0xF);
    121 }
    122 
    123 /********************************************************************//**
    124  * @brief		Initializes the SPIx peripheral according to the specified
    125 *               parameters in the UART_ConfigStruct.
    126  * @param[in]	SPIx	SPI peripheral selected, should be LPC_SPI
    127  * @param[in]	SPI_ConfigStruct Pointer to a SPI_CFG_Type structure
    128 *                    that contains the configuration information for the
    129 *                    specified SPI peripheral.
    130  * @return 		None
    131  *********************************************************************/
    132 void SPI_Init(LPC_SPI_TypeDef *SPIx, SPI_CFG_Type *SPI_ConfigStruct)
    133 {
    134 	uint32_t tmp;
    135 
    136 	CHECK_PARAM(PARAM_SPIx(SPIx));
    137 
    138 	if(SPIx == LPC_SPI){
    139 		/* Set up clock and power for UART module */
    140 		CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSPI, ENABLE);
    141 	} else {
    142 		return;
    143 	}
    144 
    145 	// Configure SPI, interrupt is disable as default
    146 	tmp = ((SPI_ConfigStruct->CPHA) | (SPI_ConfigStruct->CPOL) \
    147 		| (SPI_ConfigStruct->DataOrder) | (SPI_ConfigStruct->Databit) \
    148 		| (SPI_ConfigStruct->Mode) | SPI_SPCR_BIT_EN) & SPI_SPCR_BITMASK;
    149 	// write back to SPI control register
    150 	SPIx->SPCR = tmp;
    151 
    152 	// Set clock rate for SPI peripheral
    153 	SPI_SetClock(SPIx, SPI_ConfigStruct->ClockRate);
    154 
    155 	// If interrupt flag is set, Write '1' to Clear interrupt flag
    156 	if (SPIx->SPINT & SPI_SPINT_INTFLAG){
    157 		SPIx->SPINT = SPI_SPINT_INTFLAG;
    158 	}
    159 }
    160 
    161 
    162 
    163 /*****************************************************************************//**
    164 * @brief		Fills each SPI_InitStruct member with its default value:
    165 * 				- CPHA = SPI_CPHA_FIRST
    166 * 				- CPOL = SPI_CPOL_HI
    167 * 				- ClockRate = 1000000
    168 * 				- DataOrder = SPI_DATA_MSB_FIRST
    169 * 				- Databit = SPI_DATABIT_8
    170 * 				- Mode = SPI_MASTER_MODE
    171 * @param[in]	SPI_InitStruct Pointer to a SPI_CFG_Type structure
    172 *                    which will be initialized.
    173 * @return		None
    174 *******************************************************************************/
    175 void SPI_ConfigStructInit(SPI_CFG_Type *SPI_InitStruct)
    176 {
    177 	SPI_InitStruct->CPHA = SPI_CPHA_FIRST;
    178 	SPI_InitStruct->CPOL = SPI_CPOL_HI;
    179 	SPI_InitStruct->ClockRate = 1000000;
    180 	SPI_InitStruct->DataOrder = SPI_DATA_MSB_FIRST;
    181 	SPI_InitStruct->Databit = SPI_DATABIT_8;
    182 	SPI_InitStruct->Mode = SPI_MASTER_MODE;
    183 }
    184 
    185 /*********************************************************************//**
    186  * @brief		Transmit a single data through SPIx peripheral
    187  * @param[in]	SPIx	SPI peripheral selected, should be LPC_SPI
    188  * @param[in]	Data	Data to transmit (must be 16 or 8-bit long,
    189  * 						this depend on SPI data bit number configured)
    190  * @return 		none
    191  **********************************************************************/
    192 void SPI_SendData(LPC_SPI_TypeDef* SPIx, uint16_t Data)
    193 {
    194 	CHECK_PARAM(PARAM_SPIx(SPIx));
    195 
    196 	SPIx->SPDR = Data & SPI_SPDR_BITMASK;
    197 }
    198 
    199 
    200 
    201 /*********************************************************************//**
    202  * @brief		Receive a single data from SPIx peripheral
    203  * @param[in]	SPIx	SPI peripheral selected, should be LPC_SPI
    204  * @return 		Data received (16-bit long)
    205  **********************************************************************/
    206 uint16_t SPI_ReceiveData(LPC_SPI_TypeDef* SPIx)
    207 {
    208 	CHECK_PARAM(PARAM_SPIx(SPIx));
    209 
    210 	return ((uint16_t) (SPIx->SPDR & SPI_SPDR_BITMASK));
    211 }
    212 
    213 /*********************************************************************//**
    214  * @brief 		SPI 	Read write data function
    215  * @param[in]	SPIx 	Pointer to SPI peripheral, should be LPC_SPI
    216  * @param[in]	dataCfg	Pointer to a SPI_DATA_SETUP_Type structure that
    217  * 						contains specified information about transmit
    218  * 						data configuration.
    219  * @param[in]	xfType	Transfer type, should be:
    220  * 						- SPI_TRANSFER_POLLING: Polling mode
    221  * 						- SPI_TRANSFER_INTERRUPT: Interrupt mode
    222  * @return 		Actual Data length has been transferred in polling mode.
    223  * 				In interrupt mode, always return (0)
    224  * 				Return (-1) if error.
    225  * Note: This function can be used in both master and slave mode.
    226  ***********************************************************************/
    227 int32_t SPI_ReadWrite (LPC_SPI_TypeDef *SPIx, SPI_DATA_SETUP_Type *dataCfg, \
    228 						SPI_TRANSFER_Type xfType)
    229 {
    230 	uint8_t *rdata8 = NULL;
    231     uint8_t *wdata8 = NULL;
    232 	uint16_t *rdata16 = NULL;
    233     uint16_t *wdata16 = NULL;
    234     uint32_t stat = 0;
    235     uint32_t temp;
    236     uint8_t dataword;
    237 
    238 	//read for empty buffer
    239 	temp = SPIx->SPDR;
    240 	//dummy to clear status
    241 	temp = SPIx->SPSR;
    242 	dataCfg->counter = 0;
    243 	dataCfg->status = 0;
    244 
    245 	if(SPI_GetDataSize (SPIx) == 8)
    246 		dataword = 0;
    247 	else dataword = 1;
    248 	if (xfType == SPI_TRANSFER_POLLING){
    249 
    250 		if (dataword == 0){
    251 			rdata8 = (uint8_t *)dataCfg->rx_data;
    252 			wdata8 = (uint8_t *)dataCfg->tx_data;
    253 		} else {
    254 			rdata16 = (uint16_t *)dataCfg->rx_data;
    255 			wdata16 = (uint16_t *)dataCfg->tx_data;
    256 		}
    257 
    258 		while(dataCfg->counter < dataCfg->length)
    259 		{
    260 			// Write data to buffer
    261 			if(dataCfg->tx_data == NULL){
    262 				if (dataword == 0){
    263 					SPI_SendData(SPIx, 0xFF);
    264 				} else {
    265 					SPI_SendData(SPIx, 0xFFFF);
    266 				}
    267 			} else {
    268 				if (dataword == 0){
    269 					SPI_SendData(SPIx, *wdata8);
    270 					wdata8++;
    271 				} else {
    272 					SPI_SendData(SPIx, *wdata16);
    273 					wdata16++;
    274 				}
    275 			}
    276 			// Wait for transfer complete
    277 			while (!((stat = SPIx->SPSR) & SPI_SPSR_SPIF));
    278 			// Check for error
    279 			if (stat & (SPI_SPSR_ABRT | SPI_SPSR_MODF | SPI_SPSR_ROVR | SPI_SPSR_WCOL)){
    280 				// save status
    281 				dataCfg->status = stat | SPI_STAT_ERROR;
    282 				return (dataCfg->counter);
    283 			}
    284 			// Read data from SPI dat
    285 			temp = (uint32_t) SPI_ReceiveData(SPIx);
    286 
    287 			// Store data to destination
    288 			if (dataCfg->rx_data != NULL)
    289 			{
    290 				if (dataword == 0){
    291 					*(rdata8) = (uint8_t) temp;
    292 					rdata8++;
    293 				} else {
    294 					*(rdata16) = (uint16_t) temp;
    295 					rdata16++;
    296 				}
    297 			}
    298 			// Increase counter
    299 			if (dataword == 0){
    300 				dataCfg->counter++;
    301 			} else {
    302 				dataCfg->counter += 2;
    303 			}
    304 		}
    305 
    306 		// Return length of actual data transferred
    307 		// save status
    308 		dataCfg->status = stat | SPI_STAT_DONE;
    309 		return (dataCfg->counter);
    310 	}
    311 	// Interrupt mode
    312 	else {
    313 
    314 		// Check if interrupt flag is already set
    315 		if(SPIx->SPINT & SPI_SPINT_INTFLAG){
    316 			SPIx->SPINT = SPI_SPINT_INTFLAG;
    317 		}
    318 		if (dataCfg->counter < dataCfg->length){
    319 			// Write data to buffer
    320 			if(dataCfg->tx_data == NULL){
    321 				if (dataword == 0){
    322 					SPI_SendData(SPIx, 0xFF);
    323 				} else {
    324 					SPI_SendData(SPIx, 0xFFFF);
    325 				}
    326 			} else {
    327 				if (dataword == 0){
    328 					SPI_SendData(SPIx, (*(uint8_t *)dataCfg->tx_data));
    329 				} else {
    330 					SPI_SendData(SPIx, (*(uint16_t *)dataCfg->tx_data));
    331 				}
    332 			}
    333 			SPI_IntCmd(SPIx, ENABLE);
    334 		} else {
    335 			// Save status
    336 			dataCfg->status = SPI_STAT_DONE;
    337 		}
    338 		return (0);
    339 	}
    340 }
    341 
    342 
    343 /********************************************************************//**
    344  * @brief 		Enable or disable SPIx interrupt.
    345  * @param[in]	SPIx	SPI peripheral selected, should be LPC_SPI
    346  * @param[in]	NewState New state of specified UART interrupt type,
    347  * 				should be:
    348  * 				- ENALBE: Enable this SPI interrupt.
    349 * 				- DISALBE: Disable this SPI interrupt.
    350  * @return 		None
    351  *********************************************************************/
    352 void SPI_IntCmd(LPC_SPI_TypeDef *SPIx, FunctionalState NewState)
    353 {
    354 	CHECK_PARAM(PARAM_SPIx(SPIx));
    355 	CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));
    356 
    357 	if (NewState == ENABLE)
    358 	{
    359 		SPIx->SPCR |= SPI_SPCR_SPIE;
    360 	}
    361 	else
    362 	{
    363 		SPIx->SPCR &= (~SPI_SPCR_SPIE) & SPI_SPCR_BITMASK;
    364 	}
    365 }
    366 
    367 
    368 /********************************************************************//**
    369  * @brief 		Checks whether the SPI interrupt flag is set or not.
    370  * @param[in]	SPIx	SPI peripheral selected, should be LPC_SPI
    371  * @return 		The new state of SPI Interrupt Flag (SET or RESET)
    372  *********************************************************************/
    373 IntStatus SPI_GetIntStatus (LPC_SPI_TypeDef *SPIx)
    374 {
    375 	CHECK_PARAM(PARAM_SPIx(SPIx));
    376 
    377 	return ((SPIx->SPINT & SPI_SPINT_INTFLAG) ? SET : RESET);
    378 }
    379 
    380 /********************************************************************//**
    381  * @brief 		Clear SPI interrupt flag.
    382  * @param[in]	SPIx	SPI peripheral selected, should be LPC_SPI
    383  * @return 		None
    384  *********************************************************************/
    385 void SPI_ClearIntPending(LPC_SPI_TypeDef *SPIx)
    386 {
    387 	CHECK_PARAM(PARAM_SPIx(SPIx));
    388 
    389 	SPIx->SPINT = SPI_SPINT_INTFLAG;
    390 }
    391 
    392 /********************************************************************//**
    393  * @brief 		Get current value of SPI Status register in SPIx peripheral.
    394  * @param[in]	SPIx	SPI peripheral selected, should be LPC_SPI
    395  * @return		Current value of SPI Status register in SPI peripheral.
    396  * Note:	The return value of this function must be used with
    397  * 			SPI_CheckStatus() to determine current flag status
    398  * 			corresponding to each SPI status type. Because some flags in
    399  * 			SPI Status register will be cleared after reading, the next reading
    400  * 			SPI Status register could not be correct. So this function used to
    401  * 			read SPI status register in one time only, then the return value
    402  * 			used to check all flags.
    403  *********************************************************************/
    404 uint32_t SPI_GetStatus(LPC_SPI_TypeDef* SPIx)
    405 {
    406 	CHECK_PARAM(PARAM_SPIx(SPIx));
    407 
    408 	return (SPIx->SPSR & SPI_SPSR_BITMASK);
    409 }
    410 
    411 /********************************************************************//**
    412  * @brief 		Checks whether the specified SPI Status flag is set or not
    413  * 				via inputSPIStatus parameter.
    414  * @param[in]	inputSPIStatus Value to check status of each flag type.
    415  * 				This value is the return value from SPI_GetStatus().
    416  * @param[in]	SPIStatus	Specifies the SPI status flag to check,
    417  * 				should be one of the following:
    418 				- SPI_STAT_ABRT: Slave abort.
    419 				- SPI_STAT_MODF: Mode fault.
    420 				- SPI_STAT_ROVR: Read overrun.
    421 				- SPI_STAT_WCOL: Write collision.
    422 				- SPI_STAT_SPIF: SPI transfer complete.
    423  * @return 		The new state of SPIStatus (SET or RESET)
    424  *********************************************************************/
    425 FlagStatus SPI_CheckStatus (uint32_t inputSPIStatus,  uint8_t SPIStatus)
    426 {
    427 	CHECK_PARAM(PARAM_SPI_STAT(SPIStatus));
    428 
    429 	return ((inputSPIStatus & SPIStatus) ? SET : RESET);
    430 }
    431 
    432 
    433 /**
    434  * @}
    435  */
    436 
    437 #endif /* _SPI */
    438 
    439 /**
    440  * @}
    441  */
    442 
    443 /* --------------------------------- End Of File ------------------------------ */