2 * @file : lpc17xx_spi.c
\r
3 * @brief : Contains all functions support for SPI firmware library on LPC17xx
\r
5 * @date : 3. April. 2009
\r
6 * @author : HieuNguyen
\r
7 **************************************************************************
\r
8 * Software that is described herein is for illustrative purposes only
\r
9 * which provides customers with programming information regarding the
\r
10 * products. This software is supplied "AS IS" without any warranties.
\r
11 * NXP Semiconductors assumes no responsibility or liability for the
\r
12 * use of the software, conveys no license or title under any patent,
\r
13 * copyright, or mask work right to the product. NXP Semiconductors
\r
14 * reserves the right to make changes in the software without
\r
15 * notification. NXP Semiconductors also make no representation or
\r
16 * warranty that such application will be suitable for the specified
\r
17 * use without further testing or modification.
\r
18 **********************************************************************/
\r
20 /* Peripheral group ----------------------------------------------------------- */
\r
25 /* Includes ------------------------------------------------------------------- */
\r
26 #include "lpc17xx_spi.h"
\r
27 #include "lpc17xx_clkpwr.h"
\r
29 /* If this source file built with example, the LPC17xx FW library configuration
\r
30 * file in each example directory ("lpc17xx_libcfg.h") must be included,
\r
31 * otherwise the default FW library configuration file must be included instead
\r
33 #ifdef __BUILD_WITH_EXAMPLE__
\r
34 #include "lpc17xx_libcfg.h"
\r
36 #include "lpc17xx_libcfg_default.h"
\r
37 #endif /* __BUILD_WITH_EXAMPLE__ */
\r
41 /* Private Types -------------------------------------------------------------- */
\r
42 /** @defgroup SPI_Private_Types
\r
46 /** @brief SPI device configuration structure type */
\r
49 int32_t dataword; /* Current data word: 0 - 8 bit; 1 - 16 bit */
\r
50 uint32_t txrx_setup; /* Transmission setup */
\r
51 void (*inthandler)(void); /* Transmission interrupt handler */
\r
59 /* Private Variables ---------------------------------------------------------- */
\r
60 /* SPI configuration data */
\r
61 static SPI_CFG_T spidat;
\r
64 /* Private Functions ---------------------------------------------------------- */
\r
65 /** @defgroup SPI_Private_Functions
\r
69 /*********************************************************************//**
\r
70 * @brief Standard Private SPI Interrupt handler
\r
73 ***********************************************************************/
\r
74 void SPI_IntHandler(void)
\r
76 SPI_DATA_SETUP_Type *xf_setup;
\r
79 xf_setup = (SPI_DATA_SETUP_Type *)spidat.txrx_setup;
\r
81 /* Dummy read to clear SPI interrupt flag */
\r
82 if (LPC_SPI->SPINT & SPI_SPINT_INTFLAG){
\r
83 LPC_SPI->SPINT = SPI_SPINT_INTFLAG;
\r
87 tmp = LPC_SPI->SPSR;
\r
88 xf_setup->status = tmp;
\r
90 if (tmp & (SPI_SPSR_ABRT | SPI_SPSR_MODF | SPI_SPSR_ROVR | SPI_SPSR_WCOL)){
\r
91 xf_setup->status |= SPI_STAT_ERROR;
\r
92 // Disable Interrupt and call call-back
\r
93 SPI_IntCmd(LPC_SPI, DISABLE);
\r
94 if (xf_setup->callback != NULL){
\r
95 xf_setup->callback();
\r
100 /* Check SPI complete flag */
\r
101 if (tmp & SPI_SPSR_SPIF){
\r
102 // Read data from SPI data
\r
103 tmp = SPI_ReceiveData(LPC_SPI);
\r
104 if (xf_setup->rx_data != NULL)
\r
106 // if (spidat.dataword == 0){
\r
107 // *(uint8_t *)(xf_setup->rx_data + xf_setup->counter) = (uint8_t) tmp;
\r
109 // *(uint16_t *)(xf_setup->rx_data + xf_setup->counter) = (uint8_t) tmp;
\r
111 if (spidat.dataword == 0){
\r
112 *(uint8_t *)((uint8_t *)(xf_setup->rx_data) + xf_setup->counter) = (uint8_t) tmp;
\r
114 *(uint16_t *)((uint8_t *)(xf_setup->rx_data) + xf_setup->counter) = (uint8_t) tmp;
\r
117 // Increase counter
\r
118 if (spidat.dataword == 0){
\r
119 xf_setup->counter++;
\r
121 xf_setup->counter += 2;
\r
125 if (xf_setup->counter < xf_setup->length){
\r
126 // Write data to buffer
\r
127 if(xf_setup->tx_data == NULL){
\r
128 if (spidat.dataword == 0){
\r
129 SPI_SendData(LPC_SPI, 0xFF);
\r
131 SPI_SendData(LPC_SPI, 0xFFFF);
\r
134 // if (spidat.dataword == 0){
\r
135 // SPI_SendData(SPI, (*(uint8_t *)(xf_setup->tx_data + xf_setup->counter)));
\r
137 // SPI_SendData(SPI, (*(uint16_t *)(xf_setup->tx_data + xf_setup->counter)));
\r
139 if (spidat.dataword == 0){
\r
140 SPI_SendData(LPC_SPI, (*(uint8_t *)((uint8_t *)(xf_setup->tx_data) + xf_setup->counter)));
\r
142 SPI_SendData(LPC_SPI, (*(uint16_t *)((uint8_t *)(xf_setup->tx_data) + xf_setup->counter)));
\r
146 // No more data to send
\r
148 xf_setup->status |= SPI_STAT_DONE;
\r
149 // Disable Interrupt and call call-back
\r
150 SPI_IntCmd(LPC_SPI, DISABLE);
\r
151 if (xf_setup->callback != NULL){
\r
152 xf_setup->callback();
\r
162 /* Public Functions ----------------------------------------------------------- */
\r
163 /** @addtogroup SPI_Public_Functions
\r
167 /*********************************************************************//**
\r
168 * @brief Setup clock rate for SPI device
\r
169 * @param[in] SPIx SPI peripheral definition, should be SPI
\r
170 * @param[in] target_clock : clock of SPI (Hz)
\r
172 ***********************************************************************/
\r
173 void SPI_SetClock (LPC_SPI_TypeDef *SPIx, uint32_t target_clock)
\r
176 uint32_t prescale, temp;
\r
178 CHECK_PARAM(PARAM_SPIx(SPIx));
\r
180 if (SPIx == LPC_SPI){
\r
181 spi_pclk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_SPI);
\r
187 // Find closest clock to target clock
\r
189 temp = target_clock * prescale;
\r
190 if (temp >= spi_pclk){
\r
194 if(prescale >= 254){
\r
199 // Write to register
\r
200 SPIx->SPCCR = SPI_SPCCR_COUNTER(prescale);
\r
204 /*********************************************************************//**
\r
205 * @brief De-initializes the SPIx peripheral registers to their
\r
206 * default reset values.
\r
207 * @param[in] SPIx SPI peripheral selected, should be SPI
\r
209 **********************************************************************/
\r
210 void SPI_DeInit(LPC_SPI_TypeDef *SPIx)
\r
212 CHECK_PARAM(PARAM_SPIx(SPIx));
\r
214 if (SPIx == LPC_SPI){
\r
215 /* Set up clock and power for SPI module */
\r
216 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSPI, DISABLE);
\r
222 /********************************************************************//**
\r
223 * @brief Initializes the SPIx peripheral according to the specified
\r
224 * parameters in the UART_ConfigStruct.
\r
225 * @param[in] SPIx SPI peripheral selected, should be SPI
\r
226 * @param[in] SPI_ConfigStruct Pointer to a SPI_CFG_Type structure
\r
227 * that contains the configuration information for the
\r
228 * specified SPI peripheral.
\r
230 *********************************************************************/
\r
231 void SPI_Init(LPC_SPI_TypeDef *SPIx, SPI_CFG_Type *SPI_ConfigStruct)
\r
235 CHECK_PARAM(PARAM_SPIx(SPIx));
\r
237 if(SPIx == LPC_SPI){
\r
238 /* Set up clock and power for UART module */
\r
239 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSPI, ENABLE);
\r
244 // Configure SPI, interrupt is disable as default
\r
245 tmp = ((SPI_ConfigStruct->CPHA) | (SPI_ConfigStruct->CPOL) \
\r
246 | (SPI_ConfigStruct->DataOrder) | (SPI_ConfigStruct->Databit) \
\r
247 | (SPI_ConfigStruct->Mode) | SPI_SPCR_BIT_EN) & SPI_SPCR_BITMASK;
\r
248 // write back to SPI control register
\r
251 if (SPI_ConfigStruct->Databit > SPI_DATABIT_8){
\r
252 spidat.dataword = 1;
\r
254 spidat.dataword = 0;
\r
257 // Set clock rate for SPI peripheral
\r
258 SPI_SetClock(SPIx, SPI_ConfigStruct->ClockRate);
\r
260 // If interrupt flag is set, Write '1' to Clear interrupt flag
\r
261 if (SPIx->SPINT & SPI_SPINT_INTFLAG){
\r
262 SPIx->SPINT = SPI_SPINT_INTFLAG;
\r
268 /*****************************************************************************//**
\r
269 * @brief Fills each SPI_InitStruct member with its default value:
\r
270 * - CPHA = SPI_CPHA_FIRST
\r
271 * - CPOL = SPI_CPOL_HI
\r
272 * - ClockRate = 1000000
\r
273 * - DataOrder = SPI_DATA_MSB_FIRST
\r
274 * - Databit = SPI_DATABIT_8
\r
275 * - Mode = SPI_MASTER_MODE
\r
276 * @param[in] SPI_InitStruct Pointer to a SPI_CFG_Type structure
\r
277 * which will be initialized.
\r
279 *******************************************************************************/
\r
280 void SPI_ConfigStructInit(SPI_CFG_Type *SPI_InitStruct)
\r
282 SPI_InitStruct->CPHA = SPI_CPHA_FIRST;
\r
283 SPI_InitStruct->CPOL = SPI_CPOL_HI;
\r
284 SPI_InitStruct->ClockRate = 1000000;
\r
285 SPI_InitStruct->DataOrder = SPI_DATA_MSB_FIRST;
\r
286 SPI_InitStruct->Databit = SPI_DATABIT_8;
\r
287 SPI_InitStruct->Mode = SPI_MASTER_MODE;
\r
290 /*********************************************************************//**
\r
291 * @brief Transmit a single data through SPIx peripheral
\r
292 * @param[in] SPIx SPI peripheral selected, should be SPI
\r
293 * @param[in] Data Data to transmit (must be 16 or 8-bit long,
\r
294 * this depend on SPI data bit number configured)
\r
296 **********************************************************************/
\r
297 void SPI_SendData(LPC_SPI_TypeDef* SPIx, uint16_t Data)
\r
299 CHECK_PARAM(PARAM_SPIx(SPIx));
\r
301 SPIx->SPDR = Data & SPI_SPDR_BITMASK;
\r
306 /*********************************************************************//**
\r
307 * @brief Receive a single data from SPIx peripheral
\r
308 * @param[in] SPIx SPI peripheral selected, should be SPI
\r
309 * @return Data received (16-bit long)
\r
310 **********************************************************************/
\r
311 uint16_t SPI_ReceiveData(LPC_SPI_TypeDef* SPIx)
\r
313 CHECK_PARAM(PARAM_SPIx(SPIx));
\r
315 return ((uint16_t) (SPIx->SPDR & SPI_SPDR_BITMASK));
\r
318 /*********************************************************************//**
\r
319 * @brief SPI Read write data function
\r
320 * @param[in] SPIx Pointer to SPI peripheral, should be SPI
\r
321 * @param[in] dataCfg Pointer to a SPI_DATA_SETUP_Type structure that
\r
322 * contains specified information about transmit
\r
323 * data configuration.
\r
324 * @param[in] xfType Transfer type, should be:
\r
325 * - SPI_TRANSFER_POLLING: Polling mode
\r
326 * - SPI_TRANSFER_INTERRUPT: Interrupt mode
\r
327 * @return Actual Data length has been transferred in polling mode.
\r
328 * In interrupt mode, always return (0)
\r
329 * Return (-1) if error.
\r
330 * Note: This function can be used in both master and slave mode.
\r
331 ***********************************************************************/
\r
332 int32_t SPI_ReadWrite (LPC_SPI_TypeDef *SPIx, SPI_DATA_SETUP_Type *dataCfg, \
\r
333 SPI_TRANSFER_Type xfType)
\r
342 //read for empty buffer
\r
344 //dummy to clear status
\r
346 dataCfg->counter = 0;
\r
347 dataCfg->status = 0;
\r
349 if (xfType == SPI_TRANSFER_POLLING){
\r
351 if (spidat.dataword == 0){
\r
352 rdata8 = (uint8_t *)dataCfg->rx_data;
\r
353 wdata8 = (uint8_t *)dataCfg->tx_data;
\r
355 rdata16 = (uint16_t *)dataCfg->rx_data;
\r
356 wdata16 = (uint16_t *)dataCfg->tx_data;
\r
359 while(dataCfg->counter < dataCfg->length)
\r
361 // Write data to buffer
\r
362 if(dataCfg->tx_data == NULL){
\r
363 if (spidat.dataword == 0){
\r
364 SPI_SendData(SPIx, 0xFF);
\r
366 SPI_SendData(SPIx, 0xFFFF);
\r
369 if (spidat.dataword == 0){
\r
370 SPI_SendData(SPIx, *wdata8);
\r
373 SPI_SendData(SPIx, *wdata16);
\r
377 // Wait for transfer complete
\r
378 while (!((stat = SPIx->SPSR) & SPI_SPSR_SPIF));
\r
380 if (stat & (SPI_SPSR_ABRT | SPI_SPSR_MODF | SPI_SPSR_ROVR | SPI_SPSR_WCOL)){
\r
382 dataCfg->status = stat | SPI_STAT_ERROR;
\r
383 return (dataCfg->counter);
\r
385 // Read data from SPI dat
\r
386 temp = (uint32_t) SPI_ReceiveData(SPIx);
\r
388 // Store data to destination
\r
389 if (dataCfg->rx_data != NULL)
\r
391 if (spidat.dataword == 0){
\r
392 *(rdata8) = (uint8_t) temp;
\r
395 *(rdata16) = (uint16_t) temp;
\r
399 // Increase counter
\r
400 if (spidat.dataword == 0){
\r
401 dataCfg->counter++;
\r
403 dataCfg->counter += 2;
\r
407 // Return length of actual data transferred
\r
409 dataCfg->status = stat | SPI_STAT_DONE;
\r
410 return (dataCfg->counter);
\r
414 spidat.txrx_setup = (uint32_t)dataCfg;
\r
415 spidat.inthandler = SPI_IntHandler;
\r
417 // Check if interrupt flag is already set
\r
418 if(SPIx->SPINT & SPI_SPINT_INTFLAG){
\r
419 SPIx->SPINT = SPI_SPINT_INTFLAG;
\r
421 if (dataCfg->counter < dataCfg->length){
\r
422 // Write data to buffer
\r
423 if(dataCfg->tx_data == NULL){
\r
424 if (spidat.dataword == 0){
\r
425 SPI_SendData(SPIx, 0xFF);
\r
427 SPI_SendData(SPIx, 0xFFFF);
\r
430 if (spidat.dataword == 0){
\r
431 SPI_SendData(SPIx, (*(uint8_t *)dataCfg->tx_data));
\r
433 SPI_SendData(SPIx, (*(uint16_t *)dataCfg->tx_data));
\r
436 SPI_IntCmd(SPIx, ENABLE);
\r
439 dataCfg->status = SPI_STAT_DONE;
\r
447 /********************************************************************//**
\r
448 * @brief Enable or disable SPIx interrupt.
\r
449 * @param[in] SPIx SPI peripheral selected, should be SPI
\r
450 * @param[in] NewState New state of specified UART interrupt type,
\r
452 * - ENALBE: Enable this SPI interrupt.
\r
453 * - DISALBE: Disable this SPI interrupt.
\r
455 *********************************************************************/
\r
456 void SPI_IntCmd(LPC_SPI_TypeDef *SPIx, FunctionalState NewState)
\r
458 CHECK_PARAM(PARAM_SPIx(SPIx));
\r
459 CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));
\r
461 if (NewState == ENABLE)
\r
463 SPIx->SPCR |= SPI_SPCR_SPIE;
\r
467 SPIx->SPCR &= (~SPI_SPCR_SPIE) & SPI_SPCR_BITMASK;
\r
472 /********************************************************************//**
\r
473 * @brief Checks whether the SPI interrupt flag is set or not.
\r
474 * @param[in] SPIx SPI peripheral selected, should be SPI
\r
475 * @return The new state of SPI Interrupt Flag (SET or RESET)
\r
476 *********************************************************************/
\r
477 IntStatus SPI_GetIntStatus (LPC_SPI_TypeDef *SPIx)
\r
479 CHECK_PARAM(PARAM_SPIx(SPIx));
\r
481 return ((SPIx->SPINT & SPI_SPINT_INTFLAG) ? SET : RESET);
\r
485 /********************************************************************//**
\r
486 * @brief Clear SPI interrupt flag.
\r
487 * @param[in] SPIx SPI peripheral selected, should be SPI
\r
489 *********************************************************************/
\r
490 void SPI_ClearIntPending(LPC_SPI_TypeDef *SPIx)
\r
492 CHECK_PARAM(PARAM_SPIx(SPIx));
\r
494 SPIx->SPINT = SPI_SPINT_INTFLAG;
\r
498 /********************************************************************//**
\r
499 * @brief Get current value of SPI Status register in SPIx peripheral.
\r
500 * @param[in] SPIx SPI peripheral selected, should be SPI
\r
501 * @return Current value of SPI Status register in SPI peripheral.
\r
502 * Note: The return value of this function must be used with
\r
503 * SPI_CheckStatus() to determine current flag status
\r
504 * corresponding to each SPI status type. Because some flags in
\r
505 * SPI Status register will be cleared after reading, the next reading
\r
506 * SPI Status register could not be correct. So this function used to
\r
507 * read SPI status register in one time only, then the return value
\r
508 * used to check all flags.
\r
509 *********************************************************************/
\r
510 uint32_t SPI_GetStatus(LPC_SPI_TypeDef* SPIx)
\r
512 CHECK_PARAM(PARAM_SPIx(SPIx));
\r
514 return (SPIx->SPSR & SPI_SPSR_BITMASK);
\r
519 /********************************************************************//**
\r
520 * @brief Checks whether the specified SPI Status flag is set or not
\r
521 * via inputSPIStatus parameter.
\r
522 * @param[in] inputSPIStatus Value to check status of each flag type.
\r
523 * This value is the return value from SPI_GetStatus().
\r
524 * @param[in] SPIStatus Specifies the SPI status flag to check,
\r
525 * should be one of the following:
\r
526 - SPI_STAT_ABRT: Slave abort.
\r
527 - SPI_STAT_MODF: Mode fault.
\r
528 - SPI_STAT_ROVR: Read overrun.
\r
529 - SPI_STAT_WCOL: Write collision.
\r
530 - SPI_STAT_SPIF: SPI transfer complete.
\r
531 * @return The new state of SPIStatus (SET or RESET)
\r
532 *********************************************************************/
\r
533 FlagStatus SPI_CheckStatus (uint32_t inputSPIStatus, uint8_t SPIStatus)
\r
535 CHECK_PARAM(PARAM_SPI_STAT(SPIStatus));
\r
537 return ((inputSPIStatus & SPIStatus) ? SET : RESET);
\r
541 * @brief Standard SPI Interrupt handler
\r
545 void SPI_StdIntHandler(void)
\r
547 // Call relevant handler
\r
548 spidat.inthandler();
\r
562 /* --------------------------------- End Of File ------------------------------ */
\r