STMicroelectronics' implementation of an I2S driver, also including DMA support.

Dependents:   temp X_NUCLEO_CCA01M1 X_NUCLEO_CCA01M1 X_NUCLEO_CCA02M1

Platform compatibility

This driver has been designed to support a wide range of the Nucleo F4 Family of platforms and MCUs, but not all members of this family support I2S and/or some of the members might require slight modifications to the sources of this driver in order to make it work on those.

This driver has for now been tested only with the following platforms:

Revision:
26:468cdd70cd3e
Parent:
24:b78825180506
Child:
27:c2fc3330d0df
--- a/targets/TARGET_STM/stm_i2s_api.c	Fri Mar 10 13:25:07 2017 +0100
+++ b/targets/TARGET_STM/stm_i2s_api.c	Mon Mar 27 16:15:20 2017 +0200
@@ -32,18 +32,27 @@
     I2S_TRANSFER_TYPE_TXRX = 3,
 } transfer_type_t;
 
+typedef enum {
+	I2S_HALF_TRANSFER = 0,
+	I2S_FULL_TRANSFER,
+} dma_transfer_state_t;
+
 typedef struct {
-    DMA_HandleTypeDef tx_dma_handle;
-    DMA_HandleTypeDef rx_dma_handle;
-} dma_handles_t;
+	DMA_HandleTypeDef dma_handle;
+	dma_transfer_state_t t_state;
+} dma_extra_state_t;
+
+typedef struct {
+	I2S_HandleTypeDef i2s_handle;
+	dma_extra_state_t dma_handles[NUM_OF_DIRECTIONS];
+} i2s_dma_handles_t;
 
 #define I2S_NUM (5) // TODO: this approach wastes quite a bit of memory - TO BE IMPROVED!?!?
 
-static I2S_HandleTypeDef I2sHandle[I2S_NUM];
-static DMA_HandleTypeDef DMaHandles[I2S_NUM][NUM_OF_DIRECTIONS];
+static i2s_dma_handles_t I2sHandle[I2S_NUM];
 
 static void init_i2s(i2s_t *obj) {
-    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
+    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
 
     __HAL_I2S_DISABLE(handle);
     HAL_I2S_Init(handle);
@@ -58,19 +67,19 @@
     switch(obj->dma.dma_direction) {
     case DMA_TX:
 	if(obj->dma.dma[DMA_TX] != NULL) {
-	    hdmatx = primary_handle = &DMaHandles[obj->i2s.module][DMA_TX];
+	    hdmatx = primary_handle = &I2sHandle[obj->i2s.module].dma_handles[DMA_TX].dma_handle;
 	}
 	if(obj->dma.dma[DMA_RX] != NULL) {
-	    secondary_handle = &DMaHandles[obj->i2s.module][DMA_RX];
+	    secondary_handle = &I2sHandle[obj->i2s.module].dma_handles[DMA_RX].dma_handle;
 	}
 	break;
     case DMA_RX:
     default:
 	if(obj->dma.dma[DMA_RX] != NULL) {
-	    primary_handle = &DMaHandles[obj->i2s.module][DMA_RX];
+	    primary_handle = &I2sHandle[obj->i2s.module].dma_handles[DMA_RX].dma_handle;
 	}
 	if(obj->dma.dma[DMA_TX] != NULL) {
-	    hdmatx = secondary_handle = &DMaHandles[obj->i2s.module][DMA_TX];
+	    hdmatx = secondary_handle = &I2sHandle[obj->i2s.module].dma_handles[DMA_TX].dma_handle;
 	}
 	break;
     }
@@ -80,9 +89,9 @@
 	HAL_DMA_Init(primary_handle);
 
 	if(hdmatx == primary_handle) {
-	    __HAL_LINKDMA(&I2sHandle[obj->i2s.module], hdmatx, *primary_handle);
+	    __HAL_LINKDMA(&I2sHandle[obj->i2s.module].i2s_handle, hdmatx, *primary_handle);
 	} else {
-	    __HAL_LINKDMA(&I2sHandle[obj->i2s.module], hdmarx, *primary_handle);
+	    __HAL_LINKDMA(&I2sHandle[obj->i2s.module].i2s_handle, hdmarx, *primary_handle);
 	}
     }
 
@@ -91,9 +100,9 @@
 	HAL_DMA_Init(secondary_handle);
 
 	if(hdmatx == secondary_handle) {
-	    __HAL_LINKDMA(&I2sHandle[obj->i2s.module], hdmatx, *secondary_handle);
+	    __HAL_LINKDMA(&I2sHandle[obj->i2s.module].i2s_handle, hdmatx, *secondary_handle);
 	} else {
-	    __HAL_LINKDMA(&I2sHandle[obj->i2s.module], hdmarx, *secondary_handle);
+	    __HAL_LINKDMA(&I2sHandle[obj->i2s.module].i2s_handle, hdmarx, *secondary_handle);
 	}
     }
 }
@@ -131,7 +140,7 @@
 
 static void dma_i2s_init(i2s_t *obj, bool *use_tx, bool *use_rx, bool circular, i2s_dma_prio_t prio) {
     // DMA declarations
-    DMA_HandleTypeDef *primary_handle = &DMaHandles[obj->i2s.module][obj->dma.dma_direction];
+    DMA_HandleTypeDef *primary_handle = &I2sHandle[obj->i2s.module].dma_handles[obj->dma.dma_direction].dma_handle;
     DMA_HandleTypeDef *secondary_handle = NULL;
 
     // DMA initialization & configuration
@@ -178,7 +187,7 @@
 	case DMA_TX:
 	    if(*use_rx) {
 		obj->dma.dma[DMA_RX] = stm_dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_RX));
-		secondary_handle = &DMaHandles[obj->i2s.module][DMA_RX];
+		secondary_handle = &I2sHandle[obj->i2s.module].dma_handles[DMA_RX].dma_handle;
 		MBED_ASSERT(obj->dma.dma[DMA_RX] != STM_DMA_ERROR_OUT_OF_CHANNELS);
 	    }
 	    break;
@@ -186,7 +195,7 @@
 	default:
 	    if(*use_tx) {
 		obj->dma.dma[DMA_TX] = stm_dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_TX));
-		secondary_handle = &DMaHandles[obj->i2s.module][DMA_TX];
+		secondary_handle = &I2sHandle[obj->i2s.module].dma_handles[DMA_TX].dma_handle;
 		MBED_ASSERT(obj->dma.dma[DMA_TX] != STM_DMA_ERROR_OUT_OF_CHANNELS);
 	    }
 	    break;
@@ -339,7 +348,7 @@
     }
 
     // initialize the handle for this master!
-    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
+    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
 
     handle->Instance               = (SPI_TypeDef *)(instance);
     handle->Init.Mode              = i2s_get_mode(mode, &dma_direction);
@@ -416,7 +425,7 @@
 }
 
 void i2s_format(i2s_t *obj, int dbits, int fbits, int polarity) {
-    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
+    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
 
     // Save new values
     if (fbits == 16) { // format MUST be 16B
@@ -447,7 +456,7 @@
 
 void i2s_set_mode(i2s_t *obj, i2s_mode_t mode) {
     uint8_t dma_direction;
-    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
+    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
 
     handle->Init.Mode = i2s_get_mode(mode, &dma_direction);
 
@@ -461,7 +470,7 @@
 }
 
 void i2s_set_protocol(i2s_t *obj, i2s_bitorder_t protocol) {
-    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
+    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
 
     switch (protocol) {
     case PHILIPS:
@@ -489,7 +498,7 @@
 }
 
 void i2s_audio_frequency(i2s_t *obj, uint32_t hz) {
-    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
+    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
 
     if (IS_I2S_AUDIO_FREQ(hz) && (hz != I2S_AUDIOFREQ_DEFAULT)) {
 	handle->Init.AudioFreq = hz;
@@ -512,7 +521,7 @@
 static void i2s_start_asynch_transfer(i2s_t *obj, transfer_type_t transfer_type,
 				      void *tx, void *rx, int length)
 {
-    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
+    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
     obj->i2s.transfer_type = transfer_type;
 
     // the HAL expects number of transfers instead of number of bytes
@@ -618,7 +627,7 @@
     direction = (direction == I2S_TX_EVENT) ? DMA_TX : DMA_RX;
 
     // use the right instance
-    I2S_HandleTypeDef *i2s_handle = &I2sHandle[obj->i2s.module];
+    I2S_HandleTypeDef *i2s_handle = &I2sHandle[obj->i2s.module].i2s_handle;
     DMA_HandleTypeDef *dma_handle = (direction == DMA_TX) ? i2s_handle->hdmatx : i2s_handle->hdmarx;
 
     MBED_ASSERT(dma_handle != NULL);
@@ -688,15 +697,15 @@
 	    // cleanup DMA (after error)
 	    dma_i2s_free(obj, direction);
 	} else { // no error detected
-	    HAL_DMA_StateTypeDef dma_state = HAL_DMA_GetState(dma_handle);
+		size_t offset_dma_handle = offsetof(dma_extra_state_t, dma_handle);
+		dma_extra_state_t *extra_state = (dma_extra_state_t*)(((void*)dma_handle) - offset_dma_handle);
+		dma_transfer_state_t dma_state = extra_state->t_state;
 
 	    switch(dma_state) {
-	    case HAL_DMA_STATE_READY_HALF_MEM0:
-	    case HAL_DMA_STATE_READY_HALF_MEM1:
+	    case I2S_HALF_TRANSFER:
 		event = ((direction == DMA_TX) ? I2S_EVENT_TX_HALF_COMPLETE : I2S_EVENT_RX_HALF_COMPLETE);
 		break;
-	    case HAL_DMA_STATE_READY_MEM0:
-	    case HAL_DMA_STATE_READY_MEM1:
+	    case I2S_FULL_TRANSFER:
 		event = ((direction == DMA_TX) ? I2S_EVENT_TX_COMPLETE : I2S_EVENT_RX_COMPLETE);
 
 		if(dma_handle->Init.Mode != DMA_CIRCULAR) {
@@ -728,7 +737,7 @@
 }
 
 uint8_t i2s_active(i2s_t *obj) {
-    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
+    I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
     HAL_I2S_StateTypeDef state = HAL_I2S_GetState(handle);
 
     switch(state) {
@@ -742,13 +751,13 @@
 }
 
 void i2s_abort_asynch(i2s_t *obj) {
-    I2S_HandleTypeDef *i2s_handle = &I2sHandle[obj->i2s.module];
+    I2S_HandleTypeDef *i2s_handle = &I2sHandle[obj->i2s.module].i2s_handle;
 
     // Stop transfer
     HAL_I2S_DMAStop(i2s_handle);
 
     if(obj->dma.dma[DMA_TX] != NULL) {
-	DMA_HandleTypeDef *dma_handle_tx = &DMaHandles[obj->i2s.module][DMA_TX];
+	DMA_HandleTypeDef *dma_handle_tx = &I2sHandle[obj->i2s.module].dma_handles[DMA_TX].dma_handle;
 
 	// disable interrupt & free resource
 	dma_i2s_free(obj, DMA_TX);
@@ -760,7 +769,7 @@
 	__HAL_DMA_ENABLE(dma_handle_tx);
     }
     if(obj->dma.dma[DMA_RX] != NULL) {
-	DMA_HandleTypeDef *dma_handle_rx = &DMaHandles[obj->i2s.module][DMA_RX];
+	DMA_HandleTypeDef *dma_handle_rx = &I2sHandle[obj->i2s.module].dma_handles[DMA_RX].dma_handle;
 
 	// disable interrupt & free resource
 	dma_i2s_free(obj, DMA_RX);
@@ -779,10 +788,43 @@
     __HAL_I2S_ENABLE(i2s_handle);
 }
 
+/*** Weak function overwrites ***/
+void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s) {
+	size_t offset_i2s_handle = offsetof(i2s_dma_handles_t, i2s_handle);
+	i2s_dma_handles_t *i2s_dma_handle = (i2s_dma_handles_t*)(((void*)hi2s) - offset_i2s_handle);
+	dma_transfer_state_t *dma_t_state = &(i2s_dma_handle->dma_handles[DMA_TX].t_state);
+
+	*dma_t_state = I2S_HALF_TRANSFER;
+}
+
+void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s) {
+	size_t offset_i2s_handle = offsetof(i2s_dma_handles_t, i2s_handle);
+	i2s_dma_handles_t *i2s_dma_handle = (i2s_dma_handles_t*)(((void*)hi2s) - offset_i2s_handle);
+	dma_transfer_state_t *dma_t_state = &(i2s_dma_handle->dma_handles[DMA_RX].t_state);
+
+	*dma_t_state = I2S_HALF_TRANSFER;
+}
+
+void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s) {
+	size_t offset_i2s_handle = offsetof(i2s_dma_handles_t, i2s_handle);
+	i2s_dma_handles_t *i2s_dma_handle = (i2s_dma_handles_t*)(((void*)hi2s) - offset_i2s_handle);
+	dma_transfer_state_t *dma_t_state = &(i2s_dma_handle->dma_handles[DMA_TX].t_state);
+
+	*dma_t_state = I2S_FULL_TRANSFER;
+}
+
+void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) {
+	size_t offset_i2s_handle = offsetof(i2s_dma_handles_t, i2s_handle);
+	i2s_dma_handles_t *i2s_dma_handle = (i2s_dma_handles_t*)(((void*)hi2s) - offset_i2s_handle);
+	dma_transfer_state_t *dma_t_state = &(i2s_dma_handle->dma_handles[DMA_RX].t_state);
+
+	*dma_t_state = I2S_FULL_TRANSFER;
+}
+
 /*** Code for harmonizing frequencies ***/
 static inline I2S_HandleTypeDef *i2s_get_handle(i2s_t *obj)
 {
-    return (I2S_HandleTypeDef *) &I2sHandle[obj->i2s.module];
+    return (I2S_HandleTypeDef *) &I2sHandle[obj->i2s.module].i2s_handle;
 }
 
 static float i2s_compute_closest_frequency(i2s_t *dev_i2s, uint32_t target_freq) {