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