23
23
24
24
#if DEVICE_SPI
25
25
26
+ /* Backwards compatibility with HALs that don't provide this */
27
+ MBED_WEAK SPIName spi_get_peripheral_name (PinName /* mosi*/ , PinName /* miso*/ , PinName /* mclk*/ )
28
+ {
29
+ return (SPIName)1 ;
30
+ }
31
+
26
32
namespace mbed {
27
33
28
- #if DEVICE_SPI_ASYNCH && TRANSACTION_QUEUE_SIZE_SPI
29
- CircularBuffer<Transaction<SPI>, TRANSACTION_QUEUE_SIZE_SPI> SPI::_transaction_buffer;
30
- #endif
34
+ SPI::spi_peripheral_s SPI::_peripherals[SPI_PERIPHERALS_USED];
35
+ int SPI::_peripherals_used;
31
36
32
37
SPI::SPI (PinName mosi, PinName miso, PinName sclk, PinName ssel) :
33
- _spi (),
34
38
#if DEVICE_SPI_ASYNCH
35
39
_irq (this ),
36
- _usage(DMA_USAGE_NEVER),
37
- _deep_sleep_locked(false ),
38
40
#endif
39
- _bits (8 ),
40
- _mode (0 ),
41
- _hz (1000000 ),
42
- _write_fill (SPI_FILL_CHAR)
41
+ _mosi (mosi),
42
+ _miso (miso),
43
+ _sclk (sclk),
44
+ _hw_ssel (ssel),
45
+ _sw_ssel (NC)
46
+ {
47
+ _do_construct ();
48
+ }
49
+
50
+ SPI::SPI (PinName mosi, PinName miso, PinName sclk, PinName ssel, use_gpio_ssel_t ) :
51
+ #if DEVICE_SPI_ASYNCH
52
+ _irq (this ),
53
+ #endif
54
+ _mosi (mosi),
55
+ _miso (miso),
56
+ _sclk (sclk),
57
+ _hw_ssel (NC),
58
+ _sw_ssel (ssel, 1 )
59
+ {
60
+ _do_construct ();
61
+ }
62
+
63
+ void SPI::_do_construct ()
43
64
{
44
65
// No lock needed in the constructor
45
- spi_init (&_spi, mosi, miso, sclk, ssel);
66
+ #if DEVICE_SPI_ASYNCH
67
+ _usage = DMA_USAGE_NEVER;
68
+ _deep_sleep_locked = false ;
69
+ #endif
70
+ _select_count = 0 ;
71
+ _bits = 8 ;
72
+ _mode = 0 ;
73
+ _hz = 1000000 ;
74
+ _write_fill = SPI_FILL_CHAR;
75
+
76
+ SPIName name = spi_get_peripheral_name (_mosi, _miso, _sclk);
77
+
78
+ core_util_critical_section_enter ();
79
+ // lookup in a critical section if we already have it else initialize it
80
+
81
+ _peripheral = SPI::_lookup (name);
82
+ if (!_peripheral) {
83
+ _peripheral = SPI::_alloc ();
84
+ _peripheral->name = name;
85
+ }
86
+ core_util_critical_section_exit ();
87
+ // we don't need to _acquire at this stage.
88
+ // this will be done anyway before any operation.
46
89
}
47
90
48
91
SPI::~SPI ()
49
92
{
50
- if (_owner == this ) {
51
- _owner = NULL ;
93
+ lock ();
94
+ /* Make sure a stale pointer isn't left in peripheral's owner field */
95
+ if (_peripheral->owner == this ) {
96
+ _peripheral->owner = NULL ;
97
+ }
98
+ unlock ();
99
+ }
100
+
101
+ SPI::spi_peripheral_s *SPI::_lookup (SPIName name)
102
+ {
103
+ SPI::spi_peripheral_s *result = NULL ;
104
+ core_util_critical_section_enter ();
105
+ for (int idx = 0 ; idx < _peripherals_used; idx++) {
106
+ if (_peripherals[idx].name == name) {
107
+ result = &_peripherals[idx];
108
+ break ;
109
+ }
52
110
}
111
+ core_util_critical_section_exit ();
112
+ return result;
113
+ }
114
+
115
+ SPI::spi_peripheral_s *SPI::_alloc ()
116
+ {
117
+ MBED_ASSERT (_peripherals_used < SPI_PERIPHERALS_USED);
118
+ return &_peripherals[_peripherals_used++];
53
119
}
54
120
55
121
void SPI::format (int bits, int mode)
@@ -60,8 +126,8 @@ void SPI::format(int bits, int mode)
60
126
// If changing format while you are the owner then just
61
127
// update format, but if owner is changed then even frequency should be
62
128
// updated which is done by acquire.
63
- if (_owner == this ) {
64
- spi_format (&_spi , _bits, _mode, 0 );
129
+ if (_peripheral-> owner == this ) {
130
+ spi_format (&_peripheral-> spi , _bits, _mode, 0 );
65
131
} else {
66
132
_acquire ();
67
133
}
@@ -75,69 +141,78 @@ void SPI::frequency(int hz)
75
141
// If changing format while you are the owner then just
76
142
// update frequency, but if owner is changed then even frequency should be
77
143
// updated which is done by acquire.
78
- if (_owner == this ) {
79
- spi_frequency (&_spi , _hz);
144
+ if (_peripheral-> owner == this ) {
145
+ spi_frequency (&_peripheral-> spi , _hz);
80
146
} else {
81
147
_acquire ();
82
148
}
83
149
unlock ();
84
150
}
85
151
86
- SPI *SPI::_owner = NULL ;
87
- SingletonPtr<PlatformMutex> SPI::_mutex;
88
-
89
- // ignore the fact there are multiple physical spis, and always update if it wasn't us last
90
- void SPI::aquire ()
91
- {
92
- lock ();
93
- if (_owner != this ) {
94
- spi_format (&_spi, _bits, _mode, 0 );
95
- spi_frequency (&_spi, _hz);
96
- _owner = this ;
97
- }
98
- unlock ();
99
- }
100
-
101
152
// Note: Private function with no locking
102
153
void SPI::_acquire ()
103
154
{
104
- if (_owner != this ) {
105
- spi_format (&_spi, _bits, _mode, 0 );
106
- spi_frequency (&_spi, _hz);
107
- _owner = this ;
155
+ if (_peripheral->owner != this ) {
156
+ spi_init (&_peripheral->spi , _mosi, _miso, _sclk, _hw_ssel);
157
+ spi_format (&_peripheral->spi , _bits, _mode, 0 );
158
+ spi_frequency (&_peripheral->spi , _hz);
159
+ _peripheral->owner = this ;
108
160
}
109
161
}
110
162
111
163
int SPI::write (int value)
112
164
{
113
- lock ();
114
- _acquire ();
115
- int ret = spi_master_write (&_spi, value);
116
- unlock ();
165
+ select ();
166
+ int ret = spi_master_write (&_peripheral->spi , value);
167
+ deselect ();
117
168
return ret;
118
169
}
119
170
120
171
int SPI::write (const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length)
121
172
{
122
- lock ();
123
- _acquire ();
124
- int ret = spi_master_block_write (&_spi, tx_buffer, tx_length, rx_buffer, rx_length, _write_fill);
125
- unlock ();
173
+ select ();
174
+ int ret = spi_master_block_write (&_peripheral->spi , tx_buffer, tx_length, rx_buffer, rx_length, _write_fill);
175
+ deselect ();
126
176
return ret;
127
177
}
128
178
179
+ void SPI::_set_ssel (int val)
180
+ {
181
+ if (_sw_ssel.is_connected ()) {
182
+ _sw_ssel = val;
183
+ }
184
+ }
185
+
129
186
void SPI::lock ()
130
187
{
131
- _mutex->lock ();
188
+ _peripheral->mutex ->lock ();
189
+ }
190
+
191
+ void SPI::select ()
192
+ {
193
+ lock ();
194
+ if (_select_count++ == 0 ) {
195
+ _acquire ();
196
+ _set_ssel (0 );
197
+ }
132
198
}
133
199
134
200
void SPI::unlock ()
135
201
{
136
- _mutex->unlock ();
202
+ _peripheral->mutex ->unlock ();
203
+ }
204
+
205
+ void SPI::deselect ()
206
+ {
207
+ if (--_select_count == 0 ) {
208
+ _set_ssel (1 );
209
+ }
210
+ unlock ();
137
211
}
138
212
139
213
void SPI::set_default_write_value (char data)
140
214
{
215
+ // this does not actually need to lock the peripheral.
141
216
lock ();
142
217
_write_fill = data;
143
218
unlock ();
@@ -147,7 +222,7 @@ void SPI::set_default_write_value(char data)
147
222
148
223
int SPI::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)
149
224
{
150
- if (spi_active (&_spi )) {
225
+ if (spi_active (&_peripheral-> spi )) {
151
226
return queue_transfer (tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
152
227
}
153
228
start_transfer (tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
@@ -156,7 +231,7 @@ int SPI::transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_
156
231
157
232
void SPI::abort_transfer ()
158
233
{
159
- spi_abort_asynch (&_spi );
234
+ spi_abort_asynch (&_peripheral-> spi );
160
235
unlock_deep_sleep ();
161
236
#if TRANSACTION_QUEUE_SIZE_SPI
162
237
dequeue_transaction ();
@@ -167,7 +242,7 @@ void SPI::abort_transfer()
167
242
void SPI::clear_transfer_buffer ()
168
243
{
169
244
#if TRANSACTION_QUEUE_SIZE_SPI
170
- _transaction_buffer. reset ();
245
+ _peripheral-> transaction_buffer -> reset ();
171
246
#endif
172
247
}
173
248
@@ -179,7 +254,7 @@ void SPI::abort_all_transfers()
179
254
180
255
int SPI::set_dma_usage (DMAUsage usage)
181
256
{
182
- if (spi_active (&_spi )) {
257
+ if (spi_active (&_peripheral-> spi )) {
183
258
return -1 ;
184
259
}
185
260
_usage = usage;
@@ -199,12 +274,12 @@ int SPI::queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, i
199
274
t.callback = callback;
200
275
t.width = bit_width;
201
276
Transaction<SPI> transaction (this , t);
202
- if (_transaction_buffer. full ()) {
277
+ if (_peripheral-> transaction_buffer -> full ()) {
203
278
return -1 ; // the buffer is full
204
279
} else {
205
280
core_util_critical_section_enter ();
206
- _transaction_buffer. push (transaction);
207
- if (!spi_active (&_spi )) {
281
+ _peripheral-> transaction_buffer -> push (transaction);
282
+ if (!spi_active (&_peripheral-> spi )) {
208
283
dequeue_transaction ();
209
284
}
210
285
core_util_critical_section_exit ();
@@ -219,9 +294,10 @@ void SPI::start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer,
219
294
{
220
295
lock_deep_sleep ();
221
296
_acquire ();
297
+ _set_ssel (0 );
222
298
_callback = callback;
223
299
_irq.callback (&SPI::irq_handler_asynch);
224
- spi_master_transfer (&_spi , tx_buffer, tx_length, rx_buffer, rx_length, bit_width, _irq.entry (), event, _usage);
300
+ spi_master_transfer (&_peripheral-> spi , tx_buffer, tx_length, rx_buffer, rx_length, bit_width, _irq.entry (), event, _usage);
225
301
}
226
302
227
303
void SPI::lock_deep_sleep ()
@@ -250,7 +326,7 @@ void SPI::start_transaction(transaction_t *data)
250
326
void SPI::dequeue_transaction ()
251
327
{
252
328
Transaction<SPI> t;
253
- if (_transaction_buffer. pop (t)) {
329
+ if (_peripheral-> transaction_buffer -> pop (t)) {
254
330
SPI *obj = t.get_object ();
255
331
transaction_t *data = t.get_transaction ();
256
332
obj->start_transaction (data);
@@ -261,8 +337,9 @@ void SPI::dequeue_transaction()
261
337
262
338
void SPI::irq_handler_asynch (void )
263
339
{
264
- int event = spi_irq_handler_asynch (&_spi );
340
+ int event = spi_irq_handler_asynch (&_peripheral-> spi );
265
341
if (_callback && (event & SPI_EVENT_ALL)) {
342
+ _set_ssel (1 );
266
343
unlock_deep_sleep ();
267
344
_callback.call (event & SPI_EVENT_ALL);
268
345
}
0 commit comments