NXP's driver library for LPC17xx, ported to mbed's online compiler. Not tested! I had to fix a lot of warings and found a couple of pretty obvious bugs, so the chances are there are more. Original: http://ics.nxp.com/support/documents/microcontrollers/zip/lpc17xx.cmsis.driver.library.zip
lpc17xx_spi.c
00001 /** 00002 * @file : lpc17xx_spi.c 00003 * @brief : Contains all functions support for SPI firmware library on LPC17xx 00004 * @version : 1.0 00005 * @date : 3. April. 2009 00006 * @author : HieuNguyen 00007 ************************************************************************** 00008 * Software that is described herein is for illustrative purposes only 00009 * which provides customers with programming information regarding the 00010 * products. This software is supplied "AS IS" without any warranties. 00011 * NXP Semiconductors assumes no responsibility or liability for the 00012 * use of the software, conveys no license or title under any patent, 00013 * copyright, or mask work right to the product. NXP Semiconductors 00014 * reserves the right to make changes in the software without 00015 * notification. NXP Semiconductors also make no representation or 00016 * warranty that such application will be suitable for the specified 00017 * use without further testing or modification. 00018 **********************************************************************/ 00019 00020 /* Peripheral group ----------------------------------------------------------- */ 00021 /** @addtogroup SPI 00022 * @{ 00023 */ 00024 00025 /* Includes ------------------------------------------------------------------- */ 00026 #include "lpc17xx_spi.h" 00027 #include "lpc17xx_clkpwr.h" 00028 00029 /* If this source file built with example, the LPC17xx FW library configuration 00030 * file in each example directory ("lpc17xx_libcfg.h") must be included, 00031 * otherwise the default FW library configuration file must be included instead 00032 */ 00033 #ifdef __BUILD_WITH_EXAMPLE__ 00034 #include "lpc17xx_libcfg.h" 00035 #else 00036 #include "lpc17xx_libcfg_default.h" 00037 #endif /* __BUILD_WITH_EXAMPLE__ */ 00038 00039 #ifdef _SPI 00040 00041 /* Private Types -------------------------------------------------------------- */ 00042 /** @defgroup SPI_Private_Types 00043 * @{ 00044 */ 00045 00046 /** @brief SPI device configuration structure type */ 00047 typedef struct 00048 { 00049 int32_t dataword; /* Current data word: 0 - 8 bit; 1 - 16 bit */ 00050 uint32_t txrx_setup; /* Transmission setup */ 00051 void (*inthandler)(void); /* Transmission interrupt handler */ 00052 } SPI_CFG_T; 00053 00054 /** 00055 * @} 00056 */ 00057 00058 00059 /* Private Variables ---------------------------------------------------------- */ 00060 /* SPI configuration data */ 00061 static SPI_CFG_T spidat; 00062 00063 00064 /* Private Functions ---------------------------------------------------------- */ 00065 /** @defgroup SPI_Private_Functions 00066 * @{ 00067 */ 00068 00069 /*********************************************************************//** 00070 * @brief Standard Private SPI Interrupt handler 00071 * @param[in] None 00072 * @return None 00073 ***********************************************************************/ 00074 void SPI_IntHandler(void) 00075 { 00076 SPI_DATA_SETUP_Type *xf_setup; 00077 uint16_t tmp; 00078 00079 xf_setup = (SPI_DATA_SETUP_Type *)spidat.txrx_setup; 00080 00081 /* Dummy read to clear SPI interrupt flag */ 00082 if (LPC_SPI->SPINT & SPI_SPINT_INTFLAG){ 00083 LPC_SPI->SPINT = SPI_SPINT_INTFLAG; 00084 } 00085 00086 // save status 00087 tmp = LPC_SPI->SPSR; 00088 xf_setup->status = tmp; 00089 // Check for error 00090 if (tmp & (SPI_SPSR_ABRT | SPI_SPSR_MODF | SPI_SPSR_ROVR | SPI_SPSR_WCOL)){ 00091 xf_setup->status |= SPI_STAT_ERROR; 00092 // Disable Interrupt and call call-back 00093 SPI_IntCmd(LPC_SPI, DISABLE); 00094 if (xf_setup->callback != NULL){ 00095 xf_setup->callback(); 00096 } 00097 return; 00098 } 00099 00100 /* Check SPI complete flag */ 00101 if (tmp & SPI_SPSR_SPIF){ 00102 // Read data from SPI data 00103 tmp = SPI_ReceiveData(LPC_SPI); 00104 if (xf_setup->rx_data != NULL) 00105 { 00106 // if (spidat.dataword == 0){ 00107 // *(uint8_t *)(xf_setup->rx_data + xf_setup->counter) = (uint8_t) tmp; 00108 // } else { 00109 // *(uint16_t *)(xf_setup->rx_data + xf_setup->counter) = (uint8_t) tmp; 00110 // } 00111 if (spidat.dataword == 0){ 00112 *(uint8_t *)((uint8_t *)(xf_setup->rx_data) + xf_setup->counter) = (uint8_t) tmp; 00113 } else { 00114 *(uint16_t *)((uint8_t *)(xf_setup->rx_data) + xf_setup->counter) = (uint8_t) tmp; 00115 } 00116 } 00117 // Increase counter 00118 if (spidat.dataword == 0){ 00119 xf_setup->counter++; 00120 } else { 00121 xf_setup->counter += 2; 00122 } 00123 } 00124 00125 if (xf_setup->counter < xf_setup->length){ 00126 // Write data to buffer 00127 if(xf_setup->tx_data == NULL){ 00128 if (spidat.dataword == 0){ 00129 SPI_SendData(LPC_SPI, 0xFF); 00130 } else { 00131 SPI_SendData(LPC_SPI, 0xFFFF); 00132 } 00133 } else { 00134 // if (spidat.dataword == 0){ 00135 // SPI_SendData(SPI, (*(uint8_t *)(xf_setup->tx_data + xf_setup->counter))); 00136 // } else { 00137 // SPI_SendData(SPI, (*(uint16_t *)(xf_setup->tx_data + xf_setup->counter))); 00138 // } 00139 if (spidat.dataword == 0){ 00140 SPI_SendData(LPC_SPI, (*(uint8_t *)((uint8_t *)(xf_setup->tx_data) + xf_setup->counter))); 00141 } else { 00142 SPI_SendData(LPC_SPI, (*(uint16_t *)((uint8_t *)(xf_setup->tx_data) + xf_setup->counter))); 00143 } 00144 } 00145 } 00146 // No more data to send 00147 else { 00148 xf_setup->status |= SPI_STAT_DONE; 00149 // Disable Interrupt and call call-back 00150 SPI_IntCmd(LPC_SPI, DISABLE); 00151 if (xf_setup->callback != NULL){ 00152 xf_setup->callback(); 00153 } 00154 } 00155 } 00156 00157 00158 /** 00159 * @} 00160 */ 00161 00162 /* Public Functions ----------------------------------------------------------- */ 00163 /** @addtogroup SPI_Public_Functions 00164 * @{ 00165 */ 00166 00167 /*********************************************************************//** 00168 * @brief Setup clock rate for SPI device 00169 * @param[in] SPIx SPI peripheral definition, should be SPI 00170 * @param[in] target_clock : clock of SPI (Hz) 00171 * @return None 00172 ***********************************************************************/ 00173 void SPI_SetClock (LPC_SPI_TypeDef *SPIx, uint32_t target_clock) 00174 { 00175 uint32_t spi_pclk; 00176 uint32_t prescale, temp; 00177 00178 CHECK_PARAM(PARAM_SPIx(SPIx)); 00179 00180 if (SPIx == LPC_SPI){ 00181 spi_pclk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_SPI); 00182 } else { 00183 return; 00184 } 00185 00186 prescale = 8; 00187 // Find closest clock to target clock 00188 while (1){ 00189 temp = target_clock * prescale; 00190 if (temp >= spi_pclk){ 00191 break; 00192 } 00193 prescale += 2; 00194 if(prescale >= 254){ 00195 break; 00196 } 00197 } 00198 00199 // Write to register 00200 SPIx->SPCCR = SPI_SPCCR_COUNTER(prescale); 00201 } 00202 00203 00204 /*********************************************************************//** 00205 * @brief De-initializes the SPIx peripheral registers to their 00206 * default reset values. 00207 * @param[in] SPIx SPI peripheral selected, should be SPI 00208 * @return None 00209 **********************************************************************/ 00210 void SPI_DeInit(LPC_SPI_TypeDef *SPIx) 00211 { 00212 CHECK_PARAM(PARAM_SPIx(SPIx)); 00213 00214 if (SPIx == LPC_SPI){ 00215 /* Set up clock and power for SPI module */ 00216 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSPI, DISABLE); 00217 } 00218 } 00219 00220 00221 00222 /********************************************************************//** 00223 * @brief Initializes the SPIx peripheral according to the specified 00224 * parameters in the UART_ConfigStruct. 00225 * @param[in] SPIx SPI peripheral selected, should be SPI 00226 * @param[in] SPI_ConfigStruct Pointer to a SPI_CFG_Type structure 00227 * that contains the configuration information for the 00228 * specified SPI peripheral. 00229 * @return None 00230 *********************************************************************/ 00231 void SPI_Init(LPC_SPI_TypeDef *SPIx, SPI_CFG_Type *SPI_ConfigStruct) 00232 { 00233 uint32_t tmp; 00234 00235 CHECK_PARAM(PARAM_SPIx(SPIx)); 00236 00237 if(SPIx == LPC_SPI){ 00238 /* Set up clock and power for UART module */ 00239 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSPI, ENABLE); 00240 } else { 00241 return; 00242 } 00243 00244 // Configure SPI, interrupt is disable as default 00245 tmp = ((SPI_ConfigStruct->CPHA) | (SPI_ConfigStruct->CPOL) \ 00246 | (SPI_ConfigStruct->DataOrder) | (SPI_ConfigStruct->Databit) \ 00247 | (SPI_ConfigStruct->Mode) | SPI_SPCR_BIT_EN) & SPI_SPCR_BITMASK; 00248 // write back to SPI control register 00249 SPIx->SPCR = tmp; 00250 00251 if (SPI_ConfigStruct->Databit > SPI_DATABIT_8){ 00252 spidat.dataword = 1; 00253 } else { 00254 spidat.dataword = 0; 00255 } 00256 00257 // Set clock rate for SPI peripheral 00258 SPI_SetClock(SPIx, SPI_ConfigStruct->ClockRate); 00259 00260 // If interrupt flag is set, Write '1' to Clear interrupt flag 00261 if (SPIx->SPINT & SPI_SPINT_INTFLAG){ 00262 SPIx->SPINT = SPI_SPINT_INTFLAG; 00263 } 00264 } 00265 00266 00267 00268 /*****************************************************************************//** 00269 * @brief Fills each SPI_InitStruct member with its default value: 00270 * - CPHA = SPI_CPHA_FIRST 00271 * - CPOL = SPI_CPOL_HI 00272 * - ClockRate = 1000000 00273 * - DataOrder = SPI_DATA_MSB_FIRST 00274 * - Databit = SPI_DATABIT_8 00275 * - Mode = SPI_MASTER_MODE 00276 * @param[in] SPI_InitStruct Pointer to a SPI_CFG_Type structure 00277 * which will be initialized. 00278 * @return None 00279 *******************************************************************************/ 00280 void SPI_ConfigStructInit(SPI_CFG_Type *SPI_InitStruct) 00281 { 00282 SPI_InitStruct->CPHA = SPI_CPHA_FIRST; 00283 SPI_InitStruct->CPOL = SPI_CPOL_HI; 00284 SPI_InitStruct->ClockRate = 1000000; 00285 SPI_InitStruct->DataOrder = SPI_DATA_MSB_FIRST; 00286 SPI_InitStruct->Databit = SPI_DATABIT_8; 00287 SPI_InitStruct->Mode = SPI_MASTER_MODE; 00288 } 00289 00290 /*********************************************************************//** 00291 * @brief Transmit a single data through SPIx peripheral 00292 * @param[in] SPIx SPI peripheral selected, should be SPI 00293 * @param[in] Data Data to transmit (must be 16 or 8-bit long, 00294 * this depend on SPI data bit number configured) 00295 * @return none 00296 **********************************************************************/ 00297 void SPI_SendData(LPC_SPI_TypeDef* SPIx, uint16_t Data) 00298 { 00299 CHECK_PARAM(PARAM_SPIx(SPIx)); 00300 00301 SPIx->SPDR = Data & SPI_SPDR_BITMASK; 00302 } 00303 00304 00305 00306 /*********************************************************************//** 00307 * @brief Receive a single data from SPIx peripheral 00308 * @param[in] SPIx SPI peripheral selected, should be SPI 00309 * @return Data received (16-bit long) 00310 **********************************************************************/ 00311 uint16_t SPI_ReceiveData(LPC_SPI_TypeDef* SPIx) 00312 { 00313 CHECK_PARAM(PARAM_SPIx(SPIx)); 00314 00315 return ((uint16_t) (SPIx->SPDR & SPI_SPDR_BITMASK)); 00316 } 00317 00318 /*********************************************************************//** 00319 * @brief SPI Read write data function 00320 * @param[in] SPIx Pointer to SPI peripheral, should be SPI 00321 * @param[in] dataCfg Pointer to a SPI_DATA_SETUP_Type structure that 00322 * contains specified information about transmit 00323 * data configuration. 00324 * @param[in] xfType Transfer type, should be: 00325 * - SPI_TRANSFER_POLLING: Polling mode 00326 * - SPI_TRANSFER_INTERRUPT: Interrupt mode 00327 * @return Actual Data length has been transferred in polling mode. 00328 * In interrupt mode, always return (0) 00329 * Return (-1) if error. 00330 * Note: This function can be used in both master and slave mode. 00331 ***********************************************************************/ 00332 int32_t SPI_ReadWrite (LPC_SPI_TypeDef *SPIx, SPI_DATA_SETUP_Type *dataCfg, \ 00333 SPI_TRANSFER_Type xfType) 00334 { 00335 uint8_t *rdata8 = NULL; 00336 uint8_t *wdata8 = NULL; 00337 uint16_t *rdata16 = NULL; 00338 uint16_t *wdata16 = NULL; 00339 uint32_t stat=0; 00340 uint32_t temp; 00341 00342 //read for empty buffer 00343 temp = SPIx->SPDR; 00344 //dummy to clear status 00345 temp = SPIx->SPSR; 00346 dataCfg->counter = 0; 00347 dataCfg->status = 0; 00348 00349 if (xfType == SPI_TRANSFER_POLLING){ 00350 00351 if (spidat.dataword == 0){ 00352 rdata8 = (uint8_t *)dataCfg->rx_data; 00353 wdata8 = (uint8_t *)dataCfg->tx_data; 00354 } else { 00355 rdata16 = (uint16_t *)dataCfg->rx_data; 00356 wdata16 = (uint16_t *)dataCfg->tx_data; 00357 } 00358 00359 while(dataCfg->counter < dataCfg->length) 00360 { 00361 // Write data to buffer 00362 if(dataCfg->tx_data == NULL){ 00363 if (spidat.dataword == 0){ 00364 SPI_SendData(SPIx, 0xFF); 00365 } else { 00366 SPI_SendData(SPIx, 0xFFFF); 00367 } 00368 } else { 00369 if (spidat.dataword == 0){ 00370 SPI_SendData(SPIx, *wdata8); 00371 wdata8++; 00372 } else { 00373 SPI_SendData(SPIx, *wdata16); 00374 wdata16++; 00375 } 00376 } 00377 // Wait for transfer complete 00378 while (!((stat = SPIx->SPSR) & SPI_SPSR_SPIF)); 00379 // Check for error 00380 if (stat & (SPI_SPSR_ABRT | SPI_SPSR_MODF | SPI_SPSR_ROVR | SPI_SPSR_WCOL)){ 00381 // save status 00382 dataCfg->status = stat | SPI_STAT_ERROR; 00383 return (dataCfg->counter); 00384 } 00385 // Read data from SPI dat 00386 temp = (uint32_t) SPI_ReceiveData(SPIx); 00387 00388 // Store data to destination 00389 if (dataCfg->rx_data != NULL) 00390 { 00391 if (spidat.dataword == 0){ 00392 *(rdata8) = (uint8_t) temp; 00393 rdata8++; 00394 } else { 00395 *(rdata16) = (uint16_t) temp; 00396 rdata16++; 00397 } 00398 } 00399 // Increase counter 00400 if (spidat.dataword == 0){ 00401 dataCfg->counter++; 00402 } else { 00403 dataCfg->counter += 2; 00404 } 00405 } 00406 00407 // Return length of actual data transferred 00408 // save status 00409 dataCfg->status = stat | SPI_STAT_DONE; 00410 return (dataCfg->counter); 00411 } 00412 // Interrupt mode 00413 else { 00414 spidat.txrx_setup = (uint32_t)dataCfg; 00415 spidat.inthandler = SPI_IntHandler; 00416 00417 // Check if interrupt flag is already set 00418 if(SPIx->SPINT & SPI_SPINT_INTFLAG){ 00419 SPIx->SPINT = SPI_SPINT_INTFLAG; 00420 } 00421 if (dataCfg->counter < dataCfg->length){ 00422 // Write data to buffer 00423 if(dataCfg->tx_data == NULL){ 00424 if (spidat.dataword == 0){ 00425 SPI_SendData(SPIx, 0xFF); 00426 } else { 00427 SPI_SendData(SPIx, 0xFFFF); 00428 } 00429 } else { 00430 if (spidat.dataword == 0){ 00431 SPI_SendData(SPIx, (*(uint8_t *)dataCfg->tx_data)); 00432 } else { 00433 SPI_SendData(SPIx, (*(uint16_t *)dataCfg->tx_data)); 00434 } 00435 } 00436 SPI_IntCmd(SPIx, ENABLE); 00437 } else { 00438 // Save status 00439 dataCfg->status = SPI_STAT_DONE; 00440 } 00441 return (0); 00442 } 00443 } 00444 00445 00446 /********************************************************************//** 00447 * @brief Enable or disable SPIx interrupt. 00448 * @param[in] SPIx SPI peripheral selected, should be SPI 00449 * @param[in] NewState New state of specified UART interrupt type, 00450 * should be: 00451 * - ENALBE: Enable this SPI interrupt. 00452 * - DISALBE: Disable this SPI interrupt. 00453 * @return None 00454 *********************************************************************/ 00455 void SPI_IntCmd(LPC_SPI_TypeDef *SPIx, FunctionalState NewState) 00456 { 00457 CHECK_PARAM(PARAM_SPIx(SPIx)); 00458 CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState)); 00459 00460 if (NewState == ENABLE) 00461 { 00462 SPIx->SPCR |= SPI_SPCR_SPIE; 00463 } 00464 else 00465 { 00466 SPIx->SPCR &= (~SPI_SPCR_SPIE) & SPI_SPCR_BITMASK; 00467 } 00468 } 00469 00470 00471 /********************************************************************//** 00472 * @brief Checks whether the SPI interrupt flag is set or not. 00473 * @param[in] SPIx SPI peripheral selected, should be SPI 00474 * @return The new state of SPI Interrupt Flag (SET or RESET) 00475 *********************************************************************/ 00476 IntStatus SPI_GetIntStatus (LPC_SPI_TypeDef *SPIx) 00477 { 00478 CHECK_PARAM(PARAM_SPIx(SPIx)); 00479 00480 return ((SPIx->SPINT & SPI_SPINT_INTFLAG) ? SET : RESET); 00481 } 00482 00483 00484 /********************************************************************//** 00485 * @brief Clear SPI interrupt flag. 00486 * @param[in] SPIx SPI peripheral selected, should be SPI 00487 * @return None 00488 *********************************************************************/ 00489 void SPI_ClearIntPending(LPC_SPI_TypeDef *SPIx) 00490 { 00491 CHECK_PARAM(PARAM_SPIx(SPIx)); 00492 00493 SPIx->SPINT = SPI_SPINT_INTFLAG; 00494 } 00495 00496 00497 /********************************************************************//** 00498 * @brief Get current value of SPI Status register in SPIx peripheral. 00499 * @param[in] SPIx SPI peripheral selected, should be SPI 00500 * @return Current value of SPI Status register in SPI peripheral. 00501 * Note: The return value of this function must be used with 00502 * SPI_CheckStatus() to determine current flag status 00503 * corresponding to each SPI status type. Because some flags in 00504 * SPI Status register will be cleared after reading, the next reading 00505 * SPI Status register could not be correct. So this function used to 00506 * read SPI status register in one time only, then the return value 00507 * used to check all flags. 00508 *********************************************************************/ 00509 uint32_t SPI_GetStatus(LPC_SPI_TypeDef* SPIx) 00510 { 00511 CHECK_PARAM(PARAM_SPIx(SPIx)); 00512 00513 return (SPIx->SPSR & SPI_SPSR_BITMASK); 00514 } 00515 00516 00517 00518 /********************************************************************//** 00519 * @brief Checks whether the specified SPI Status flag is set or not 00520 * via inputSPIStatus parameter. 00521 * @param[in] inputSPIStatus Value to check status of each flag type. 00522 * This value is the return value from SPI_GetStatus(). 00523 * @param[in] SPIStatus Specifies the SPI status flag to check, 00524 * should be one of the following: 00525 - SPI_STAT_ABRT: Slave abort. 00526 - SPI_STAT_MODF: Mode fault. 00527 - SPI_STAT_ROVR: Read overrun. 00528 - SPI_STAT_WCOL: Write collision. 00529 - SPI_STAT_SPIF: SPI transfer complete. 00530 * @return The new state of SPIStatus (SET or RESET) 00531 *********************************************************************/ 00532 FlagStatus SPI_CheckStatus (uint32_t inputSPIStatus, uint8_t SPIStatus) 00533 { 00534 CHECK_PARAM(PARAM_SPI_STAT(SPIStatus)); 00535 00536 return ((inputSPIStatus & SPIStatus) ? SET : RESET); 00537 } 00538 00539 /** 00540 * @brief Standard SPI Interrupt handler 00541 * @param[in] None 00542 * @return None 00543 */ 00544 void SPI_StdIntHandler(void) 00545 { 00546 // Call relevant handler 00547 spidat.inthandler(); 00548 } 00549 00550 00551 /** 00552 * @} 00553 */ 00554 00555 #endif /* _SPI */ 00556 00557 /** 00558 * @} 00559 */ 00560 00561 /* --------------------------------- End Of File ------------------------------ */
Generated on Tue Jul 12 2022 17:06:02 by 1.7.2