Mistake on this page?
Report an issue in GitHub or email us
SPI.h
1 /* mbed Microcontroller Library
2  * Copyright (c) 2006-2015 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 "platform/PlatformMutex.h"
25 #include "hal/spi_api.h"
26 #include "drivers/DigitalOut.h"
27 #include "platform/SingletonPtr.h"
28 #include "platform/NonCopyable.h"
29 
30 #if defined MBED_CONF_DRIVERS_SPI_COUNT_MAX && DEVICE_SPI_COUNT > MBED_CONF_DRIVERS_SPI_COUNT_MAX
31 #define SPI_PERIPHERALS_USED MBED_CONF_DRIVERS_SPI_COUNT_MAX
32 #elif defined DEVICE_SPI_COUNT
33 #define SPI_PERIPHERALS_USED DEVICE_SPI_COUNT
34 #else
35 /* Backwards compatibility with HALs not providing DEVICE_SPI_COUNT */
36 #define SPI_PERIPHERALS_USED 1
37 #endif
38 
39 #if DEVICE_SPI_ASYNCH
40 #include "platform/CThunk.h"
41 #include "hal/dma_api.h"
42 #include "platform/CircularBuffer.h"
43 #include "platform/FunctionPointer.h"
44 #include "platform/Transaction.h"
45 #endif
46 
47 namespace mbed {
48 /** \addtogroup drivers */
49 
50 struct use_gpio_ssel_t { };
51 const use_gpio_ssel_t use_gpio_ssel;
52 
53 /** A SPI Master, used for communicating with SPI slave devices.
54  *
55  * The default format is set to 8-bits, mode 0, and a clock frequency of 1MHz.
56  *
57  * Most SPI devices will also require Chip Select and Reset signals. These
58  * can be controlled using DigitalOut pins.
59  *
60  * @note Synchronization level: Thread safe
61  *
62  * Example of how to send a byte to a SPI slave and record the response:
63  * @code
64  * #include "mbed.h"
65  *
66  * SPI device(SPI_MOSI, SPI_MISO, SPI_SCLK)
67  *
68  * DigitalOut chip_select(SPI_CS);
69  *
70  * int main() {
71  * device.lock();
72  * chip_select = 0;
73  *
74  * int response = device.write(0xFF);
75  *
76  * chip_select = 1;
77  * device.unlock();
78  * }
79  * @endcode
80  *
81  * Example using hardware Chip Select line:
82  * @code
83  * #include "mbed.h"
84  *
85  * SPI device(SPI_MOSI, SPI_MISO, SPI_SCLK, SPI_CS)
86  *
87  * int main() {
88  * device.lock();
89  * int response = device.write(0xFF);
90  * device.unlock();
91  * }
92  * @endcode
93  * @ingroup drivers
94  */
95 class SPI : private NonCopyable<SPI> {
96 
97 public:
98 
99  /** Create a SPI master connected to the specified pins.
100  *
101  * @note This constructor passes the SSEL pin selection to the target HAL.
102  * Not all targets support SSEL, so this cannot be relied on in portable code.
103  * Portable code should use the alternative constructor that uses GPIO
104  * for SSEL.
105  *
106  * @note You can specify mosi or miso as NC if not used.
107  *
108  * @param mosi SPI Master Out, Slave In pin.
109  * @param miso SPI Master In, Slave Out pin.
110  * @param sclk SPI Clock pin.
111  * @param ssel SPI Chip Select pin.
112  */
113  SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel = NC);
114 
115  /** Create a SPI master connected to the specified pins.
116  *
117  * @note This constructor manipulates the SSEL pin as a GPIO output
118  * using a DigitalOut object. This should work on any target, and permits
119  * the use of select() and deselect() methods to keep the pin asserted
120  * between transfers.
121  *
122  * @note You can specify mosi or miso as NC if not used.
123  *
124  * @param mosi SPI Master Out, Slave In pin.
125  * @param miso SPI Master In, Slave Out pin.
126  * @param sclk SPI Clock pin.
127  * @param ssel SPI Chip Select pin.
128  */
129  SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel, use_gpio_ssel_t);
130 
131  virtual ~SPI();
132 
133  /** Configure the data transmission format.
134  *
135  * @param bits Number of bits per SPI frame (4 - 16).
136  * @param mode Clock polarity and phase mode (0 - 3).
137  *
138  * @code
139  * mode | POL PHA
140  * -----+--------
141  * 0 | 0 0
142  * 1 | 0 1
143  * 2 | 1 0
144  * 3 | 1 1
145  * @endcode
146  */
147  void format(int bits, int mode = 0);
148 
149  /** Set the SPI bus clock frequency.
150  *
151  * @param hz Clock frequency in Hz (default = 1MHz).
152  */
153  void frequency(int hz = 1000000);
154 
155  /** Write to the SPI Slave and return the response.
156  *
157  * @param value Data to be sent to the SPI slave.
158  *
159  * @return Response from the SPI slave.
160  */
161  virtual int write(int value);
162 
163  /** Write to the SPI Slave and obtain the response.
164  *
165  * The total number of bytes sent and received will be the maximum of
166  * tx_length and rx_length. The bytes written will be padded with the
167  * value 0xff.
168  *
169  * @param tx_buffer Pointer to the byte-array of data to write to the device.
170  * @param tx_length Number of bytes to write, may be zero.
171  * @param rx_buffer Pointer to the byte-array of data to read from the device.
172  * @param rx_length Number of bytes to read, may be zero.
173  * @return
174  * The number of bytes written and read from the device. This is
175  * maximum of tx_length and rx_length.
176  */
177  virtual int write(const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length);
178 
179  /** Acquire exclusive access to this SPI bus.
180  */
181  virtual void lock(void);
182 
183  /** Release exclusive access to this SPI bus.
184  */
185  virtual void unlock(void);
186 
187  /** Assert the Slave Select line, acquiring exclusive access to this SPI bus.
188  *
189  * If use_gpio_ssel was not passed to the constructor, this only acquires
190  * exclusive access; it cannot assert the Slave Select line.
191  */
192  void select(void);
193 
194  /** Deassert the Slave Select line, releasing exclusive access to this SPI bus.
195  */
196  void deselect(void);
197 
198  /** Set default write data.
199  * SPI requires the master to send some data during a read operation.
200  * Different devices may require different default byte values.
201  * For example: A SD Card requires default bytes to be 0xFF.
202  *
203  * @param data Default character to be transmitted during a read operation.
204  */
205  void set_default_write_value(char data);
206 
207 #if DEVICE_SPI_ASYNCH
208 
209  /** Start non-blocking SPI transfer using 8bit buffers.
210  *
211  * This function locks the deep sleep until any event has occurred.
212  *
213  * @param tx_buffer The TX buffer with data to be transferred. If NULL is passed,
214  * the default SPI value is sent.
215  * @param tx_length The length of TX buffer in bytes.
216  * @param rx_buffer The RX buffer which is used for received data. If NULL is passed,
217  * received data are ignored.
218  * @param rx_length The length of RX buffer in bytes.
219  * @param callback The event callback function.
220  * @param event The event mask of events to modify. @see spi_api.h for SPI events.
221  *
222  * @return Operation result.
223  * @retval 0 If the transfer has started.
224  * @retval -1 If SPI peripheral is busy.
225  */
226  template<typename Type>
227  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)
228  {
229  if (spi_active(&_peripheral->spi)) {
230  return queue_transfer(tx_buffer, tx_length, rx_buffer, rx_length, sizeof(Type) * 8, callback, event);
231  }
232  start_transfer(tx_buffer, tx_length, rx_buffer, rx_length, sizeof(Type) * 8, callback, event);
233  return 0;
234  }
235 
236  /** Abort the on-going SPI transfer, and continue with transfers in the queue, if any.
237  */
238  void abort_transfer();
239 
240  /** Clear the queue of transfers.
241  */
242  void clear_transfer_buffer();
243 
244  /** Clear the queue of transfers and abort the on-going transfer.
245  */
246  void abort_all_transfers();
247 
248  /** Configure DMA usage suggestion for non-blocking transfers.
249  *
250  * @param usage The usage DMA hint for peripheral.
251  *
252  * @return Result of the operation.
253  * @retval 0 The usage was set.
254  * @retval -1 Usage cannot be set as there is an ongoing transaction.
255  */
256  int set_dma_usage(DMAUsage usage);
257 
258 #if !defined(DOXYGEN_ONLY)
259 protected:
260 
261  /** SPI interrupt handler.
262  */
263  void irq_handler_asynch(void);
264 
265  /** Start the transfer or put it on the queue.
266  *
267  * @param tx_buffer The TX buffer with data to be transferred. If NULL is passed,
268  * the default SPI value is sent
269  * @param tx_length The length of TX buffer in bytes.
270  * @param rx_buffer The RX buffer which is used for received data. If NULL is passed,
271  * received data are ignored.
272  * @param rx_length The length of RX buffer in bytes.
273  * @param bit_width The buffers element width in bits.
274  * @param callback The event callback function.
275  * @param event The event mask of events to modify.
276  *
277  * @return Operation success.
278  * @retval 0 A transfer was started or added to the queue.
279  * @retval -1 Transfer can't be added because queue is full.
280  */
281  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);
282 
283  /** Put a transfer on the transfer queue.
284  *
285  * @param tx_buffer The TX buffer with data to be transferred. If NULL is passed,
286  * the default SPI value is sent.
287  * @param tx_length The length of TX buffer in bytes.
288  * @param rx_buffer The RX buffer which is used for received data. If NULL is passed,
289  * received data are ignored.
290  * @param rx_length The length of RX buffer in bytes.
291  * @param bit_width The buffers element width in bits.
292  * @param callback The event callback function.
293  * @param event The event mask of events to modify.
294  *
295  * @return Operation success.
296  * @retval 0 A transfer was added to the queue.
297  * @retval -1 Transfer can't be added because queue is full.
298  */
299  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);
300 
301  /** Configure a callback, SPI peripheral, and initiate a new transfer.
302  *
303  * @param tx_buffer The TX buffer with data to be transferred. If NULL is passed,
304  * the default SPI value is sent.
305  * @param tx_length The length of TX buffer in bytes.
306  * @param rx_buffer The RX buffer which is used for received data. If NULL is passed,
307  * received data are ignored.
308  * @param rx_length The length of RX buffer in bytes.
309  * @param bit_width The buffers element width.
310  * @param callback The event callback function.
311  * @param event The event mask of events to modify.
312  */
313  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);
314 
315 private:
316  /** Lock deep sleep only if it is not yet locked */
317  void lock_deep_sleep();
318 
319  /** Unlock deep sleep in case it is locked */
320  void unlock_deep_sleep();
321 
322 
323 #if TRANSACTION_QUEUE_SIZE_SPI
324  /** Start a new transaction.
325  *
326  * @param data Transaction data.
327  */
328  void start_transaction(transaction_t *data);
329 
330  /** Dequeue a transaction and start the transfer if there was one pending.
331  */
332  void dequeue_transaction();
333 
334 #endif // TRANSACTION_QUEUE_SIZE_SPI
335 #endif // !defined(DOXYGEN_ONLY)
336 #endif // DEVICE_SPI_ASYNCH
337 
338 #if !defined(DOXYGEN_ONLY)
339 protected:
340 #ifdef DEVICE_SPI_COUNT
341  // HAL must have defined this as a global enum
342  typedef ::SPIName SPIName;
343 #else
344  // HAL may or may not have defined it - use a local definition
345  enum SPIName { GlobalSPI };
346 #endif
347 
348  struct spi_peripheral_s {
349  /* Internal SPI name identifying the resources. */
350  SPIName name;
351  /* Internal SPI object handling the resources' state. */
352  spi_t spi;
353  /* Used by lock and unlock for thread safety */
355  /* Current user of the SPI */
356  SPI *owner;
357 #if DEVICE_SPI_ASYNCH && TRANSACTION_QUEUE_SIZE_SPI
358  /* Queue of pending transfers */
359  SingletonPtr<CircularBuffer<Transaction<SPI>, TRANSACTION_QUEUE_SIZE_SPI> > transaction_buffer;
360 #endif
361  };
362 
363  // holds spi_peripheral_s per peripheral on the device.
364  // Drawback: it costs ram size even if the device is not used, however
365  // application can limit the allocation via JSON.
366  static spi_peripheral_s _peripherals[SPI_PERIPHERALS_USED];
367  static int _peripherals_used;
368 
369  // Holds the reference to the associated peripheral.
370  spi_peripheral_s *_peripheral;
371 
372 #if DEVICE_SPI_ASYNCH
373  /* Interrupt */
374  CThunk<SPI> _irq;
375  /* Interrupt handler callback */
376  event_callback_t _callback;
377  /* Current preferred DMA mode @see dma_api.h */
378  DMAUsage _usage;
379  /* Current sate of the sleep manager */
380  bool _deep_sleep_locked;
381 #endif // DEVICE_SPI_ASYNCH
382 
383  // Configuration.
384  PinName _mosi;
385  PinName _miso;
386  PinName _sclk;
387  PinName _hw_ssel;
388 
389  // The Slave Select GPIO if we're doing it ourselves.
390  DigitalOut _sw_ssel;
391 
392  /* Size of the SPI frame */
393  int _bits;
394  /* Clock polairy and phase */
395  int _mode;
396  /* Clock frequency */
397  int _hz;
398  /* Default character used for NULL transfers */
399  char _write_fill;
400  /* Select count to handle re-entrant selection */
401  int8_t _select_count;
402 
403 private:
404  void _do_construct();
405 
406  /** Private acquire function without locking/unlocking.
407  * Implemented in order to avoid duplicate locking and boost performance.
408  */
409  void _acquire(void);
410  void _set_ssel(int);
411 
412  /** Private lookup in the static _peripherals table.
413  */
414  static spi_peripheral_s *_lookup(SPIName name);
415  /** Allocate an entry in the static _peripherals table.
416  */
417  static spi_peripheral_s *_alloc();
418 
419 #endif //!defined(DOXYGEN_ONLY)
420 };
421 
422 } // namespace mbed
423 
424 #endif // DEVICE_SPI || DOXYGEN_ONLY
425 
426 #endif // MBED_SPI_H
uint8_t spi_active(spi_t *obj)
Attempts to determine if the SPI peripheral is already in use.
Prevents generation of copy constructor and copy assignment operator in derived classes.
Definition: NonCopyable.h:168
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)
Start non-blocking SPI transfer using 8bit buffers.
Definition: SPI.h:227
Callback< R()> callback(R(*func)()=0)
Create a callback class with type inferred from the arguments.
Definition: Callback.h:3848
Transaction structure.
Definition: Transaction.h:33
A digital output, used for setting the state of a pin.
Definition: DigitalOut.h:47
A SPI Master, used for communicating with SPI slave devices.
Definition: SPI.h:95
Class for created a pointer with data bound to it.
Definition: CThunk.h:50
Definition: AnalogIn.h:28
Asynch SPI HAL structure.
Definition: spi_api.h:43
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.