Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
SPI.h
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2019 ARM Limited 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 #ifndef MBED_SPI_H 00018 #define MBED_SPI_H 00019 00020 #include "platform/platform.h" 00021 00022 #if DEVICE_SPI || defined(DOXYGEN_ONLY) 00023 00024 #include "platform/PlatformMutex.h" 00025 #include "hal/spi_api.h" 00026 #include "drivers/DigitalOut.h" 00027 #include "platform/SingletonPtr.h" 00028 #include "platform/NonCopyable.h" 00029 00030 #if defined MBED_CONF_DRIVERS_SPI_COUNT_MAX && DEVICE_SPI_COUNT > MBED_CONF_DRIVERS_SPI_COUNT_MAX 00031 #define SPI_PERIPHERALS_USED MBED_CONF_DRIVERS_SPI_COUNT_MAX 00032 #elif defined DEVICE_SPI_COUNT 00033 #define SPI_PERIPHERALS_USED DEVICE_SPI_COUNT 00034 #else 00035 /* Backwards compatibility with HALs not providing DEVICE_SPI_COUNT */ 00036 #define SPI_PERIPHERALS_USED 1 00037 #endif 00038 00039 #if DEVICE_SPI_ASYNCH 00040 #include "platform/CThunk.h" 00041 #include "hal/dma_api.h" 00042 #include "platform/CircularBuffer.h" 00043 #include "platform/Callback.h" 00044 #include "platform/Transaction.h" 00045 #endif 00046 00047 namespace mbed { 00048 /** 00049 * \defgroup drivers_SPI SPI class 00050 * \ingroup drivers-public-api-spi 00051 * @{ 00052 */ 00053 00054 struct use_gpio_ssel_t { }; 00055 const use_gpio_ssel_t use_gpio_ssel; 00056 00057 /** A SPI Master, used for communicating with SPI slave devices. 00058 * 00059 * The default format is set to 8-bits, mode 0, and a clock frequency of 1MHz. 00060 * 00061 * Most SPI devices will also require Chip Select and Reset signals. These 00062 * can be controlled using DigitalOut pins. 00063 * 00064 * @note Synchronization level: Thread safe 00065 * 00066 * Example of how to send a byte to a SPI slave and record the response: 00067 * @code 00068 * #include "mbed.h" 00069 * 00070 * SPI device(SPI_MOSI, SPI_MISO, SPI_SCLK) 00071 * 00072 * DigitalOut chip_select(SPI_CS); 00073 * 00074 * int main() { 00075 * device.lock(); 00076 * chip_select = 0; 00077 * 00078 * int response = device.write(0xFF); 00079 * 00080 * chip_select = 1; 00081 * device.unlock(); 00082 * } 00083 * @endcode 00084 * 00085 * Example using hardware Chip Select line: 00086 * @code 00087 * #include "mbed.h" 00088 * 00089 * SPI device(SPI_MOSI, SPI_MISO, SPI_SCLK, SPI_CS) 00090 * 00091 * int main() { 00092 * device.lock(); 00093 * int response = device.write(0xFF); 00094 * device.unlock(); 00095 * } 00096 * @endcode 00097 */ 00098 class SPI : private NonCopyable<SPI> { 00099 00100 public: 00101 00102 /** Create a SPI master connected to the specified pins. 00103 * 00104 * @note This constructor passes the SSEL pin selection to the target HAL. 00105 * Not all targets support SSEL, so this cannot be relied on in portable code. 00106 * Portable code should use the alternative constructor that uses GPIO 00107 * for SSEL. 00108 * 00109 * @note You can specify mosi or miso as NC if not used. 00110 * 00111 * @param mosi SPI Master Out, Slave In pin. 00112 * @param miso SPI Master In, Slave Out pin. 00113 * @param sclk SPI Clock pin. 00114 * @param ssel SPI Chip Select pin. 00115 */ 00116 SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel = NC); 00117 00118 /** Create a SPI master connected to the specified pins. 00119 * 00120 * @note This constructor manipulates the SSEL pin as a GPIO output 00121 * using a DigitalOut object. This should work on any target, and permits 00122 * the use of select() and deselect() methods to keep the pin asserted 00123 * between transfers. 00124 * 00125 * @note You can specify mosi or miso as NC if not used. 00126 * 00127 * @param mosi SPI Master Out, Slave In pin. 00128 * @param miso SPI Master In, Slave Out pin. 00129 * @param sclk SPI Clock pin. 00130 * @param ssel SPI Chip Select pin. 00131 */ 00132 SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel, use_gpio_ssel_t); 00133 00134 /** Create a SPI master connected to the specified pins. 00135 * 00136 * @note This constructor passes the SSEL pin selection to the target HAL. 00137 * Not all targets support SSEL, so this cannot be relied on in portable code. 00138 * Portable code should use the alternative constructor that uses GPIO 00139 * for SSEL. 00140 * 00141 * @note You can specify mosi or miso as NC if not used. 00142 * 00143 * @param static_pinmap reference to structure which holds static pinmap. 00144 */ 00145 SPI(const spi_pinmap_t &static_pinmap); 00146 SPI(const spi_pinmap_t &&) = delete; // prevent passing of temporary objects 00147 00148 /** Create a SPI master connected to the specified pins. 00149 * 00150 * @note This constructor manipulates the SSEL pin as a GPIO output 00151 * using a DigitalOut object. This should work on any target, and permits 00152 * the use of select() and deselect() methods to keep the pin asserted 00153 * between transfers. 00154 * 00155 * @note You can specify mosi or miso as NC if not used. 00156 * 00157 * @param static_pinmap reference to structure which holds static pinmap. 00158 * @param ssel SPI Chip Select pin. 00159 */ 00160 SPI(const spi_pinmap_t &static_pinmap, PinName ssel); 00161 SPI(const spi_pinmap_t &&, PinName) = delete; // prevent passing of temporary objects 00162 00163 virtual ~SPI(); 00164 00165 /** Configure the data transmission format. 00166 * 00167 * @param bits Number of bits per SPI frame (4 - 16). 00168 * @param mode Clock polarity and phase mode (0 - 3). 00169 * 00170 * @code 00171 * mode | POL PHA 00172 * -----+-------- 00173 * 0 | 0 0 00174 * 1 | 0 1 00175 * 2 | 1 0 00176 * 3 | 1 1 00177 * @endcode 00178 */ 00179 void format(int bits, int mode = 0); 00180 00181 /** Set the SPI bus clock frequency. 00182 * 00183 * @param hz Clock frequency in Hz (default = 1MHz). 00184 */ 00185 void frequency(int hz = 1000000); 00186 00187 /** Write to the SPI Slave and return the response. 00188 * 00189 * @param value Data to be sent to the SPI slave. 00190 * 00191 * @return Response from the SPI slave. 00192 */ 00193 virtual int write(int value); 00194 00195 /** Write to the SPI Slave and obtain the response. 00196 * 00197 * The total number of bytes sent and received will be the maximum of 00198 * tx_length and rx_length. The bytes written will be padded with the 00199 * value 0xff. 00200 * 00201 * @param tx_buffer Pointer to the byte-array of data to write to the device. 00202 * @param tx_length Number of bytes to write, may be zero. 00203 * @param rx_buffer Pointer to the byte-array of data to read from the device. 00204 * @param rx_length Number of bytes to read, may be zero. 00205 * @return 00206 * The number of bytes written and read from the device. This is 00207 * maximum of tx_length and rx_length. 00208 */ 00209 virtual int write(const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length); 00210 00211 /** Acquire exclusive access to this SPI bus. 00212 */ 00213 virtual void lock(void); 00214 00215 /** Release exclusive access to this SPI bus. 00216 */ 00217 virtual void unlock(void); 00218 00219 /** Assert the Slave Select line, acquiring exclusive access to this SPI bus. 00220 * 00221 * If use_gpio_ssel was not passed to the constructor, this only acquires 00222 * exclusive access; it cannot assert the Slave Select line. 00223 */ 00224 void select(void); 00225 00226 /** Deassert the Slave Select line, releasing exclusive access to this SPI bus. 00227 */ 00228 void deselect(void); 00229 00230 /** Set default write data. 00231 * SPI requires the master to send some data during a read operation. 00232 * Different devices may require different default byte values. 00233 * For example: A SD Card requires default bytes to be 0xFF. 00234 * 00235 * @param data Default character to be transmitted during a read operation. 00236 */ 00237 void set_default_write_value(char data); 00238 00239 #if DEVICE_SPI_ASYNCH 00240 00241 /** Start non-blocking SPI transfer using 8bit buffers. 00242 * 00243 * This function locks the deep sleep until any event has occurred. 00244 * 00245 * @param tx_buffer The TX buffer with data to be transferred. If NULL is passed, 00246 * the default SPI value is sent. 00247 * @param tx_length The length of TX buffer in bytes. 00248 * @param rx_buffer The RX buffer which is used for received data. If NULL is passed, 00249 * received data are ignored. 00250 * @param rx_length The length of RX buffer in bytes. 00251 * @param callback The event callback function. 00252 * @param event The event mask of events to modify. @see spi_api.h for SPI events. 00253 * 00254 * @return Operation result. 00255 * @retval 0 If the transfer has started. 00256 * @retval -1 If SPI peripheral is busy. 00257 */ 00258 template<typename Type> 00259 int transfer(const Type *tx_buffer, int tx_length, Type *rx_buffer, int rx_length, const event_callback_t &callback, int event = SPI_EVENT_COMPLETE) 00260 { 00261 if (spi_active(&_peripheral->spi)) { 00262 return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, sizeof(Type) * 8, callback, event); 00263 } 00264 start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, sizeof(Type) * 8, callback, event); 00265 return 0; 00266 } 00267 00268 /** Abort the on-going SPI transfer, and continue with transfers in the queue, if any. 00269 */ 00270 void abort_transfer(); 00271 00272 /** Clear the queue of transfers. 00273 */ 00274 void clear_transfer_buffer(); 00275 00276 /** Clear the queue of transfers and abort the on-going transfer. 00277 */ 00278 void abort_all_transfers(); 00279 00280 /** Configure DMA usage suggestion for non-blocking transfers. 00281 * 00282 * @param usage The usage DMA hint for peripheral. 00283 * 00284 * @return Result of the operation. 00285 * @retval 0 The usage was set. 00286 * @retval -1 Usage cannot be set as there is an ongoing transaction. 00287 */ 00288 int set_dma_usage(DMAUsage usage); 00289 00290 #if !defined(DOXYGEN_ONLY) 00291 protected: 00292 00293 /** SPI interrupt handler. 00294 */ 00295 void irq_handler_asynch(void); 00296 00297 /** Start the transfer or put it on the queue. 00298 * 00299 * @param tx_buffer The TX buffer with data to be transferred. If NULL is passed, 00300 * the default SPI value is sent 00301 * @param tx_length The length of TX buffer in bytes. 00302 * @param rx_buffer The RX buffer which is used for received data. If NULL is passed, 00303 * received data are ignored. 00304 * @param rx_length The length of RX buffer in bytes. 00305 * @param bit_width The buffers element width in bits. 00306 * @param callback The event callback function. 00307 * @param event The event mask of events to modify. 00308 * 00309 * @return Operation success. 00310 * @retval 0 A transfer was started or added to the queue. 00311 * @retval -1 Transfer can't be added because queue is full. 00312 */ 00313 int transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event); 00314 00315 /** Put a transfer on the transfer queue. 00316 * 00317 * @param tx_buffer The TX buffer with data to be transferred. If NULL is passed, 00318 * the default SPI value is sent. 00319 * @param tx_length The length of TX buffer in bytes. 00320 * @param rx_buffer The RX buffer which is used for received data. If NULL is passed, 00321 * received data are ignored. 00322 * @param rx_length The length of RX buffer in bytes. 00323 * @param bit_width The buffers element width in bits. 00324 * @param callback The event callback function. 00325 * @param event The event mask of events to modify. 00326 * 00327 * @return Operation success. 00328 * @retval 0 A transfer was added to the queue. 00329 * @retval -1 Transfer can't be added because queue is full. 00330 */ 00331 int queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event); 00332 00333 /** Configure a callback, SPI peripheral, and initiate a new transfer. 00334 * 00335 * @param tx_buffer The TX buffer with data to be transferred. If NULL is passed, 00336 * the default SPI value is sent. 00337 * @param tx_length The length of TX buffer in bytes. 00338 * @param rx_buffer The RX buffer which is used for received data. If NULL is passed, 00339 * received data are ignored. 00340 * @param rx_length The length of RX buffer in bytes. 00341 * @param bit_width The buffers element width. 00342 * @param callback The event callback function. 00343 * @param event The event mask of events to modify. 00344 */ 00345 void start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t &callback, int event); 00346 00347 private: 00348 /** Lock deep sleep only if it is not yet locked */ 00349 void lock_deep_sleep(); 00350 00351 /** Unlock deep sleep in case it is locked */ 00352 void unlock_deep_sleep(); 00353 00354 00355 #if TRANSACTION_QUEUE_SIZE_SPI 00356 /** Start a new transaction. 00357 * 00358 * @param data Transaction data. 00359 */ 00360 void start_transaction(transaction_t *data); 00361 00362 /** Dequeue a transaction and start the transfer if there was one pending. 00363 */ 00364 void dequeue_transaction(); 00365 00366 #endif // TRANSACTION_QUEUE_SIZE_SPI 00367 #endif // !defined(DOXYGEN_ONLY) 00368 #endif // DEVICE_SPI_ASYNCH 00369 00370 #if !defined(DOXYGEN_ONLY) 00371 protected: 00372 #ifdef DEVICE_SPI_COUNT 00373 // HAL must have defined this as a global enum 00374 typedef ::SPIName SPIName; 00375 #else 00376 // HAL may or may not have defined it - use a local definition 00377 enum SPIName { GlobalSPI }; 00378 #endif 00379 00380 // All members of spi_peripheral_s must be initialized to make the structure 00381 // constant-initialized, and hence able to be omitted by the linker, 00382 // as SingletonPtr now relies on C++ constant-initialization. (Previously it 00383 // worked through C++ zero-initialization). And all the constants should be zero 00384 // to ensure it stays in the actual zero-init part of the image if used, avoiding 00385 // an initialized-data cost. 00386 struct spi_peripheral_s { 00387 /* Internal SPI name identifying the resources. */ 00388 SPIName name = SPIName(0); 00389 /* Internal SPI object handling the resources' state. */ 00390 spi_t spi{}; 00391 /* Used by lock and unlock for thread safety */ 00392 SingletonPtr<PlatformMutex> mutex; 00393 /* Current user of the SPI */ 00394 SPI *owner = nullptr; 00395 #if DEVICE_SPI_ASYNCH && TRANSACTION_QUEUE_SIZE_SPI 00396 /* Queue of pending transfers */ 00397 SingletonPtr<CircularBuffer<Transaction<SPI>, TRANSACTION_QUEUE_SIZE_SPI> > transaction_buffer; 00398 #endif 00399 }; 00400 00401 // holds spi_peripheral_s per peripheral on the device. 00402 // Drawback: it costs ram size even if the device is not used, however 00403 // application can limit the allocation via JSON. 00404 static spi_peripheral_s _peripherals[SPI_PERIPHERALS_USED]; 00405 static int _peripherals_used; 00406 00407 // Holds the reference to the associated peripheral. 00408 spi_peripheral_s *_peripheral; 00409 00410 #if DEVICE_SPI_ASYNCH 00411 /* Interrupt */ 00412 CThunk<SPI> _irq; 00413 /* Interrupt handler callback */ 00414 event_callback_t _callback; 00415 /* Current preferred DMA mode @see dma_api.h */ 00416 DMAUsage _usage; 00417 /* Current sate of the sleep manager */ 00418 bool _deep_sleep_locked; 00419 #endif // DEVICE_SPI_ASYNCH 00420 00421 // Configuration. 00422 PinName _mosi; 00423 PinName _miso; 00424 PinName _sclk; 00425 PinName _hw_ssel; 00426 00427 // The Slave Select GPIO if we're doing it ourselves. 00428 DigitalOut _sw_ssel; 00429 00430 /* Size of the SPI frame */ 00431 int _bits; 00432 /* Clock polairy and phase */ 00433 int _mode; 00434 /* Clock frequency */ 00435 int _hz; 00436 /* Default character used for NULL transfers */ 00437 char _write_fill; 00438 /* Select count to handle re-entrant selection */ 00439 int8_t _select_count; 00440 /* Static pinmap data */ 00441 const spi_pinmap_t *_static_pinmap; 00442 /* SPI peripheral name */ 00443 SPIName _peripheral_name; 00444 /* Pointer to spi init function */ 00445 void (*_init_func)(SPI *); 00446 00447 private: 00448 void _do_construct(); 00449 00450 /** Private acquire function without locking/unlocking. 00451 * Implemented in order to avoid duplicate locking and boost performance. 00452 */ 00453 void _acquire(void); 00454 void _set_ssel(int); 00455 00456 /** Private lookup in the static _peripherals table. 00457 */ 00458 static spi_peripheral_s *_lookup(SPIName name); 00459 /** Allocate an entry in the static _peripherals table. 00460 */ 00461 static spi_peripheral_s *_alloc(); 00462 00463 static void _do_init(SPI *obj); 00464 static void _do_init_direct(SPI *obj); 00465 00466 00467 #endif //!defined(DOXYGEN_ONLY) 00468 }; 00469 00470 /** @}*/ 00471 00472 } // namespace mbed 00473 00474 #endif // DEVICE_SPI || DOXYGEN_ONLY 00475 00476 #endif // MBED_SPI_H
Generated on Tue Jul 12 2022 13:54:51 by
