@@ -143,6 +143,48 @@ static uint8_t nu_spi_get_bytes_per_word(struct spi_s const * const nu_spi)
143143 }
144144}
145145
146+ // Set the DMA usage of this SPI instance.
147+ // Allocates or deallocates channels as necessary.
148+ // If no DMA channels are available, sets DMA usage to DMA_USAGE_NEVER
149+ static void nu_spi_set_dma_usage (struct spi_s * const spi , DMAUsage new_dma_usage )
150+ {
151+ if (new_dma_usage == DMA_USAGE_NEVER )
152+ {
153+ if (spi -> dma_usage != DMA_USAGE_NEVER )
154+ {
155+ // Free channels
156+ dma_channel_free (spi -> dma_chn_id_tx );
157+ spi -> dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS ;
158+ dma_channel_free (spi -> dma_chn_id_rx );
159+ spi -> dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS ;
160+ }
161+ }
162+ else
163+ {
164+ // Temporary or permanent DMA usage
165+ if (spi -> dma_usage == DMA_USAGE_NEVER )
166+ {
167+ // Need to allocate channels
168+ spi -> dma_chn_id_tx = dma_channel_allocate (DMA_CAP_NONE );
169+ if (spi -> dma_chn_id_tx == DMA_ERROR_OUT_OF_CHANNELS )
170+ {
171+ new_dma_usage = DMA_USAGE_NEVER ;
172+ }
173+ else
174+ {
175+ spi -> dma_chn_id_rx = dma_channel_allocate (DMA_CAP_NONE );
176+ if (spi -> dma_chn_id_rx == DMA_ERROR_OUT_OF_CHANNELS )
177+ {
178+ new_dma_usage = DMA_USAGE_NEVER ;
179+ dma_channel_free (spi -> dma_chn_id_tx );
180+ }
181+ }
182+ }
183+ }
184+
185+ spi -> dma_usage = new_dma_usage ;
186+ }
187+
146188#if DEVICE_SPI_ASYNCH
147189static void spi_enable_vector_interrupt (spi_t * obj , uint32_t handler , uint8_t enable );
148190static void spi_master_enable_interrupt (spi_t * obj , uint8_t enable );
@@ -259,10 +301,8 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
259301 SYS_ResetModule (modinit -> rsetidx );
260302
261303#if DEVICE_SPI_ASYNCH
262- obj -> spi .dma_usage = DMA_USAGE_NEVER ;
263- obj -> spi .event = 0 ;
264- obj -> spi .dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS ;
265- obj -> spi .dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS ;
304+ // Note: We don't want to touch the DMA usage here, because either this is a completely new SPI and the DMA usage is already set to 0 (NEVER),
305+ // or it's a re-initialization of an existing SPI and we can allow it to keep its existing DMA settings.
266306
267307 /* NOTE: We use vector to judge if asynchronous transfer is on-going (spi_active).
268308 * At initial time, asynchronous transfer is not on-going and so vector must
@@ -278,14 +318,8 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
278318void spi_free (spi_t * obj )
279319{
280320#if DEVICE_SPI_ASYNCH
281- if (obj -> spi .dma_chn_id_tx != DMA_ERROR_OUT_OF_CHANNELS ) {
282- dma_channel_free (obj -> spi .dma_chn_id_tx );
283- obj -> spi .dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS ;
284- }
285- if (obj -> spi .dma_chn_id_rx != DMA_ERROR_OUT_OF_CHANNELS ) {
286- dma_channel_free (obj -> spi .dma_chn_id_rx );
287- obj -> spi .dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS ;
288- }
321+ // Free DMA channels
322+ nu_spi_set_dma_usage (& obj -> spi , DMA_USAGE_NEVER );
289323#endif
290324
291325 if (spi_is_qspi (obj )) {
@@ -533,20 +567,17 @@ bool spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx,
533567 MBED_ASSERT (tx_length % word_size_bytes == 0 );
534568 MBED_ASSERT (rx_length % word_size_bytes == 0 );
535569
536- obj -> spi .dma_usage = hint ;
537- spi_check_dma_usage (& obj -> spi .dma_usage , & obj -> spi .dma_chn_id_tx , & obj -> spi .dma_chn_id_rx );
538570 // Conditions to go DMA way:
539571 // (1) No DMA support for non-8 multiple data width.
540572 // (2) tx length >= rx length. Otherwise, as tx DMA is done, no bus activity for remaining rx.
541573 if (((obj -> spi .word_size_bits % 8 ) != 0 ) ||
542574 (tx_length < rx_length )) {
543- obj -> spi .dma_usage = DMA_USAGE_NEVER ;
544- dma_channel_free (obj -> spi .dma_chn_id_tx );
545- obj -> spi .dma_chn_id_tx = DMA_ERROR_OUT_OF_CHANNELS ;
546- dma_channel_free (obj -> spi .dma_chn_id_rx );
547- obj -> spi .dma_chn_id_rx = DMA_ERROR_OUT_OF_CHANNELS ;
575+ hint = DMA_USAGE_NEVER ;
548576 }
549577
578+ // Set DMA usage, allocating or releasing DMA channels
579+ nu_spi_set_dma_usage (& obj -> spi , hint );
580+
550581 // SPI IRQ is necessary for both interrupt way and DMA way
551582 spi_enable_event (obj , event , 1 );
552583 spi_buffer_set (obj , tx , tx_length , rx , rx_length );
@@ -689,6 +720,12 @@ void spi_abort_asynch(spi_t *obj)
689720 pdma_base -> CHCTL &= ~(1 << obj -> spi .dma_chn_id_rx );
690721 }
691722 SPI_DISABLE_RX_PDMA (((SPI_T * ) NU_MODBASE (obj -> spi .spi )));
723+
724+ // If DMA was temporary, free its channels
725+ if (obj -> spi .dma_usage == DMA_USAGE_TEMPORARY_ALLOCATED || obj -> spi .dma_usage == DMA_USAGE_OPPORTUNISTIC )
726+ {
727+ nu_spi_set_dma_usage (& obj -> spi , DMA_USAGE_NEVER );
728+ }
692729 }
693730
694731 // Necessary for both interrupt way and DMA way
@@ -927,29 +964,6 @@ static void spi_buffer_set(spi_t *obj, const void *tx, size_t tx_length, void *r
927964 obj -> rx_buff .width = nu_spi_get_bytes_per_word (& obj -> spi ) * 8 ;
928965}
929966
930- static void spi_check_dma_usage (DMAUsage * dma_usage , int * dma_ch_tx , int * dma_ch_rx )
931- {
932- if (* dma_usage != DMA_USAGE_NEVER ) {
933- if (* dma_ch_tx == DMA_ERROR_OUT_OF_CHANNELS ) {
934- * dma_ch_tx = dma_channel_allocate (DMA_CAP_NONE );
935- }
936- if (* dma_ch_rx == DMA_ERROR_OUT_OF_CHANNELS ) {
937- * dma_ch_rx = dma_channel_allocate (DMA_CAP_NONE );
938- }
939-
940- if (* dma_ch_tx == DMA_ERROR_OUT_OF_CHANNELS || * dma_ch_rx == DMA_ERROR_OUT_OF_CHANNELS ) {
941- * dma_usage = DMA_USAGE_NEVER ;
942- }
943- }
944-
945- if (* dma_usage == DMA_USAGE_NEVER ) {
946- dma_channel_free (* dma_ch_tx );
947- * dma_ch_tx = DMA_ERROR_OUT_OF_CHANNELS ;
948- dma_channel_free (* dma_ch_rx );
949- * dma_ch_rx = DMA_ERROR_OUT_OF_CHANNELS ;
950- }
951- }
952-
953967static int spi_is_tx_complete (spi_t * obj )
954968{
955969 return (obj -> tx_buff .pos == obj -> tx_buff .length );
0 commit comments