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 ------------------------------ */