2525
2626namespace mbed {
2727
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;
3130
3231SPI::SPI (PinName mosi, PinName miso, PinName sclk, PinName ssel) :
33- _spi (),
3432#if DEVICE_SPI_ASYNCH
3533 _irq (this ),
36- _usage(DMA_USAGE_NEVER),
37- _deep_sleep_locked(false ),
3834#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 ()
4358{
4459 // 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.
4688}
4789
4890SPI::~SPI ()
4991{
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+ }
52109 }
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++];
53118}
54119
55120void SPI::format (int bits, int mode)
@@ -60,8 +125,8 @@ void SPI::format(int bits, int mode)
60125 // If changing format while you are the owner then just
61126 // update format, but if owner is changed then even frequency should be
62127 // 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 );
65130 } else {
66131 _acquire ();
67132 }
@@ -75,69 +140,78 @@ void SPI::frequency(int hz)
75140 // If changing format while you are the owner then just
76141 // update frequency, but if owner is changed then even frequency should be
77142 // 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);
80145 } else {
81146 _acquire ();
82147 }
83148 unlock ();
84149}
85150
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-
101151// Note: Private function with no locking
102152void SPI::_acquire ()
103153{
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 ;
108159 }
109160}
110161
111162int SPI::write (int value)
112163{
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 ();
117167 return ret;
118168}
119169
120170int SPI::write (const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length)
121171{
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 ();
126175 return ret;
127176}
128177
178+ void SPI::_set_ssel (int val)
179+ {
180+ if (_sw_ssel.is_connected ()) {
181+ _sw_ssel = val;
182+ }
183+ }
184+
129185void SPI::lock ()
130186{
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+ }
132197}
133198
134199void SPI::unlock ()
135200{
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 ();
137210}
138211
139212void SPI::set_default_write_value (char data)
140213{
214+ // this does not actually need to lock the peripheral.
141215 lock ();
142216 _write_fill = data;
143217 unlock ();
@@ -147,7 +221,7 @@ void SPI::set_default_write_value(char data)
147221
148222int 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)
149223{
150- if (spi_active (&_spi )) {
224+ if (spi_active (&_peripheral-> spi )) {
151225 return queue_transfer (tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
152226 }
153227 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_
156230
157231void SPI::abort_transfer ()
158232{
159- spi_abort_asynch (&_spi );
233+ spi_abort_asynch (&_peripheral-> spi );
160234 unlock_deep_sleep ();
161235#if TRANSACTION_QUEUE_SIZE_SPI
162236 dequeue_transaction ();
@@ -167,7 +241,7 @@ void SPI::abort_transfer()
167241void SPI::clear_transfer_buffer ()
168242{
169243#if TRANSACTION_QUEUE_SIZE_SPI
170- _transaction_buffer. reset ();
244+ _peripheral-> transaction_buffer -> reset ();
171245#endif
172246}
173247
@@ -179,7 +253,7 @@ void SPI::abort_all_transfers()
179253
180254int SPI::set_dma_usage (DMAUsage usage)
181255{
182- if (spi_active (&_spi )) {
256+ if (spi_active (&_peripheral-> spi )) {
183257 return -1 ;
184258 }
185259 _usage = usage;
@@ -199,12 +273,12 @@ int SPI::queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, i
199273 t.callback = callback;
200274 t.width = bit_width;
201275 Transaction<SPI> transaction (this , t);
202- if (_transaction_buffer. full ()) {
276+ if (_peripheral-> transaction_buffer -> full ()) {
203277 return -1 ; // the buffer is full
204278 } else {
205279 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 )) {
208282 dequeue_transaction ();
209283 }
210284 core_util_critical_section_exit ();
@@ -219,9 +293,10 @@ void SPI::start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer,
219293{
220294 lock_deep_sleep ();
221295 _acquire ();
296+ _set_ssel (0 );
222297 _callback = callback;
223298 _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);
225300}
226301
227302void SPI::lock_deep_sleep ()
@@ -250,7 +325,7 @@ void SPI::start_transaction(transaction_t *data)
250325void SPI::dequeue_transaction ()
251326{
252327 Transaction<SPI> t;
253- if (_transaction_buffer. pop (t)) {
328+ if (_peripheral-> transaction_buffer -> pop (t)) {
254329 SPI *obj = t.get_object ();
255330 transaction_t *data = t.get_transaction ();
256331 obj->start_transaction (data);
@@ -261,8 +336,9 @@ void SPI::dequeue_transaction()
261336
262337void SPI::irq_handler_asynch (void )
263338{
264- int event = spi_irq_handler_asynch (&_spi );
339+ int event = spi_irq_handler_asynch (&_peripheral-> spi );
265340 if (_callback && (event & SPI_EVENT_ALL)) {
341+ _set_ssel (1 );
266342 unlock_deep_sleep ();
267343 _callback.call (event & SPI_EVENT_ALL);
268344 }
0 commit comments