Mbed OS Reference
Loading...
Searching...
No Matches
SPI.h
1/* mbed Microcontroller Library
2 * Copyright (c) 2006-2019 ARM Limited
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17#ifndef MBED_SPI_H
18#define MBED_SPI_H
19
20#include "platform/platform.h"
21
22#if DEVICE_SPI || defined(DOXYGEN_ONLY)
23
24#include "rtos/Mutex.h"
25#include "hal/spi_api.h"
26#include "drivers/DigitalOut.h"
27#include "platform/SingletonPtr.h"
28#include "platform/NonCopyable.h"
29#include "platform/CacheAlignedBuffer.h"
30
31#if defined MBED_CONF_DRIVERS_SPI_COUNT_MAX && DEVICE_SPI_COUNT > MBED_CONF_DRIVERS_SPI_COUNT_MAX
32#define SPI_PERIPHERALS_USED MBED_CONF_DRIVERS_SPI_COUNT_MAX
33#elif defined DEVICE_SPI_COUNT
34#define SPI_PERIPHERALS_USED DEVICE_SPI_COUNT
35#else
36/* Backwards compatibility with HALs not providing DEVICE_SPI_COUNT */
37#define SPI_PERIPHERALS_USED 1
38#endif
39
40#if DEVICE_SPI_ASYNCH
41#include "platform/CThunk.h"
42#include "hal/dma_api.h"
43#include "platform/CircularBuffer.h"
44#include "platform/Callback.h"
45#include "platform/Transaction.h"
46#include "rtos/EventFlags.h"
47#endif
48
49namespace mbed {
50/**
51 * \defgroup drivers_SPI SPI class
52 * \ingroup drivers-public-api-spi
53 * @{
54 */
55
56struct use_gpio_ssel_t { };
57const use_gpio_ssel_t use_gpio_ssel;
58
59/**
60 * @brief An %SPI Master, used for communicating with %SPI slave devices.
61 *
62 * The default format is set to 8-bits, mode 0, and a clock frequency of 1MHz.
63 *
64 * @note Synchronization level: Thread safe
65 *
66 * %SPI allows you to transfer data to and from peripheral devices using single-word transfers, transactions,
67 * or an asynchronous API.
68 *
69 * Here's how to talk to a chip using the single-word API:
70 * @code{.cpp}
71 * #include "mbed.h"
72 *
73 * SPI device(SPI_MOSI, SPI_MISO, SPI_SCLK, SPI_CS, use_gpio_ssel)
74 *
75 * int main() {
76 * device.format(8, 0);
77 *
78 * device.lock();
79 * device.select();
80 * int response = device.write(0x0A);
81 * int response2 = device.write(0x0B);
82 * device.deselect();
83 * device.unlock();
84 * }
85 * @endcode
86 *
87 * And here's how to do the same thing using a transaction:
88 * @code
89 * #include "mbed.h"
90 *
91 * SPI device(SPI_MOSI, SPI_MISO, SPI_SCLK, SPI_CS, use_gpio_ssel)
92 *
93 * int main() {
94 * device.format(8, 0);
95 *
96 * uint8_t command[2] = {0x0A, 0x0B};
97 * uint8_t response[2];
98 * int result = device.write(command, sizeof(command), response, sizeof(response));
99 * }
100 * @endcode
101 *
102 * <h1>Hardware vs Software Chip Selects</h1>
103 * <p>Most ARM chips have specific pins marked as "hardware chip selects". This means that they are connected
104 * to the %SPI peripheral and are automatically brought low by hardware when data is sent. However, chips
105 * often only have only one pin for each SPI bus that can be used as a hardware chip select. If you wish to
106 * use multiple peripheral devices with one SPI bus, or just don't have access to the HW CS pin, you must use the
107 * %SPI object in "GPIO chip select" mode.</p>
108 *
109 * <p>To use GPIO CS mode, simply pass the CS pin as the 4th constructor parameter, then pass the
110 * special constant \c use_gpio_ssel as the 5th parameter. This puts the object in GPIO mode, where
111 * it will operate the CS line as a regular GPIO pin before and after doing an SPI transfer. This mode
112 * is marginally slower than HW CS mode, but otherwise should offer the same functionality. In fact,
113 * since the pin mapping is more flexible, it may be advisable to use GPIO CS mode by default.</p>
114 *
115 * \warning It is not recommended to control the CS line using a separate DigitalOut instance!
116 * This was needed in very old Mbed versions but should now be considered a legacy practice.
117 * Not only does it make it difficult to use the asynchronous API, but it can also lead to corner
118 * cases which corrupt data. The CS line, whether done through GPIO or HW, should always be managed through
119 * the SPI class.
120 *
121 * <h1>Sharing a Bus</h1>
122 * <p>Multiple %SPI devices may share the same physical bus, so long as each has its own dedicated chip select
123 * (CS) pin. To implement this sharing, each chip's driver should create its own instance of the SPI class, passing
124 * the same MOSI, MISO, and SCLK pins but a different CS pin. Mbed OS will internally share the %SPI hardware
125 * between these objects. Note that this is <i>completely different</i> from how the I2C class handles
126 * sharing.</p>
127 *
128 * <h1>Frame/Word Size</h1>
129 * <p>Mbed OS supports configuration of the %SPI frame size, also known as the word size, which controls how
130 * many bits are sent in one transfer operation (one call to SPI::write()). This parameter should match
131 * the "register size" of the %SPI peripheral that you are talking to. For example, if you're working with a chip
132 * which uses 16-bit registers, you should set the frame size to 16 using SPI::format(). Some Mbed devices also
133 * support 32-bit frames -- use the \c DEVICE_SPI_32BIT_WORDS feature macro to test if yours does.</p>
134 *
135 * <p>The frame size controls the effective width of data written and read from the chip. For example, if you set
136 * frame size to 8, SPI::write(int) will take one byte and return one byte, but if you set it to 16, SPI::write(int)
137 * will take a 16 bit value and return a 16 bit value. You can also do transactions with frame sizes other
138 * than 8. Just be sure to pass the length in bytes, not words!</p>
139 *
140 * <p>It should be noted that changing the frame size can perform an apparent "endian swap" on data being
141 * transmitted. For example, suppose you have the 32-bit integer 0x01020408. On a little-endian processor,
142 * this will be encoded with the LSByte <i>first</i> in memory: <tt>08 04 02 01</tt>. If you send that
143 * integer using one-byte word size, it will appear as such. Consider the following example:</p>
144 * @code{.cpp}
145 * spi.format(8, 0);
146 * uint32_t myInteger = 0x01020408;
147 * spi.write(reinterpret_cast<const char *>(&myInteger), sizeof(myInteger), nullptr, 0);
148 * @endcode
149 *
150 * <p>If you ran this code, then used a logic analyzer to view the bytes on the MOSI line, it would show bytes
151 * matching the layout of the integer in memory:</p>
152 * <pre>
153 * MOSI -> 08 04 02 01
154 * </pre>
155 *
156 * <p>But what about if you used a 32-bit frame size?</p>
157 * @code{.cpp}
158 * spi.format(32, 0);
159 * uint32_t myInteger = 0x01020408;
160 * spi.write<uint32_t>(&myInteger, sizeof(myInteger), nullptr, 0);
161 * @endcode
162 *
163 * <p>In this case, the complete 32-bit integer is sent as a single unit, from its MSBit to its LSBit, without
164 * breaking it into bytes. This will send the data in an order different from the order in memory. Viewed as
165 * bytes, it would look like:</p>
166 *
167 * <pre>
168 * MOSI -> 01 02 04 08
169 * </pre>
170 *
171 * <p>But viewed by a peripheral chip which uses 32-bit SPI words, it would look like:</p>
172 *
173 * <pre>
174 * MOSI -> 0x01020408
175 * </pre>
176 *
177 * <p>When viewed as bytes, it's almost as if you did an endian swap on the data before sending it,
178 * but in fact it's standard %SPI behavior when using frame sizes greater than one byte. This same rule
179 * applies to receiving data, so be sure to check examples in the datasheet to determine what frame
180 * size to use and whether byte swapping is needed when working with an external chip.</p>
181 *
182 * \note Some Mbed targets support frame sizes that are not standard integer sizes, e.g. 4 bits, 7 bits, or
183 * 24 bits. However, the behavior of these frame sizes is currently not tested, and you may need to test what works or
184 * inspect your target's SPI driver code. More work is needed to make these consistent. When available, using these frame sizes
185 * requires writing each word to be transmitted into the next-largest C integer type. For example, to send 24-bit frames, you
186 * would create an array of uint32_ts and write each 24-bit integer into its own uint32_t.
187 * Then you would pass in the byte length of the array (number of frames * 4, NOT number of frames * 3) to the SPI driver.
188 *
189 * <h1>Asynchronous API</h1>
190 * <p>On many processors, Mbed OS also supports asynchronous %SPI. This feature allows you to run %SPI
191 * transfers completely in the background, while other threads execute in the foreground. This can
192 * be extremely useful if you need to send large amounts of data over the %SPI bus but don't want to
193 * block your main thread for ages. To see if your processor supports async %SPI, look for the
194 * DEVICE_SPI_ASYNCH macro.</p>
195 *
196 * <p>The asynchronous API has two different modes: nonblocking (where your thread can keep running, and
197 * the transfer calls a callback when finished) and blocking (where your thread blocks for the duration of
198 * the transfer but others can execute). Here's a sample of how to send the same data as above
199 * using the blocking async API:</p>
200 *
201 * <p>Note that when using the asynchronous API, you must use the CacheAlignedBuffer class when declaring the
202 * receive buffer. This is because some processors' async SPI implementations require the received buffer to
203 * be at an address which is aligned to the processor cache line size. CacheAlignedBuffer takes care of this
204 * for you and provides functions (data(), begin(), end()) to access the underlying data in the buffer.</p>
205 *
206 * @code
207 * #include "mbed.h"
208 *
209 * SPI device(SPI_MOSI, SPI_MISO, SPI_SCLK, SPI_CS, use_gpio_ssel)
210 *
211 * int main() {
212 * device.format(8, 0);
213 *
214 * uint8_t command[2] = {0x0A, 0x0B};
215 * CacheAlignedBuffer<uint8_t, 2> response;
216 * int result = device.transfer_and_wait(command, sizeof(command), response, sizeof(command));
217 * }
218 * @endcode
219 *
220 * <p>This code will cause the data in \c command to be sent to the device and the response to be received into
221 * \c response . During the transfer, the current thread is paused, but other threads can execute.
222 * The non-blocking API does not pause the current thread, but is a bit more complicated to use.
223 * See the SPI::transfer_and_wait() implementation in SPI.cpp for an example.</p>
224 *
225 * <h3>Async: DMA vs Interrupts</h3>
226 * <p>Some processors only provide asynchronous %SPI via interrupts, some only support DMA, and some offer both.
227 * Using interrupts is simpler and generally doesn't require additional resources from the chip, however,
228 * some CPU time will be spent servicing the interrupt while the transfer is running. This can become very
229 * performance-intensive -- on some chips, running async %SPI at frequencies of just a few MHz can be enough
230 * to make the interrupt use 100% of CPU time. In contrast, DMA can require additional resources to be allocated,
231 * (e.g. chips with few DMA channels might only support DMA on one or two %SPI busses at a time), but
232 * can run the bus at full speed without any CPU overhead. Generally, DMA should be preferred if available,
233 * especially if medium to fast bus speeds are needed.</p>
234 *
235 * <p>Consult your chip documentation and the Mbed port docs for your target to find out what is needed to enable
236 * DMA support. For example, for STMicro targets, see
237 * <a href="https://github.com/mbed-ce/mbed-os/wiki/STM32-DMA-SPI-Support">here</a>.To select DMA or interrupts,
238 * use the SPI::set_dma_usage() function. By default, interrupt %SPI will be used unless you change the
239 * setting.</p>
240 *
241 * <h3>Async: Queueing</h3>
242 * <p>The async %SPI system supports an optional transaction queueing mechanism. When this is enabled,
243 * Mbed will allow multiple transactions to be queued up on a single bus, and will execute each one
244 * and deliver the appropriate callback in series. This is mainly useful for the non-blocking
245 * async api (SPI::transfer()), though you can also use it with the blocking API by having multiple
246 * threads call it at once.</p>
247 *
248 * <p>The transaction queue size defaults to 2 on most devices, but you can change that using the
249 * \c drivers.spi_transaction_queue_len option, e.g.</p>
250 * \code{.json}
251 * {
252 * "target_overrides": {
253 * "*": {
254 * "drivers.spi_transaction_queue_len": 3
255 * }
256 * }
257 * }
258 * \endcode
259 *
260 * <p>To save a little bit of memory, you can also set the queue length to 0 to disable the queueing mechanism.</p>
261 *
262 * \warning Currently, the value set by SPI::set_default_write_value() is
263 * <a href="https://github.com/ARMmbed/mbed-os/issues/13941">not respected</a> by the asynchronous %SPI
264 * code. This needs to be fixed.
265 */
266class SPI : private NonCopyable<SPI> {
267
268public:
269
270 /** Create a SPI master connected to the specified pins.
271 *
272 * @note This constructor passes the SSEL pin selection to the target HAL.
273 * Not all targets support SSEL, so this cannot be relied on in portable code.
274 * Portable code should use the alternative constructor that uses GPIO
275 * for SSEL.
276 *
277 * @note You can specify mosi or miso as NC if not used.
278 *
279 * @param mosi SPI Master Out, Slave In pin.
280 * @param miso SPI Master In, Slave Out pin.
281 * @param sclk SPI Clock pin.
282 * @param ssel SPI Chip Select pin.
283 */
284 SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel = NC);
285
286 /** Create a SPI master connected to the specified pins.
287 *
288 * @note This constructor manipulates the SSEL pin as a GPIO output
289 * using a DigitalOut object. This should work on any target, and permits
290 * the use of select() and deselect() methods to keep the pin asserted
291 * between transfers.
292 *
293 * @note You can specify mosi or miso as NC if not used.
294 *
295 * @param mosi SPI Master Out, Slave In pin.
296 * @param miso SPI Master In, Slave Out pin.
297 * @param sclk SPI Clock pin.
298 * @param ssel SPI Chip Select pin.
299 */
300 SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel, use_gpio_ssel_t);
301
302 /** Create a SPI master connected to the specified pins.
303 *
304 * @note This constructor passes the SSEL pin selection to the target HAL.
305 * Not all targets support SSEL, so this cannot be relied on in portable code.
306 * Portable code should use the alternative constructor that uses GPIO
307 * for SSEL.
308 *
309 * @note You can specify mosi or miso as NC if not used.
310 *
311 * @param static_pinmap reference to structure which holds static pinmap.
312 */
313 SPI(const spi_pinmap_t &static_pinmap);
314 SPI(const spi_pinmap_t &&) = delete; // prevent passing of temporary objects
315
316 /** Create a SPI master connected to the specified pins.
317 *
318 * @note This constructor manipulates the SSEL pin as a GPIO output
319 * using a DigitalOut object. This should work on any target, and permits
320 * the use of select() and deselect() methods to keep the pin asserted
321 * between transfers.
322 *
323 * @note You can specify mosi or miso as NC if not used.
324 *
325 * @param static_pinmap reference to structure which holds static pinmap.
326 * @param ssel SPI Chip Select pin.
327 */
328 SPI(const spi_pinmap_t &static_pinmap, PinName ssel);
329 SPI(const spi_pinmap_t &&, PinName) = delete; // prevent passing of temporary objects
330
331 virtual ~SPI();
332
333 /**
334 * @brief Configure the data transmission format.
335 *
336 * @param bits Number of bits per %SPI frame (4 - 32, target dependent).
337 * @param mode Clock polarity and phase mode (0 - 3).
338 *
339 * @code
340 * mode | POL PHA
341 * -----+--------
342 * 0 | 0 0
343 * 1 | 0 1
344 * 2 | 1 0
345 * 3 | 1 1
346 * @endcode
347 */
348 void format(int bits, int mode = 0);
349
350 /**
351 * @brief Set the %SPI bus clock frequency.
352 *
353 * @param hz Clock frequency in Hz (default = 1MHz).
354 */
355 void frequency(int hz = 1000000);
356
357 /**
358 * @brief Write to the %SPI Slave and return the response.
359 *
360 * @param value Data to be sent to the SPI slave. The number of significant bits in this
361 * value depend on the \c bits parameter to format().
362 *
363 * @return Response from the %SPI slave. The number of significant bits in this
364 * value depend on the \c bits parameter to format().
365 */
366 virtual int write(int value);
367
368 /**
369 * @brief Write to the SPI Slave and obtain the response.
370 *
371 * The total number of bytes sent and received will be the maximum of
372 * tx_length and rx_length. The bytes written will be padded with the
373 * value 0xff.
374 *
375 * Note: Even if the word size / bits per frame is not 8, \c rx_length and \c tx_length
376 * still count bytes of input data, not numbers of words.
377 *
378 * @param tx_buffer Pointer to the byte-array of data to write to the device.
379 * @param tx_length Number of bytes to write, may be zero.
380 * @param rx_buffer Pointer to the byte-array of data to read from the device.
381 * @param rx_length Number of bytes to read, may be zero.
382 * @return
383 * The number of bytes written and read from the device (as an int). This is
384 * maximum of tx_length and rx_length.
385 */
386 template<typename WordT>
387 typename std::enable_if<std::is_integral<WordT>::value, int>::type
388 write(const WordT *tx_buffer, int tx_length, WordT *rx_buffer, int rx_length)
389 {
390 return write_internal(reinterpret_cast<char const *>(tx_buffer), tx_length, reinterpret_cast<char *>(rx_buffer), rx_length);
391 }
392
393 // Overloads of the above to support passing nullptr
394 template<typename WordT>
395 typename std::enable_if<std::is_integral<WordT>::value, int>::type
396 write(const std::nullptr_t tx_buffer, int tx_length, WordT *rx_buffer, int rx_length)
397 {
398 return write_internal(tx_buffer, tx_length, reinterpret_cast<char *>(rx_buffer), rx_length);
399 }
400
401 template<typename WordT>
402 typename std::enable_if<std::is_integral<WordT>::value, int>::type
403 write(const WordT *tx_buffer, int tx_length, std::nullptr_t rx_buffer, int rx_length)
404 {
405 return write_internal(reinterpret_cast<char const *>(tx_buffer), tx_length, rx_buffer, rx_length);
406 }
407
408 /**
409 * @brief Acquire exclusive access to this SPI bus.
410 *
411 * This function blocks until the chosen SPI peripheral is not being used by any other SPI objects.
412 * Careful -- if other code leaves the bus locked, this could block forever!
413 */
414 virtual void lock(void);
415
416 /**
417 * @brief Release exclusive access to this SPI bus.
418 *
419 * This allows other code to do operations using the SPI peripheral.
420 */
421 virtual void unlock(void);
422
423 /**
424 * @brief Assert the Slave Select line and acquire exclusive access to this SPI bus.
425 *
426 * The slave select line will remain selected (low) for all following operations until
427 * you call #deselect() on this instance. This allows you to string together multiple SPI transactions
428 * as if they were a single operation (from the perspective of peripheral chips).
429 *
430 * If use_gpio_ssel was not passed to the constructor, manual control of the SSEL line is not possible,
431 * and this function behaves identically to #lock().
432 *
433 * Like #lock(), this function will block until exclusive access can be acquired.
434 *
435 * \warning Do not call this function while an asynchronous transfer is in progress,
436 * as undefined behavior can occur.
437 */
438 void select(void);
439
440 /**
441 * @brief Deassert the Slave Select line, releasing exclusive access to this SPI bus.
442 *
443 * If use_gpio_ssel was not passed to the constructor, manual control of the SSEL line is not possible,
444 * and this function behaves identically to #unlock().
445 *
446 * \warning Do not call this function while an asynchronous transfer is in progress,
447 * as undefined behavior can occur.
448 */
449 void deselect(void);
450
451 /** Set default write data.
452 * SPI requires the master to send some data during a read operation.
453 * Different devices may require different default byte values.
454 * For example: A SD Card requires default bytes to be 0xFF.
455 *
456 * @param data Default character to be transmitted during a read operation.
457 */
458 void set_default_write_value(char data);
459
460#if DEVICE_SPI_ASYNCH
461
462 /**
463 * @brief Start non-blocking %SPI transfer.
464 *
465 * This function locks the deep sleep until any event has occurred.
466 *
467 * @param tx_buffer The TX buffer with data to be transferred. If NULL is passed,
468 * the default %SPI value is sent.
469 * @param tx_length The length of TX buffer in bytes.
470 * @param rx_buffer The RX buffer which is used for received data. Rather than a C array, a CacheAlignedBuffer
471 * structure must be passed so that cache alignment can be handled for data received from DMA.
472 * May be nullptr if rx_length is 0.
473 * @param rx_length The length of RX buffer in bytes.
474 * @param callback The event callback function.
475 * @param event The logical OR of events to subscribe to. May be #SPI_EVENT_ALL, or some combination
476 * of the flags #SPI_EVENT_ERROR, #SPI_EVENT_COMPLETE, or #SPI_EVENT_RX_OVERFLOW
477 *
478 * @return Operation result (integer)
479 * @retval 0 If the transfer has started.
480 * @retval -1 if the transfer could not be enqueued (increase drivers.spi_transaction_queue_len option)
481 */
482 template<typename WordT>
483 typename std::enable_if<std::is_integral<WordT>::value, int>::type
484 transfer(const WordT *tx_buffer, int tx_length, CacheAlignedBuffer<WordT> &rx_buffer, int rx_length, const event_callback_t &callback, int event = SPI_EVENT_COMPLETE)
485 {
486 MBED_ASSERT(rx_length <= static_cast<int>(rx_buffer.capacity() * sizeof(WordT)));
487 return transfer_internal(tx_buffer, tx_length, rx_buffer.data(), rx_length, callback, event);
488 }
489
490 // Overloads of the above to support passing nullptr
491 template<typename WordT>
492 typename std::enable_if<std::is_integral<WordT>::value, int>::type
493 transfer(const std::nullptr_t tx_buffer, int tx_length, CacheAlignedBuffer<WordT> &rx_buffer, int rx_length, const event_callback_t &callback, int event = SPI_EVENT_COMPLETE)
494 {
495 MBED_ASSERT(rx_length <= static_cast<int>(rx_buffer.capacity() * sizeof(WordT)));
496 return transfer_internal(tx_buffer, tx_length, rx_buffer.data(), rx_length, callback, event);
497 }
498 template<typename WordT>
499 typename std::enable_if<std::is_integral<WordT>::value, int>::type
500 transfer(const WordT *tx_buffer, int tx_length, std::nullptr_t rx_buffer, int rx_length, const event_callback_t &callback, int event = SPI_EVENT_COMPLETE)
501 {
502 return transfer_internal(tx_buffer, tx_length, rx_buffer, rx_length, callback, event);
503 }
504
505 /**
506 * @brief Start %SPI transfer and wait until it is complete.
507 *
508 * Like the transactional API this blocks the current thread,
509 * however all work is done in the background and other threads may execute.
510 *
511 * As long as there is space, this function will enqueue the transfer request onto the peripheral,
512 * and block until it is done.
513 *
514 * Internally, the chip vendor may implement this function using either DMA or interrupts.
515 *
516 * @param tx_buffer The TX buffer with data to be transferred. May be nullptr if tx_length is 0.
517 * @param tx_length The length of TX buffer in bytes. If 0, the default %SPI data value is sent when receiving data.
518 * @param rx_buffer The RX buffer which is used for received data. Rather than a C array, a CacheAlignedBuffer
519 * structure must be passed so that cache alignment can be handled for data received from DMA.
520 * May be nullptr if rx_length is 0.
521 * @param rx_length The length of RX buffer in bytes If 0, no reception is done.
522 * @param timeout timeout value. Use #rtos::Kernel::wait_for_u32_forever to wait forever (the default).
523 *
524 * @return Operation result (integer)
525 * @retval -1 if the transfer could not be enqueued (increase drivers.spi_transaction_queue_len option)
526 * @retval 1 on timeout
527 * @retval 2 on other error
528 * @retval 0 on success
529 */
530 template<typename WordT>
531 typename std::enable_if<std::is_integral<WordT>::value, int>::type
532 transfer_and_wait(const WordT *tx_buffer, int tx_length, CacheAlignedBuffer<WordT> &rx_buffer, int rx_length, rtos::Kernel::Clock::duration_u32 timeout = rtos::Kernel::wait_for_u32_forever)
533 {
534 MBED_ASSERT(rx_length <= static_cast<int>(rx_buffer.capacity() * sizeof(WordT)));
535 return transfer_and_wait_internal(tx_buffer, tx_length, rx_buffer.data(), rx_length, timeout);
536 }
537
538 // Overloads of the above to support passing nullptr
539 template<typename WordT>
540 typename std::enable_if<std::is_integral<WordT>::value, int>::type
541 transfer_and_wait(const std::nullptr_t tx_buffer, int tx_length, CacheAlignedBuffer<WordT> &rx_buffer, int rx_length, rtos::Kernel::Clock::duration_u32 timeout = rtos::Kernel::wait_for_u32_forever)
542 {
543 MBED_ASSERT(rx_length <= static_cast<int>(rx_buffer.capacity() * sizeof(WordT)));
544 return transfer_and_wait_internal(tx_buffer, tx_length, rx_buffer.data(), rx_length, timeout);
545 }
546 template<typename WordT>
547 typename std::enable_if<std::is_integral<WordT>::value, int>::type
548 transfer_and_wait(const WordT *tx_buffer, int tx_length, std::nullptr_t rx_buffer, int rx_length, rtos::Kernel::Clock::duration_u32 timeout = rtos::Kernel::wait_for_u32_forever)
549 {
550 return transfer_and_wait_internal(tx_buffer, tx_length, rx_buffer, rx_length, timeout);
551 }
552
553 /**
554 * @brief Abort the on-going SPI transfer, if any, and continue with transfers in the queue, if any.
555 *
556 * @note If a transfer is aborted, its callback will not be called at all.
557 */
559
560 /**
561 * @brief Clear the queue of transfers.
562 *
563 * If a transfer is currently active, it will continue until complete.
564 */
566
567 /**
568 * @brief Clear the queue of transfers and abort any on-going transfer.
569 */
571
572 /** Configure DMA usage suggestion for non-blocking transfers.
573 *
574 * @param usage The usage DMA hint for peripheral.
575 *
576 * @return Result of the operation.
577 * @retval 0 The usage was set.
578 * @retval -1 Usage cannot be set as there is an ongoing transaction.
579 */
581
582#if !defined(DOXYGEN_ONLY)
583protected:
584
585 /** SPI interrupt handler.
586 */
587 void irq_handler_asynch(void);
588
589 /** Start the transfer or put it on the queue.
590 *
591 * @param tx_buffer The TX buffer with data to be transferred. If NULL is passed,
592 * the default SPI value is sent
593 * @param tx_length The length of TX buffer in bytes.
594 * @param rx_buffer The RX buffer which is used for received data. If NULL is passed,
595 * received data are ignored. This buffer is guaranteed to be cache aligned
596 * if the MCU has a cache.
597 * @param rx_length The length of RX buffer in bytes.
598 * @param callback The event callback function.
599 * @param event The event mask of events to modify.
600 *
601 * @return Operation success.
602 * @retval 0 A transfer was started or added to the queue.
603 * @retval -1 Transfer can't be added because queue is full.
604 */
605 int transfer_internal(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, const event_callback_t &callback, int event);
606
607 /**
608 * @brief Start %SPI transfer and wait until it is complete.
609 *
610 * Like the transactional API this blocks the current thread,
611 * however all work is done in the background and other threads may execute.
612 *
613 * As long as there is space, this function will enqueue the transfer request onto the peripheral,
614 * and block until it is done.
615 *
616 * Internally, the chip vendor may implement this function using either DMA or interrupts.
617 *
618 * @param tx_buffer The TX buffer with data to be transferred. May be nullptr if tx_length is 0.
619 * @param tx_length The length of TX buffer in bytes. If 0, no transmission is done.
620 * @param rx_buffer The RX buffer, which is used for received data. May be nullptr if tx_length is 0.
621 * This buffer is guaranteed to be cache aligned if the MCU has a cache.
622 * @param rx_length The length of RX buffer in bytes If 0, no reception is done.
623 * @param timeout timeout value. Use #rtos::Kernel::wait_for_u32_forever to wait forever (the default).
624 *
625 * @return Operation result (integer)
626 * @retval -1 if the transfer could not be enqueued (increase drivers.spi_transaction_queue_len option)
627 * @retval 1 on timeout
628 * @retval 2 on other error
629 * @retval 0 on success
630 */
631 int transfer_and_wait_internal(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, rtos::Kernel::Clock::duration_u32 timeout);
632
633 /** Put a transfer on the transfer queue.
634 *
635 * @param tx_buffer The TX buffer with data to be transferred. If NULL is passed,
636 * the default SPI value is sent.
637 * @param tx_length The length of TX buffer in bytes.
638 * @param rx_buffer The RX buffer which is used for received data. If NULL is passed,
639 * received data are ignored.
640 * @param rx_length The length of RX buffer in bytes.
641 * @param bit_width The buffers element width in bits.
642 * @param callback The event callback function.
643 * @param event The event mask of events to modify.
644 *
645 * @return Operation success.
646 * @retval 0 A transfer was added to the queue.
647 * @retval -1 Transfer can't be added because queue is full.
648 */
649 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);
650
651 /** Configure a callback, SPI peripheral, and initiate a new transfer.
652 *
653 * @param tx_buffer The TX buffer with data to be transferred. If NULL is passed,
654 * the default SPI value is sent.
655 * @param tx_length The length of TX buffer in bytes.
656 * @param rx_buffer The RX buffer which is used for received data. If NULL is passed,
657 * received data are ignored.
658 * @param rx_length The length of RX buffer in bytes.
659 * @param bit_width The buffers element width.
660 * @param callback The event callback function.
661 * @param event The event mask of events to modify.
662 */
663 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);
664
665private:
666 /** Lock deep sleep only if it is not yet locked */
667 void lock_deep_sleep();
668
669 /** Unlock deep sleep in case it is locked */
670 void unlock_deep_sleep();
671
672
673#if MBED_CONF_DRIVERS_SPI_TRANSACTION_QUEUE_LEN
674 /** Start a new transaction.
675 *
676 * @param data Transaction data.
677 */
678 void start_transaction(transaction_t *data);
679
680 /** Dequeue a transaction and start the transfer if there was one pending.
681 */
682 void dequeue_transaction();
683
684#endif // MBED_CONF_DRIVERS_SPI_TRANSACTION_QUEUE_LEN
685#endif // !defined(DOXYGEN_ONLY)
686#endif // DEVICE_SPI_ASYNCH
687
688#if !defined(DOXYGEN_ONLY)
689protected:
690#ifdef DEVICE_SPI_COUNT
691 // HAL must have defined this as a global enum
692 typedef ::SPIName SPIName;
693#else
694 // HAL may or may not have defined it - use a local definition
695 enum SPIName { GlobalSPI };
696#endif
697
698 // All members of spi_peripheral_s must be initialized to make the structure
699 // constant-initialized, and hence able to be omitted by the linker,
700 // as SingletonPtr now relies on C++ constant-initialization. (Previously it
701 // worked through C++ zero-initialization). And all the constants should be zero
702 // to ensure it stays in the actual zero-init part of the image if used, avoiding
703 // an initialized-data cost.
704 struct spi_peripheral_s {
705 /* Internal SPI name identifying the resources. */
706 SPIName name = SPIName(0);
707 /* Internal SPI object handling the resources' state. */
708 spi_t spi{};
709 /* Used by lock and unlock for thread safety */
711 /* Current user of the SPI, if any. */
712 SPI *owner = nullptr;
713 /* Number of SPI objects that have been created which reference this peripheral. */
714 uint8_t numUsers = 0;
715 /* True iff anyone has ever called spi_init() / spi_init_direct() for this peripheral */
716 bool initialized = false;
717#if DEVICE_SPI_ASYNCH && MBED_CONF_DRIVERS_SPI_TRANSACTION_QUEUE_LEN
718 /* Queue of pending transfers */
719 SingletonPtr<CircularBuffer<Transaction<SPI>, MBED_CONF_DRIVERS_SPI_TRANSACTION_QUEUE_LEN> > transaction_buffer;
720#endif
721 };
722
723 // holds spi_peripheral_s per peripheral on the device.
724 // Drawback: it costs ram size even if the device is not used, however
725 // application can limit the allocation via JSON.
726 static spi_peripheral_s _peripherals[SPI_PERIPHERALS_USED];
727 static int _peripherals_used;
728
729 // Holds the reference to the associated peripheral.
730 spi_peripheral_s *_peripheral;
731
732#if DEVICE_SPI_ASYNCH
733 /* Interrupt */
734 CThunk<SPI> _irq;
735 /* Interrupt handler callback */
736 event_callback_t _callback;
737 /* Current preferred DMA mode @see dma_api.h */
738 DMAUsage _usage;
739 /* Current sate of the sleep manager */
740 bool _deep_sleep_locked;
741 /* Whether an async transfer is currently in progress. Specifically, this is true
742 * iff start_transfer() has been called and the chip has been selected but irq_handler_asynch()
743 * has NOT been called yet. */
744 volatile bool _transfer_in_progress = false;
745
746 // If there is a transfer in progress, this indicates whether it used DMA and therefore requires a cache
747 // flush at the end
748 bool _transfer_in_progress_uses_dma;
749
750#if __DCACHE_PRESENT
751 // These variables store the location and length in bytes of the Rx buffer if an async transfer
752 // is in progress. They are used for invalidating the cache after the transfer completes.
753 void *_transfer_in_progress_rx_buffer;
754 size_t _transfer_in_progress_rx_len;
755#endif
756
757 /* Event flags used for transfer_and_wait() */
758 rtos::EventFlags _transfer_and_wait_flags;
759#endif // DEVICE_SPI_ASYNCH
760
761 // Configuration.
762 PinName _mosi;
763 PinName _miso;
764 PinName _sclk;
765 PinName _hw_ssel;
766
767 // The Slave Select GPIO if we're doing it ourselves.
768 DigitalOut _sw_ssel;
769
770 /* Size of the SPI frame */
771 int _bits;
772 /* Clock polarity and phase */
773 int _mode;
774 /* Clock frequency */
775 int _hz;
776 /* Default character used for NULL transfers */
777 char _write_fill;
778 /* Select count to handle re-entrant selection */
779 volatile uint8_t _select_count = 0;
780 /* Static pinmap data */
781 const spi_pinmap_t *_static_pinmap;
782 /* SPI peripheral name */
783 SPIName _peripheral_name;
784 /* Pointer to spi init function */
785 void (*_init_func)(SPI *);
786
787private:
788
789 /**
790 * Get a reference to the mutex used to protect the peripherals array.
791 */
792 rtos::Mutex &_get_peripherals_mutex();
793
794 void _do_construct();
795
796 /** Private acquire function without locking/unlocking.
797 * Implemented in order to avoid duplicate locking and boost performance.
798 */
799 void _acquire(void);
800 void _set_ssel(int);
801
802 /** Private lookup in the static _peripherals table.
803 * Should be called with _peripherals_mutex locked.
804 */
805 static spi_peripheral_s *_lookup(SPIName name);
806
807 /** Allocate an entry in the static _peripherals table.
808 * Should be called with _peripherals_mutex locked.
809 */
810 static spi_peripheral_s *_alloc();
811
812 /// Deallocate the given peripheral.
813 /// Should be called with _peripherals_mutex locked.
814 static void _dealloc(spi_peripheral_s *peripheral);
815
816 static void _do_init(SPI *obj);
817 static void _do_init_direct(SPI *obj);
818
819 /**
820 * @brief Write to the SPI Slave and obtain the response.
821 *
822 * The total number of bytes sent and received will be the maximum of
823 * tx_length and rx_length. The bytes written will be padded with the
824 * value 0xff.
825 *
826 * Note: Even if the word size / bits per frame is not 8, \c rx_length and \c tx_length
827 * still count bytes of input data, not numbers of words.
828 *
829 * @param tx_buffer Pointer to the byte-array of data to write to the device.
830 * @param tx_length Number of bytes to write, may be zero.
831 * @param rx_buffer Pointer to the byte-array of data to read from the device.
832 * @param rx_length Number of bytes to read, may be zero.
833 * @return
834 * The number of bytes written and read from the device. This is
835 * maximum of tx_length and rx_length.
836 */
837 virtual int write_internal(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length);
838
839
840#endif //!defined(DOXYGEN_ONLY)
841};
842
843/** @}*/
844
845} // namespace mbed
846
847#endif // DEVICE_SPI || DOXYGEN_ONLY
848
849#endif // MBED_SPI_H
Class for created a pointer with data bound to it.
Definition CThunk.h:45
CacheAlignedBuffer is used by Mbed in locations where we need a cache-aligned buffer.
Prevents generation of copy constructor and copy assignment operator in derived classes.
An SPI Master, used for communicating with SPI slave devices.
Definition SPI.h:266
std::enable_if< std::is_integral< WordT >::value, int >::type transfer(const WordT *tx_buffer, int tx_length, CacheAlignedBuffer< WordT > &rx_buffer, int rx_length, const event_callback_t &callback, int event=SPI_EVENT_COMPLETE)
Start non-blocking SPI transfer.
Definition SPI.h:484
SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel, use_gpio_ssel_t)
Create a SPI master connected to the specified pins.
void deselect(void)
Deassert the Slave Select line, releasing exclusive access to this SPI bus.
void set_default_write_value(char data)
Set default write data.
std::enable_if< std::is_integral< WordT >::value, int >::type write(const WordT *tx_buffer, int tx_length, WordT *rx_buffer, int rx_length)
Write to the SPI Slave and obtain the response.
Definition SPI.h:388
SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel=NC)
Create a SPI master connected to the specified pins.
std::enable_if< std::is_integral< WordT >::value, int >::type transfer_and_wait(const WordT *tx_buffer, int tx_length, CacheAlignedBuffer< WordT > &rx_buffer, int rx_length, rtos::Kernel::Clock::duration_u32 timeout=rtos::Kernel::wait_for_u32_forever)
Start SPI transfer and wait until it is complete.
Definition SPI.h:532
SPI(const spi_pinmap_t &static_pinmap, PinName ssel)
Create a SPI master connected to the specified pins.
void frequency(int hz=1000000)
Set the SPI bus clock frequency.
int set_dma_usage(DMAUsage usage)
Configure DMA usage suggestion for non-blocking transfers.
virtual int write(int value)
Write to the SPI Slave and return the response.
virtual void unlock(void)
Release exclusive access to this SPI bus.
void format(int bits, int mode=0)
Configure the data transmission format.
void abort_all_transfers()
Clear the queue of transfers and abort any on-going transfer.
void abort_transfer()
Abort the on-going SPI transfer, if any, and continue with transfers in the queue,...
void clear_transfer_buffer()
Clear the queue of transfers.
SPI(const spi_pinmap_t &static_pinmap)
Create a SPI master connected to the specified pins.
void select(void)
Assert the Slave Select line and acquire exclusive access to this SPI bus.
virtual void lock(void)
Acquire exclusive access to this SPI bus.
The EventFlags class is used to control event flags or wait for event flags other threads control.
Definition EventFlags.h:53
The Mutex class is used to synchronize the execution of threads.
Definition Mutex.h:79
#define SPI_EVENT_COMPLETE
Indicates that the transfer completed successfully.
Definition spi_api.h:46
DMAUsage
Enumeration of possible DMA usage hints.
Definition dma_api.h:32
DataT * data()
Get a pointer to the aligned data array inside the buffer.
#define MBED_ASSERT(expr)
MBED_ASSERT Declare runtime assertions: results in runtime error if condition is false.
Definition mbed_assert.h:67
Callback< R(ArgTs...)> callback(R(*func)(ArgTs...)=nullptr) noexcept
Create a callback class with type inferred from the arguments.
Definition Callback.h:678
constexpr Clock::duration_u32 wait_for_u32_forever
Magic "wait forever" constant for Kernel::Clock::duration_u32-based APIs.
Definition Kernel.h:120
Utility class for creating and using a singleton.
Transaction structure.
Definition Transaction.h:33
Asynch SPI HAL structure.
Definition spi_api.h:69