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:

Committer:
Davide Aliprandi
Date:
Tue Dec 13 18:09:02 2016 +0100
Revision:
2:0c9ce59aee25
Parent:
1:f90318e0923b
Child:
3:25de898f5354
Restored default at 44100Hz, added setting of PLL into the i2s_audio_frequency() API.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wolfgang Betz 1:f90318e0923b 1 #include "mbed_assert.h"
Wolfgang Betz 1:f90318e0923b 2 #include "mbed_error.h"
Wolfgang Betz 1:f90318e0923b 3 #include "stm_i2s_api.h"
Wolfgang Betz 1:f90318e0923b 4
Wolfgang Betz 1:f90318e0923b 5 #include "stm_dma_caps.h"
Wolfgang Betz 1:f90318e0923b 6
Wolfgang Betz 1:f90318e0923b 7 #if DEVICE_I2S
Wolfgang Betz 1:f90318e0923b 8
Wolfgang Betz 1:f90318e0923b 9 #include <math.h>
Wolfgang Betz 1:f90318e0923b 10 #include <string.h>
Wolfgang Betz 1:f90318e0923b 11 #include "cmsis.h"
Wolfgang Betz 1:f90318e0923b 12 #include "pinmap.h"
Wolfgang Betz 1:f90318e0923b 13 #include "PeripheralPins.h"
Davide Aliprandi 2:0c9ce59aee25 14 #include "StmI2sPeripheralPins.h"
Wolfgang Betz 1:f90318e0923b 15
Davide Aliprandi 2:0c9ce59aee25 16 //#define DEBUG_STDIO 1 // betzw - TODO: temporarily enable debug printfs
Wolfgang Betz 1:f90318e0923b 17
Wolfgang Betz 1:f90318e0923b 18 #ifndef DEBUG_STDIO
Wolfgang Betz 1:f90318e0923b 19 # define DEBUG_STDIO 0
Wolfgang Betz 1:f90318e0923b 20 #endif
Wolfgang Betz 1:f90318e0923b 21
Wolfgang Betz 1:f90318e0923b 22 #if DEBUG_STDIO
Wolfgang Betz 1:f90318e0923b 23 # include <stdio.h>
Wolfgang Betz 1:f90318e0923b 24 # define DEBUG_PRINTF(...) do { printf(__VA_ARGS__); } while(0)
Wolfgang Betz 1:f90318e0923b 25 #else
Wolfgang Betz 1:f90318e0923b 26 # define DEBUG_PRINTF(...) {}
Wolfgang Betz 1:f90318e0923b 27 #endif
Wolfgang Betz 1:f90318e0923b 28
Wolfgang Betz 1:f90318e0923b 29 typedef enum {
Wolfgang Betz 1:f90318e0923b 30 I2S_TRANSFER_TYPE_TX = 1,
Wolfgang Betz 1:f90318e0923b 31 I2S_TRANSFER_TYPE_RX = 2,
Wolfgang Betz 1:f90318e0923b 32 I2S_TRANSFER_TYPE_TXRX = 3,
Wolfgang Betz 1:f90318e0923b 33 } transfer_type_t;
Wolfgang Betz 1:f90318e0923b 34
Wolfgang Betz 1:f90318e0923b 35 typedef struct {
Wolfgang Betz 1:f90318e0923b 36 DMA_HandleTypeDef tx_dma_handle;
Wolfgang Betz 1:f90318e0923b 37 DMA_HandleTypeDef rx_dma_handle;
Wolfgang Betz 1:f90318e0923b 38 } dma_handles_t;
Wolfgang Betz 1:f90318e0923b 39
Wolfgang Betz 1:f90318e0923b 40 #define I2S_NUM (5) // betzw: this approach wastes quite a bit of memory - TO BE IMPROVED!?!?
Wolfgang Betz 1:f90318e0923b 41
Wolfgang Betz 1:f90318e0923b 42 static I2S_HandleTypeDef I2sHandle[I2S_NUM];
Wolfgang Betz 1:f90318e0923b 43 static DMA_HandleTypeDef DMaHandles[I2S_NUM][NUM_OF_DIRECTIONS];
Wolfgang Betz 1:f90318e0923b 44
Davide Aliprandi 2:0c9ce59aee25 45 static void init_i2s(i2s_t *obj) {
Wolfgang Betz 1:f90318e0923b 46 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 47
Wolfgang Betz 1:f90318e0923b 48 __HAL_I2S_DISABLE(handle);
Wolfgang Betz 1:f90318e0923b 49 HAL_I2S_Init(handle);
Wolfgang Betz 1:f90318e0923b 50 __HAL_I2S_ENABLE(handle);
Wolfgang Betz 1:f90318e0923b 51 }
Wolfgang Betz 1:f90318e0923b 52
Davide Aliprandi 2:0c9ce59aee25 53 static void init_dmas(i2s_t *obj) {
Wolfgang Betz 1:f90318e0923b 54 DMA_HandleTypeDef *primary_handle = NULL;
Wolfgang Betz 1:f90318e0923b 55 DMA_HandleTypeDef *secondary_handle = NULL;
Wolfgang Betz 1:f90318e0923b 56 DMA_HandleTypeDef *hdmatx = NULL;
Wolfgang Betz 1:f90318e0923b 57
Wolfgang Betz 1:f90318e0923b 58 switch(obj->dma.dma_direction) {
Davide Aliprandi 2:0c9ce59aee25 59 case DMA_TX:
Davide Aliprandi 2:0c9ce59aee25 60 if(obj->dma.dma[DMA_TX] != NULL) {
Davide Aliprandi 2:0c9ce59aee25 61 hdmatx = primary_handle = &DMaHandles[obj->i2s.module][DMA_TX];
Davide Aliprandi 2:0c9ce59aee25 62 }
Davide Aliprandi 2:0c9ce59aee25 63 if(obj->dma.dma[DMA_RX] != NULL) {
Davide Aliprandi 2:0c9ce59aee25 64 secondary_handle = &DMaHandles[obj->i2s.module][DMA_RX];
Davide Aliprandi 2:0c9ce59aee25 65 }
Davide Aliprandi 2:0c9ce59aee25 66 break;
Davide Aliprandi 2:0c9ce59aee25 67 case DMA_RX:
Davide Aliprandi 2:0c9ce59aee25 68 default:
Davide Aliprandi 2:0c9ce59aee25 69 if(obj->dma.dma[DMA_RX] != NULL) {
Davide Aliprandi 2:0c9ce59aee25 70 primary_handle = &DMaHandles[obj->i2s.module][DMA_RX];
Davide Aliprandi 2:0c9ce59aee25 71 }
Davide Aliprandi 2:0c9ce59aee25 72 if(obj->dma.dma[DMA_TX] != NULL) {
Davide Aliprandi 2:0c9ce59aee25 73 hdmatx = secondary_handle = &DMaHandles[obj->i2s.module][DMA_TX];
Davide Aliprandi 2:0c9ce59aee25 74 }
Davide Aliprandi 2:0c9ce59aee25 75 break;
Wolfgang Betz 1:f90318e0923b 76 }
Wolfgang Betz 1:f90318e0923b 77
Wolfgang Betz 1:f90318e0923b 78 if(primary_handle != NULL) {
Davide Aliprandi 2:0c9ce59aee25 79 __HAL_DMA_DISABLE(primary_handle);
Davide Aliprandi 2:0c9ce59aee25 80 HAL_DMA_Init(primary_handle);
Wolfgang Betz 1:f90318e0923b 81
Davide Aliprandi 2:0c9ce59aee25 82 if(hdmatx == primary_handle) {
Davide Aliprandi 2:0c9ce59aee25 83 __HAL_LINKDMA(&I2sHandle[obj->i2s.module], hdmatx, *primary_handle);
Davide Aliprandi 2:0c9ce59aee25 84 } else {
Davide Aliprandi 2:0c9ce59aee25 85 __HAL_LINKDMA(&I2sHandle[obj->i2s.module], hdmarx, *primary_handle);
Davide Aliprandi 2:0c9ce59aee25 86 }
Wolfgang Betz 1:f90318e0923b 87 }
Wolfgang Betz 1:f90318e0923b 88
Wolfgang Betz 1:f90318e0923b 89 if(secondary_handle != NULL) {
Davide Aliprandi 2:0c9ce59aee25 90 __HAL_DMA_DISABLE(secondary_handle);
Davide Aliprandi 2:0c9ce59aee25 91 HAL_DMA_Init(secondary_handle);
Wolfgang Betz 1:f90318e0923b 92
Davide Aliprandi 2:0c9ce59aee25 93 if(hdmatx == secondary_handle) {
Davide Aliprandi 2:0c9ce59aee25 94 __HAL_LINKDMA(&I2sHandle[obj->i2s.module], hdmatx, *secondary_handle);
Davide Aliprandi 2:0c9ce59aee25 95 } else {
Davide Aliprandi 2:0c9ce59aee25 96 __HAL_LINKDMA(&I2sHandle[obj->i2s.module], hdmarx, *secondary_handle);
Davide Aliprandi 2:0c9ce59aee25 97 }
Wolfgang Betz 1:f90318e0923b 98 }
Wolfgang Betz 1:f90318e0923b 99 }
Wolfgang Betz 1:f90318e0923b 100
Wolfgang Betz 1:f90318e0923b 101 static inline uint32_t i2s_get_mode(i2s_mode_t mode, uint8_t *direction) {
Wolfgang Betz 1:f90318e0923b 102 switch(mode) {
Davide Aliprandi 2:0c9ce59aee25 103 case SLAVE_TX:
Davide Aliprandi 2:0c9ce59aee25 104 *direction = DMA_TX;
Davide Aliprandi 2:0c9ce59aee25 105 return I2S_MODE_SLAVE_TX;
Davide Aliprandi 2:0c9ce59aee25 106 case SLAVE_RX:
Davide Aliprandi 2:0c9ce59aee25 107 *direction = DMA_RX;
Davide Aliprandi 2:0c9ce59aee25 108 return I2S_MODE_SLAVE_RX;
Davide Aliprandi 2:0c9ce59aee25 109 case MASTER_TX:
Davide Aliprandi 2:0c9ce59aee25 110 *direction = DMA_TX;
Davide Aliprandi 2:0c9ce59aee25 111 return I2S_MODE_MASTER_TX;
Davide Aliprandi 2:0c9ce59aee25 112 case MASTER_RX:
Davide Aliprandi 2:0c9ce59aee25 113 default:
Davide Aliprandi 2:0c9ce59aee25 114 *direction = DMA_RX;
Davide Aliprandi 2:0c9ce59aee25 115 return I2S_MODE_MASTER_RX;
Wolfgang Betz 1:f90318e0923b 116 }
Wolfgang Betz 1:f90318e0923b 117 }
Wolfgang Betz 1:f90318e0923b 118
Wolfgang Betz 1:f90318e0923b 119 static inline uint32_t i2s_get_priority(i2s_dma_prio_t priority) {
Wolfgang Betz 1:f90318e0923b 120 switch(priority) {
Davide Aliprandi 2:0c9ce59aee25 121 case LOW:
Davide Aliprandi 2:0c9ce59aee25 122 return DMA_PRIORITY_LOW;
Davide Aliprandi 2:0c9ce59aee25 123 case URGENT:
Davide Aliprandi 2:0c9ce59aee25 124 return DMA_PRIORITY_VERY_HIGH;
Davide Aliprandi 2:0c9ce59aee25 125 case HIGH:
Davide Aliprandi 2:0c9ce59aee25 126 return DMA_PRIORITY_HIGH;
Davide Aliprandi 2:0c9ce59aee25 127 default:
Davide Aliprandi 2:0c9ce59aee25 128 return DMA_PRIORITY_MEDIUM;
Wolfgang Betz 1:f90318e0923b 129 }
Wolfgang Betz 1:f90318e0923b 130 }
Wolfgang Betz 1:f90318e0923b 131
Wolfgang Betz 1:f90318e0923b 132 static void dma_i2s_init(i2s_t *obj, bool *use_tx, bool *use_rx, bool circular, i2s_dma_prio_t prio) {
Wolfgang Betz 1:f90318e0923b 133 // DMA declarations
Wolfgang Betz 1:f90318e0923b 134 DMA_HandleTypeDef *primary_handle = &DMaHandles[obj->i2s.module][obj->dma.dma_direction];
Wolfgang Betz 1:f90318e0923b 135 DMA_HandleTypeDef *secondary_handle = NULL;
Wolfgang Betz 1:f90318e0923b 136
Wolfgang Betz 1:f90318e0923b 137 // DMA initialization & configuration
Davide Aliprandi 2:0c9ce59aee25 138 stm_dma_init();
Wolfgang Betz 1:f90318e0923b 139 obj->dma.dma[DMA_TX] = obj->dma.dma[DMA_RX] = NULL;
Wolfgang Betz 1:f90318e0923b 140
Wolfgang Betz 1:f90318e0923b 141 switch(obj->dma.dma_direction) {
Davide Aliprandi 2:0c9ce59aee25 142 case DMA_TX:
Davide Aliprandi 2:0c9ce59aee25 143 if(*use_tx) {
Davide Aliprandi 2:0c9ce59aee25 144 obj->dma.dma[DMA_TX] = stm_dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_TX));
Davide Aliprandi 2:0c9ce59aee25 145 MBED_ASSERT(obj->dma.dma[DMA_TX] != DMA_ERROR_OUT_OF_CHANNELS);
Davide Aliprandi 2:0c9ce59aee25 146 }
Davide Aliprandi 2:0c9ce59aee25 147 break;
Davide Aliprandi 2:0c9ce59aee25 148 case DMA_RX:
Davide Aliprandi 2:0c9ce59aee25 149 default:
Davide Aliprandi 2:0c9ce59aee25 150 if(*use_rx) {
Davide Aliprandi 2:0c9ce59aee25 151 obj->dma.dma[DMA_RX] = stm_dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_RX));
Davide Aliprandi 2:0c9ce59aee25 152 MBED_ASSERT(obj->dma.dma[DMA_RX] != DMA_ERROR_OUT_OF_CHANNELS);
Davide Aliprandi 2:0c9ce59aee25 153 }
Davide Aliprandi 2:0c9ce59aee25 154 break;
Wolfgang Betz 1:f90318e0923b 155 }
Wolfgang Betz 1:f90318e0923b 156
Wolfgang Betz 1:f90318e0923b 157 // Primary DMA configuration
Wolfgang Betz 1:f90318e0923b 158 if(obj->dma.dma[obj->dma.dma_direction] != NULL) {
Davide Aliprandi 2:0c9ce59aee25 159 primary_handle->Instance = obj->dma.dma[obj->dma.dma_direction]->dma_stream;
Davide Aliprandi 2:0c9ce59aee25 160 primary_handle->Init.Channel = obj->dma.dma[obj->dma.dma_direction]->channel_nr;
Davide Aliprandi 2:0c9ce59aee25 161 primary_handle->Init.Direction = (obj->dma.dma_direction == DMA_TX) ?
Davide Aliprandi 2:0c9ce59aee25 162 DMA_MEMORY_TO_PERIPH : DMA_PERIPH_TO_MEMORY;
Davide Aliprandi 2:0c9ce59aee25 163 primary_handle->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
Davide Aliprandi 2:0c9ce59aee25 164 primary_handle->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
Davide Aliprandi 2:0c9ce59aee25 165 primary_handle->Init.MemBurst = DMA_MBURST_SINGLE;
Davide Aliprandi 2:0c9ce59aee25 166 primary_handle->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
Davide Aliprandi 2:0c9ce59aee25 167 primary_handle->Init.MemInc = DMA_MINC_ENABLE;
Davide Aliprandi 2:0c9ce59aee25 168 primary_handle->Init.Mode = (circular ? DMA_CIRCULAR : DMA_NORMAL);
Davide Aliprandi 2:0c9ce59aee25 169 primary_handle->Init.PeriphBurst = DMA_PBURST_SINGLE;
Davide Aliprandi 2:0c9ce59aee25 170 primary_handle->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
Davide Aliprandi 2:0c9ce59aee25 171 primary_handle->Init.PeriphInc = DMA_PINC_DISABLE;
Davide Aliprandi 2:0c9ce59aee25 172 primary_handle->Init.Priority = i2s_get_priority(prio);
Wolfgang Betz 1:f90318e0923b 173 }
Wolfgang Betz 1:f90318e0923b 174
Wolfgang Betz 1:f90318e0923b 175 // Allocate secondary DMA channel (if full-duplex)
Wolfgang Betz 1:f90318e0923b 176 if(obj->i2s.pin_fdpx != NC) {
Davide Aliprandi 2:0c9ce59aee25 177 switch(obj->dma.dma_direction) {
Davide Aliprandi 2:0c9ce59aee25 178 case DMA_TX:
Davide Aliprandi 2:0c9ce59aee25 179 if(*use_rx) {
Davide Aliprandi 2:0c9ce59aee25 180 obj->dma.dma[DMA_RX] = stm_dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_RX));
Davide Aliprandi 2:0c9ce59aee25 181 secondary_handle = &DMaHandles[obj->i2s.module][DMA_RX];
Davide Aliprandi 2:0c9ce59aee25 182 MBED_ASSERT(obj->dma.dma[DMA_RX] != DMA_ERROR_OUT_OF_CHANNELS);
Davide Aliprandi 2:0c9ce59aee25 183 }
Davide Aliprandi 2:0c9ce59aee25 184 break;
Davide Aliprandi 2:0c9ce59aee25 185 case DMA_RX:
Davide Aliprandi 2:0c9ce59aee25 186 default:
Davide Aliprandi 2:0c9ce59aee25 187 if(*use_tx) {
Davide Aliprandi 2:0c9ce59aee25 188 obj->dma.dma[DMA_TX] = stm_dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_TX));
Davide Aliprandi 2:0c9ce59aee25 189 secondary_handle = &DMaHandles[obj->i2s.module][DMA_TX];
Davide Aliprandi 2:0c9ce59aee25 190 MBED_ASSERT(obj->dma.dma[DMA_TX] != DMA_ERROR_OUT_OF_CHANNELS);
Davide Aliprandi 2:0c9ce59aee25 191 }
Davide Aliprandi 2:0c9ce59aee25 192 break;
Davide Aliprandi 2:0c9ce59aee25 193 }
Wolfgang Betz 1:f90318e0923b 194 }
Wolfgang Betz 1:f90318e0923b 195
Wolfgang Betz 1:f90318e0923b 196 // Secondary DMA configuration
Wolfgang Betz 1:f90318e0923b 197 if(secondary_handle != NULL) {
Davide Aliprandi 2:0c9ce59aee25 198 uint8_t secondary_dma_direction = (obj->dma.dma_direction == DMA_TX) ? DMA_RX : DMA_TX;
Wolfgang Betz 1:f90318e0923b 199
Davide Aliprandi 2:0c9ce59aee25 200 secondary_handle->Instance = obj->dma.dma[secondary_dma_direction]->dma_stream;
Davide Aliprandi 2:0c9ce59aee25 201 secondary_handle->Init.Channel = obj->dma.dma[secondary_dma_direction]->channel_nr_fd;
Davide Aliprandi 2:0c9ce59aee25 202 secondary_handle->Init.Direction = (secondary_dma_direction == DMA_TX) ?
Davide Aliprandi 2:0c9ce59aee25 203 DMA_MEMORY_TO_PERIPH : DMA_PERIPH_TO_MEMORY;
Davide Aliprandi 2:0c9ce59aee25 204 secondary_handle->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
Davide Aliprandi 2:0c9ce59aee25 205 secondary_handle->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
Davide Aliprandi 2:0c9ce59aee25 206 secondary_handle->Init.MemBurst = DMA_MBURST_SINGLE;
Davide Aliprandi 2:0c9ce59aee25 207 secondary_handle->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
Davide Aliprandi 2:0c9ce59aee25 208 secondary_handle->Init.MemInc = DMA_MINC_ENABLE;
Davide Aliprandi 2:0c9ce59aee25 209 secondary_handle->Init.Mode = (circular ? DMA_CIRCULAR : DMA_NORMAL);
Davide Aliprandi 2:0c9ce59aee25 210 secondary_handle->Init.PeriphBurst = DMA_PBURST_SINGLE;
Davide Aliprandi 2:0c9ce59aee25 211 secondary_handle->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
Davide Aliprandi 2:0c9ce59aee25 212 secondary_handle->Init.PeriphInc = DMA_PINC_DISABLE;
Davide Aliprandi 2:0c9ce59aee25 213 secondary_handle->Init.Priority = i2s_get_priority(prio);
Wolfgang Betz 1:f90318e0923b 214 }
Wolfgang Betz 1:f90318e0923b 215
Wolfgang Betz 1:f90318e0923b 216 if(obj->dma.dma[DMA_TX] == NULL) *use_tx = false;
Wolfgang Betz 1:f90318e0923b 217 if(obj->dma.dma[DMA_RX] == NULL) *use_rx = false;
Wolfgang Betz 1:f90318e0923b 218
Wolfgang Betz 1:f90318e0923b 219 // don't do anything, if the buffers aren't valid
Wolfgang Betz 1:f90318e0923b 220 if (!use_tx && !use_rx) {
Davide Aliprandi 2:0c9ce59aee25 221 DEBUG_PRINTF(" I2S%u: No DMAs to init\r\n", obj->i2s.module + 1);
Davide Aliprandi 2:0c9ce59aee25 222 return;
Wolfgang Betz 1:f90318e0923b 223 }
Wolfgang Betz 1:f90318e0923b 224
Davide Aliprandi 2:0c9ce59aee25 225 DEBUG_PRINTF(" I2S%u: DMA(s) Init\r\n", obj->i2s.module + 1);
Davide Aliprandi 2:0c9ce59aee25 226
Wolfgang Betz 1:f90318e0923b 227 init_dmas(obj);
Wolfgang Betz 1:f90318e0923b 228 }
Wolfgang Betz 1:f90318e0923b 229
Wolfgang Betz 1:f90318e0923b 230 static void dma_i2s_free(i2s_t *obj, uint8_t direction) {
Wolfgang Betz 1:f90318e0923b 231 const struct dma_stream_s *stream = obj->dma.dma[direction];
Wolfgang Betz 1:f90318e0923b 232
Wolfgang Betz 1:f90318e0923b 233 MBED_ASSERT(stream != NULL);
Wolfgang Betz 1:f90318e0923b 234
Wolfgang Betz 1:f90318e0923b 235 // disable irq
Wolfgang Betz 1:f90318e0923b 236 NVIC_DisableIRQ(stream->dma_stream_irq);
Wolfgang Betz 1:f90318e0923b 237
Wolfgang Betz 1:f90318e0923b 238 // free channel
Davide Aliprandi 2:0c9ce59aee25 239 stm_dma_channel_free((void*)stream);
Wolfgang Betz 1:f90318e0923b 240 obj->dma.dma[direction] = NULL;
Wolfgang Betz 1:f90318e0923b 241 }
Wolfgang Betz 1:f90318e0923b 242
Davide Aliprandi 2:0c9ce59aee25 243 void i2s_init(i2s_t *obj, PinName data, PinName sclk, PinName wsel, PinName fdpx, PinName mclk, i2s_mode_t mode) {
Wolfgang Betz 1:f90318e0923b 244 uint8_t dma_dev = 0, dma_direction = 0;
Wolfgang Betz 1:f90318e0923b 245
Wolfgang Betz 1:f90318e0923b 246 // Determine the I2S/SPI to use
Wolfgang Betz 1:f90318e0923b 247 SPIName i2s_data = (SPIName)pinmap_peripheral(data, PinMap_I2S_DATA);
Wolfgang Betz 1:f90318e0923b 248 SPIName i2s_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_I2S_SCLK);
Wolfgang Betz 1:f90318e0923b 249
Wolfgang Betz 1:f90318e0923b 250 SPIName i2s_wsel = (SPIName)pinmap_peripheral(wsel, PinMap_I2S_WSEL);
Wolfgang Betz 1:f90318e0923b 251 SPIName i2s_fdpx = (SPIName)pinmap_peripheral(fdpx, PinMap_I2S_FDPX);
Wolfgang Betz 1:f90318e0923b 252
Wolfgang Betz 1:f90318e0923b 253 SPIName i2s_mclk = (SPIName)pinmap_peripheral(mclk, PinMap_I2S_MCLK);
Wolfgang Betz 1:f90318e0923b 254
Wolfgang Betz 1:f90318e0923b 255 SPIName i2s_merge1 = (SPIName)pinmap_merge(i2s_data, i2s_sclk);
Wolfgang Betz 1:f90318e0923b 256 SPIName i2s_merge2 = (SPIName)pinmap_merge(i2s_wsel, i2s_fdpx);
Wolfgang Betz 1:f90318e0923b 257
Wolfgang Betz 1:f90318e0923b 258 SPIName i2s_merge3 = (SPIName)pinmap_merge(i2s_merge1, i2s_merge2);
Wolfgang Betz 1:f90318e0923b 259 SPIName instance = (SPIName)pinmap_merge(i2s_merge3, i2s_mclk);
Wolfgang Betz 1:f90318e0923b 260 MBED_ASSERT(instance != (SPIName)NC);
Wolfgang Betz 1:f90318e0923b 261
Wolfgang Betz 1:f90318e0923b 262 // Enable I2S/SPI clock and set the right module number
Wolfgang Betz 1:f90318e0923b 263 switch(instance) {
Wolfgang Betz 1:f90318e0923b 264 #if defined(I2S1ext_BASE)
Wolfgang Betz 1:f90318e0923b 265 case SPI_1:
Wolfgang Betz 1:f90318e0923b 266 __SPI1_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 267 obj->i2s.module = 0;
Wolfgang Betz 1:f90318e0923b 268 dma_dev = DMA_SPI1;
Wolfgang Betz 1:f90318e0923b 269 break;
Wolfgang Betz 1:f90318e0923b 270 #endif
Wolfgang Betz 1:f90318e0923b 271 #if defined(I2S2ext_BASE)
Wolfgang Betz 1:f90318e0923b 272 case SPI_2:
Wolfgang Betz 1:f90318e0923b 273 __SPI2_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 274 obj->i2s.module = 1;
Wolfgang Betz 1:f90318e0923b 275 dma_dev = DMA_SPI2;
Wolfgang Betz 1:f90318e0923b 276 break;
Wolfgang Betz 1:f90318e0923b 277 #endif
Wolfgang Betz 1:f90318e0923b 278 #if defined(I2S3ext_BASE)
Wolfgang Betz 1:f90318e0923b 279 case SPI_3:
Wolfgang Betz 1:f90318e0923b 280 __SPI3_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 281 obj->i2s.module = 2;
Wolfgang Betz 1:f90318e0923b 282 dma_dev = DMA_SPI3;
Wolfgang Betz 1:f90318e0923b 283 break;
Wolfgang Betz 1:f90318e0923b 284 #endif
Wolfgang Betz 1:f90318e0923b 285 #if defined(I2S4ext_BASE)
Wolfgang Betz 1:f90318e0923b 286 case SPI_4:
Wolfgang Betz 1:f90318e0923b 287 __SPI4_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 288 obj->i2s.module = 3;
Wolfgang Betz 1:f90318e0923b 289 dma_dev = DMA_SPI4;
Wolfgang Betz 1:f90318e0923b 290 break;
Wolfgang Betz 1:f90318e0923b 291 #endif
Wolfgang Betz 1:f90318e0923b 292 #if defined(I2S5ext_BASE)
Wolfgang Betz 1:f90318e0923b 293 case SPI_5:
Wolfgang Betz 1:f90318e0923b 294 __SPI5_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 295 obj->i2s.module = 4;
Wolfgang Betz 1:f90318e0923b 296 dma_dev = DMA_SPI5;
Wolfgang Betz 1:f90318e0923b 297 break;
Wolfgang Betz 1:f90318e0923b 298 #endif
Wolfgang Betz 1:f90318e0923b 299 default:
Wolfgang Betz 1:f90318e0923b 300 MBED_ASSERT(0);
Wolfgang Betz 1:f90318e0923b 301 break;
Wolfgang Betz 1:f90318e0923b 302 }
Wolfgang Betz 1:f90318e0923b 303
Wolfgang Betz 1:f90318e0923b 304 // Save DMA device
Wolfgang Betz 1:f90318e0923b 305 obj->dma.dma_device = dma_dev;
Wolfgang Betz 1:f90318e0923b 306
Wolfgang Betz 1:f90318e0923b 307 // Configure the I2S pins
Wolfgang Betz 1:f90318e0923b 308 pinmap_pinout(data, PinMap_I2S_DATA);
Wolfgang Betz 1:f90318e0923b 309 pinmap_pinout(wsel, PinMap_I2S_WSEL);
Wolfgang Betz 1:f90318e0923b 310 pinmap_pinout(sclk, PinMap_I2S_SCLK);
Wolfgang Betz 1:f90318e0923b 311 pinmap_pinout(fdpx, PinMap_I2S_FDPX);
Wolfgang Betz 1:f90318e0923b 312 pinmap_pinout(mclk, PinMap_I2S_MCLK);
Wolfgang Betz 1:f90318e0923b 313
Wolfgang Betz 1:f90318e0923b 314 obj->i2s.pin_wsel = wsel;
Wolfgang Betz 1:f90318e0923b 315 obj->i2s.pin_data = data;
Wolfgang Betz 1:f90318e0923b 316 obj->i2s.pin_sclk = sclk;
Wolfgang Betz 1:f90318e0923b 317 obj->i2s.pin_fdpx = fdpx;
Wolfgang Betz 1:f90318e0923b 318 obj->i2s.pin_mclk = mclk;
Wolfgang Betz 1:f90318e0923b 319
Davide Aliprandi 2:0c9ce59aee25 320 /* Configure PLLI2S */
Wolfgang Betz 1:f90318e0923b 321 static bool first_time = true;
Davide Aliprandi 2:0c9ce59aee25 322 if (first_time)
Davide Aliprandi 2:0c9ce59aee25 323 {
Davide Aliprandi 2:0c9ce59aee25 324 RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
Wolfgang Betz 1:f90318e0923b 325
Davide Aliprandi 2:0c9ce59aee25 326 /* Get RTCClockSelection */
Davide Aliprandi 2:0c9ce59aee25 327 HAL_RCCEx_GetPeriphCLKConfig(&PeriphClkInitStruct);
Wolfgang Betz 1:f90318e0923b 328
Davide Aliprandi 2:0c9ce59aee25 329 /* Set default configuration. Default frequency is 44100Hz. */
Davide Aliprandi 2:0c9ce59aee25 330 PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;
Davide Aliprandi 2:0c9ce59aee25 331 PeriphClkInitStruct.PLLI2S.PLLI2SN = 271; // betzw: use values which are suggested in Table 91 of the
Davide Aliprandi 2:0c9ce59aee25 332 PeriphClkInitStruct.PLLI2S.PLLI2SR = 2; // reference manual for master clock enabled & 44100Hz.
Davide Aliprandi 2:0c9ce59aee25 333
Wolfgang Betz 1:f90318e0923b 334 #ifdef NDEBUG
Davide Aliprandi 2:0c9ce59aee25 335 HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
Wolfgang Betz 1:f90318e0923b 336 #else
Davide Aliprandi 2:0c9ce59aee25 337 HAL_StatusTypeDef ret = HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
Wolfgang Betz 1:f90318e0923b 338 #endif
Davide Aliprandi 2:0c9ce59aee25 339 MBED_ASSERT(ret == HAL_OK);
Davide Aliprandi 2:0c9ce59aee25 340
Davide Aliprandi 2:0c9ce59aee25 341 first_time = false;
Wolfgang Betz 1:f90318e0923b 342 }
Wolfgang Betz 1:f90318e0923b 343
Davide Aliprandi 2:0c9ce59aee25 344 /* Initializing the handle for this master. */
Wolfgang Betz 1:f90318e0923b 345 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 346
Wolfgang Betz 1:f90318e0923b 347 handle->Instance = (SPI_TypeDef *)(instance);
Wolfgang Betz 1:f90318e0923b 348 handle->Init.Mode = i2s_get_mode(mode, &dma_direction);
Wolfgang Betz 1:f90318e0923b 349 handle->Init.Standard = I2S_STANDARD_PCM_SHORT;
Wolfgang Betz 1:f90318e0923b 350 handle->Init.DataFormat = I2S_DATAFORMAT_16B;
Wolfgang Betz 1:f90318e0923b 351 handle->Init.CPOL = I2S_CPOL_LOW;
Davide Aliprandi 2:0c9ce59aee25 352 handle->Init.AudioFreq = I2S_AUDIOFREQ_44K; //Default frequency is 44100Hz.
Wolfgang Betz 1:f90318e0923b 353 handle->Init.ClockSource = I2S_CLOCK_PLL;
Davide Aliprandi 2:0c9ce59aee25 354 handle->Init.FullDuplexMode = (fdpx == NC ? I2S_FULLDUPLEXMODE_DISABLE : I2S_FULLDUPLEXMODE_ENABLE);
Davide Aliprandi 2:0c9ce59aee25 355 handle->Init.MCLKOutput = (mclk == NC ? I2S_MCLKOUTPUT_DISABLE : I2S_MCLKOUTPUT_ENABLE); //Davide: Microphones need master clock disabled, while sound terminal needs it enabled.
Davide Aliprandi 2:0c9ce59aee25 356
Davide Aliprandi 2:0c9ce59aee25 357 DEBUG_PRINTF("--> %s\r\n", __FUNCTION__);
Davide Aliprandi 2:0c9ce59aee25 358 DEBUG_PRINTF(" I2S%u: Mode: %u (%u)\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 359 (unsigned int)handle->Init.Mode, (unsigned int)mode);
Davide Aliprandi 2:0c9ce59aee25 360 DEBUG_PRINTF(" I2S%u: Standard: %u\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 361 (unsigned int)handle->Init.Standard);
Davide Aliprandi 2:0c9ce59aee25 362 DEBUG_PRINTF(" I2S%u: DataFormat: %u\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 363 (unsigned int)handle->Init.DataFormat);
Davide Aliprandi 2:0c9ce59aee25 364 DEBUG_PRINTF(" I2S%u: CPOL: %u\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 365 (unsigned int)handle->Init.CPOL);
Davide Aliprandi 2:0c9ce59aee25 366 DEBUG_PRINTF(" I2S%u: AudioFreq: %u\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 367 (unsigned int)handle->Init.AudioFreq);
Davide Aliprandi 2:0c9ce59aee25 368 DEBUG_PRINTF(" I2S%u: ClockSource: %u\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 369 (unsigned int)handle->Init.ClockSource);
Davide Aliprandi 2:0c9ce59aee25 370 DEBUG_PRINTF(" I2S%u: FullDuplexMode: %u\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 371 (unsigned int)handle->Init.FullDuplexMode);
Davide Aliprandi 2:0c9ce59aee25 372 DEBUG_PRINTF(" I2S%u: MCLKOutput: %u\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 373 (unsigned int)handle->Init.MCLKOutput);
Wolfgang Betz 1:f90318e0923b 374
Wolfgang Betz 1:f90318e0923b 375 // Save primary DMA direction
Wolfgang Betz 1:f90318e0923b 376 obj->dma.dma_direction = dma_direction;
Wolfgang Betz 1:f90318e0923b 377
Wolfgang Betz 1:f90318e0923b 378 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 379 }
Wolfgang Betz 1:f90318e0923b 380
Davide Aliprandi 2:0c9ce59aee25 381 void i2s_free(i2s_t *obj) {
Wolfgang Betz 1:f90318e0923b 382 // Reset I2S and disable clock
Wolfgang Betz 1:f90318e0923b 383 switch(obj->i2s.module) {
Wolfgang Betz 1:f90318e0923b 384 #if defined(I2S1ext_BASE)
Davide Aliprandi 2:0c9ce59aee25 385 case 0:
Davide Aliprandi 2:0c9ce59aee25 386 __SPI1_FORCE_RESET();
Davide Aliprandi 2:0c9ce59aee25 387 __SPI1_RELEASE_RESET();
Davide Aliprandi 2:0c9ce59aee25 388 __SPI1_CLK_DISABLE();
Davide Aliprandi 2:0c9ce59aee25 389 break;
Wolfgang Betz 1:f90318e0923b 390 #endif
Wolfgang Betz 1:f90318e0923b 391 #if defined(I2S2ext_BASE)
Davide Aliprandi 2:0c9ce59aee25 392 case 1:
Davide Aliprandi 2:0c9ce59aee25 393 __SPI2_FORCE_RESET();
Davide Aliprandi 2:0c9ce59aee25 394 __SPI2_RELEASE_RESET();
Davide Aliprandi 2:0c9ce59aee25 395 __SPI2_CLK_DISABLE();
Davide Aliprandi 2:0c9ce59aee25 396 break;
Wolfgang Betz 1:f90318e0923b 397 #endif
Wolfgang Betz 1:f90318e0923b 398 #if defined(I2S3ext_BASE)
Davide Aliprandi 2:0c9ce59aee25 399 case 2:
Davide Aliprandi 2:0c9ce59aee25 400 __SPI3_FORCE_RESET();
Davide Aliprandi 2:0c9ce59aee25 401 __SPI3_RELEASE_RESET();
Davide Aliprandi 2:0c9ce59aee25 402 __SPI3_CLK_DISABLE();
Davide Aliprandi 2:0c9ce59aee25 403 break;
Wolfgang Betz 1:f90318e0923b 404 #endif
Wolfgang Betz 1:f90318e0923b 405 #if defined(I2S4ext_BASE)
Davide Aliprandi 2:0c9ce59aee25 406 case 3:
Davide Aliprandi 2:0c9ce59aee25 407 __SPI4_FORCE_RESET();
Davide Aliprandi 2:0c9ce59aee25 408 __SPI4_RELEASE_RESET();
Davide Aliprandi 2:0c9ce59aee25 409 __SPI4_CLK_DISABLE();
Davide Aliprandi 2:0c9ce59aee25 410 break;
Wolfgang Betz 1:f90318e0923b 411 #endif
Wolfgang Betz 1:f90318e0923b 412 #if defined(I2S5ext_BASE)
Davide Aliprandi 2:0c9ce59aee25 413 case 4:
Davide Aliprandi 2:0c9ce59aee25 414 __SPI5_FORCE_RESET();
Davide Aliprandi 2:0c9ce59aee25 415 __SPI5_RELEASE_RESET();
Davide Aliprandi 2:0c9ce59aee25 416 __SPI5_CLK_DISABLE();
Davide Aliprandi 2:0c9ce59aee25 417 break;
Wolfgang Betz 1:f90318e0923b 418 #endif
Davide Aliprandi 2:0c9ce59aee25 419 default:
Davide Aliprandi 2:0c9ce59aee25 420 MBED_ASSERT(0);
Davide Aliprandi 2:0c9ce59aee25 421 break;
Wolfgang Betz 1:f90318e0923b 422 }
Wolfgang Betz 1:f90318e0923b 423
Wolfgang Betz 1:f90318e0923b 424 // betzw - TODO: what about 'PLLI2S'?!?
Wolfgang Betz 1:f90318e0923b 425 // for the moment we leave it enabled!
Wolfgang Betz 1:f90318e0923b 426
Wolfgang Betz 1:f90318e0923b 427 // Configure GPIOs
Wolfgang Betz 1:f90318e0923b 428 pin_function(obj->i2s.pin_wsel, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 429 pin_function(obj->i2s.pin_data, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 430 pin_function(obj->i2s.pin_sclk, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 431 pin_function(obj->i2s.pin_fdpx, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 432 pin_function(obj->i2s.pin_mclk, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 433
Davide Aliprandi 2:0c9ce59aee25 434 DEBUG_PRINTF("--> %s\r\n", __FUNCTION__);
Wolfgang Betz 1:f90318e0923b 435 }
Wolfgang Betz 1:f90318e0923b 436
Davide Aliprandi 2:0c9ce59aee25 437 void i2s_format(i2s_t *obj, int dbits, int fbits, int polarity) {
Wolfgang Betz 1:f90318e0923b 438 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 439
Wolfgang Betz 1:f90318e0923b 440 // Save new values
Davide Aliprandi 2:0c9ce59aee25 441 if (fbits == 16)
Davide Aliprandi 2:0c9ce59aee25 442 { // format MUST be 16B
Davide Aliprandi 2:0c9ce59aee25 443 handle->Init.DataFormat = I2S_DATAFORMAT_16B;
Wolfgang Betz 1:f90318e0923b 444 } else { // format may NOT be 16B
Davide Aliprandi 2:0c9ce59aee25 445 switch (dbits)
Davide Aliprandi 2:0c9ce59aee25 446 {
Davide Aliprandi 2:0c9ce59aee25 447 case 16:
Davide Aliprandi 2:0c9ce59aee25 448 handle->Init.DataFormat = I2S_DATAFORMAT_16B_EXTENDED;
Davide Aliprandi 2:0c9ce59aee25 449 break;
Davide Aliprandi 2:0c9ce59aee25 450 case 24:
Davide Aliprandi 2:0c9ce59aee25 451 handle->Init.DataFormat = I2S_DATAFORMAT_24B;
Davide Aliprandi 2:0c9ce59aee25 452 break;
Davide Aliprandi 2:0c9ce59aee25 453 case 32:
Davide Aliprandi 2:0c9ce59aee25 454 default:
Davide Aliprandi 2:0c9ce59aee25 455 handle->Init.DataFormat = I2S_DATAFORMAT_32B;
Davide Aliprandi 2:0c9ce59aee25 456 break;
Davide Aliprandi 2:0c9ce59aee25 457 }
Wolfgang Betz 1:f90318e0923b 458 }
Wolfgang Betz 1:f90318e0923b 459
Wolfgang Betz 1:f90318e0923b 460 handle->Init.CPOL = (polarity == 0) ? I2S_CPOL_LOW : I2S_CPOL_HIGH;
Wolfgang Betz 1:f90318e0923b 461
Davide Aliprandi 2:0c9ce59aee25 462 DEBUG_PRINTF("--> %s\r\n", __FUNCTION__);
Davide Aliprandi 2:0c9ce59aee25 463 DEBUG_PRINTF(" I2S%u: DataFormat: %u\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 464 (unsigned int)handle->Init.DataFormat);
Davide Aliprandi 2:0c9ce59aee25 465 DEBUG_PRINTF(" I2S%u: CPOL: %u\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 466 (unsigned int)handle->Init.CPOL);
Davide Aliprandi 2:0c9ce59aee25 467 DEBUG_PRINTF(" I2S%u: (dbits, fbits): (%u, %u)\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 468 (unsigned int)dbits, (unsigned int)fbits);
Davide Aliprandi 2:0c9ce59aee25 469 DEBUG_PRINTF(" I2S%u: Polarity: %u\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 470 (unsigned int)polarity);
Wolfgang Betz 1:f90318e0923b 471
Wolfgang Betz 1:f90318e0923b 472 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 473 }
Wolfgang Betz 1:f90318e0923b 474
Davide Aliprandi 2:0c9ce59aee25 475 void i2s_set_mode(i2s_t *obj, i2s_mode_t mode) {
Wolfgang Betz 1:f90318e0923b 476 uint8_t dma_direction;
Wolfgang Betz 1:f90318e0923b 477 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 478
Wolfgang Betz 1:f90318e0923b 479 handle->Init.Mode = i2s_get_mode(mode, &dma_direction);
Wolfgang Betz 1:f90318e0923b 480
Wolfgang Betz 1:f90318e0923b 481 // Save primary DMA direction
Wolfgang Betz 1:f90318e0923b 482 obj->dma.dma_direction = dma_direction;
Wolfgang Betz 1:f90318e0923b 483
Davide Aliprandi 2:0c9ce59aee25 484 DEBUG_PRINTF("--> %s\r\n", __FUNCTION__);
Davide Aliprandi 2:0c9ce59aee25 485 DEBUG_PRINTF(" I2S%u: Mode: %u (%u)\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 486 (unsigned int)handle->Init.Mode, (unsigned int)mode);
Davide Aliprandi 2:0c9ce59aee25 487
Davide Aliprandi 2:0c9ce59aee25 488 init_i2s(obj);
Davide Aliprandi 2:0c9ce59aee25 489 }
Davide Aliprandi 2:0c9ce59aee25 490
Davide Aliprandi 2:0c9ce59aee25 491 void i2s_set_protocol(i2s_t *obj, i2s_bitorder_t protocol) {
Davide Aliprandi 2:0c9ce59aee25 492 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Davide Aliprandi 2:0c9ce59aee25 493
Davide Aliprandi 2:0c9ce59aee25 494 switch (protocol)
Davide Aliprandi 2:0c9ce59aee25 495 {
Davide Aliprandi 2:0c9ce59aee25 496 case PHILIPS:
Davide Aliprandi 2:0c9ce59aee25 497 handle->Init.Standard = I2S_STANDARD_PHILIPS;
Davide Aliprandi 2:0c9ce59aee25 498 break;
Davide Aliprandi 2:0c9ce59aee25 499 case MSB:
Davide Aliprandi 2:0c9ce59aee25 500 handle->Init.Standard = I2S_STANDARD_MSB;
Davide Aliprandi 2:0c9ce59aee25 501 break;
Davide Aliprandi 2:0c9ce59aee25 502 case LSB:
Davide Aliprandi 2:0c9ce59aee25 503 handle->Init.Standard = I2S_STANDARD_LSB;
Davide Aliprandi 2:0c9ce59aee25 504 break;
Davide Aliprandi 2:0c9ce59aee25 505 case PCM_SHORT:
Davide Aliprandi 2:0c9ce59aee25 506 handle->Init.Standard = I2S_STANDARD_PCM_SHORT;
Davide Aliprandi 2:0c9ce59aee25 507 break;
Davide Aliprandi 2:0c9ce59aee25 508 case PCM_LONG:
Davide Aliprandi 2:0c9ce59aee25 509 default:
Davide Aliprandi 2:0c9ce59aee25 510 handle->Init.Standard = I2S_STANDARD_PCM_LONG;
Davide Aliprandi 2:0c9ce59aee25 511 break;
Davide Aliprandi 2:0c9ce59aee25 512 }
Davide Aliprandi 2:0c9ce59aee25 513
Davide Aliprandi 2:0c9ce59aee25 514 DEBUG_PRINTF("--> %s\r\n", __FUNCTION__);
Davide Aliprandi 2:0c9ce59aee25 515 DEBUG_PRINTF(" I2S%u: Standard: %u\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 516 (unsigned int)handle->Init.Standard);
Wolfgang Betz 1:f90318e0923b 517
Wolfgang Betz 1:f90318e0923b 518 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 519 }
Wolfgang Betz 1:f90318e0923b 520
Davide Aliprandi 2:0c9ce59aee25 521 void i2s_audio_frequency(i2s_t *obj, uint32_t hz) {
Wolfgang Betz 1:f90318e0923b 522 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 523
Davide Aliprandi 2:0c9ce59aee25 524 if (IS_I2S_AUDIO_FREQ(hz) && (hz != I2S_AUDIOFREQ_DEFAULT)) {
Davide Aliprandi 2:0c9ce59aee25 525 handle->Init.AudioFreq = hz;
Davide Aliprandi 2:0c9ce59aee25 526 }
Davide Aliprandi 2:0c9ce59aee25 527 else if (hz < I2S_AUDIOFREQ_8K) {
Davide Aliprandi 2:0c9ce59aee25 528 handle->Init.AudioFreq = I2S_AUDIOFREQ_8K;
Davide Aliprandi 2:0c9ce59aee25 529 }
Davide Aliprandi 2:0c9ce59aee25 530 else {
Davide Aliprandi 2:0c9ce59aee25 531 handle->Init.AudioFreq = I2S_AUDIOFREQ_192K;
Wolfgang Betz 1:f90318e0923b 532 }
Wolfgang Betz 1:f90318e0923b 533
Davide Aliprandi 2:0c9ce59aee25 534 /* Configuring PLLI2S. */
Davide Aliprandi 2:0c9ce59aee25 535 RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
Davide Aliprandi 2:0c9ce59aee25 536
Davide Aliprandi 2:0c9ce59aee25 537 /* Getting RTCClockSelection. */
Davide Aliprandi 2:0c9ce59aee25 538 HAL_RCCEx_GetPeriphCLKConfig(&PeriphClkInitStruct);
Davide Aliprandi 2:0c9ce59aee25 539
Davide Aliprandi 2:0c9ce59aee25 540 /* Setting configuration. */
Davide Aliprandi 2:0c9ce59aee25 541 PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;
Davide Aliprandi 2:0c9ce59aee25 542
Davide Aliprandi 2:0c9ce59aee25 543 // Davide: All the following values are taken from Table 91 of the
Davide Aliprandi 2:0c9ce59aee25 544 // reference manual for master clock enabled.
Davide Aliprandi 2:0c9ce59aee25 545 switch (hz) {
Davide Aliprandi 2:0c9ce59aee25 546 case I2S_AUDIOFREQ_8K:
Davide Aliprandi 2:0c9ce59aee25 547 PeriphClkInitStruct.PLLI2S.PLLI2SN = 256;
Davide Aliprandi 2:0c9ce59aee25 548 PeriphClkInitStruct.PLLI2S.PLLI2SR = 5;
Davide Aliprandi 2:0c9ce59aee25 549 break;
Davide Aliprandi 2:0c9ce59aee25 550
Davide Aliprandi 2:0c9ce59aee25 551 case I2S_AUDIOFREQ_16K:
Davide Aliprandi 2:0c9ce59aee25 552 case I2S_AUDIOFREQ_32K:
Davide Aliprandi 2:0c9ce59aee25 553 case (I2S_AUDIOFREQ_32K << 1):
Davide Aliprandi 2:0c9ce59aee25 554 PeriphClkInitStruct.PLLI2S.PLLI2SN = 213;
Davide Aliprandi 2:0c9ce59aee25 555 PeriphClkInitStruct.PLLI2S.PLLI2SR = 2;
Davide Aliprandi 2:0c9ce59aee25 556 break;
Davide Aliprandi 2:0c9ce59aee25 557
Davide Aliprandi 2:0c9ce59aee25 558 case I2S_AUDIOFREQ_48K:
Davide Aliprandi 2:0c9ce59aee25 559 PeriphClkInitStruct.PLLI2S.PLLI2SN = 258;
Davide Aliprandi 2:0c9ce59aee25 560 PeriphClkInitStruct.PLLI2S.PLLI2SR = 3;
Davide Aliprandi 2:0c9ce59aee25 561 break;
Davide Aliprandi 2:0c9ce59aee25 562
Davide Aliprandi 2:0c9ce59aee25 563 case I2S_AUDIOFREQ_96K:
Davide Aliprandi 2:0c9ce59aee25 564 PeriphClkInitStruct.PLLI2S.PLLI2SN = 344;
Davide Aliprandi 2:0c9ce59aee25 565 PeriphClkInitStruct.PLLI2S.PLLI2SR = 2;
Davide Aliprandi 2:0c9ce59aee25 566 break;
Davide Aliprandi 2:0c9ce59aee25 567
Davide Aliprandi 2:0c9ce59aee25 568 case I2S_AUDIOFREQ_44K:
Davide Aliprandi 2:0c9ce59aee25 569 default:
Davide Aliprandi 2:0c9ce59aee25 570 PeriphClkInitStruct.PLLI2S.PLLI2SN = 271;
Davide Aliprandi 2:0c9ce59aee25 571 PeriphClkInitStruct.PLLI2S.PLLI2SR = 2;
Davide Aliprandi 2:0c9ce59aee25 572 break;
Davide Aliprandi 2:0c9ce59aee25 573 }
Davide Aliprandi 2:0c9ce59aee25 574 #ifdef NDEBUG
Davide Aliprandi 2:0c9ce59aee25 575 HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
Davide Aliprandi 2:0c9ce59aee25 576 #else
Davide Aliprandi 2:0c9ce59aee25 577 HAL_StatusTypeDef ret = HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
Davide Aliprandi 2:0c9ce59aee25 578 #endif
Davide Aliprandi 2:0c9ce59aee25 579 MBED_ASSERT(ret == HAL_OK);
Davide Aliprandi 2:0c9ce59aee25 580
Davide Aliprandi 2:0c9ce59aee25 581 DEBUG_PRINTF("--> %s\r\n", __FUNCTION__);
Davide Aliprandi 2:0c9ce59aee25 582 DEBUG_PRINTF(" I2S%u: AudioFreq: %u\r\n", obj->i2s.module + 1,
Davide Aliprandi 2:0c9ce59aee25 583 (unsigned int)handle->Init.AudioFreq);
Wolfgang Betz 1:f90318e0923b 584
Wolfgang Betz 1:f90318e0923b 585 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 586 }
Wolfgang Betz 1:f90318e0923b 587
Davide Aliprandi 2:0c9ce59aee25 588 uint8_t i2s_get_module(i2s_t *obj) {
Wolfgang Betz 1:f90318e0923b 589 return obj->i2s.module;
Wolfgang Betz 1:f90318e0923b 590 }
Wolfgang Betz 1:f90318e0923b 591
Davide Aliprandi 2:0c9ce59aee25 592 static void i2s_start_asynch_transfer(i2s_t *obj, transfer_type_t transfer_type, void *tx, void *rx, int length) {
Wolfgang Betz 1:f90318e0923b 593 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 594 obj->i2s.transfer_type = transfer_type;
Wolfgang Betz 1:f90318e0923b 595
Wolfgang Betz 1:f90318e0923b 596 // the HAL expects number of transfers instead of number of bytes
Wolfgang Betz 1:f90318e0923b 597 int words;
Wolfgang Betz 1:f90318e0923b 598 switch(handle->Init.DataFormat) {
Davide Aliprandi 2:0c9ce59aee25 599 case I2S_DATAFORMAT_16B:
Davide Aliprandi 2:0c9ce59aee25 600 case I2S_DATAFORMAT_16B_EXTENDED:
Davide Aliprandi 2:0c9ce59aee25 601 words = length / 2;
Davide Aliprandi 2:0c9ce59aee25 602 if(words > 0xFFFC) words = 0xFFFC; // truncate in order to respect max DMA length
Davide Aliprandi 2:0c9ce59aee25 603 break;
Davide Aliprandi 2:0c9ce59aee25 604 case I2S_DATAFORMAT_24B:
Davide Aliprandi 2:0c9ce59aee25 605 case I2S_DATAFORMAT_32B:
Davide Aliprandi 2:0c9ce59aee25 606 default:
Davide Aliprandi 2:0c9ce59aee25 607 words = length / 4;
Davide Aliprandi 2:0c9ce59aee25 608 if(words > 0x7FFC) words = 0x7FFC; // truncate in order to respect max DMA length
Davide Aliprandi 2:0c9ce59aee25 609 break;
Wolfgang Betz 1:f90318e0923b 610 }
Wolfgang Betz 1:f90318e0923b 611
Wolfgang Betz 1:f90318e0923b 612 // enable the right hal transfer
Wolfgang Betz 1:f90318e0923b 613 int rc = 0;
Wolfgang Betz 1:f90318e0923b 614 switch(transfer_type) {
Davide Aliprandi 2:0c9ce59aee25 615 case I2S_TRANSFER_TYPE_TXRX:
Davide Aliprandi 2:0c9ce59aee25 616 // enable the interrupts
Davide Aliprandi 2:0c9ce59aee25 617 NVIC_EnableIRQ(obj->dma.dma[DMA_TX]->dma_stream_irq);
Davide Aliprandi 2:0c9ce59aee25 618 NVIC_EnableIRQ(obj->dma.dma[DMA_RX]->dma_stream_irq);
Davide Aliprandi 2:0c9ce59aee25 619 // trigger DMA transfers
Davide Aliprandi 2:0c9ce59aee25 620 rc = HAL_I2SEx_TransmitReceive_DMA(handle, (uint16_t*)tx, (uint16_t*)rx, (uint16_t)words);
Davide Aliprandi 2:0c9ce59aee25 621 break;
Davide Aliprandi 2:0c9ce59aee25 622 case I2S_TRANSFER_TYPE_TX:
Davide Aliprandi 2:0c9ce59aee25 623 // enable the interrupt
Davide Aliprandi 2:0c9ce59aee25 624 NVIC_EnableIRQ(obj->dma.dma[DMA_TX]->dma_stream_irq);
Davide Aliprandi 2:0c9ce59aee25 625 // trigger DMA transfer
Davide Aliprandi 2:0c9ce59aee25 626 rc = HAL_I2S_Transmit_DMA(handle, (uint16_t*)tx, (uint16_t)words);
Davide Aliprandi 2:0c9ce59aee25 627 break;
Davide Aliprandi 2:0c9ce59aee25 628 case I2S_TRANSFER_TYPE_RX:
Davide Aliprandi 2:0c9ce59aee25 629 // enable the interrupt
Davide Aliprandi 2:0c9ce59aee25 630 NVIC_EnableIRQ(obj->dma.dma[DMA_RX]->dma_stream_irq);
Davide Aliprandi 2:0c9ce59aee25 631 // trigger DMA transfer
Davide Aliprandi 2:0c9ce59aee25 632 rc = HAL_I2S_Receive_DMA(handle, (uint16_t*)rx, (uint16_t)words);
Davide Aliprandi 2:0c9ce59aee25 633 break;
Wolfgang Betz 1:f90318e0923b 634 }
Wolfgang Betz 1:f90318e0923b 635
Wolfgang Betz 1:f90318e0923b 636 if (rc) {
Davide Aliprandi 2:0c9ce59aee25 637 DEBUG_PRINTF(" I2S%u: RC: %d\r\n", obj->i2s.module + 1, rc);
Wolfgang Betz 1:f90318e0923b 638 }
Wolfgang Betz 1:f90318e0923b 639
Wolfgang Betz 1:f90318e0923b 640 return;
Wolfgang Betz 1:f90318e0923b 641 }
Wolfgang Betz 1:f90318e0923b 642
Wolfgang Betz 1:f90318e0923b 643 // asynchronous API
Wolfgang Betz 1:f90318e0923b 644 void i2s_transfer(i2s_t *obj,
Wolfgang Betz 1:f90318e0923b 645 void *tx, int tx_length,
Wolfgang Betz 1:f90318e0923b 646 void *rx, int rx_length,
Wolfgang Betz 1:f90318e0923b 647 bool circular, i2s_dma_prio_t prio,
Davide Aliprandi 2:0c9ce59aee25 648 uint32_t handler_tx, uint32_t handler_rx, uint32_t event) {
Wolfgang Betz 1:f90318e0923b 649 // check which use-case we have
Wolfgang Betz 1:f90318e0923b 650 bool use_tx = (tx != NULL && tx_length > 0);
Wolfgang Betz 1:f90318e0923b 651 bool use_rx = (rx != NULL && rx_length > 0);
Wolfgang Betz 1:f90318e0923b 652
Wolfgang Betz 1:f90318e0923b 653 // Init DMAs
Wolfgang Betz 1:f90318e0923b 654 dma_i2s_init(obj, &use_tx, &use_rx, circular, prio);
Wolfgang Betz 1:f90318e0923b 655
Wolfgang Betz 1:f90318e0923b 656 // don't do anything, if the buffers aren't valid
Wolfgang Betz 1:f90318e0923b 657 if (!use_tx && !use_rx)
Wolfgang Betz 1:f90318e0923b 658 return;
Wolfgang Betz 1:f90318e0923b 659
Wolfgang Betz 1:f90318e0923b 660 // copy the buffers to the I2S object
Wolfgang Betz 1:f90318e0923b 661 obj->tx_buff.buffer = tx;
Wolfgang Betz 1:f90318e0923b 662 obj->tx_buff.length = tx_length;
Wolfgang Betz 1:f90318e0923b 663 obj->tx_buff.pos = 0;
Wolfgang Betz 1:f90318e0923b 664 obj->tx_buff.width = 16;
Wolfgang Betz 1:f90318e0923b 665
Wolfgang Betz 1:f90318e0923b 666 obj->rx_buff.buffer = rx;
Wolfgang Betz 1:f90318e0923b 667 obj->rx_buff.length = rx_length;
Wolfgang Betz 1:f90318e0923b 668 obj->rx_buff.pos = 0;
Wolfgang Betz 1:f90318e0923b 669 obj->rx_buff.width = obj->tx_buff.width;
Wolfgang Betz 1:f90318e0923b 670
Wolfgang Betz 1:f90318e0923b 671 obj->i2s.event = event;
Wolfgang Betz 1:f90318e0923b 672
Davide Aliprandi 2:0c9ce59aee25 673 DEBUG_PRINTF(" I2S%u: Transfer: %u, %u\r\n", obj->i2s.module + 1, tx_length, rx_length);
Wolfgang Betz 1:f90318e0923b 674
Wolfgang Betz 1:f90318e0923b 675 // register the thunking handler
Davide Aliprandi 2:0c9ce59aee25 676 if (use_tx) {
Davide Aliprandi 2:0c9ce59aee25 677 NVIC_SetVector(obj->dma.dma[DMA_TX]->dma_stream_irq, handler_tx);
Wolfgang Betz 1:f90318e0923b 678 }
Davide Aliprandi 2:0c9ce59aee25 679 if (use_rx) {
Davide Aliprandi 2:0c9ce59aee25 680 NVIC_SetVector(obj->dma.dma[DMA_RX]->dma_stream_irq, handler_rx);
Wolfgang Betz 1:f90318e0923b 681 }
Wolfgang Betz 1:f90318e0923b 682
Wolfgang Betz 1:f90318e0923b 683 // enable the right hal transfer
Wolfgang Betz 1:f90318e0923b 684 if (use_tx && use_rx) {
Davide Aliprandi 2:0c9ce59aee25 685 int size = (tx_length < rx_length)? tx_length : rx_length;
Davide Aliprandi 2:0c9ce59aee25 686 i2s_start_asynch_transfer(obj, I2S_TRANSFER_TYPE_TXRX, tx, rx, size);
Wolfgang Betz 1:f90318e0923b 687 } else if (use_tx) {
Davide Aliprandi 2:0c9ce59aee25 688 i2s_start_asynch_transfer(obj, I2S_TRANSFER_TYPE_TX, tx, NULL, tx_length);
Wolfgang Betz 1:f90318e0923b 689 } else if (use_rx) {
Davide Aliprandi 2:0c9ce59aee25 690 i2s_start_asynch_transfer(obj, I2S_TRANSFER_TYPE_RX, NULL, rx, rx_length);
Wolfgang Betz 1:f90318e0923b 691 }
Wolfgang Betz 1:f90318e0923b 692 }
Wolfgang Betz 1:f90318e0923b 693
Davide Aliprandi 2:0c9ce59aee25 694 uint32_t i2s_irq_handler_asynch(i2s_t *obj, uint8_t direction) {
Wolfgang Betz 1:f90318e0923b 695 direction = (direction == I2S_TX_EVENT) ? DMA_TX : DMA_RX;
Wolfgang Betz 1:f90318e0923b 696
Wolfgang Betz 1:f90318e0923b 697 // use the right instance
Wolfgang Betz 1:f90318e0923b 698 I2S_HandleTypeDef *i2s_handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 699 DMA_HandleTypeDef *dma_handle = (direction == DMA_TX) ? i2s_handle->hdmatx : i2s_handle->hdmarx;
Wolfgang Betz 1:f90318e0923b 700
Wolfgang Betz 1:f90318e0923b 701 MBED_ASSERT(dma_handle != NULL);
Wolfgang Betz 1:f90318e0923b 702
Wolfgang Betz 1:f90318e0923b 703 int event = 0;
Wolfgang Betz 1:f90318e0923b 704
Wolfgang Betz 1:f90318e0923b 705 // call the Cube handler, this will update the handle
Wolfgang Betz 1:f90318e0923b 706 HAL_DMA_IRQHandler(dma_handle);
Wolfgang Betz 1:f90318e0923b 707
Davide Aliprandi 2:0c9ce59aee25 708 switch(HAL_I2S_GetState(i2s_handle))
Davide Aliprandi 2:0c9ce59aee25 709 {
Davide Aliprandi 2:0c9ce59aee25 710 case HAL_I2S_STATE_READY: {
Davide Aliprandi 2:0c9ce59aee25 711 // adjust buffer positions (betzw - TODO: to be checked for DMA transfers!!!)
Davide Aliprandi 2:0c9ce59aee25 712 int tx_size = (i2s_handle->TxXferSize - i2s_handle->TxXferCount);
Davide Aliprandi 2:0c9ce59aee25 713 int rx_size = (i2s_handle->RxXferSize - i2s_handle->RxXferCount);
Wolfgang Betz 1:f90318e0923b 714
Davide Aliprandi 2:0c9ce59aee25 715 // take data format into consideration
Davide Aliprandi 2:0c9ce59aee25 716 switch(i2s_handle->Init.DataFormat)
Davide Aliprandi 2:0c9ce59aee25 717 {
Davide Aliprandi 2:0c9ce59aee25 718 case I2S_DATAFORMAT_16B:
Davide Aliprandi 2:0c9ce59aee25 719 case I2S_DATAFORMAT_16B_EXTENDED:
Davide Aliprandi 2:0c9ce59aee25 720 tx_size *= 2;
Davide Aliprandi 2:0c9ce59aee25 721 rx_size *= 2;
Davide Aliprandi 2:0c9ce59aee25 722 break;
Davide Aliprandi 2:0c9ce59aee25 723 case I2S_DATAFORMAT_24B:
Davide Aliprandi 2:0c9ce59aee25 724 case I2S_DATAFORMAT_32B:
Davide Aliprandi 2:0c9ce59aee25 725 default:
Davide Aliprandi 2:0c9ce59aee25 726 tx_size *= 4;
Davide Aliprandi 2:0c9ce59aee25 727 rx_size *= 4;
Davide Aliprandi 2:0c9ce59aee25 728 break;
Davide Aliprandi 2:0c9ce59aee25 729 }
Wolfgang Betz 1:f90318e0923b 730
Davide Aliprandi 2:0c9ce59aee25 731 // adjust buffer positions
Davide Aliprandi 2:0c9ce59aee25 732 if (obj->i2s.transfer_type != I2S_TRANSFER_TYPE_RX) {
Davide Aliprandi 2:0c9ce59aee25 733 obj->tx_buff.pos += tx_size;
Davide Aliprandi 2:0c9ce59aee25 734 }
Davide Aliprandi 2:0c9ce59aee25 735 if (obj->i2s.transfer_type != I2S_TRANSFER_TYPE_TX) {
Davide Aliprandi 2:0c9ce59aee25 736 obj->rx_buff.pos += rx_size;
Davide Aliprandi 2:0c9ce59aee25 737 }
Wolfgang Betz 1:f90318e0923b 738
Davide Aliprandi 2:0c9ce59aee25 739 if (i2s_handle->TxXferCount > 0) {
Davide Aliprandi 2:0c9ce59aee25 740 DEBUG_PRINTF(" I2S%u: TxXferCount: %u\r\n", obj->i2s.module + 1, i2s_handle->TxXferCount);
Davide Aliprandi 2:0c9ce59aee25 741 }
Davide Aliprandi 2:0c9ce59aee25 742 if (i2s_handle->RxXferCount > 0) {
Davide Aliprandi 2:0c9ce59aee25 743 DEBUG_PRINTF(" I2S%u: RxXferCount: %u\r\n", obj->i2s.module + 1, i2s_handle->RxXferCount);
Davide Aliprandi 2:0c9ce59aee25 744 }
Davide Aliprandi 2:0c9ce59aee25 745 }
Davide Aliprandi 2:0c9ce59aee25 746 /* no break */
Wolfgang Betz 1:f90318e0923b 747
Davide Aliprandi 2:0c9ce59aee25 748 case HAL_I2S_STATE_BUSY_TX:
Davide Aliprandi 2:0c9ce59aee25 749 case HAL_I2S_STATE_BUSY_RX:
Davide Aliprandi 2:0c9ce59aee25 750 case HAL_I2S_STATE_BUSY_TX_RX:
Davide Aliprandi 2:0c9ce59aee25 751 {
Davide Aliprandi 2:0c9ce59aee25 752 int error = HAL_I2S_GetError(i2s_handle);
Wolfgang Betz 1:f90318e0923b 753
Davide Aliprandi 2:0c9ce59aee25 754 if (error != HAL_I2S_ERROR_NONE) {
Davide Aliprandi 2:0c9ce59aee25 755 // something went wrong and the transfer has definitely completed
Davide Aliprandi 2:0c9ce59aee25 756 event = ((direction == DMA_TX) ? I2S_EVENT_TX_ERROR : I2S_EVENT_RX_ERROR) | I2S_EVENT_INTERNAL_TRANSFER_COMPLETE;
Wolfgang Betz 1:f90318e0923b 757
Davide Aliprandi 2:0c9ce59aee25 758 if (error & HAL_I2S_ERROR_OVR) {
Davide Aliprandi 2:0c9ce59aee25 759 // buffer overrun
Davide Aliprandi 2:0c9ce59aee25 760 event |= I2S_EVENT_RX_OVERFLOW;
Davide Aliprandi 2:0c9ce59aee25 761 }
Wolfgang Betz 1:f90318e0923b 762
Davide Aliprandi 2:0c9ce59aee25 763 if (error & HAL_I2S_ERROR_UDR) {
Davide Aliprandi 2:0c9ce59aee25 764 // buffer underrun
Davide Aliprandi 2:0c9ce59aee25 765 event |= I2S_EVENT_TX_UNDERRUN;
Davide Aliprandi 2:0c9ce59aee25 766 }
Wolfgang Betz 1:f90318e0923b 767
Davide Aliprandi 2:0c9ce59aee25 768 // cleanup DMA (after error)
Davide Aliprandi 2:0c9ce59aee25 769 dma_i2s_free(obj, direction);
Davide Aliprandi 2:0c9ce59aee25 770 } else
Davide Aliprandi 2:0c9ce59aee25 771 { // no error detected
Davide Aliprandi 2:0c9ce59aee25 772 HAL_DMA_StateTypeDef dma_state = HAL_DMA_GetState(dma_handle);
Wolfgang Betz 1:f90318e0923b 773
Davide Aliprandi 2:0c9ce59aee25 774 switch(dma_state)
Davide Aliprandi 2:0c9ce59aee25 775 {
Davide Aliprandi 2:0c9ce59aee25 776 case HAL_DMA_STATE_READY_HALF_MEM0:
Davide Aliprandi 2:0c9ce59aee25 777 case HAL_DMA_STATE_READY_HALF_MEM1:
Davide Aliprandi 2:0c9ce59aee25 778 event = ((direction == DMA_TX) ? I2S_EVENT_TX_HALF_COMPLETE : I2S_EVENT_RX_HALF_COMPLETE);
Davide Aliprandi 2:0c9ce59aee25 779 break;
Davide Aliprandi 2:0c9ce59aee25 780 case HAL_DMA_STATE_READY_MEM0:
Davide Aliprandi 2:0c9ce59aee25 781 case HAL_DMA_STATE_READY_MEM1:
Davide Aliprandi 2:0c9ce59aee25 782 event = ((direction == DMA_TX) ? I2S_EVENT_TX_COMPLETE : I2S_EVENT_RX_COMPLETE);
Davide Aliprandi 2:0c9ce59aee25 783 if(dma_handle->Init.Mode != DMA_CIRCULAR)
Davide Aliprandi 2:0c9ce59aee25 784 {
Davide Aliprandi 2:0c9ce59aee25 785 if (!i2s_active(obj))
Davide Aliprandi 2:0c9ce59aee25 786 { // Check for full-duplex transfer complete!
Davide Aliprandi 2:0c9ce59aee25 787 event |= I2S_EVENT_INTERNAL_TRANSFER_COMPLETE;
Davide Aliprandi 2:0c9ce59aee25 788 }
Wolfgang Betz 1:f90318e0923b 789
Davide Aliprandi 2:0c9ce59aee25 790 // cleanup DMA (because we are done)
Davide Aliprandi 2:0c9ce59aee25 791 dma_i2s_free(obj, direction);
Davide Aliprandi 2:0c9ce59aee25 792 }
Davide Aliprandi 2:0c9ce59aee25 793 break;
Davide Aliprandi 2:0c9ce59aee25 794 default:
Davide Aliprandi 2:0c9ce59aee25 795 printf("betzw(%s, %d): dma_state=0x%x\r\n", __func__, __LINE__, (int)dma_state);
Davide Aliprandi 2:0c9ce59aee25 796 MBED_ASSERT(0);
Davide Aliprandi 2:0c9ce59aee25 797 break;
Davide Aliprandi 2:0c9ce59aee25 798 }
Davide Aliprandi 2:0c9ce59aee25 799 }
Davide Aliprandi 2:0c9ce59aee25 800 }
Davide Aliprandi 2:0c9ce59aee25 801 break;
Wolfgang Betz 1:f90318e0923b 802 default:
Davide Aliprandi 2:0c9ce59aee25 803 // nothing to do?!?
Davide Aliprandi 2:0c9ce59aee25 804 break;
Wolfgang Betz 1:f90318e0923b 805 }
Wolfgang Betz 1:f90318e0923b 806
Davide Aliprandi 2:0c9ce59aee25 807 if (event) DEBUG_PRINTF(" I2S%u: Event: 0x%x\r\n", obj->i2s.module + 1, event);
Wolfgang Betz 1:f90318e0923b 808
Wolfgang Betz 1:f90318e0923b 809 return (event & (obj->i2s.event | I2S_EVENT_INTERNAL_TRANSFER_COMPLETE));
Wolfgang Betz 1:f90318e0923b 810 }
Wolfgang Betz 1:f90318e0923b 811
Davide Aliprandi 2:0c9ce59aee25 812 uint8_t i2s_active(i2s_t *obj) {
Wolfgang Betz 1:f90318e0923b 813 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 814 HAL_I2S_StateTypeDef state = HAL_I2S_GetState(handle);
Wolfgang Betz 1:f90318e0923b 815
Davide Aliprandi 2:0c9ce59aee25 816 switch(state){
Davide Aliprandi 2:0c9ce59aee25 817 case HAL_I2S_STATE_RESET:
Davide Aliprandi 2:0c9ce59aee25 818 case HAL_I2S_STATE_READY:
Davide Aliprandi 2:0c9ce59aee25 819 case HAL_I2S_STATE_ERROR:
Davide Aliprandi 2:0c9ce59aee25 820 return 0;
Davide Aliprandi 2:0c9ce59aee25 821 default:
Davide Aliprandi 2:0c9ce59aee25 822 return -1;
Wolfgang Betz 1:f90318e0923b 823 }
Wolfgang Betz 1:f90318e0923b 824 }
Wolfgang Betz 1:f90318e0923b 825
Davide Aliprandi 2:0c9ce59aee25 826 void i2s_abort_asynch(i2s_t *obj) {
Wolfgang Betz 1:f90318e0923b 827 I2S_HandleTypeDef *i2s_handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 828
Wolfgang Betz 1:f90318e0923b 829 // Stop transfer
Wolfgang Betz 1:f90318e0923b 830 HAL_I2S_DMAStop(i2s_handle);
Wolfgang Betz 1:f90318e0923b 831
Wolfgang Betz 1:f90318e0923b 832 if(obj->dma.dma[DMA_TX] != NULL) {
Davide Aliprandi 2:0c9ce59aee25 833 DMA_HandleTypeDef *dma_handle_tx = &DMaHandles[obj->i2s.module][DMA_TX];
Wolfgang Betz 1:f90318e0923b 834
Davide Aliprandi 2:0c9ce59aee25 835 // disable interrupt & free resource
Davide Aliprandi 2:0c9ce59aee25 836 dma_i2s_free(obj, DMA_TX);
Davide Aliprandi 2:0c9ce59aee25 837
Davide Aliprandi 2:0c9ce59aee25 838 //clean up
Davide Aliprandi 2:0c9ce59aee25 839 __HAL_DMA_DISABLE(dma_handle_tx);
Davide Aliprandi 2:0c9ce59aee25 840 HAL_DMA_DeInit(dma_handle_tx);
Davide Aliprandi 2:0c9ce59aee25 841 HAL_DMA_Init(dma_handle_tx);
Davide Aliprandi 2:0c9ce59aee25 842 __HAL_DMA_ENABLE(dma_handle_tx);
Wolfgang Betz 1:f90318e0923b 843 }
Wolfgang Betz 1:f90318e0923b 844 if(obj->dma.dma[DMA_RX] != NULL) {
Davide Aliprandi 2:0c9ce59aee25 845 DMA_HandleTypeDef *dma_handle_rx = &DMaHandles[obj->i2s.module][DMA_RX];
Wolfgang Betz 1:f90318e0923b 846
Davide Aliprandi 2:0c9ce59aee25 847 // disable interrupt & free resource
Davide Aliprandi 2:0c9ce59aee25 848 dma_i2s_free(obj, DMA_RX);
Wolfgang Betz 1:f90318e0923b 849
Davide Aliprandi 2:0c9ce59aee25 850 //clean up
Davide Aliprandi 2:0c9ce59aee25 851 __HAL_DMA_DISABLE(dma_handle_rx);
Davide Aliprandi 2:0c9ce59aee25 852 HAL_DMA_DeInit(dma_handle_rx);
Davide Aliprandi 2:0c9ce59aee25 853 HAL_DMA_Init(dma_handle_rx);
Davide Aliprandi 2:0c9ce59aee25 854 __HAL_DMA_ENABLE(dma_handle_rx);
Wolfgang Betz 1:f90318e0923b 855 }
Wolfgang Betz 1:f90318e0923b 856
Wolfgang Betz 1:f90318e0923b 857 // clean-up I2S
Wolfgang Betz 1:f90318e0923b 858 __HAL_I2S_DISABLE(i2s_handle);
Wolfgang Betz 1:f90318e0923b 859 HAL_I2S_DeInit(i2s_handle);
Wolfgang Betz 1:f90318e0923b 860 HAL_I2S_Init(i2s_handle);
Wolfgang Betz 1:f90318e0923b 861 __HAL_I2S_ENABLE(i2s_handle);
Wolfgang Betz 1:f90318e0923b 862 }
Wolfgang Betz 1:f90318e0923b 863
Wolfgang Betz 1:f90318e0923b 864 #endif