Controller.h
Go to the documentation of this file.
1 /****
2  * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development.
3  * Created 2015 by Skurydin Alexey
4  * http://github.com/anakod/Sming
5  * All files of the Sming Core are provided under the LGPL v3 license.
6  *
7  * Controller.h
8  *
9  * @author: 11 December 2018 - mikee47 <mike@sillyhouse.net>
10  *
11  * # SPI master-mode hardware controller
12  *
13  * The ESP8266 SPI hardware is capable of very high transfer speeds and has a number of
14  * features which require a more flexible driver to take advantage of. This module,
15  * together with Device, provide the following features:
16  *
17  * - Support multiple slave devices sharing the same bus
18  * - Custom CS multiplexing supported via callbacks. For example, routing CS2 via HC138
19  * 3:8 decoder allows 8 (or more) SPI devices to share the same bus.
20  * - Use of HSPI (SPI1) using either its own pins or sharing pins with SPI0 (overlapped)
21  * - (Potentially) enabling use of dual/quad operating modes when overlapped
22  * - Making use of hardware command/address/data phases for best efficiency
23  * - Pre-calculation of all register values to optimise switching between slave devices
24  * - Write-only transactions can return immediately rather than waiting for the transfer to
25  * complete. The time spent waiting can be used to prepare the next transaction which can
26  * potentially double the throughput
27  * - Interrupt callback on transaction completion. This can be used to improve system efficiency
28  * on slower devices.
29  * - (Potentially) Using DMA for larger read/write transactions. The SDK only demonstrates
30  * DMA for I2S services but it _may_ be possible to use it for SPI.
31  *
32  *
33  * # Transactions
34  *
35  * Applications call Controller to perform a transfer, or sequence of transfers, as follows:
36  *
37  * - Session setup
38  * - Wait for any HSPI transaction to complete (WAIT_READY)
39  * - Configure clock & mode settings
40  * - Transaction
41  * - WAIT_READY
42  * - Configure command / address / data
43  * - Start operation
44  * - If read required:
45  * - WAIT_READY
46  * - Copy data from FIFO
47  *
48  * Transaction may be repeated for subsequent transfers on same device
49  * CS will be asserted/de-asserted by hardware so not need to end a transaction
50  *
51  * # Overlapped operation
52  *
53  * Both SPI controllers are able to share the pin signals from the flash SPI interface (SPI0).
54  * This is handled through hardware.
55  *
56  * Advantages:
57  * - Gain three pins (GPIO12-14), which liberates the I2S controller
58  * - Dual and quad SPI modes can be used with HSPI
59  *
60  * Disadvantages:
61  * - Slow SPI devices may reduce retrieval speed of program code from Flash memory
62  *
63  * A primary IO MUX (PERIPHS_IO_MUX_CONF_U) selects whether the CPU clock goes through the
64  * SPI clock divider circuitry or not. In overlapped mode the SPI0 setting is used for both,
65  * therefore as most SPI slave devices will not operate at 80MHz this setting has to be disabled
66  * to allow the clocks to be set independently. See PERIPHS_IO_MUX_CONF_U.
67  *
68  * The ESP32 Technical Reference manual gives a very useful insight into how the two SPI
69  * devices work together, as the hardware appears largely similar.
70  *
71  */
72 
73 #pragma once
74 
75 #include <stdint.h>
76 #include <esp_attr.h>
77 #include "Request.h"
78 #include <bitset>
79 #include "Common.h"
80 
81 namespace HSPI
82 {
83 class Device;
84 
91 {
92 public:
93  struct Config {
94  bool dirty{true};
95  // Pre-calculated register values - see updateConfig()
96  struct {
97  uint32_t clock{0};
98  uint32_t ctrl{0};
99  uint32_t pin{0};
100  uint32_t user{0};
101  uint32_t user1{0};
102  } reg;
103  };
104 
115  using SelectDevice = void (*)(uint8_t chipSelect, bool active);
116 
117  virtual ~Controller()
118  {
119  }
120 
121  /* @brief Initialize the HSPI controller
122  */
123  void begin();
124 
128  void end();
129 
137  {
138  selectDeviceCallback = callback;
139  }
140 
148  virtual bool startDevice(Device& dev, PinSet pinSet, uint8_t chipSelect);
149 
153  virtual void stopDevice(Device& dev);
154 
159  void configChanged(Device& dev);
160 
167  uint32_t setSpeed(Device& dev, uint32_t frequency);
168 
169  uint32_t getSpeed(Device& dev) const;
170 
171 #ifdef HSPI_ENABLE_STATS
172  struct Stats {
173  uint32_t requestCount;
174  uint32_t transCount;
175  uint32_t waitCycles;
176  uint32_t tasksQueued;
177  uint32_t tasksCancelled;
178 
179  void clear() volatile
180  {
181  requestCount = 0;
182  transCount = 0;
183  waitCycles = 0;
184  tasksQueued = 0;
185  tasksCancelled = 0;
186  }
187  };
188  static volatile Stats stats;
189 #endif
190 
191  PinSet IRAM_ATTR getActivePinSet() const
192  {
193  return activePinSet;
194  }
195 
196 protected:
197  friend Device;
198 
199  virtual void execute(Request& request);
200 
201 private:
202  static void updateConfig(Device& dev);
203 
204  void queueTask();
205  void executeTask();
206  void startRequest();
207  void nextTransaction();
208  static void isr(Controller* spi);
209  void transactionDone();
210 
211  PinSet activePinSet{PinSet::none};
212  SelectDevice selectDeviceCallback{nullptr};
213  uint8_t overlapDevices{0};
214  uint8_t normalDevices{0};
215  std::bitset<8> chipSelectsInUse;
216  struct Flags {
217  bool spi0ClockChanged : 1;
218  bool taskQueued : 1;
219  };
220  Flags flags{};
221 
222  static constexpr size_t SPI_BUFSIZE{64};
223 
224  // State of the current transaction in progress
225  struct Transaction {
226  Request* request;
227  uint32_t addr;
228  uint16_t outOffset;
229  uint16_t inOffset;
230  uint8_t inlen;
231  IoMode ioMode;
232  // Flags
233  uint8_t bitOrder : 1;
234  volatile uint8_t busy : 1;
235  uint8_t addrShift;
236  uint32_t addrCmdMask;
237  };
238  Transaction trans{};
239 };
240 
241 } // namespace HSPI
PinSet
How SPI hardware pins are connected.
Definition: Common.h:95
virtual void execute(Request &request)
Defines an SPI Request Packet.
Definition: HardwareSPI/src/include/HSPI/Request.h:45
virtual ~Controller()
Definition: Controller.h:117
uint32_t user1
Definition: Controller.h:101
Definition: Common.h:24
void end()
Disable HSPI controller.
uint32_t clock
Definition: Controller.h:97
void configChanged(Device &dev)
Devices call this method to tell the Controller about configuration changes. Internally, we just set a flag and update the register values when required.
virtual bool startDevice(Device &dev, PinSet pinSet, uint8_t chipSelect)
Assign a device to a CS# using a specific pin set. Only one device may be assigned to any CS...
bool dirty
Set when values require updating.
Definition: Controller.h:94
uint32_t getSpeed(Device &dev) const
void onSelectDevice(SelectDevice callback)
Set interrupt callback to use for manual CS control (PinSet::manual) or if CS pin is multiplexed...
Definition: Controller.h:136
uint32_t user
Definition: Controller.h:100
uint32_t setSpeed(Device &dev, uint32_t frequency)
Set the clock for a given frequency.
friend Device
Definition: Controller.h:197
Manages access to SPI hardware.
Definition: Controller.h:90
IoMode
Mode of data transfer.
Definition: Common.h:39
PinSet getActivePinSet() const
Definition: Controller.h:191
uint32_t pin
Definition: Controller.h:99
Definition: Controller.h:93
uint32_t ctrl
Definition: Controller.h:98
void(*)(uint8_t chipSelect, bool active) SelectDevice
Interrupt callback for custom Controllers.
Definition: Controller.h:115
Manages a specific SPI device instance attached to a controller.
Definition: Libraries/HardwareSPI/src/include/HSPI/Device.h:35
struct HSPI::Controller::Config::@42 reg
virtual void stopDevice(Device &dev)
Release CS for a device.