2323
2424#if DEVICE_SPI
2525
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+
2632namespace mbed {
2733
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;
3136
3237SPI::SPI (PinName mosi, PinName miso, PinName sclk, PinName ssel) :
33- _spi (),
3438#if DEVICE_SPI_ASYNCH
3539 _irq (this ),
36- _usage(DMA_USAGE_NEVER),
37- _deep_sleep_locked(false ),
3840#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 ()
4364{
4465 // 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.
4689}
4790
4891SPI::~SPI ()
4992{
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+ }
52110 }
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++];
53119}
54120
55121void SPI::format (int bits, int mode)
@@ -60,8 +126,8 @@ void SPI::format(int bits, int mode)
60126 // If changing format while you are the owner then just
61127 // update format, but if owner is changed then even frequency should be
62128 // 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 );
65131 } else {
66132 _acquire ();
67133 }
@@ -75,69 +141,78 @@ void SPI::frequency(int hz)
75141 // If changing format while you are the owner then just
76142 // update frequency, but if owner is changed then even frequency should be
77143 // 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);
80146 } else {
81147 _acquire ();
82148 }
83149 unlock ();
84150}
85151
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-
101152// Note: Private function with no locking
102153void SPI::_acquire ()
103154{
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 ;
108160 }
109161}
110162
111163int SPI::write (int value)
112164{
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 ();
117168 return ret;
118169}
119170
120171int SPI::write (const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length)
121172{
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 ();
126176 return ret;
127177}
128178
179+ void SPI::_set_ssel (int val)
180+ {
181+ if (_sw_ssel.is_connected ()) {
182+ _sw_ssel = val;
183+ }
184+ }
185+
129186void SPI::lock ()
130187{
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+ }
132198}
133199
134200void SPI::unlock ()
135201{
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 ();
137211}
138212
139213void SPI::set_default_write_value (char data)
140214{
215+ // this does not actually need to lock the peripheral.
141216 lock ();
142217 _write_fill = data;
143218 unlock ();
@@ -147,7 +222,7 @@ void SPI::set_default_write_value(char data)
147222
148223int 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)
149224{
150- if (spi_active (&_spi )) {
225+ if (spi_active (&_peripheral-> spi )) {
151226 return queue_transfer (tx_buffer, tx_length, rx_buffer, rx_length, bit_width, callback, event);
152227 }
153228 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_
156231
157232void SPI::abort_transfer ()
158233{
159- spi_abort_asynch (&_spi );
234+ spi_abort_asynch (&_peripheral-> spi );
160235 unlock_deep_sleep ();
161236#if TRANSACTION_QUEUE_SIZE_SPI
162237 dequeue_transaction ();
@@ -167,7 +242,7 @@ void SPI::abort_transfer()
167242void SPI::clear_transfer_buffer ()
168243{
169244#if TRANSACTION_QUEUE_SIZE_SPI
170- _transaction_buffer. reset ();
245+ _peripheral-> transaction_buffer -> reset ();
171246#endif
172247}
173248
@@ -179,7 +254,7 @@ void SPI::abort_all_transfers()
179254
180255int SPI::set_dma_usage (DMAUsage usage)
181256{
182- if (spi_active (&_spi )) {
257+ if (spi_active (&_peripheral-> spi )) {
183258 return -1 ;
184259 }
185260 _usage = usage;
@@ -199,12 +274,12 @@ int SPI::queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, i
199274 t.callback = callback;
200275 t.width = bit_width;
201276 Transaction<SPI> transaction (this , t);
202- if (_transaction_buffer. full ()) {
277+ if (_peripheral-> transaction_buffer -> full ()) {
203278 return -1 ; // the buffer is full
204279 } else {
205280 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 )) {
208283 dequeue_transaction ();
209284 }
210285 core_util_critical_section_exit ();
@@ -219,9 +294,10 @@ void SPI::start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer,
219294{
220295 lock_deep_sleep ();
221296 _acquire ();
297+ _set_ssel (0 );
222298 _callback = callback;
223299 _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);
225301}
226302
227303void SPI::lock_deep_sleep ()
@@ -250,7 +326,7 @@ void SPI::start_transaction(transaction_t *data)
250326void SPI::dequeue_transaction ()
251327{
252328 Transaction<SPI> t;
253- if (_transaction_buffer. pop (t)) {
329+ if (_peripheral-> transaction_buffer -> pop (t)) {
254330 SPI *obj = t.get_object ();
255331 transaction_t *data = t.get_transaction ();
256332 obj->start_transaction (data);
@@ -261,8 +337,9 @@ void SPI::dequeue_transaction()
261337
262338void SPI::irq_handler_asynch (void )
263339{
264- int event = spi_irq_handler_asynch (&_spi );
340+ int event = spi_irq_handler_asynch (&_peripheral-> spi );
265341 if (_callback && (event & SPI_EVENT_ALL)) {
342+ _set_ssel (1 );
266343 unlock_deep_sleep ();
267344 _callback.call (event & SPI_EVENT_ALL);
268345 }
0 commit comments