|
ChibiOS/RT
2.5.1 |
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 /** @} */