ChibiOS/RT
2.5.1
spi.c
Go to the documentation of this file.
00001 /*
00002     ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
00003                  2011,2012 Giovanni Di Sirio.
00004 
00005     This file is part of ChibiOS/RT.
00006 
00007     ChibiOS/RT is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 3 of the License, or
00010     (at your option) any later version.
00011 
00012     ChibiOS/RT is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019 */
00020 
00021 /**
00022  * @file    spi.c
00023  * @brief   SPI Driver code.
00024  *
00025  * @addtogroup SPI
00026  * @{
00027  */
00028 
00029 #include "ch.h"
00030 #include "hal.h"
00031 
00032 #if HAL_USE_SPI || defined(__DOXYGEN__)
00033 
00034 /*===========================================================================*/
00035 /* Driver local definitions.                                                 */
00036 /*===========================================================================*/
00037 
00038 /*===========================================================================*/
00039 /* Driver exported variables.                                                */
00040 /*===========================================================================*/
00041 
00042 /*===========================================================================*/
00043 /* Driver local variables.                                                   */
00044 /*===========================================================================*/
00045 
00046 /*===========================================================================*/
00047 /* Driver local functions.                                                   */
00048 /*===========================================================================*/
00049 
00050 /*===========================================================================*/
00051 /* Driver exported functions.                                                */
00052 /*===========================================================================*/
00053 
00054 /**
00055  * @brief   SPI Driver initialization.
00056  * @note    This function is implicitly invoked by @p halInit(), there is
00057  *          no need to explicitly initialize the driver.
00058  *
00059  * @init
00060  */
00061 void spiInit(void) {
00062 
00063   spi_lld_init();
00064 }
00065 
00066 /**
00067  * @brief   Initializes the standard part of a @p SPIDriver structure.
00068  *
00069  * @param[out] spip     pointer to the @p SPIDriver object
00070  *
00071  * @init
00072  */
00073 void spiObjectInit(SPIDriver *spip) {
00074 
00075   spip->state = SPI_STOP;
00076   spip->config = NULL;
00077 #if SPI_USE_WAIT
00078   spip->thread = NULL;
00079 #endif /* SPI_USE_WAIT */
00080 #if SPI_USE_MUTUAL_EXCLUSION
00081 #if CH_USE_MUTEXES
00082   chMtxInit(&spip->mutex);
00083 #else
00084   chSemInit(&spip->semaphore, 1);
00085 #endif
00086 #endif /* SPI_USE_MUTUAL_EXCLUSION */
00087 #if defined(SPI_DRIVER_EXT_INIT_HOOK)
00088   SPI_DRIVER_EXT_INIT_HOOK(spip);
00089 #endif
00090 }
00091 
00092 /**
00093  * @brief   Configures and activates the SPI peripheral.
00094  *
00095  * @param[in] spip      pointer to the @p SPIDriver object
00096  * @param[in] config    pointer to the @p SPIConfig object
00097  *
00098  * @api
00099  */
00100 void spiStart(SPIDriver *spip, const SPIConfig *config) {
00101 
00102   chDbgCheck((spip != NULL) && (config != NULL), "spiStart");
00103 
00104   chSysLock();
00105   chDbgAssert((spip->state == SPI_STOP) || (spip->state == SPI_READY),
00106               "spiStart(), #1", "invalid state");
00107   spip->config = config;
00108   spi_lld_start(spip);
00109   spip->state = SPI_READY;
00110   chSysUnlock();
00111 }
00112 
00113 /**
00114  * @brief Deactivates the SPI peripheral.
00115  * @note  Deactivating the peripheral also enforces a release of the slave
00116  *        select line.
00117  *
00118  * @param[in] spip      pointer to the @p SPIDriver object
00119  *
00120  * @api
00121  */
00122 void spiStop(SPIDriver *spip) {
00123 
00124   chDbgCheck(spip != NULL, "spiStop");
00125 
00126   chSysLock();
00127   chDbgAssert((spip->state == SPI_STOP) || (spip->state == SPI_READY),
00128               "spiStop(), #1", "invalid state");
00129   spi_lld_unselect(spip);
00130   spi_lld_stop(spip);
00131   spip->state = SPI_STOP;
00132   chSysUnlock();
00133 }
00134 
00135 /**
00136  * @brief   Asserts the slave select signal and prepares for transfers.
00137  *
00138  * @param[in] spip      pointer to the @p SPIDriver object
00139  *
00140  * @api
00141  */
00142 void spiSelect(SPIDriver *spip) {
00143 
00144   chDbgCheck(spip != NULL, "spiSelect");
00145 
00146   chSysLock();
00147   chDbgAssert(spip->state == SPI_READY, "spiSelect(), #1", "not ready");
00148   spiSelectI(spip);
00149   chSysUnlock();
00150 }
00151 
00152 /**
00153  * @brief   Deasserts the slave select signal.
00154  * @details The previously selected peripheral is unselected.
00155  *
00156  * @param[in] spip      pointer to the @p SPIDriver object
00157  *
00158  * @api
00159  */
00160 void spiUnselect(SPIDriver *spip) {
00161 
00162   chDbgCheck(spip != NULL, "spiUnselect");
00163 
00164   chSysLock();
00165   chDbgAssert(spip->state == SPI_READY, "spiUnselect(), #1", "not ready");
00166   spiUnselectI(spip);
00167   chSysUnlock();
00168 }
00169 
00170 /**
00171  * @brief   Ignores data on the SPI bus.
00172  * @details This asynchronous function starts the transmission of a series of
00173  *          idle words on the SPI bus and ignores the received data.
00174  * @pre     A slave must have been selected using @p spiSelect() or
00175  *          @p spiSelectI().
00176  * @post    At the end of the operation the configured callback is invoked.
00177  *
00178  * @param[in] spip      pointer to the @p SPIDriver object
00179  * @param[in] n         number of words to be ignored
00180  *
00181  * @api
00182  */
00183 void spiStartIgnore(SPIDriver *spip, size_t n) {
00184 
00185   chDbgCheck((spip != NULL) && (n > 0), "spiStartIgnore");
00186 
00187   chSysLock();
00188   chDbgAssert(spip->state == SPI_READY, "spiStartIgnore(), #1", "not ready");
00189   spiStartIgnoreI(spip, n);
00190   chSysUnlock();
00191 }
00192 
00193 /**
00194  * @brief   Exchanges data on the SPI bus.
00195  * @details This asynchronous function starts a simultaneous transmit/receive
00196  *          operation.
00197  * @pre     A slave must have been selected using @p spiSelect() or
00198  *          @p spiSelectI().
00199  * @post    At the end of the operation the configured callback is invoked.
00200  * @note    The buffers are organized as uint8_t arrays for data sizes below
00201  *          or equal to 8 bits else it is organized as uint16_t arrays.
00202  *
00203  * @param[in] spip      pointer to the @p SPIDriver object
00204  * @param[in] n         number of words to be exchanged
00205  * @param[in] txbuf     the pointer to the transmit buffer
00206  * @param[out] rxbuf    the pointer to the receive buffer
00207  *
00208  * @api
00209  */
00210 void spiStartExchange(SPIDriver *spip, size_t n,
00211                       const void *txbuf, void *rxbuf) {
00212 
00213   chDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL) && (txbuf != NULL),
00214              "spiStartExchange");
00215 
00216   chSysLock();
00217   chDbgAssert(spip->state == SPI_READY, "spiStartExchange(), #1", "not ready");
00218   spiStartExchangeI(spip, n, txbuf, rxbuf);
00219   chSysUnlock();
00220 }
00221 
00222 /**
00223  * @brief   Sends data over the SPI bus.
00224  * @details This asynchronous function starts a transmit operation.
00225  * @pre     A slave must have been selected using @p spiSelect() or
00226  *          @p spiSelectI().
00227  * @post    At the end of the operation the configured callback is invoked.
00228  * @note    The buffers are organized as uint8_t arrays for data sizes below
00229  *          or equal to 8 bits else it is organized as uint16_t arrays.
00230  *
00231  * @param[in] spip      pointer to the @p SPIDriver object
00232  * @param[in] n         number of words to send
00233  * @param[in] txbuf     the pointer to the transmit buffer
00234  *
00235  * @api
00236  */
00237 void spiStartSend(SPIDriver *spip, size_t n, const void *txbuf) {
00238 
00239   chDbgCheck((spip != NULL) && (n > 0) && (txbuf != NULL),
00240              "spiStartSend");
00241 
00242   chSysLock();
00243   chDbgAssert(spip->state == SPI_READY, "spiStartSend(), #1", "not ready");
00244   spiStartSendI(spip, n, txbuf);
00245   chSysUnlock();
00246 }
00247 
00248 /**
00249  * @brief   Receives data from the SPI bus.
00250  * @details This asynchronous function starts a receive operation.
00251  * @pre     A slave must have been selected using @p spiSelect() or
00252  *          @p spiSelectI().
00253  * @post    At the end of the operation the configured callback is invoked.
00254  * @note    The buffers are organized as uint8_t arrays for data sizes below
00255  *          or equal to 8 bits else it is organized as uint16_t arrays.
00256  *
00257  * @param[in] spip      pointer to the @p SPIDriver object
00258  * @param[in] n         number of words to receive
00259  * @param[out] rxbuf    the pointer to the receive buffer
00260  *
00261  * @api
00262  */
00263 void spiStartReceive(SPIDriver *spip, size_t n, void *rxbuf) {
00264 
00265   chDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL),
00266              "spiStartReceive");
00267 
00268   chSysLock();
00269   chDbgAssert(spip->state == SPI_READY, "spiStartReceive(), #1", "not ready");
00270   spiStartReceiveI(spip, n, rxbuf);
00271   chSysUnlock();
00272 }
00273 
00274 #if SPI_USE_WAIT || defined(__DOXYGEN__)
00275 /**
00276  * @brief   Ignores data on the SPI bus.
00277  * @details This synchronous function performs the transmission of a series of
00278  *          idle words on the SPI bus and ignores the received data.
00279  * @pre     In order to use this function the option @p SPI_USE_WAIT must be
00280  *          enabled.
00281  * @pre     In order to use this function the driver must have been configured
00282  *          without callbacks (@p end_cb = @p NULL).
00283  *
00284  * @param[in] spip      pointer to the @p SPIDriver object
00285  * @param[in] n         number of words to be ignored
00286  *
00287  * @api
00288  */
00289 void spiIgnore(SPIDriver *spip, size_t n) {
00290 
00291   chDbgCheck((spip != NULL) && (n > 0), "spiIgnoreWait");
00292 
00293   chSysLock();
00294   chDbgAssert(spip->state == SPI_READY, "spiIgnore(), #1", "not ready");
00295   chDbgAssert(spip->config->end_cb == NULL, "spiIgnore(), #2", "has callback");
00296   spiStartIgnoreI(spip, n);
00297   _spi_wait_s(spip);
00298   chSysUnlock();
00299 }
00300 
00301 /**
00302  * @brief   Exchanges data on the SPI bus.
00303  * @details This synchronous function performs a simultaneous transmit/receive
00304  *          operation.
00305  * @pre     In order to use this function the option @p SPI_USE_WAIT must be
00306  *          enabled.
00307  * @pre     In order to use this function the driver must have been configured
00308  *          without callbacks (@p end_cb = @p NULL).
00309  * @note    The buffers are organized as uint8_t arrays for data sizes below
00310  *          or equal to 8 bits else it is organized as uint16_t arrays.
00311  *
00312  * @param[in] spip      pointer to the @p SPIDriver object
00313  * @param[in] n         number of words to be exchanged
00314  * @param[in] txbuf     the pointer to the transmit buffer
00315  * @param[out] rxbuf    the pointer to the receive buffer
00316  *
00317  * @api
00318  */
00319 void spiExchange(SPIDriver *spip, size_t n,
00320                  const void *txbuf, void *rxbuf) {
00321 
00322   chDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL) && (txbuf != NULL),
00323              "spiExchange");
00324 
00325   chSysLock();
00326   chDbgAssert(spip->state == SPI_READY, "spiExchange(), #1", "not ready");
00327   chDbgAssert(spip->config->end_cb == NULL,
00328               "spiExchange(), #2", "has callback");
00329   spiStartExchangeI(spip, n, txbuf, rxbuf);
00330   _spi_wait_s(spip);
00331   chSysUnlock();
00332 }
00333 
00334 /**
00335  * @brief   Sends data over the SPI bus.
00336  * @details This synchronous function performs a transmit operation.
00337  * @pre     In order to use this function the option @p SPI_USE_WAIT must be
00338  *          enabled.
00339  * @pre     In order to use this function the driver must have been configured
00340  *          without callbacks (@p end_cb = @p NULL).
00341  * @note    The buffers are organized as uint8_t arrays for data sizes below
00342  *          or equal to 8 bits else it is organized as uint16_t arrays.
00343  *
00344  * @param[in] spip      pointer to the @p SPIDriver object
00345  * @param[in] n         number of words to send
00346  * @param[in] txbuf     the pointer to the transmit buffer
00347  *
00348  * @api
00349  */
00350 void spiSend(SPIDriver *spip, size_t n, const void *txbuf) {
00351 
00352   chDbgCheck((spip != NULL) && (n > 0) && (txbuf != NULL), "spiSend");
00353 
00354   chSysLock();
00355   chDbgAssert(spip->state == SPI_READY, "spiSend(), #1", "not ready");
00356   chDbgAssert(spip->config->end_cb == NULL, "spiSend(), #2", "has callback");
00357   spiStartSendI(spip, n, txbuf);
00358   _spi_wait_s(spip);
00359   chSysUnlock();
00360 }
00361 
00362 /**
00363  * @brief   Receives data from the SPI bus.
00364  * @details This synchronous function performs a receive operation.
00365  * @pre     In order to use this function the option @p SPI_USE_WAIT must be
00366  *          enabled.
00367  * @pre     In order to use this function the driver must have been configured
00368  *          without callbacks (@p end_cb = @p NULL).
00369  * @note    The buffers are organized as uint8_t arrays for data sizes below
00370  *          or equal to 8 bits else it is organized as uint16_t arrays.
00371  *
00372  * @param[in] spip      pointer to the @p SPIDriver object
00373  * @param[in] n         number of words to receive
00374  * @param[out] rxbuf    the pointer to the receive buffer
00375  *
00376  * @api
00377  */
00378 void spiReceive(SPIDriver *spip, size_t n, void *rxbuf) {
00379 
00380   chDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL),
00381              "spiReceive");
00382 
00383   chSysLock();
00384   chDbgAssert(spip->state == SPI_READY, "spiReceive(), #1", "not ready");
00385   chDbgAssert(spip->config->end_cb == NULL,
00386               "spiReceive(), #2", "has callback");
00387   spiStartReceiveI(spip, n, rxbuf);
00388   _spi_wait_s(spip);
00389   chSysUnlock();
00390 }
00391 #endif /* SPI_USE_WAIT */
00392 
00393 #if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
00394 /**
00395  * @brief   Gains exclusive access to the SPI bus.
00396  * @details This function tries to gain ownership to the SPI bus, if the bus
00397  *          is already being used then the invoking thread is queued.
00398  * @pre     In order to use this function the option @p SPI_USE_MUTUAL_EXCLUSION
00399  *          must be enabled.
00400  *
00401  * @param[in] spip      pointer to the @p SPIDriver object
00402  *
00403  * @api
00404  */
00405 void spiAcquireBus(SPIDriver *spip) {
00406 
00407   chDbgCheck(spip != NULL, "spiAcquireBus");
00408 
00409 #if CH_USE_MUTEXES
00410   chMtxLock(&spip->mutex);
00411 #elif CH_USE_SEMAPHORES
00412   chSemWait(&spip->semaphore);
00413 #endif
00414 }
00415 
00416 /**
00417  * @brief   Releases exclusive access to the SPI bus.
00418  * @pre     In order to use this function the option @p SPI_USE_MUTUAL_EXCLUSION
00419  *          must be enabled.
00420  *
00421  * @param[in] spip      pointer to the @p SPIDriver object
00422  *
00423  * @api
00424  */
00425 void spiReleaseBus(SPIDriver *spip) {
00426 
00427   chDbgCheck(spip != NULL, "spiReleaseBus");
00428 
00429 #if CH_USE_MUTEXES
00430   (void)spip;
00431   chMtxUnlock();
00432 #elif CH_USE_SEMAPHORES
00433   chSemSignal(&spip->semaphore);
00434 #endif
00435 }
00436 #endif /* SPI_USE_MUTUAL_EXCLUSION */
00437 
00438 #endif /* HAL_USE_SPI */
00439 
00440 /** @} */