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

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lpc17xx_spi.c Source File

lpc17xx_spi.c

Go to the documentation of this file.
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 ------------------------------ */