57
57
#endif
58
58
59
59
StaticSemaphore_t xEfxSpiIntfSemaBuffer ;
60
- static SemaphoreHandle_t spi_sem ;
60
+ static SemaphoreHandle_t spiTransferLock ;
61
+ static TaskHandle_t spiInitiatorTaskHandle = NULL ;
61
62
62
63
#if defined(EFR32MG12 )
63
64
#include "sl_spidrv_exp_config.h"
64
65
extern SPIDRV_Handle_t sl_spidrv_exp_handle ;
65
- #endif
66
-
67
- #if defined(EFR32MG24 )
66
+ #define SPI_HANDLE sl_spidrv_exp_handle
67
+ #elif defined(EFR32MG24 )
68
68
#include "sl_spidrv_eusart_exp_config.h"
69
69
extern SPIDRV_Handle_t sl_spidrv_eusart_exp_handle ;
70
+ #define SPI_HANDLE sl_spidrv_eusart_exp_handle
71
+ #else
72
+ #error "Unknown platform"
70
73
#endif
71
74
72
- static unsigned int tx_dma_channel ;
73
- static unsigned int rx_dma_channel ;
74
-
75
- static uint32_t dummy_data ; /* Used for DMA - when results don't matter */
76
75
extern void rsi_gpio_irq_cb (uint8_t irqnum );
77
76
//#define RS911X_USE_LDMA
78
77
@@ -137,20 +136,8 @@ void sl_wfx_host_reset_chip(void)
137
136
****************************************************************/
138
137
void rsi_hal_board_init (void )
139
138
{
140
- spi_sem = xSemaphoreCreateBinaryStatic (& xEfxSpiIntfSemaBuffer );
141
- xSemaphoreGive (spi_sem );
142
-
143
- /* Assign DMA channel from Handle*/
144
- #if defined(EFR32MG12 )
145
- /* MG12 + rs9116 combination uses USART driver */
146
- tx_dma_channel = sl_spidrv_exp_handle -> txDMACh ;
147
- rx_dma_channel = sl_spidrv_exp_handle -> rxDMACh ;
148
-
149
- #elif defined(EFR32MG24 )
150
- /* MG24 + rs9116 combination uses EUSART driver */
151
- tx_dma_channel = sl_spidrv_eusart_exp_handle -> txDMACh ;
152
- rx_dma_channel = sl_spidrv_eusart_exp_handle -> rxDMACh ;
153
- #endif
139
+ spiTransferLock = xSemaphoreCreateBinaryStatic (& xEfxSpiIntfSemaBuffer );
140
+ xSemaphoreGive (spiTransferLock );
154
141
155
142
/* GPIO INIT of MG12 & MG24 : Reset, Wakeup, Interrupt */
156
143
WFX_RSI_LOG ("RSI_HAL: init GPIO" );
@@ -163,115 +150,24 @@ void rsi_hal_board_init(void)
163
150
}
164
151
165
152
/*****************************************************************************
166
- *@fn static bool dma_complete_cb(unsigned int channel, unsigned int sequenceNo, void *userParam)
167
- *
168
153
*@brief
169
- * DMA transfer completion callback. Called by the DMA interrupt handler.
170
- * This is being set in the tx/rx of the DMA
171
- *
172
- * @param[in] channel:
173
- * @param[in] sequenceNO: sequence number
174
- * @param[in] userParam :user parameter
154
+ * Spi dma transfer is complete Callback
155
+ * Notify the task that initiated the SPI transfer that it is completed.
156
+ * The callback needs is a SPIDRV_Callback_t function pointer type
157
+ * @param[in] pxHandle: spidrv instance handle
158
+ * @param[in] transferStatus: Error code linked to the completed spi transfer. As master, the return code is irrelevant
159
+ * @param[in] lCount: number of bytes transferred.
175
160
*
176
161
* @return
177
162
* None
178
163
******************************************************************************/
179
- static bool dma_complete_cb ( unsigned int channel , unsigned int sequenceNo , void * userParam )
164
+ static void spi_dmaTransfertComplete ( SPIDRV_HandleData_t * pxHandle , Ecode_t transferStatus , int itemsTransferred )
180
165
{
166
+ configASSERT (spiInitiatorTaskHandle != NULL );
181
167
BaseType_t xHigherPriorityTaskWoken = pdFALSE ;
182
- // uint8_t *buf = (void *)userParam;
183
-
184
- (void ) channel ;
185
- (void ) sequenceNo ;
186
- (void ) userParam ;
187
-
188
- // WFX_RSI_LOG ("SPI: DMA done [%x,%x,%x,%x]", buf [0], buf [1], buf [2], buf [3]);
189
- xSemaphoreGiveFromISR (spi_sem , & xHigherPriorityTaskWoken );
168
+ vTaskNotifyGiveFromISR (spiInitiatorTaskHandle , & xHigherPriorityTaskWoken );
169
+ spiInitiatorTaskHandle = NULL ;
190
170
portYIELD_FROM_ISR (xHigherPriorityTaskWoken );
191
-
192
- #if defined(SL_CATALOG_POWER_MANAGER_PRESENT )
193
- sl_power_manager_remove_em_requirement (SL_POWER_MANAGER_EM1 );
194
- #endif
195
-
196
- return true;
197
- }
198
-
199
- /*************************************************************
200
- * @fn static void receiveDMA(uint8_t *rx_buf, uint16_t xlen)
201
- * @brief
202
- * RX buf was specified
203
- * TX buf was not specified by caller - so we
204
- * transmit dummy data (typically 0)
205
- * @param[in] rx_buf:
206
- * @param[in] xlen:
207
- * @return
208
- * None
209
- *******************************************************************/
210
- static void receiveDMA (uint8_t * rx_buf , uint16_t xlen )
211
- {
212
- /*
213
- * The caller wants to receive data -
214
- * The xmit can be dummy data (no src increment for tx)
215
- */
216
- dummy_data = 0 ;
217
- #if defined(SL_CATALOG_POWER_MANAGER_PRESENT )
218
- sl_power_manager_add_em_requirement (SL_POWER_MANAGER_EM1 );
219
- #endif
220
-
221
- // Start receive DMA
222
- DMADRV_PeripheralMemory (rx_dma_channel , MY_USART_RX_SIGNAL , (void * ) rx_buf , (void * ) & (MY_USART -> RXDATA ), true, xlen ,
223
- dmadrvDataSize1 , dma_complete_cb , NULL );
224
-
225
- // Start transmit DMA.
226
- DMADRV_MemoryPeripheral (tx_dma_channel , MY_USART_TX_SIGNAL , (void * ) & (MY_USART -> TXDATA ), (void * ) & (dummy_data ), false, xlen ,
227
- dmadrvDataSize1 , NULL , NULL );
228
- }
229
-
230
- /*****************************************************************************
231
- *@fn static void transmitDMA(void *rx_buf, void *tx_buf, uint8_t xlen)
232
- *@brief
233
- * we have a tx_buf. There are some instances where
234
- * a rx_buf is not specifed. If one is specified then
235
- * the caller wants results (auto increment src)
236
- * @param[in] rx_buf:
237
- * @param[in] tx_buf:
238
- * @param[in] xlen:
239
- * @return
240
- * None
241
- ******************************************************************************/
242
- static void transmitDMA (uint8_t * rx_buf , uint8_t * tx_buf , uint16_t xlen )
243
- {
244
- void * buf ;
245
- bool srcinc ;
246
- /*
247
- * we have a tx_buf. There are some instances where
248
- * a rx_buf is not specifed. If one is specified then
249
- * the caller wants results (auto increment src)
250
- * TODO - the caller specified 8/32 bit - we should use this
251
- * instead of dmadrvDataSize1 always
252
- */
253
- if (rx_buf == NULL )
254
- {
255
- buf = & dummy_data ;
256
- srcinc = false;
257
- }
258
- else
259
- {
260
- buf = rx_buf ;
261
- srcinc = true;
262
- /* DEBUG */ rx_buf [0 ] = 0xAA ;
263
- rx_buf [1 ] = 0x55 ;
264
- }
265
- #if defined(SL_CATALOG_POWER_MANAGER_PRESENT )
266
- sl_power_manager_add_em_requirement (SL_POWER_MANAGER_EM1 );
267
- #endif
268
-
269
- // Start receive DMA
270
- DMADRV_PeripheralMemory (rx_dma_channel , MY_USART_RX_SIGNAL , buf , (void * ) & (MY_USART -> RXDATA ), srcinc , xlen , dmadrvDataSize1 ,
271
- dma_complete_cb , buf );
272
- // Start transmit DMA.
273
- DMADRV_MemoryPeripheral (tx_dma_channel , MY_USART_TX_SIGNAL , (void * ) & (MY_USART -> TXDATA ), (void * ) tx_buf , true, xlen ,
274
- dmadrvDataSize1 , NULL , NULL );
275
171
}
276
172
277
173
/*********************************************************************
@@ -287,57 +183,60 @@ static void transmitDMA(uint8_t * rx_buf, uint8_t * tx_buf, uint16_t xlen)
287
183
**************************************************************************/
288
184
int16_t rsi_spi_transfer (uint8_t * tx_buf , uint8_t * rx_buf , uint16_t xlen , uint8_t mode )
289
185
{
290
- // WFX_RSI_LOG ("SPI: Xfer: tx=%x,rx=%x,len=%d",(uint32_t)tx_buf, (uint32_t)rx_buf, xlen);
291
- if (xlen > MIN_XLEN )
186
+ if (xlen <= MIN_XLEN || (tx_buf == NULL && rx_buf == NULL )) // at least one buffer needs to be provided
292
187
{
293
- MY_USART -> CMD = USART_CMD_CLEARRX | USART_CMD_CLEARTX ;
294
- if (xSemaphoreTake (spi_sem , portMAX_DELAY ) != pdTRUE )
295
- {
296
- return RSI_FALSE ;
297
- }
298
- if (tx_buf == NULL )
299
- {
300
- receiveDMA (rx_buf , xlen );
301
- }
302
- else
303
- {
304
- transmitDMA (rx_buf , tx_buf , xlen );
305
- }
188
+ return RSI_ERROR_INVALID_PARAM ;
189
+ }
306
190
307
- /*
308
- * receiveDMA() and transmitDMA() are asynchronous
309
- * Our application design assumes that this function is synchronous
310
- * To make it synchronous, we wait to re-acquire the semaphore before exiting this function
311
- * dma_complete_cb() gives back the semaphore when the SPI transfer is done
312
- */
313
- if (xSemaphoreTake (spi_sem , pdMS_TO_TICKS (RSI_SEM_BLOCK_MIN_TIMER_VALUE_MS )) == pdTRUE )
314
- {
315
- // Transfer complete
316
- // Give back the semaphore before exiting, so that it may be re-acquired
317
- // in this function, just before the next transfer
318
- xSemaphoreGive (spi_sem );
319
- }
320
- // Temporary patch
321
- // Sometimes the xSemaphoreTake() above is getting stuck indefinitely
322
- // As a workaround, if the transfer is not done within RSI_SEM_BLOCK_MIN_TIMER_VALUE_MS
323
- // stop and start it again
324
- // No need to re-acquire the semaphore since this is the function that acquired it
325
- // TODO: Remove this after a permanent solution is found to the problem of the transfer getting stuck
326
- else
191
+ (void ) mode ; // currently not used;
192
+ rsi_error_t rsiError = RSI_ERROR_NONE ;
193
+
194
+ if (xSemaphoreTake (spiTransferLock , portMAX_DELAY ) != pdTRUE )
195
+ {
196
+ return RSI_ERROR_SPI_BUSY ;
197
+ }
198
+
199
+ configASSERT (spiInitiatorTaskHandle == NULL ); // No other task should currently be waiting for the dma completion
200
+ spiInitiatorTaskHandle = xTaskGetCurrentTaskHandle ();
201
+
202
+ Ecode_t spiError ;
203
+ if (tx_buf == NULL ) // Rx operation only
204
+ {
205
+ spiError = SPIDRV_MReceive (SPI_HANDLE , rx_buf , xlen , spi_dmaTransfertComplete );
206
+ }
207
+ else if (rx_buf == NULL ) // Tx operation only
208
+ {
209
+ spiError = SPIDRV_MTransmit (SPI_HANDLE , tx_buf , xlen , spi_dmaTransfertComplete );
210
+ }
211
+ else // Tx and Rx operation
212
+ {
213
+ spiError = SPIDRV_MTransfer (SPI_HANDLE , tx_buf , rx_buf , xlen , spi_dmaTransfertComplete );
214
+ }
215
+
216
+ if (spiError == ECODE_EMDRV_SPIDRV_OK )
217
+ {
218
+ // rsi implementation expect a synchronous operation
219
+ // wait for the notification that the dma completed in a block state.
220
+ // it does not consume any CPU time.
221
+ if (ulTaskNotifyTake (pdTRUE , RSI_SEM_BLOCK_MIN_TIMER_VALUE_MS ) != pdPASS )
327
222
{
328
- uint32_t ldma_flags = 0 ;
329
- uint32_t rem_len = 0 ;
330
- rem_len = LDMA_TransferRemainingCount (RSI_LDMA_TRANSFER_CHANNEL_NUM );
331
- LDMA_StopTransfer (RSI_LDMA_TRANSFER_CHANNEL_NUM );
332
- ldma_flags = LDMA_IntGet ();
333
- LDMA_IntClear (ldma_flags );
334
- receiveDMA (rx_buf , rem_len );
335
- if (xSemaphoreTake (spi_sem , portMAX_DELAY ) == pdTRUE )
336
- {
337
- xSemaphoreGive (spi_sem );
338
- }
223
+ int itemsTransferred = 0 ;
224
+ int itemsRemaining = 0 ;
225
+ SPIDRV_GetTransferStatus (SPI_HANDLE , & itemsTransferred , & itemsRemaining );
226
+ WFX_RSI_LOG ("SPI transfert timed out %d/%d (rx%x rx%x)" , itemsTransferred , itemsRemaining , (uint32_t ) tx_buf ,
227
+ (uint32_t ) rx_buf );
228
+
229
+ SPIDRV_AbortTransfer (SPI_HANDLE );
230
+ rsiError = RSI_ERROR_SPI_TIMEOUT ;
339
231
}
340
232
}
233
+ else
234
+ {
235
+ WFX_RSI_LOG ("SPI transfert failed with err:%x (tx%x rx%x)" , spiError , (uint32_t ) tx_buf , (uint32_t ) rx_buf );
236
+ rsiError = RSI_ERROR_SPI_FAIL ;
237
+ spiInitiatorTaskHandle = NULL ; // SPI operation failed. No notification to received.
238
+ }
341
239
342
- return RSI_ERROR_NONE ;
240
+ xSemaphoreGive (spiTransferLock );
241
+ return rsiError ;
343
242
}
0 commit comments