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:
Wolfgang Betz
Date:
Mon Mar 27 16:15:20 2017 +0200
Revision:
26:468cdd70cd3e
Parent:
24:b78825180506
Child:
27:c2fc3330d0df
Enable I2S w/o requirement for HAL patches

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"
Wolfgang Betz 5:74da3773bf43 14 #include "StmI2sPeripheralPins.h"
Wolfgang Betz 1:f90318e0923b 15
Wolfgang Betz 16:04e1abb4cca3 16 // #define DEBUG_STDIO 1
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 26:468cdd70cd3e 35 typedef enum {
Wolfgang Betz 26:468cdd70cd3e 36 I2S_HALF_TRANSFER = 0,
Wolfgang Betz 26:468cdd70cd3e 37 I2S_FULL_TRANSFER,
Wolfgang Betz 26:468cdd70cd3e 38 } dma_transfer_state_t;
Wolfgang Betz 26:468cdd70cd3e 39
Wolfgang Betz 1:f90318e0923b 40 typedef struct {
Wolfgang Betz 26:468cdd70cd3e 41 DMA_HandleTypeDef dma_handle;
Wolfgang Betz 26:468cdd70cd3e 42 dma_transfer_state_t t_state;
Wolfgang Betz 26:468cdd70cd3e 43 } dma_extra_state_t;
Wolfgang Betz 26:468cdd70cd3e 44
Wolfgang Betz 26:468cdd70cd3e 45 typedef struct {
Wolfgang Betz 26:468cdd70cd3e 46 I2S_HandleTypeDef i2s_handle;
Wolfgang Betz 26:468cdd70cd3e 47 dma_extra_state_t dma_handles[NUM_OF_DIRECTIONS];
Wolfgang Betz 26:468cdd70cd3e 48 } i2s_dma_handles_t;
Wolfgang Betz 1:f90318e0923b 49
Wolfgang Betz 19:ef6ef1795e30 50 #define I2S_NUM (5) // TODO: this approach wastes quite a bit of memory - TO BE IMPROVED!?!?
Wolfgang Betz 1:f90318e0923b 51
Wolfgang Betz 26:468cdd70cd3e 52 static i2s_dma_handles_t I2sHandle[I2S_NUM];
Wolfgang Betz 1:f90318e0923b 53
Wolfgang Betz 5:74da3773bf43 54 static void init_i2s(i2s_t *obj) {
Wolfgang Betz 26:468cdd70cd3e 55 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
Wolfgang Betz 1:f90318e0923b 56
Wolfgang Betz 1:f90318e0923b 57 __HAL_I2S_DISABLE(handle);
Wolfgang Betz 1:f90318e0923b 58 HAL_I2S_Init(handle);
Wolfgang Betz 1:f90318e0923b 59 __HAL_I2S_ENABLE(handle);
Wolfgang Betz 1:f90318e0923b 60 }
Wolfgang Betz 1:f90318e0923b 61
Wolfgang Betz 5:74da3773bf43 62 static void init_dmas(i2s_t *obj) {
Wolfgang Betz 1:f90318e0923b 63 DMA_HandleTypeDef *primary_handle = NULL;
Wolfgang Betz 1:f90318e0923b 64 DMA_HandleTypeDef *secondary_handle = NULL;
Wolfgang Betz 1:f90318e0923b 65 DMA_HandleTypeDef *hdmatx = NULL;
Wolfgang Betz 1:f90318e0923b 66
Wolfgang Betz 1:f90318e0923b 67 switch(obj->dma.dma_direction) {
Wolfgang Betz 1:f90318e0923b 68 case DMA_TX:
Wolfgang Betz 1:f90318e0923b 69 if(obj->dma.dma[DMA_TX] != NULL) {
Wolfgang Betz 26:468cdd70cd3e 70 hdmatx = primary_handle = &I2sHandle[obj->i2s.module].dma_handles[DMA_TX].dma_handle;
Wolfgang Betz 1:f90318e0923b 71 }
Wolfgang Betz 1:f90318e0923b 72 if(obj->dma.dma[DMA_RX] != NULL) {
Wolfgang Betz 26:468cdd70cd3e 73 secondary_handle = &I2sHandle[obj->i2s.module].dma_handles[DMA_RX].dma_handle;
Wolfgang Betz 1:f90318e0923b 74 }
Wolfgang Betz 1:f90318e0923b 75 break;
Wolfgang Betz 1:f90318e0923b 76 case DMA_RX:
Wolfgang Betz 1:f90318e0923b 77 default:
Wolfgang Betz 1:f90318e0923b 78 if(obj->dma.dma[DMA_RX] != NULL) {
Wolfgang Betz 26:468cdd70cd3e 79 primary_handle = &I2sHandle[obj->i2s.module].dma_handles[DMA_RX].dma_handle;
Wolfgang Betz 1:f90318e0923b 80 }
Wolfgang Betz 1:f90318e0923b 81 if(obj->dma.dma[DMA_TX] != NULL) {
Wolfgang Betz 26:468cdd70cd3e 82 hdmatx = secondary_handle = &I2sHandle[obj->i2s.module].dma_handles[DMA_TX].dma_handle;
Wolfgang Betz 1:f90318e0923b 83 }
Wolfgang Betz 1:f90318e0923b 84 break;
Wolfgang Betz 1:f90318e0923b 85 }
Wolfgang Betz 1:f90318e0923b 86
Wolfgang Betz 1:f90318e0923b 87 if(primary_handle != NULL) {
Wolfgang Betz 1:f90318e0923b 88 __HAL_DMA_DISABLE(primary_handle);
Wolfgang Betz 1:f90318e0923b 89 HAL_DMA_Init(primary_handle);
Wolfgang Betz 1:f90318e0923b 90
Wolfgang Betz 1:f90318e0923b 91 if(hdmatx == primary_handle) {
Wolfgang Betz 26:468cdd70cd3e 92 __HAL_LINKDMA(&I2sHandle[obj->i2s.module].i2s_handle, hdmatx, *primary_handle);
Wolfgang Betz 1:f90318e0923b 93 } else {
Wolfgang Betz 26:468cdd70cd3e 94 __HAL_LINKDMA(&I2sHandle[obj->i2s.module].i2s_handle, hdmarx, *primary_handle);
Wolfgang Betz 1:f90318e0923b 95 }
Wolfgang Betz 1:f90318e0923b 96 }
Wolfgang Betz 1:f90318e0923b 97
Wolfgang Betz 1:f90318e0923b 98 if(secondary_handle != NULL) {
Wolfgang Betz 1:f90318e0923b 99 __HAL_DMA_DISABLE(secondary_handle);
Wolfgang Betz 1:f90318e0923b 100 HAL_DMA_Init(secondary_handle);
Wolfgang Betz 1:f90318e0923b 101
Wolfgang Betz 1:f90318e0923b 102 if(hdmatx == secondary_handle) {
Wolfgang Betz 26:468cdd70cd3e 103 __HAL_LINKDMA(&I2sHandle[obj->i2s.module].i2s_handle, hdmatx, *secondary_handle);
Wolfgang Betz 1:f90318e0923b 104 } else {
Wolfgang Betz 26:468cdd70cd3e 105 __HAL_LINKDMA(&I2sHandle[obj->i2s.module].i2s_handle, hdmarx, *secondary_handle);
Wolfgang Betz 1:f90318e0923b 106 }
Wolfgang Betz 1:f90318e0923b 107 }
Wolfgang Betz 1:f90318e0923b 108 }
Wolfgang Betz 1:f90318e0923b 109
Wolfgang Betz 1:f90318e0923b 110 static inline uint32_t i2s_get_mode(i2s_mode_t mode, uint8_t *direction) {
Wolfgang Betz 1:f90318e0923b 111 switch(mode) {
Wolfgang Betz 1:f90318e0923b 112 case SLAVE_TX:
Wolfgang Betz 1:f90318e0923b 113 *direction = DMA_TX;
Wolfgang Betz 1:f90318e0923b 114 return I2S_MODE_SLAVE_TX;
Wolfgang Betz 1:f90318e0923b 115 case SLAVE_RX:
Wolfgang Betz 1:f90318e0923b 116 *direction = DMA_RX;
Wolfgang Betz 1:f90318e0923b 117 return I2S_MODE_SLAVE_RX;
Wolfgang Betz 1:f90318e0923b 118 case MASTER_TX:
Wolfgang Betz 1:f90318e0923b 119 *direction = DMA_TX;
Wolfgang Betz 1:f90318e0923b 120 return I2S_MODE_MASTER_TX;
Wolfgang Betz 1:f90318e0923b 121 case MASTER_RX:
Wolfgang Betz 1:f90318e0923b 122 default:
Wolfgang Betz 1:f90318e0923b 123 *direction = DMA_RX;
Wolfgang Betz 1:f90318e0923b 124 return I2S_MODE_MASTER_RX;
Wolfgang Betz 1:f90318e0923b 125 }
Wolfgang Betz 1:f90318e0923b 126 }
Wolfgang Betz 1:f90318e0923b 127
Wolfgang Betz 1:f90318e0923b 128 static inline uint32_t i2s_get_priority(i2s_dma_prio_t priority) {
Wolfgang Betz 1:f90318e0923b 129 switch(priority) {
Wolfgang Betz 1:f90318e0923b 130 case LOW:
Wolfgang Betz 1:f90318e0923b 131 return DMA_PRIORITY_LOW;
Wolfgang Betz 1:f90318e0923b 132 case URGENT:
Wolfgang Betz 1:f90318e0923b 133 return DMA_PRIORITY_VERY_HIGH;
Wolfgang Betz 1:f90318e0923b 134 case HIGH:
Wolfgang Betz 1:f90318e0923b 135 return DMA_PRIORITY_HIGH;
Wolfgang Betz 1:f90318e0923b 136 default:
Wolfgang Betz 1:f90318e0923b 137 return DMA_PRIORITY_MEDIUM;
Wolfgang Betz 1:f90318e0923b 138 }
Wolfgang Betz 1:f90318e0923b 139 }
Wolfgang Betz 1:f90318e0923b 140
Wolfgang Betz 1:f90318e0923b 141 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 142 // DMA declarations
Wolfgang Betz 26:468cdd70cd3e 143 DMA_HandleTypeDef *primary_handle = &I2sHandle[obj->i2s.module].dma_handles[obj->dma.dma_direction].dma_handle;
Wolfgang Betz 1:f90318e0923b 144 DMA_HandleTypeDef *secondary_handle = NULL;
Wolfgang Betz 1:f90318e0923b 145
Wolfgang Betz 1:f90318e0923b 146 // DMA initialization & configuration
Wolfgang Betz 5:74da3773bf43 147 stm_dma_init();
Wolfgang Betz 1:f90318e0923b 148 obj->dma.dma[DMA_TX] = obj->dma.dma[DMA_RX] = NULL;
Wolfgang Betz 1:f90318e0923b 149
Wolfgang Betz 1:f90318e0923b 150 switch(obj->dma.dma_direction) {
Wolfgang Betz 1:f90318e0923b 151 case DMA_TX:
Wolfgang Betz 1:f90318e0923b 152 if(*use_tx) {
Wolfgang Betz 5:74da3773bf43 153 obj->dma.dma[DMA_TX] = stm_dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_TX));
Wolfgang Betz 7:e9105ae127ad 154 MBED_ASSERT(obj->dma.dma[DMA_TX] != STM_DMA_ERROR_OUT_OF_CHANNELS);
Wolfgang Betz 1:f90318e0923b 155 }
Wolfgang Betz 1:f90318e0923b 156 break;
Wolfgang Betz 1:f90318e0923b 157 case DMA_RX:
Wolfgang Betz 1:f90318e0923b 158 default:
Wolfgang Betz 1:f90318e0923b 159 if(*use_rx) {
Wolfgang Betz 5:74da3773bf43 160 obj->dma.dma[DMA_RX] = stm_dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_RX));
Wolfgang Betz 7:e9105ae127ad 161 MBED_ASSERT(obj->dma.dma[DMA_RX] != STM_DMA_ERROR_OUT_OF_CHANNELS);
Wolfgang Betz 1:f90318e0923b 162 }
Wolfgang Betz 1:f90318e0923b 163 break;
Wolfgang Betz 1:f90318e0923b 164 }
Wolfgang Betz 1:f90318e0923b 165
Wolfgang Betz 1:f90318e0923b 166 // Primary DMA configuration
Wolfgang Betz 1:f90318e0923b 167 if(obj->dma.dma[obj->dma.dma_direction] != NULL) {
Wolfgang Betz 1:f90318e0923b 168 primary_handle->Instance = obj->dma.dma[obj->dma.dma_direction]->dma_stream;
Wolfgang Betz 1:f90318e0923b 169 primary_handle->Init.Channel = obj->dma.dma[obj->dma.dma_direction]->channel_nr;
Wolfgang Betz 1:f90318e0923b 170 primary_handle->Init.Direction = (obj->dma.dma_direction == DMA_TX) ?
Wolfgang Betz 1:f90318e0923b 171 DMA_MEMORY_TO_PERIPH : DMA_PERIPH_TO_MEMORY;
Wolfgang Betz 1:f90318e0923b 172 primary_handle->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
Wolfgang Betz 1:f90318e0923b 173 primary_handle->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
Wolfgang Betz 1:f90318e0923b 174 primary_handle->Init.MemBurst = DMA_MBURST_SINGLE;
Wolfgang Betz 1:f90318e0923b 175 primary_handle->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
Wolfgang Betz 1:f90318e0923b 176 primary_handle->Init.MemInc = DMA_MINC_ENABLE;
Wolfgang Betz 1:f90318e0923b 177 primary_handle->Init.Mode = (circular ? DMA_CIRCULAR : DMA_NORMAL);
Wolfgang Betz 1:f90318e0923b 178 primary_handle->Init.PeriphBurst = DMA_PBURST_SINGLE;
Wolfgang Betz 1:f90318e0923b 179 primary_handle->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
Wolfgang Betz 1:f90318e0923b 180 primary_handle->Init.PeriphInc = DMA_PINC_DISABLE;
Wolfgang Betz 1:f90318e0923b 181 primary_handle->Init.Priority = i2s_get_priority(prio);
Wolfgang Betz 1:f90318e0923b 182 }
Wolfgang Betz 1:f90318e0923b 183
Wolfgang Betz 1:f90318e0923b 184 // Allocate secondary DMA channel (if full-duplex)
Wolfgang Betz 1:f90318e0923b 185 if(obj->i2s.pin_fdpx != NC) {
Wolfgang Betz 1:f90318e0923b 186 switch(obj->dma.dma_direction) {
Wolfgang Betz 1:f90318e0923b 187 case DMA_TX:
Wolfgang Betz 1:f90318e0923b 188 if(*use_rx) {
Wolfgang Betz 5:74da3773bf43 189 obj->dma.dma[DMA_RX] = stm_dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_RX));
Wolfgang Betz 26:468cdd70cd3e 190 secondary_handle = &I2sHandle[obj->i2s.module].dma_handles[DMA_RX].dma_handle;
Wolfgang Betz 7:e9105ae127ad 191 MBED_ASSERT(obj->dma.dma[DMA_RX] != STM_DMA_ERROR_OUT_OF_CHANNELS);
Wolfgang Betz 1:f90318e0923b 192 }
Wolfgang Betz 1:f90318e0923b 193 break;
Wolfgang Betz 1:f90318e0923b 194 case DMA_RX:
Wolfgang Betz 1:f90318e0923b 195 default:
Wolfgang Betz 1:f90318e0923b 196 if(*use_tx) {
Wolfgang Betz 5:74da3773bf43 197 obj->dma.dma[DMA_TX] = stm_dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_TX));
Wolfgang Betz 26:468cdd70cd3e 198 secondary_handle = &I2sHandle[obj->i2s.module].dma_handles[DMA_TX].dma_handle;
Wolfgang Betz 7:e9105ae127ad 199 MBED_ASSERT(obj->dma.dma[DMA_TX] != STM_DMA_ERROR_OUT_OF_CHANNELS);
Wolfgang Betz 1:f90318e0923b 200 }
Wolfgang Betz 1:f90318e0923b 201 break;
Wolfgang Betz 1:f90318e0923b 202 }
Wolfgang Betz 1:f90318e0923b 203 }
Wolfgang Betz 1:f90318e0923b 204
Wolfgang Betz 1:f90318e0923b 205 // Secondary DMA configuration
Wolfgang Betz 1:f90318e0923b 206 if(secondary_handle != NULL) {
Wolfgang Betz 1:f90318e0923b 207 uint8_t secondary_dma_direction = (obj->dma.dma_direction == DMA_TX) ? DMA_RX : DMA_TX;
Wolfgang Betz 1:f90318e0923b 208
Wolfgang Betz 1:f90318e0923b 209 secondary_handle->Instance = obj->dma.dma[secondary_dma_direction]->dma_stream;
Wolfgang Betz 1:f90318e0923b 210 secondary_handle->Init.Channel = obj->dma.dma[secondary_dma_direction]->channel_nr_fd;
Wolfgang Betz 1:f90318e0923b 211 secondary_handle->Init.Direction = (secondary_dma_direction == DMA_TX) ?
Wolfgang Betz 1:f90318e0923b 212 DMA_MEMORY_TO_PERIPH : DMA_PERIPH_TO_MEMORY;
Wolfgang Betz 1:f90318e0923b 213 secondary_handle->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
Wolfgang Betz 1:f90318e0923b 214 secondary_handle->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
Wolfgang Betz 1:f90318e0923b 215 secondary_handle->Init.MemBurst = DMA_MBURST_SINGLE;
Wolfgang Betz 1:f90318e0923b 216 secondary_handle->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
Wolfgang Betz 1:f90318e0923b 217 secondary_handle->Init.MemInc = DMA_MINC_ENABLE;
Wolfgang Betz 1:f90318e0923b 218 secondary_handle->Init.Mode = (circular ? DMA_CIRCULAR : DMA_NORMAL);
Wolfgang Betz 1:f90318e0923b 219 secondary_handle->Init.PeriphBurst = DMA_PBURST_SINGLE;
Wolfgang Betz 1:f90318e0923b 220 secondary_handle->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
Wolfgang Betz 1:f90318e0923b 221 secondary_handle->Init.PeriphInc = DMA_PINC_DISABLE;
Wolfgang Betz 1:f90318e0923b 222 secondary_handle->Init.Priority = i2s_get_priority(prio);
Wolfgang Betz 1:f90318e0923b 223 }
Wolfgang Betz 1:f90318e0923b 224
Wolfgang Betz 1:f90318e0923b 225 if(obj->dma.dma[DMA_TX] == NULL) *use_tx = false;
Wolfgang Betz 1:f90318e0923b 226 if(obj->dma.dma[DMA_RX] == NULL) *use_rx = false;
Wolfgang Betz 1:f90318e0923b 227
Wolfgang Betz 1:f90318e0923b 228 // don't do anything, if the buffers aren't valid
Wolfgang Betz 1:f90318e0923b 229 if (!use_tx && !use_rx) {
Wolfgang Betz 1:f90318e0923b 230 DEBUG_PRINTF("I2S%u: No DMAs to init\n", obj->i2s.module+1);
Wolfgang Betz 1:f90318e0923b 231 return;
Wolfgang Betz 1:f90318e0923b 232 }
Wolfgang Betz 1:f90318e0923b 233
Wolfgang Betz 1:f90318e0923b 234 DEBUG_PRINTF("I2S%u: DMA(s) Init\n", obj->i2s.module+1);
Wolfgang Betz 1:f90318e0923b 235 init_dmas(obj);
Wolfgang Betz 1:f90318e0923b 236 }
Wolfgang Betz 1:f90318e0923b 237
Wolfgang Betz 1:f90318e0923b 238 static void dma_i2s_free(i2s_t *obj, uint8_t direction) {
Wolfgang Betz 1:f90318e0923b 239 const struct dma_stream_s *stream = obj->dma.dma[direction];
Wolfgang Betz 1:f90318e0923b 240
Wolfgang Betz 1:f90318e0923b 241 MBED_ASSERT(stream != NULL);
Wolfgang Betz 1:f90318e0923b 242
Wolfgang Betz 1:f90318e0923b 243 // disable irq
Wolfgang Betz 1:f90318e0923b 244 NVIC_DisableIRQ(stream->dma_stream_irq);
Wolfgang Betz 1:f90318e0923b 245
Wolfgang Betz 1:f90318e0923b 246 // free channel
Wolfgang Betz 5:74da3773bf43 247 stm_dma_channel_free((void*)stream);
Wolfgang Betz 1:f90318e0923b 248 obj->dma.dma[direction] = NULL;
Wolfgang Betz 1:f90318e0923b 249 }
Wolfgang Betz 1:f90318e0923b 250
Wolfgang Betz 5:74da3773bf43 251 void i2s_init(i2s_t *obj, PinName data, PinName sclk, PinName wsel, PinName fdpx, PinName mclk, i2s_mode_t mode) {
Wolfgang Betz 1:f90318e0923b 252 uint8_t dma_dev = 0, dma_direction = 0;
Wolfgang Betz 1:f90318e0923b 253
Wolfgang Betz 1:f90318e0923b 254 // Determine the I2S/SPI to use
Wolfgang Betz 1:f90318e0923b 255 SPIName i2s_data = (SPIName)pinmap_peripheral(data, PinMap_I2S_DATA);
Wolfgang Betz 1:f90318e0923b 256 SPIName i2s_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_I2S_SCLK);
Wolfgang Betz 1:f90318e0923b 257
Wolfgang Betz 1:f90318e0923b 258 SPIName i2s_wsel = (SPIName)pinmap_peripheral(wsel, PinMap_I2S_WSEL);
Wolfgang Betz 1:f90318e0923b 259 SPIName i2s_fdpx = (SPIName)pinmap_peripheral(fdpx, PinMap_I2S_FDPX);
Wolfgang Betz 1:f90318e0923b 260
Wolfgang Betz 1:f90318e0923b 261 SPIName i2s_mclk = (SPIName)pinmap_peripheral(mclk, PinMap_I2S_MCLK);
Wolfgang Betz 1:f90318e0923b 262
Wolfgang Betz 1:f90318e0923b 263 SPIName i2s_merge1 = (SPIName)pinmap_merge(i2s_data, i2s_sclk);
Wolfgang Betz 1:f90318e0923b 264 SPIName i2s_merge2 = (SPIName)pinmap_merge(i2s_wsel, i2s_fdpx);
Wolfgang Betz 1:f90318e0923b 265
Wolfgang Betz 1:f90318e0923b 266 SPIName i2s_merge3 = (SPIName)pinmap_merge(i2s_merge1, i2s_merge2);
Wolfgang Betz 1:f90318e0923b 267 SPIName instance = (SPIName)pinmap_merge(i2s_merge3, i2s_mclk);
Wolfgang Betz 1:f90318e0923b 268 MBED_ASSERT(instance != (SPIName)NC);
Wolfgang Betz 1:f90318e0923b 269
Wolfgang Betz 1:f90318e0923b 270 // Enable I2S/SPI clock and set the right module number
Wolfgang Betz 1:f90318e0923b 271 switch(instance) {
Wolfgang Betz 1:f90318e0923b 272 #if defined(I2S1ext_BASE)
Wolfgang Betz 1:f90318e0923b 273 case SPI_1:
Wolfgang Betz 1:f90318e0923b 274 __SPI1_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 275 obj->i2s.module = 0;
Wolfgang Betz 1:f90318e0923b 276 dma_dev = DMA_SPI1;
Wolfgang Betz 1:f90318e0923b 277 break;
Wolfgang Betz 1:f90318e0923b 278 #endif
Wolfgang Betz 1:f90318e0923b 279 #if defined(I2S2ext_BASE)
Wolfgang Betz 1:f90318e0923b 280 case SPI_2:
Wolfgang Betz 1:f90318e0923b 281 __SPI2_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 282 obj->i2s.module = 1;
Wolfgang Betz 1:f90318e0923b 283 dma_dev = DMA_SPI2;
Wolfgang Betz 1:f90318e0923b 284 break;
Wolfgang Betz 1:f90318e0923b 285 #endif
Wolfgang Betz 1:f90318e0923b 286 #if defined(I2S3ext_BASE)
Wolfgang Betz 1:f90318e0923b 287 case SPI_3:
Wolfgang Betz 1:f90318e0923b 288 __SPI3_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 289 obj->i2s.module = 2;
Wolfgang Betz 1:f90318e0923b 290 dma_dev = DMA_SPI3;
Wolfgang Betz 1:f90318e0923b 291 break;
Wolfgang Betz 1:f90318e0923b 292 #endif
Wolfgang Betz 1:f90318e0923b 293 #if defined(I2S4ext_BASE)
Wolfgang Betz 1:f90318e0923b 294 case SPI_4:
Wolfgang Betz 1:f90318e0923b 295 __SPI4_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 296 obj->i2s.module = 3;
Wolfgang Betz 1:f90318e0923b 297 dma_dev = DMA_SPI4;
Wolfgang Betz 1:f90318e0923b 298 break;
Wolfgang Betz 1:f90318e0923b 299 #endif
Wolfgang Betz 1:f90318e0923b 300 #if defined(I2S5ext_BASE)
Wolfgang Betz 1:f90318e0923b 301 case SPI_5:
Wolfgang Betz 1:f90318e0923b 302 __SPI5_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 303 obj->i2s.module = 4;
Wolfgang Betz 1:f90318e0923b 304 dma_dev = DMA_SPI5;
Wolfgang Betz 1:f90318e0923b 305 break;
Wolfgang Betz 1:f90318e0923b 306 #endif
Wolfgang Betz 1:f90318e0923b 307 default:
Wolfgang Betz 1:f90318e0923b 308 MBED_ASSERT(0);
Wolfgang Betz 1:f90318e0923b 309 break;
Wolfgang Betz 1:f90318e0923b 310 }
Wolfgang Betz 1:f90318e0923b 311
Wolfgang Betz 1:f90318e0923b 312 // Save DMA device
Wolfgang Betz 1:f90318e0923b 313 obj->dma.dma_device = dma_dev;
Wolfgang Betz 1:f90318e0923b 314
Wolfgang Betz 1:f90318e0923b 315 // Configure the I2S pins
Wolfgang Betz 1:f90318e0923b 316 pinmap_pinout(data, PinMap_I2S_DATA);
Wolfgang Betz 1:f90318e0923b 317 pinmap_pinout(wsel, PinMap_I2S_WSEL);
Wolfgang Betz 1:f90318e0923b 318 pinmap_pinout(sclk, PinMap_I2S_SCLK);
Wolfgang Betz 1:f90318e0923b 319 pinmap_pinout(fdpx, PinMap_I2S_FDPX);
Wolfgang Betz 1:f90318e0923b 320 pinmap_pinout(mclk, PinMap_I2S_MCLK);
Wolfgang Betz 1:f90318e0923b 321
Wolfgang Betz 1:f90318e0923b 322 obj->i2s.pin_wsel = wsel;
Wolfgang Betz 1:f90318e0923b 323 obj->i2s.pin_data = data;
Wolfgang Betz 1:f90318e0923b 324 obj->i2s.pin_sclk = sclk;
Wolfgang Betz 1:f90318e0923b 325 obj->i2s.pin_fdpx = fdpx;
Wolfgang Betz 1:f90318e0923b 326 obj->i2s.pin_mclk = mclk;
Wolfgang Betz 1:f90318e0923b 327
Wolfgang Betz 1:f90318e0923b 328 /* Configure PLLI2S */
Wolfgang Betz 1:f90318e0923b 329 static bool first_time = true;
Wolfgang Betz 1:f90318e0923b 330 if(first_time) {
Wolfgang Betz 1:f90318e0923b 331 RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
Wolfgang Betz 1:f90318e0923b 332
Wolfgang Betz 1:f90318e0923b 333 /* Get RTCClockSelection */
Wolfgang Betz 1:f90318e0923b 334 HAL_RCCEx_GetPeriphCLKConfig(&PeriphClkInitStruct);
Wolfgang Betz 1:f90318e0923b 335
Wolfgang Betz 8:561d7ee70ef6 336 /* Set default configuration. Default frequency is 44100Hz. */
Wolfgang Betz 1:f90318e0923b 337 PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;
Wolfgang Betz 19:ef6ef1795e30 338 PeriphClkInitStruct.PLLI2S.PLLI2SN = 271; // NOTE: using values which are suggested in Table 91 of the
Wolfgang Betz 19:ef6ef1795e30 339 PeriphClkInitStruct.PLLI2S.PLLI2SR = 2; // reference manual for master clock enabled & 44100Hz.
Davide Aliprandi 2:0c9ce59aee25 340
Wolfgang Betz 1:f90318e0923b 341 #ifdef NDEBUG
Wolfgang Betz 1:f90318e0923b 342 HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
Wolfgang Betz 1:f90318e0923b 343 #else
Wolfgang Betz 1:f90318e0923b 344 HAL_StatusTypeDef ret = HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
Wolfgang Betz 1:f90318e0923b 345 #endif
Wolfgang Betz 1:f90318e0923b 346 MBED_ASSERT(ret == HAL_OK);
Wolfgang Betz 1:f90318e0923b 347 first_time = false;
Wolfgang Betz 1:f90318e0923b 348 }
Wolfgang Betz 1:f90318e0923b 349
Wolfgang Betz 1:f90318e0923b 350 // initialize the handle for this master!
Wolfgang Betz 26:468cdd70cd3e 351 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
Wolfgang Betz 1:f90318e0923b 352
Wolfgang Betz 1:f90318e0923b 353 handle->Instance = (SPI_TypeDef *)(instance);
Wolfgang Betz 1:f90318e0923b 354 handle->Init.Mode = i2s_get_mode(mode, &dma_direction);
Wolfgang Betz 1:f90318e0923b 355 handle->Init.Standard = I2S_STANDARD_PCM_SHORT;
Wolfgang Betz 1:f90318e0923b 356 handle->Init.DataFormat = I2S_DATAFORMAT_16B;
Wolfgang Betz 22:e04af8667cad 357 handle->Init.MCLKOutput = (mclk == NC ? I2S_MCLKOUTPUT_DISABLE : I2S_MCLKOUTPUT_ENABLE);
Wolfgang Betz 1:f90318e0923b 358 handle->Init.AudioFreq = I2S_AUDIOFREQ_44K;
Wolfgang Betz 1:f90318e0923b 359 handle->Init.CPOL = I2S_CPOL_LOW;
Wolfgang Betz 1:f90318e0923b 360 handle->Init.ClockSource = I2S_CLOCK_PLL;
Wolfgang Betz 1:f90318e0923b 361 handle->Init.FullDuplexMode = (fdpx == NC) ? I2S_FULLDUPLEXMODE_DISABLE : I2S_FULLDUPLEXMODE_ENABLE;
Wolfgang Betz 1:f90318e0923b 362
Wolfgang Betz 1:f90318e0923b 363 // Save primary DMA direction
Wolfgang Betz 1:f90318e0923b 364 obj->dma.dma_direction = dma_direction;
Wolfgang Betz 1:f90318e0923b 365
Wolfgang Betz 1:f90318e0923b 366 DEBUG_PRINTF("I2S%u: Init\n", obj->i2s.module+1);
Wolfgang Betz 1:f90318e0923b 367
Wolfgang Betz 1:f90318e0923b 368 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 369 }
Wolfgang Betz 1:f90318e0923b 370
Wolfgang Betz 5:74da3773bf43 371 void i2s_free(i2s_t *obj) {
Wolfgang Betz 1:f90318e0923b 372 // Reset I2S and disable clock
Wolfgang Betz 1:f90318e0923b 373 switch(obj->i2s.module) {
Wolfgang Betz 1:f90318e0923b 374 #if defined(I2S1ext_BASE)
Wolfgang Betz 1:f90318e0923b 375 case 0:
Wolfgang Betz 1:f90318e0923b 376 __SPI1_FORCE_RESET();
Wolfgang Betz 1:f90318e0923b 377 __SPI1_RELEASE_RESET();
Wolfgang Betz 1:f90318e0923b 378 __SPI1_CLK_DISABLE();
Wolfgang Betz 1:f90318e0923b 379 break;
Wolfgang Betz 1:f90318e0923b 380 #endif
Wolfgang Betz 1:f90318e0923b 381 #if defined(I2S2ext_BASE)
Wolfgang Betz 1:f90318e0923b 382 case 1:
Wolfgang Betz 1:f90318e0923b 383 __SPI2_FORCE_RESET();
Wolfgang Betz 1:f90318e0923b 384 __SPI2_RELEASE_RESET();
Wolfgang Betz 1:f90318e0923b 385 __SPI2_CLK_DISABLE();
Wolfgang Betz 1:f90318e0923b 386 break;
Wolfgang Betz 1:f90318e0923b 387 #endif
Wolfgang Betz 1:f90318e0923b 388 #if defined(I2S3ext_BASE)
Wolfgang Betz 1:f90318e0923b 389 case 2:
Wolfgang Betz 1:f90318e0923b 390 __SPI3_FORCE_RESET();
Wolfgang Betz 1:f90318e0923b 391 __SPI3_RELEASE_RESET();
Wolfgang Betz 1:f90318e0923b 392 __SPI3_CLK_DISABLE();
Wolfgang Betz 1:f90318e0923b 393 break;
Wolfgang Betz 1:f90318e0923b 394 #endif
Wolfgang Betz 1:f90318e0923b 395 #if defined(I2S4ext_BASE)
Wolfgang Betz 1:f90318e0923b 396 case 3:
Wolfgang Betz 1:f90318e0923b 397 __SPI4_FORCE_RESET();
Wolfgang Betz 1:f90318e0923b 398 __SPI4_RELEASE_RESET();
Wolfgang Betz 1:f90318e0923b 399 __SPI4_CLK_DISABLE();
Wolfgang Betz 1:f90318e0923b 400 break;
Wolfgang Betz 1:f90318e0923b 401 #endif
Wolfgang Betz 1:f90318e0923b 402 #if defined(I2S5ext_BASE)
Wolfgang Betz 1:f90318e0923b 403 case 4:
Wolfgang Betz 1:f90318e0923b 404 __SPI5_FORCE_RESET();
Wolfgang Betz 1:f90318e0923b 405 __SPI5_RELEASE_RESET();
Wolfgang Betz 1:f90318e0923b 406 __SPI5_CLK_DISABLE();
Wolfgang Betz 1:f90318e0923b 407 break;
Wolfgang Betz 1:f90318e0923b 408 #endif
Wolfgang Betz 1:f90318e0923b 409 default:
Wolfgang Betz 1:f90318e0923b 410 MBED_ASSERT(0);
Wolfgang Betz 1:f90318e0923b 411 break;
Wolfgang Betz 1:f90318e0923b 412 }
Wolfgang Betz 1:f90318e0923b 413
Wolfgang Betz 19:ef6ef1795e30 414 // TODO: what about 'PLLI2S'?!?
Wolfgang Betz 19:ef6ef1795e30 415 // for the moment we leave it enabled!
Wolfgang Betz 1:f90318e0923b 416
Wolfgang Betz 1:f90318e0923b 417 // Configure GPIOs
Wolfgang Betz 1:f90318e0923b 418 pin_function(obj->i2s.pin_wsel, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 419 pin_function(obj->i2s.pin_data, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 420 pin_function(obj->i2s.pin_sclk, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 421 pin_function(obj->i2s.pin_fdpx, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 422 pin_function(obj->i2s.pin_mclk, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 423
Wolfgang Betz 1:f90318e0923b 424 DEBUG_PRINTF("I2S%u: Free\n", obj->i2s.module+1);
Wolfgang Betz 1:f90318e0923b 425 }
Wolfgang Betz 1:f90318e0923b 426
Wolfgang Betz 5:74da3773bf43 427 void i2s_format(i2s_t *obj, int dbits, int fbits, int polarity) {
Wolfgang Betz 26:468cdd70cd3e 428 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
Wolfgang Betz 1:f90318e0923b 429
Wolfgang Betz 1:f90318e0923b 430 // Save new values
Wolfgang Betz 1:f90318e0923b 431 if (fbits == 16) { // format MUST be 16B
Wolfgang Betz 1:f90318e0923b 432 handle->Init.DataFormat = I2S_DATAFORMAT_16B;
Wolfgang Betz 1:f90318e0923b 433 } else { // format may NOT be 16B
Wolfgang Betz 1:f90318e0923b 434 switch (dbits) {
Wolfgang Betz 1:f90318e0923b 435 case 16:
Wolfgang Betz 1:f90318e0923b 436 handle->Init.DataFormat = I2S_DATAFORMAT_16B_EXTENDED;
Wolfgang Betz 1:f90318e0923b 437 break;
Wolfgang Betz 1:f90318e0923b 438 case 24:
Wolfgang Betz 1:f90318e0923b 439 handle->Init.DataFormat = I2S_DATAFORMAT_24B;
Wolfgang Betz 1:f90318e0923b 440 break;
Wolfgang Betz 1:f90318e0923b 441 case 32:
Wolfgang Betz 1:f90318e0923b 442 default:
Wolfgang Betz 1:f90318e0923b 443 handle->Init.DataFormat = I2S_DATAFORMAT_32B;
Wolfgang Betz 1:f90318e0923b 444 break;
Wolfgang Betz 1:f90318e0923b 445 }
Wolfgang Betz 1:f90318e0923b 446 }
Wolfgang Betz 1:f90318e0923b 447
Wolfgang Betz 1:f90318e0923b 448 handle->Init.CPOL = (polarity == 0) ? I2S_CPOL_LOW : I2S_CPOL_HIGH;
Wolfgang Betz 1:f90318e0923b 449
Wolfgang Betz 1:f90318e0923b 450 DEBUG_PRINTF("I2S%u: Format: %u (%u, %u), %u (%u)\n", obj->i2s.module+1,
Wolfgang Betz 1:f90318e0923b 451 (unsigned int)handle->Init.DataFormat, (unsigned int)dbits, (unsigned int)fbits,
Wolfgang Betz 1:f90318e0923b 452 (unsigned int)handle->Init.CPOL, (unsigned int)polarity);
Wolfgang Betz 1:f90318e0923b 453
Wolfgang Betz 1:f90318e0923b 454 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 455 }
Wolfgang Betz 1:f90318e0923b 456
Wolfgang Betz 5:74da3773bf43 457 void i2s_set_mode(i2s_t *obj, i2s_mode_t mode) {
Wolfgang Betz 1:f90318e0923b 458 uint8_t dma_direction;
Wolfgang Betz 26:468cdd70cd3e 459 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
Wolfgang Betz 1:f90318e0923b 460
Wolfgang Betz 1:f90318e0923b 461 handle->Init.Mode = i2s_get_mode(mode, &dma_direction);
Wolfgang Betz 1:f90318e0923b 462
Wolfgang Betz 1:f90318e0923b 463 // Save primary DMA direction
Wolfgang Betz 1:f90318e0923b 464 obj->dma.dma_direction = dma_direction;
Wolfgang Betz 1:f90318e0923b 465
Wolfgang Betz 1:f90318e0923b 466 DEBUG_PRINTF("I2S%u: Mode: %u (%u)\n", obj->i2s.module+1,
Wolfgang Betz 1:f90318e0923b 467 (unsigned int)handle->Init.Mode, (unsigned int)mode);
Wolfgang Betz 1:f90318e0923b 468
Wolfgang Betz 1:f90318e0923b 469 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 470 }
Wolfgang Betz 1:f90318e0923b 471
Wolfgang Betz 5:74da3773bf43 472 void i2s_set_protocol(i2s_t *obj, i2s_bitorder_t protocol) {
Wolfgang Betz 26:468cdd70cd3e 473 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
Wolfgang Betz 1:f90318e0923b 474
Wolfgang Betz 1:f90318e0923b 475 switch (protocol) {
Wolfgang Betz 1:f90318e0923b 476 case PHILIPS:
Wolfgang Betz 1:f90318e0923b 477 handle->Init.Standard = I2S_STANDARD_PHILIPS;
Wolfgang Betz 1:f90318e0923b 478 break;
Wolfgang Betz 1:f90318e0923b 479 case MSB:
Wolfgang Betz 1:f90318e0923b 480 handle->Init.Standard = I2S_STANDARD_MSB;
Wolfgang Betz 1:f90318e0923b 481 break;
Wolfgang Betz 1:f90318e0923b 482 case LSB:
Wolfgang Betz 1:f90318e0923b 483 handle->Init.Standard = I2S_STANDARD_LSB;
Wolfgang Betz 1:f90318e0923b 484 break;
Wolfgang Betz 1:f90318e0923b 485 case PCM_SHORT:
Wolfgang Betz 1:f90318e0923b 486 handle->Init.Standard = I2S_STANDARD_PCM_SHORT;
Wolfgang Betz 1:f90318e0923b 487 break;
Wolfgang Betz 1:f90318e0923b 488 case PCM_LONG:
Wolfgang Betz 1:f90318e0923b 489 default:
Wolfgang Betz 1:f90318e0923b 490 handle->Init.Standard = I2S_STANDARD_PCM_LONG;
Wolfgang Betz 1:f90318e0923b 491 break;
Wolfgang Betz 1:f90318e0923b 492 }
Wolfgang Betz 1:f90318e0923b 493
Wolfgang Betz 1:f90318e0923b 494 DEBUG_PRINTF("I2S%u: Protocol: %u (%u)\n", obj->i2s.module+1,
Wolfgang Betz 1:f90318e0923b 495 (unsigned int)handle->Init.Standard, (unsigned int)protocol);
Wolfgang Betz 1:f90318e0923b 496
Wolfgang Betz 1:f90318e0923b 497 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 498 }
Wolfgang Betz 1:f90318e0923b 499
Wolfgang Betz 5:74da3773bf43 500 void i2s_audio_frequency(i2s_t *obj, uint32_t hz) {
Wolfgang Betz 26:468cdd70cd3e 501 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
Wolfgang Betz 1:f90318e0923b 502
Wolfgang Betz 1:f90318e0923b 503 if (IS_I2S_AUDIO_FREQ(hz) && (hz != I2S_AUDIOFREQ_DEFAULT)) {
Wolfgang Betz 1:f90318e0923b 504 handle->Init.AudioFreq = hz;
Wolfgang Betz 1:f90318e0923b 505 } else if (hz < I2S_AUDIOFREQ_8K) {
Wolfgang Betz 1:f90318e0923b 506 handle->Init.AudioFreq = I2S_AUDIOFREQ_8K;
Wolfgang Betz 1:f90318e0923b 507 } else {
Wolfgang Betz 1:f90318e0923b 508 handle->Init.AudioFreq = I2S_AUDIOFREQ_192K;
Wolfgang Betz 1:f90318e0923b 509 }
Wolfgang Betz 1:f90318e0923b 510
Wolfgang Betz 1:f90318e0923b 511 DEBUG_PRINTF("I2S%u: Audio frequency: %u (%u)\n", obj->i2s.module+1,
Wolfgang Betz 1:f90318e0923b 512 (unsigned int)handle->Init.AudioFreq, (unsigned int)hz);
Wolfgang Betz 1:f90318e0923b 513
Wolfgang Betz 1:f90318e0923b 514 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 515 }
Wolfgang Betz 1:f90318e0923b 516
Wolfgang Betz 5:74da3773bf43 517 uint8_t i2s_get_module(i2s_t *obj) {
Wolfgang Betz 1:f90318e0923b 518 return obj->i2s.module;
Wolfgang Betz 1:f90318e0923b 519 }
Wolfgang Betz 1:f90318e0923b 520
Wolfgang Betz 1:f90318e0923b 521 static void i2s_start_asynch_transfer(i2s_t *obj, transfer_type_t transfer_type,
Wolfgang Betz 1:f90318e0923b 522 void *tx, void *rx, int length)
Wolfgang Betz 1:f90318e0923b 523 {
Wolfgang Betz 26:468cdd70cd3e 524 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
Wolfgang Betz 1:f90318e0923b 525 obj->i2s.transfer_type = transfer_type;
Wolfgang Betz 1:f90318e0923b 526
Wolfgang Betz 1:f90318e0923b 527 // the HAL expects number of transfers instead of number of bytes
Wolfgang Betz 1:f90318e0923b 528 int words;
Wolfgang Betz 1:f90318e0923b 529 switch(handle->Init.DataFormat) {
Wolfgang Betz 1:f90318e0923b 530 case I2S_DATAFORMAT_16B:
Wolfgang Betz 1:f90318e0923b 531 case I2S_DATAFORMAT_16B_EXTENDED:
Wolfgang Betz 1:f90318e0923b 532 words = length / 2;
Wolfgang Betz 1:f90318e0923b 533 if(words > 0xFFFC) words = 0xFFFC; // truncate in order to respect max DMA length
Wolfgang Betz 1:f90318e0923b 534 break;
Wolfgang Betz 1:f90318e0923b 535 case I2S_DATAFORMAT_24B:
Wolfgang Betz 1:f90318e0923b 536 case I2S_DATAFORMAT_32B:
Wolfgang Betz 1:f90318e0923b 537 default:
Wolfgang Betz 1:f90318e0923b 538 words = length / 4;
Wolfgang Betz 1:f90318e0923b 539 if(words > 0x7FFC) words = 0x7FFC; // truncate in order to respect max DMA length
Wolfgang Betz 1:f90318e0923b 540 break;
Wolfgang Betz 1:f90318e0923b 541 }
Wolfgang Betz 1:f90318e0923b 542
Wolfgang Betz 1:f90318e0923b 543 // enable the right hal transfer
Wolfgang Betz 1:f90318e0923b 544 int rc = 0;
Wolfgang Betz 1:f90318e0923b 545 switch(transfer_type) {
Wolfgang Betz 1:f90318e0923b 546 case I2S_TRANSFER_TYPE_TXRX:
Wolfgang Betz 1:f90318e0923b 547 // enable the interrupts
Wolfgang Betz 1:f90318e0923b 548 NVIC_EnableIRQ(obj->dma.dma[DMA_TX]->dma_stream_irq);
Wolfgang Betz 1:f90318e0923b 549 NVIC_EnableIRQ(obj->dma.dma[DMA_RX]->dma_stream_irq);
Wolfgang Betz 1:f90318e0923b 550 // trigger DMA transfers
Wolfgang Betz 1:f90318e0923b 551 rc = HAL_I2SEx_TransmitReceive_DMA(handle, (uint16_t*)tx, (uint16_t*)rx, (uint16_t)words);
Wolfgang Betz 1:f90318e0923b 552 break;
Wolfgang Betz 1:f90318e0923b 553 case I2S_TRANSFER_TYPE_TX:
Wolfgang Betz 1:f90318e0923b 554 // enable the interrupt
Wolfgang Betz 1:f90318e0923b 555 NVIC_EnableIRQ(obj->dma.dma[DMA_TX]->dma_stream_irq);
Wolfgang Betz 1:f90318e0923b 556 // trigger DMA transfer
Wolfgang Betz 1:f90318e0923b 557 rc = HAL_I2S_Transmit_DMA(handle, (uint16_t*)tx, (uint16_t)words);
Wolfgang Betz 1:f90318e0923b 558 break;
Wolfgang Betz 1:f90318e0923b 559 case I2S_TRANSFER_TYPE_RX:
Wolfgang Betz 1:f90318e0923b 560 // enable the interrupt
Wolfgang Betz 1:f90318e0923b 561 NVIC_EnableIRQ(obj->dma.dma[DMA_RX]->dma_stream_irq);
Wolfgang Betz 1:f90318e0923b 562 // trigger DMA transfer
Wolfgang Betz 1:f90318e0923b 563 rc = HAL_I2S_Receive_DMA(handle, (uint16_t*)rx, (uint16_t)words);
Wolfgang Betz 1:f90318e0923b 564 break;
Wolfgang Betz 1:f90318e0923b 565 }
Wolfgang Betz 1:f90318e0923b 566
Wolfgang Betz 1:f90318e0923b 567 if (rc) {
Wolfgang Betz 1:f90318e0923b 568 DEBUG_PRINTF("I2S%u: RC=%d\n", obj->i2s.module+1, rc);
Wolfgang Betz 1:f90318e0923b 569 }
Wolfgang Betz 1:f90318e0923b 570
Wolfgang Betz 1:f90318e0923b 571 return;
Wolfgang Betz 1:f90318e0923b 572 }
Wolfgang Betz 1:f90318e0923b 573
Wolfgang Betz 1:f90318e0923b 574 // asynchronous API
Wolfgang Betz 1:f90318e0923b 575 void i2s_transfer(i2s_t *obj,
Wolfgang Betz 1:f90318e0923b 576 void *tx, int tx_length,
Wolfgang Betz 1:f90318e0923b 577 void *rx, int rx_length,
Wolfgang Betz 1:f90318e0923b 578 bool circular, i2s_dma_prio_t prio,
Wolfgang Betz 1:f90318e0923b 579 uint32_t handler_tx, uint32_t handler_rx, uint32_t event)
Wolfgang Betz 1:f90318e0923b 580 {
Wolfgang Betz 1:f90318e0923b 581 // check which use-case we have
Wolfgang Betz 1:f90318e0923b 582 bool use_tx = (tx != NULL && tx_length > 0);
Wolfgang Betz 1:f90318e0923b 583 bool use_rx = (rx != NULL && rx_length > 0);
Wolfgang Betz 1:f90318e0923b 584
Wolfgang Betz 1:f90318e0923b 585 // Init DMAs
Wolfgang Betz 1:f90318e0923b 586 dma_i2s_init(obj, &use_tx, &use_rx, circular, prio);
Wolfgang Betz 1:f90318e0923b 587
Wolfgang Betz 1:f90318e0923b 588 // don't do anything, if the buffers aren't valid
Wolfgang Betz 1:f90318e0923b 589 if (!use_tx && !use_rx)
Wolfgang Betz 1:f90318e0923b 590 return;
Wolfgang Betz 1:f90318e0923b 591
Wolfgang Betz 1:f90318e0923b 592 // copy the buffers to the I2S object
Wolfgang Betz 1:f90318e0923b 593 obj->tx_buff.buffer = tx;
Wolfgang Betz 1:f90318e0923b 594 obj->tx_buff.length = tx_length;
Wolfgang Betz 1:f90318e0923b 595 obj->tx_buff.pos = 0;
Wolfgang Betz 1:f90318e0923b 596 obj->tx_buff.width = 16;
Wolfgang Betz 1:f90318e0923b 597
Wolfgang Betz 1:f90318e0923b 598 obj->rx_buff.buffer = rx;
Wolfgang Betz 1:f90318e0923b 599 obj->rx_buff.length = rx_length;
Wolfgang Betz 1:f90318e0923b 600 obj->rx_buff.pos = 0;
Wolfgang Betz 1:f90318e0923b 601 obj->rx_buff.width = obj->tx_buff.width;
Wolfgang Betz 1:f90318e0923b 602
Wolfgang Betz 1:f90318e0923b 603 obj->i2s.event = event;
Wolfgang Betz 1:f90318e0923b 604
Wolfgang Betz 1:f90318e0923b 605 DEBUG_PRINTF("I2S%u: Transfer: %u, %u\n", obj->i2s.module+1, tx_length, rx_length);
Wolfgang Betz 1:f90318e0923b 606
Wolfgang Betz 1:f90318e0923b 607 // register the thunking handler
Wolfgang Betz 1:f90318e0923b 608 if(use_tx) {
Wolfgang Betz 1:f90318e0923b 609 NVIC_SetVector(obj->dma.dma[DMA_TX]->dma_stream_irq, handler_tx);
Wolfgang Betz 1:f90318e0923b 610 }
Wolfgang Betz 1:f90318e0923b 611 if(use_rx) {
Wolfgang Betz 1:f90318e0923b 612 NVIC_SetVector(obj->dma.dma[DMA_RX]->dma_stream_irq, handler_rx);
Wolfgang Betz 1:f90318e0923b 613 }
Wolfgang Betz 1:f90318e0923b 614
Wolfgang Betz 1:f90318e0923b 615 // enable the right hal transfer
Wolfgang Betz 1:f90318e0923b 616 if (use_tx && use_rx) {
Wolfgang Betz 1:f90318e0923b 617 int size = (tx_length < rx_length)? tx_length : rx_length;
Wolfgang Betz 1:f90318e0923b 618 i2s_start_asynch_transfer(obj, I2S_TRANSFER_TYPE_TXRX, tx, rx, size);
Wolfgang Betz 1:f90318e0923b 619 } else if (use_tx) {
Wolfgang Betz 1:f90318e0923b 620 i2s_start_asynch_transfer(obj, I2S_TRANSFER_TYPE_TX, tx, NULL, tx_length);
Wolfgang Betz 1:f90318e0923b 621 } else if (use_rx) {
Wolfgang Betz 1:f90318e0923b 622 i2s_start_asynch_transfer(obj, I2S_TRANSFER_TYPE_RX, NULL, rx, rx_length);
Wolfgang Betz 1:f90318e0923b 623 }
Wolfgang Betz 1:f90318e0923b 624 }
Wolfgang Betz 1:f90318e0923b 625
Wolfgang Betz 5:74da3773bf43 626 uint32_t i2s_irq_handler_asynch(i2s_t *obj, uint8_t direction) {
Wolfgang Betz 1:f90318e0923b 627 direction = (direction == I2S_TX_EVENT) ? DMA_TX : DMA_RX;
Wolfgang Betz 1:f90318e0923b 628
Wolfgang Betz 1:f90318e0923b 629 // use the right instance
Wolfgang Betz 26:468cdd70cd3e 630 I2S_HandleTypeDef *i2s_handle = &I2sHandle[obj->i2s.module].i2s_handle;
Wolfgang Betz 1:f90318e0923b 631 DMA_HandleTypeDef *dma_handle = (direction == DMA_TX) ? i2s_handle->hdmatx : i2s_handle->hdmarx;
Wolfgang Betz 1:f90318e0923b 632
Wolfgang Betz 1:f90318e0923b 633 MBED_ASSERT(dma_handle != NULL);
Wolfgang Betz 1:f90318e0923b 634
Wolfgang Betz 1:f90318e0923b 635 int event = 0;
Wolfgang Betz 1:f90318e0923b 636
Wolfgang Betz 1:f90318e0923b 637 // call the Cube handler, this will update the handle
Wolfgang Betz 1:f90318e0923b 638 HAL_DMA_IRQHandler(dma_handle);
Wolfgang Betz 1:f90318e0923b 639
Wolfgang Betz 1:f90318e0923b 640 switch(HAL_I2S_GetState(i2s_handle)) {
Wolfgang Betz 1:f90318e0923b 641 case HAL_I2S_STATE_READY: {
Wolfgang Betz 16:04e1abb4cca3 642 // adjust buffer positions
Wolfgang Betz 1:f90318e0923b 643 int tx_size = (i2s_handle->TxXferSize - i2s_handle->TxXferCount);
Wolfgang Betz 1:f90318e0923b 644 int rx_size = (i2s_handle->RxXferSize - i2s_handle->RxXferCount);
Wolfgang Betz 1:f90318e0923b 645
Wolfgang Betz 1:f90318e0923b 646 // take data format into consideration
Wolfgang Betz 1:f90318e0923b 647 switch(i2s_handle->Init.DataFormat) {
Wolfgang Betz 1:f90318e0923b 648 case I2S_DATAFORMAT_16B:
Wolfgang Betz 1:f90318e0923b 649 case I2S_DATAFORMAT_16B_EXTENDED:
Wolfgang Betz 1:f90318e0923b 650 tx_size *= 2;
Wolfgang Betz 1:f90318e0923b 651 rx_size *= 2;
Wolfgang Betz 1:f90318e0923b 652 break;
Wolfgang Betz 1:f90318e0923b 653 case I2S_DATAFORMAT_24B:
Wolfgang Betz 1:f90318e0923b 654 case I2S_DATAFORMAT_32B:
Wolfgang Betz 1:f90318e0923b 655 default:
Wolfgang Betz 1:f90318e0923b 656 tx_size *= 4;
Wolfgang Betz 1:f90318e0923b 657 rx_size *= 4;
Wolfgang Betz 1:f90318e0923b 658 break;
Wolfgang Betz 1:f90318e0923b 659 }
Wolfgang Betz 1:f90318e0923b 660
Wolfgang Betz 1:f90318e0923b 661 // adjust buffer positions
Wolfgang Betz 1:f90318e0923b 662 if (obj->i2s.transfer_type != I2S_TRANSFER_TYPE_RX) {
Wolfgang Betz 1:f90318e0923b 663 obj->tx_buff.pos += tx_size;
Wolfgang Betz 1:f90318e0923b 664 }
Wolfgang Betz 1:f90318e0923b 665 if (obj->i2s.transfer_type != I2S_TRANSFER_TYPE_TX) {
Wolfgang Betz 1:f90318e0923b 666 obj->rx_buff.pos += rx_size;
Wolfgang Betz 1:f90318e0923b 667 }
Wolfgang Betz 1:f90318e0923b 668
Wolfgang Betz 1:f90318e0923b 669 if (i2s_handle->TxXferCount > 0) {
Wolfgang Betz 1:f90318e0923b 670 DEBUG_PRINTF("I2S%u: TxXferCount: %u\n", obj->i2s.module+1, i2s_handle->TxXferCount);
Wolfgang Betz 1:f90318e0923b 671 }
Wolfgang Betz 1:f90318e0923b 672 if (i2s_handle->RxXferCount > 0) {
Wolfgang Betz 1:f90318e0923b 673 DEBUG_PRINTF("I2S%u: RxXferCount: %u\n", obj->i2s.module+1, i2s_handle->RxXferCount);
Wolfgang Betz 1:f90318e0923b 674 }
Wolfgang Betz 1:f90318e0923b 675 }
Wolfgang Betz 5:74da3773bf43 676 /* no break */
Wolfgang Betz 1:f90318e0923b 677
Wolfgang Betz 1:f90318e0923b 678 case HAL_I2S_STATE_BUSY_TX:
Wolfgang Betz 1:f90318e0923b 679 case HAL_I2S_STATE_BUSY_RX:
Wolfgang Betz 1:f90318e0923b 680 case HAL_I2S_STATE_BUSY_TX_RX: {
Wolfgang Betz 1:f90318e0923b 681 int error = HAL_I2S_GetError(i2s_handle);
Wolfgang Betz 1:f90318e0923b 682
Wolfgang Betz 1:f90318e0923b 683 if(error != HAL_I2S_ERROR_NONE) {
Wolfgang Betz 1:f90318e0923b 684 // something went wrong and the transfer has definitely completed
Wolfgang Betz 1:f90318e0923b 685 event = ((direction == DMA_TX) ? I2S_EVENT_TX_ERROR : I2S_EVENT_RX_ERROR) | I2S_EVENT_INTERNAL_TRANSFER_COMPLETE;
Wolfgang Betz 1:f90318e0923b 686
Wolfgang Betz 1:f90318e0923b 687 if (error & HAL_I2S_ERROR_OVR) {
Wolfgang Betz 1:f90318e0923b 688 // buffer overrun
Wolfgang Betz 1:f90318e0923b 689 event |= I2S_EVENT_RX_OVERFLOW;
Wolfgang Betz 1:f90318e0923b 690 }
Wolfgang Betz 1:f90318e0923b 691
Wolfgang Betz 1:f90318e0923b 692 if (error & HAL_I2S_ERROR_UDR) {
Wolfgang Betz 1:f90318e0923b 693 // buffer underrun
Wolfgang Betz 1:f90318e0923b 694 event |= I2S_EVENT_TX_UNDERRUN;
Wolfgang Betz 1:f90318e0923b 695 }
Wolfgang Betz 1:f90318e0923b 696
Wolfgang Betz 1:f90318e0923b 697 // cleanup DMA (after error)
Wolfgang Betz 1:f90318e0923b 698 dma_i2s_free(obj, direction);
Wolfgang Betz 1:f90318e0923b 699 } else { // no error detected
Wolfgang Betz 26:468cdd70cd3e 700 size_t offset_dma_handle = offsetof(dma_extra_state_t, dma_handle);
Wolfgang Betz 26:468cdd70cd3e 701 dma_extra_state_t *extra_state = (dma_extra_state_t*)(((void*)dma_handle) - offset_dma_handle);
Wolfgang Betz 26:468cdd70cd3e 702 dma_transfer_state_t dma_state = extra_state->t_state;
Wolfgang Betz 1:f90318e0923b 703
Wolfgang Betz 1:f90318e0923b 704 switch(dma_state) {
Wolfgang Betz 26:468cdd70cd3e 705 case I2S_HALF_TRANSFER:
Wolfgang Betz 1:f90318e0923b 706 event = ((direction == DMA_TX) ? I2S_EVENT_TX_HALF_COMPLETE : I2S_EVENT_RX_HALF_COMPLETE);
Wolfgang Betz 1:f90318e0923b 707 break;
Wolfgang Betz 26:468cdd70cd3e 708 case I2S_FULL_TRANSFER:
Wolfgang Betz 1:f90318e0923b 709 event = ((direction == DMA_TX) ? I2S_EVENT_TX_COMPLETE : I2S_EVENT_RX_COMPLETE);
Wolfgang Betz 1:f90318e0923b 710
Wolfgang Betz 1:f90318e0923b 711 if(dma_handle->Init.Mode != DMA_CIRCULAR) {
Wolfgang Betz 1:f90318e0923b 712 if (!i2s_active(obj)) { // Check for full-duplex transfer complete!
Wolfgang Betz 1:f90318e0923b 713 event |= I2S_EVENT_INTERNAL_TRANSFER_COMPLETE;
Wolfgang Betz 1:f90318e0923b 714 }
Wolfgang Betz 1:f90318e0923b 715
Wolfgang Betz 1:f90318e0923b 716 // cleanup DMA (because we are done)
Wolfgang Betz 1:f90318e0923b 717 dma_i2s_free(obj, direction);
Wolfgang Betz 1:f90318e0923b 718 }
Wolfgang Betz 1:f90318e0923b 719 break;
Wolfgang Betz 1:f90318e0923b 720 default:
Wolfgang Betz 19:ef6ef1795e30 721 printf("(%s, %d): dma_state=0x%x\r\n", __func__, __LINE__, (int)dma_state);
Wolfgang Betz 1:f90318e0923b 722 MBED_ASSERT(0);
Wolfgang Betz 1:f90318e0923b 723 break;
Wolfgang Betz 1:f90318e0923b 724 }
Wolfgang Betz 1:f90318e0923b 725 }
Wolfgang Betz 1:f90318e0923b 726 }
Wolfgang Betz 1:f90318e0923b 727 break;
Wolfgang Betz 1:f90318e0923b 728
Wolfgang Betz 1:f90318e0923b 729 default:
Wolfgang Betz 1:f90318e0923b 730 // nothing to do?!?
Wolfgang Betz 1:f90318e0923b 731 break;
Wolfgang Betz 1:f90318e0923b 732 }
Wolfgang Betz 1:f90318e0923b 733
Wolfgang Betz 1:f90318e0923b 734 if (event) DEBUG_PRINTF("I2S%u: Event: 0x%x\n", obj->i2s.module+1, event);
Wolfgang Betz 1:f90318e0923b 735
Wolfgang Betz 1:f90318e0923b 736 return (event & (obj->i2s.event | I2S_EVENT_INTERNAL_TRANSFER_COMPLETE));
Wolfgang Betz 1:f90318e0923b 737 }
Wolfgang Betz 1:f90318e0923b 738
Wolfgang Betz 5:74da3773bf43 739 uint8_t i2s_active(i2s_t *obj) {
Wolfgang Betz 26:468cdd70cd3e 740 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module].i2s_handle;
Wolfgang Betz 1:f90318e0923b 741 HAL_I2S_StateTypeDef state = HAL_I2S_GetState(handle);
Wolfgang Betz 1:f90318e0923b 742
Wolfgang Betz 1:f90318e0923b 743 switch(state) {
Wolfgang Betz 1:f90318e0923b 744 case HAL_I2S_STATE_RESET:
Wolfgang Betz 1:f90318e0923b 745 case HAL_I2S_STATE_READY:
Wolfgang Betz 1:f90318e0923b 746 case HAL_I2S_STATE_ERROR:
Wolfgang Betz 1:f90318e0923b 747 return 0;
Wolfgang Betz 1:f90318e0923b 748 default:
Wolfgang Betz 24:b78825180506 749 return 1;
Wolfgang Betz 1:f90318e0923b 750 }
Wolfgang Betz 1:f90318e0923b 751 }
Wolfgang Betz 1:f90318e0923b 752
Wolfgang Betz 5:74da3773bf43 753 void i2s_abort_asynch(i2s_t *obj) {
Wolfgang Betz 26:468cdd70cd3e 754 I2S_HandleTypeDef *i2s_handle = &I2sHandle[obj->i2s.module].i2s_handle;
Wolfgang Betz 1:f90318e0923b 755
Wolfgang Betz 1:f90318e0923b 756 // Stop transfer
Wolfgang Betz 1:f90318e0923b 757 HAL_I2S_DMAStop(i2s_handle);
Wolfgang Betz 1:f90318e0923b 758
Wolfgang Betz 1:f90318e0923b 759 if(obj->dma.dma[DMA_TX] != NULL) {
Wolfgang Betz 26:468cdd70cd3e 760 DMA_HandleTypeDef *dma_handle_tx = &I2sHandle[obj->i2s.module].dma_handles[DMA_TX].dma_handle;
Wolfgang Betz 1:f90318e0923b 761
Wolfgang Betz 1:f90318e0923b 762 // disable interrupt & free resource
Wolfgang Betz 1:f90318e0923b 763 dma_i2s_free(obj, DMA_TX);
Wolfgang Betz 1:f90318e0923b 764
Wolfgang Betz 1:f90318e0923b 765 //clean up
Wolfgang Betz 1:f90318e0923b 766 __HAL_DMA_DISABLE(dma_handle_tx);
Wolfgang Betz 1:f90318e0923b 767 HAL_DMA_DeInit(dma_handle_tx);
Wolfgang Betz 1:f90318e0923b 768 HAL_DMA_Init(dma_handle_tx);
Wolfgang Betz 1:f90318e0923b 769 __HAL_DMA_ENABLE(dma_handle_tx);
Wolfgang Betz 1:f90318e0923b 770 }
Wolfgang Betz 1:f90318e0923b 771 if(obj->dma.dma[DMA_RX] != NULL) {
Wolfgang Betz 26:468cdd70cd3e 772 DMA_HandleTypeDef *dma_handle_rx = &I2sHandle[obj->i2s.module].dma_handles[DMA_RX].dma_handle;
Wolfgang Betz 1:f90318e0923b 773
Wolfgang Betz 1:f90318e0923b 774 // disable interrupt & free resource
Wolfgang Betz 1:f90318e0923b 775 dma_i2s_free(obj, DMA_RX);
Wolfgang Betz 1:f90318e0923b 776
Wolfgang Betz 1:f90318e0923b 777 //clean up
Wolfgang Betz 1:f90318e0923b 778 __HAL_DMA_DISABLE(dma_handle_rx);
Wolfgang Betz 1:f90318e0923b 779 HAL_DMA_DeInit(dma_handle_rx);
Wolfgang Betz 1:f90318e0923b 780 HAL_DMA_Init(dma_handle_rx);
Wolfgang Betz 1:f90318e0923b 781 __HAL_DMA_ENABLE(dma_handle_rx);
Wolfgang Betz 1:f90318e0923b 782 }
Wolfgang Betz 1:f90318e0923b 783
Wolfgang Betz 1:f90318e0923b 784 // clean-up I2S
Wolfgang Betz 1:f90318e0923b 785 __HAL_I2S_DISABLE(i2s_handle);
Wolfgang Betz 1:f90318e0923b 786 HAL_I2S_DeInit(i2s_handle);
Wolfgang Betz 1:f90318e0923b 787 HAL_I2S_Init(i2s_handle);
Wolfgang Betz 1:f90318e0923b 788 __HAL_I2S_ENABLE(i2s_handle);
Wolfgang Betz 1:f90318e0923b 789 }
Wolfgang Betz 1:f90318e0923b 790
Wolfgang Betz 26:468cdd70cd3e 791 /*** Weak function overwrites ***/
Wolfgang Betz 26:468cdd70cd3e 792 void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s) {
Wolfgang Betz 26:468cdd70cd3e 793 size_t offset_i2s_handle = offsetof(i2s_dma_handles_t, i2s_handle);
Wolfgang Betz 26:468cdd70cd3e 794 i2s_dma_handles_t *i2s_dma_handle = (i2s_dma_handles_t*)(((void*)hi2s) - offset_i2s_handle);
Wolfgang Betz 26:468cdd70cd3e 795 dma_transfer_state_t *dma_t_state = &(i2s_dma_handle->dma_handles[DMA_TX].t_state);
Wolfgang Betz 26:468cdd70cd3e 796
Wolfgang Betz 26:468cdd70cd3e 797 *dma_t_state = I2S_HALF_TRANSFER;
Wolfgang Betz 26:468cdd70cd3e 798 }
Wolfgang Betz 26:468cdd70cd3e 799
Wolfgang Betz 26:468cdd70cd3e 800 void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s) {
Wolfgang Betz 26:468cdd70cd3e 801 size_t offset_i2s_handle = offsetof(i2s_dma_handles_t, i2s_handle);
Wolfgang Betz 26:468cdd70cd3e 802 i2s_dma_handles_t *i2s_dma_handle = (i2s_dma_handles_t*)(((void*)hi2s) - offset_i2s_handle);
Wolfgang Betz 26:468cdd70cd3e 803 dma_transfer_state_t *dma_t_state = &(i2s_dma_handle->dma_handles[DMA_RX].t_state);
Wolfgang Betz 26:468cdd70cd3e 804
Wolfgang Betz 26:468cdd70cd3e 805 *dma_t_state = I2S_HALF_TRANSFER;
Wolfgang Betz 26:468cdd70cd3e 806 }
Wolfgang Betz 26:468cdd70cd3e 807
Wolfgang Betz 26:468cdd70cd3e 808 void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s) {
Wolfgang Betz 26:468cdd70cd3e 809 size_t offset_i2s_handle = offsetof(i2s_dma_handles_t, i2s_handle);
Wolfgang Betz 26:468cdd70cd3e 810 i2s_dma_handles_t *i2s_dma_handle = (i2s_dma_handles_t*)(((void*)hi2s) - offset_i2s_handle);
Wolfgang Betz 26:468cdd70cd3e 811 dma_transfer_state_t *dma_t_state = &(i2s_dma_handle->dma_handles[DMA_TX].t_state);
Wolfgang Betz 26:468cdd70cd3e 812
Wolfgang Betz 26:468cdd70cd3e 813 *dma_t_state = I2S_FULL_TRANSFER;
Wolfgang Betz 26:468cdd70cd3e 814 }
Wolfgang Betz 26:468cdd70cd3e 815
Wolfgang Betz 26:468cdd70cd3e 816 void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) {
Wolfgang Betz 26:468cdd70cd3e 817 size_t offset_i2s_handle = offsetof(i2s_dma_handles_t, i2s_handle);
Wolfgang Betz 26:468cdd70cd3e 818 i2s_dma_handles_t *i2s_dma_handle = (i2s_dma_handles_t*)(((void*)hi2s) - offset_i2s_handle);
Wolfgang Betz 26:468cdd70cd3e 819 dma_transfer_state_t *dma_t_state = &(i2s_dma_handle->dma_handles[DMA_RX].t_state);
Wolfgang Betz 26:468cdd70cd3e 820
Wolfgang Betz 26:468cdd70cd3e 821 *dma_t_state = I2S_FULL_TRANSFER;
Wolfgang Betz 26:468cdd70cd3e 822 }
Wolfgang Betz 26:468cdd70cd3e 823
Wolfgang Betz 9:c4c2240e06d6 824 /*** Code for harmonizing frequencies ***/
Wolfgang Betz 9:c4c2240e06d6 825 static inline I2S_HandleTypeDef *i2s_get_handle(i2s_t *obj)
Wolfgang Betz 9:c4c2240e06d6 826 {
Wolfgang Betz 26:468cdd70cd3e 827 return (I2S_HandleTypeDef *) &I2sHandle[obj->i2s.module].i2s_handle;
Wolfgang Betz 9:c4c2240e06d6 828 }
Wolfgang Betz 9:c4c2240e06d6 829
Wolfgang Betz 20:54b1a9b620c5 830 static float i2s_compute_closest_frequency(i2s_t *dev_i2s, uint32_t target_freq) {
Wolfgang Betz 9:c4c2240e06d6 831 uint32_t i2sclk = 0U, i2sdiv = 2U, i2sodd = 0U, packetlength = 1U, tmp = 0U;
Wolfgang Betz 9:c4c2240e06d6 832 I2S_HandleTypeDef *hi2s;
Wolfgang Betz 9:c4c2240e06d6 833
Wolfgang Betz 9:c4c2240e06d6 834 /* Get the I2S handle. */
Wolfgang Betz 9:c4c2240e06d6 835 hi2s = i2s_get_handle(dev_i2s);
Wolfgang Betz 9:c4c2240e06d6 836
Wolfgang Betz 9:c4c2240e06d6 837 /* Check the frame length (For the Prescaler computing). */
Wolfgang Betz 9:c4c2240e06d6 838 if (hi2s->Init.DataFormat != I2S_DATAFORMAT_16B)
Wolfgang Betz 9:c4c2240e06d6 839 {
Wolfgang Betz 9:c4c2240e06d6 840 /* Packet length is 32 bits */
Wolfgang Betz 9:c4c2240e06d6 841 packetlength = 2U;
Wolfgang Betz 9:c4c2240e06d6 842 }
Wolfgang Betz 9:c4c2240e06d6 843
Wolfgang Betz 9:c4c2240e06d6 844 /* Get I2S source Clock frequency. */
Wolfgang Betz 9:c4c2240e06d6 845 i2sclk = I2S_GetInputClock(hi2s);
Wolfgang Betz 9:c4c2240e06d6 846
Wolfgang Betz 9:c4c2240e06d6 847 /* Compute the Real divider depending on the MCLK output state, with a floating point. */
Wolfgang Betz 9:c4c2240e06d6 848 if (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE)
Wolfgang Betz 9:c4c2240e06d6 849 {
Wolfgang Betz 9:c4c2240e06d6 850 /* MCLK output is enabled. */
Wolfgang Betz 14:0060a9850c5f 851 tmp = (uint32_t)(((((i2sclk / 256U) * 10U) / target_freq)) + 5U);
Wolfgang Betz 9:c4c2240e06d6 852 }
Wolfgang Betz 9:c4c2240e06d6 853 else
Wolfgang Betz 9:c4c2240e06d6 854 {
Wolfgang Betz 9:c4c2240e06d6 855 /* MCLK output is disabled. */
Wolfgang Betz 14:0060a9850c5f 856 tmp = (uint32_t)(((((i2sclk / (32U * packetlength)) * 10U) / target_freq)) + 5U);
Wolfgang Betz 9:c4c2240e06d6 857 }
Wolfgang Betz 9:c4c2240e06d6 858
Wolfgang Betz 9:c4c2240e06d6 859 /* Remove the flatting point. */
Wolfgang Betz 9:c4c2240e06d6 860 tmp = tmp / 10U;
Wolfgang Betz 9:c4c2240e06d6 861
Wolfgang Betz 9:c4c2240e06d6 862 /* Check the parity of the divider. */
Wolfgang Betz 9:c4c2240e06d6 863 i2sodd = (uint32_t)(tmp & (uint32_t)1U);
Wolfgang Betz 9:c4c2240e06d6 864
Wolfgang Betz 9:c4c2240e06d6 865 /* Compute the i2sdiv prescaler. */
Wolfgang Betz 9:c4c2240e06d6 866 i2sdiv = (uint32_t)((tmp - i2sodd) / 2U);
Wolfgang Betz 9:c4c2240e06d6 867
Wolfgang Betz 9:c4c2240e06d6 868 /* Test if the divider is 1 or 0 or greater than 0xFF. */
Wolfgang Betz 9:c4c2240e06d6 869 if ((i2sdiv < 2U) || (i2sdiv > 0xFFU))
Wolfgang Betz 9:c4c2240e06d6 870 {
Wolfgang Betz 9:c4c2240e06d6 871 /* Set the default values. */
Wolfgang Betz 9:c4c2240e06d6 872 i2sdiv = 2U;
Wolfgang Betz 9:c4c2240e06d6 873 i2sodd = 0U;
Wolfgang Betz 9:c4c2240e06d6 874 }
Wolfgang Betz 9:c4c2240e06d6 875
Wolfgang Betz 9:c4c2240e06d6 876 /* Compute the I2S frequencies. */
Wolfgang Betz 9:c4c2240e06d6 877 uint32_t format_factor = (hi2s->Init.DataFormat == I2S_DATAFORMAT_16B ? 16 : 32);
Wolfgang Betz 9:c4c2240e06d6 878 uint32_t mclk_factor = (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE ? (format_factor == 16 ? 8 : 4) : 1);
Wolfgang Betz 18:1ccbfe84f550 879 float f = ((float)i2sclk / (float)(2 * format_factor * ((2 * i2sdiv) + i2sodd) * mclk_factor));
Wolfgang Betz 9:c4c2240e06d6 880
Wolfgang Betz 20:54b1a9b620c5 881 return f;
Wolfgang Betz 9:c4c2240e06d6 882 }
Wolfgang Betz 9:c4c2240e06d6 883
Wolfgang Betz 14:0060a9850c5f 884 /** Compute the real frequency of a given I2S objects.
Wolfgang Betz 9:c4c2240e06d6 885 *
Wolfgang Betz 9:c4c2240e06d6 886 * @param dev_i2s reference to the I2S object.
Wolfgang Betz 14:0060a9850c5f 887 * @return the computed real frequency.
Wolfgang Betz 9:c4c2240e06d6 888 */
Wolfgang Betz 20:54b1a9b620c5 889 static inline float i2s_compute_real_frequency(i2s_t *dev_i2s)
Davide Aliprandi 4:21603d68bcf7 890 {
Wolfgang Betz 9:c4c2240e06d6 891 I2S_HandleTypeDef *hi2s;
Wolfgang Betz 9:c4c2240e06d6 892
Wolfgang Betz 9:c4c2240e06d6 893 /* Get the I2S handle. */
Wolfgang Betz 9:c4c2240e06d6 894 hi2s = i2s_get_handle(dev_i2s);
Wolfgang Betz 9:c4c2240e06d6 895
Wolfgang Betz 14:0060a9850c5f 896 return i2s_compute_closest_frequency(dev_i2s, hi2s->Init.AudioFreq);
Wolfgang Betz 9:c4c2240e06d6 897 }
Wolfgang Betz 9:c4c2240e06d6 898
Wolfgang Betz 22:e04af8667cad 899 static inline bool i2s_has_mclk(i2s_t *dev_i2s)
Wolfgang Betz 22:e04af8667cad 900 {
Wolfgang Betz 22:e04af8667cad 901 I2S_HandleTypeDef *hi2s;
Wolfgang Betz 22:e04af8667cad 902
Wolfgang Betz 22:e04af8667cad 903 /* Get the I2S handle. */
Wolfgang Betz 22:e04af8667cad 904 hi2s = i2s_get_handle(dev_i2s);
Wolfgang Betz 22:e04af8667cad 905
Wolfgang Betz 22:e04af8667cad 906 return (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE);
Wolfgang Betz 22:e04af8667cad 907 }
Wolfgang Betz 22:e04af8667cad 908
Wolfgang Betz 23:6ebde375d2d1 909 static inline uint32_t i2s_get_matching_freq(i2s_t *dev_i2s, float freq) {
Wolfgang Betz 23:6ebde375d2d1 910 uint32_t freq_int_ceil = (uint32_t)ceilf(freq);
Wolfgang Betz 23:6ebde375d2d1 911 uint32_t freq_int_floor = (uint32_t)freq;
Wolfgang Betz 23:6ebde375d2d1 912
Wolfgang Betz 23:6ebde375d2d1 913 float real_freq = i2s_compute_closest_frequency(dev_i2s, freq_int_ceil);
Wolfgang Betz 23:6ebde375d2d1 914 if(real_freq == freq) {
Wolfgang Betz 23:6ebde375d2d1 915 return freq_int_ceil;
Wolfgang Betz 23:6ebde375d2d1 916 } else {
Wolfgang Betz 23:6ebde375d2d1 917 real_freq = i2s_compute_closest_frequency(dev_i2s, freq_int_floor);
Wolfgang Betz 23:6ebde375d2d1 918 if(real_freq == freq) {
Wolfgang Betz 23:6ebde375d2d1 919 return freq_int_floor;
Wolfgang Betz 23:6ebde375d2d1 920 } else {
Wolfgang Betz 23:6ebde375d2d1 921 return 0;
Wolfgang Betz 23:6ebde375d2d1 922 }
Wolfgang Betz 23:6ebde375d2d1 923 }
Wolfgang Betz 23:6ebde375d2d1 924 }
Wolfgang Betz 23:6ebde375d2d1 925
Wolfgang Betz 14:0060a9850c5f 926 /** Computing the harmonized frequencies of two I2S peripherals.
Wolfgang Betz 14:0060a9850c5f 927 *
Wolfgang Betz 14:0060a9850c5f 928 * @param[in] i2s_t_l reference to the i2s_t structure with the lower frequency.
Wolfgang Betz 14:0060a9850c5f 929 * @param[in] i2s_t_h reference to the i2s_t structure with the higher frequency.
Wolfgang Betz 14:0060a9850c5f 930 * @param[in|out] ptr_low_freq pointer to lower frequency.
Wolfgang Betz 14:0060a9850c5f 931 * @param[in|out] ptr_high_freq pointer to higher frequency.
Wolfgang Betz 14:0060a9850c5f 932 * @param[in] real_low_freq real higher frequency.
Wolfgang Betz 14:0060a9850c5f 933 * @param[in] real_high_freq real lower frequency.
Wolfgang Betz 14:0060a9850c5f 934 * @return "0" if the frequencies have been harmonized, "-1" otherwise.
Wolfgang Betz 14:0060a9850c5f 935 */
Wolfgang Betz 20:54b1a9b620c5 936 static int8_t i2s_compute_harmonized_frequencies(i2s_t *i2s_t_l, i2s_t *i2s_t_h, uint32_t *ptr_low_freq, uint32_t *ptr_high_freq,
Wolfgang Betz 22:e04af8667cad 937 float real_low_freq, float real_high_freq)
Wolfgang Betz 14:0060a9850c5f 938 {
Wolfgang Betz 14:0060a9850c5f 939 /* Returning if the two real frequencies are already multiple one of the other. */
Wolfgang Betz 20:54b1a9b620c5 940 float division = real_high_freq / real_low_freq;
Wolfgang Betz 18:1ccbfe84f550 941 float rest = (division - (uint32_t)division);
Wolfgang Betz 14:0060a9850c5f 942 MBED_ASSERT(rest >= 0);
Wolfgang Betz 14:0060a9850c5f 943 if (rest == 0) {
Wolfgang Betz 14:0060a9850c5f 944 return 0;
Wolfgang Betz 14:0060a9850c5f 945 }
Wolfgang Betz 24:b78825180506 946 uint32_t multiplier = ((rest >= 0.5f) ? ((uint32_t)division + 1) : (uint32_t)division);
Wolfgang Betz 22:e04af8667cad 947
Wolfgang Betz 22:e04af8667cad 948 /* Get MCLK settings for both devices */
Wolfgang Betz 22:e04af8667cad 949 bool low_freq_mclk = i2s_has_mclk(i2s_t_l);
Wolfgang Betz 22:e04af8667cad 950 bool high_freq_mclk = i2s_has_mclk(i2s_t_h);
Wolfgang Betz 22:e04af8667cad 951
Wolfgang Betz 23:6ebde375d2d1 952 uint32_t new_low_freq_int = i2s_get_matching_freq(i2s_t_l, real_low_freq);
Wolfgang Betz 23:6ebde375d2d1 953 uint32_t new_high_freq_int = i2s_get_matching_freq(i2s_t_h, real_high_freq);
Wolfgang Betz 23:6ebde375d2d1 954 MBED_ASSERT((new_low_freq_int != 0) && (new_high_freq_int != 0));
Wolfgang Betz 14:0060a9850c5f 955
Wolfgang Betz 14:0060a9850c5f 956 /* Computing the harmonized frequencies so that they are multiple one of the
Wolfgang Betz 14:0060a9850c5f 957 other by a certain factor. */
Wolfgang Betz 22:e04af8667cad 958 if(low_freq_mclk && !high_freq_mclk) { // start from low frequency
Wolfgang Betz 22:e04af8667cad 959 float new_high_freq = real_low_freq * multiplier;
Wolfgang Betz 23:6ebde375d2d1 960 new_high_freq_int = i2s_get_matching_freq(i2s_t_h, new_high_freq);
Wolfgang Betz 23:6ebde375d2d1 961 if(new_high_freq_int == 0) {
Wolfgang Betz 23:6ebde375d2d1 962 return -1; // should never happen!
Wolfgang Betz 22:e04af8667cad 963 }
Wolfgang Betz 22:e04af8667cad 964 } else { // start from high frequency
Wolfgang Betz 22:e04af8667cad 965 float new_low_freq = real_high_freq / multiplier;
Wolfgang Betz 23:6ebde375d2d1 966 new_low_freq_int = i2s_get_matching_freq(i2s_t_l, new_low_freq);
Wolfgang Betz 23:6ebde375d2d1 967 if(new_low_freq_int == 0) {
Wolfgang Betz 23:6ebde375d2d1 968 return -1; /* might happen for both devices with MCLK disabled &
Wolfgang Betz 23:6ebde375d2d1 969 higher frequency 16-bit wide and lower frequency 32-bit wide
Wolfgang Betz 23:6ebde375d2d1 970 and odd multiplier!
Wolfgang Betz 23:6ebde375d2d1 971 */
Wolfgang Betz 22:e04af8667cad 972 }
Wolfgang Betz 14:0060a9850c5f 973 }
Wolfgang Betz 23:6ebde375d2d1 974
Wolfgang Betz 20:54b1a9b620c5 975 *ptr_low_freq = new_low_freq_int;
Wolfgang Betz 22:e04af8667cad 976 *ptr_high_freq = new_high_freq_int;
Wolfgang Betz 14:0060a9850c5f 977
Wolfgang Betz 14:0060a9850c5f 978 return 0;
Wolfgang Betz 14:0060a9850c5f 979 }
Wolfgang Betz 14:0060a9850c5f 980
Wolfgang Betz 9:c4c2240e06d6 981 int8_t i2s_harmonize(i2s_t *dev_i2s_1, uint32_t *freq_i2s_1, i2s_t *dev_i2s_2, uint32_t *freq_i2s_2)
Wolfgang Betz 9:c4c2240e06d6 982 {
Wolfgang Betz 14:0060a9850c5f 983 /* Returning if the two set frequencies are not multiple one of the other. */
Wolfgang Betz 14:0060a9850c5f 984 if((*freq_i2s_1 < *freq_i2s_2) ? ((*freq_i2s_2 % *freq_i2s_1) != 0) : ((*freq_i2s_1 % *freq_i2s_2) != 0)) {
Wolfgang Betz 14:0060a9850c5f 985 return -1;
Wolfgang Betz 14:0060a9850c5f 986 }
Wolfgang Betz 9:c4c2240e06d6 987
Wolfgang Betz 14:0060a9850c5f 988 /* Compute the real frequencies. */
Wolfgang Betz 20:54b1a9b620c5 989 float real_f1 = i2s_compute_real_frequency(dev_i2s_1);
Wolfgang Betz 20:54b1a9b620c5 990 float real_f2 = i2s_compute_real_frequency(dev_i2s_2);
Wolfgang Betz 14:0060a9850c5f 991
Wolfgang Betz 14:0060a9850c5f 992 /* Computing the harmonized frequencies. */
Wolfgang Betz 14:0060a9850c5f 993 if(real_f1 < real_f2) {
Wolfgang Betz 14:0060a9850c5f 994 return i2s_compute_harmonized_frequencies(dev_i2s_1, dev_i2s_2, freq_i2s_1, freq_i2s_2, real_f1, real_f2);
Wolfgang Betz 14:0060a9850c5f 995 } else {
Wolfgang Betz 14:0060a9850c5f 996 return i2s_compute_harmonized_frequencies(dev_i2s_2, dev_i2s_1, freq_i2s_2, freq_i2s_1, real_f2, real_f1);
Wolfgang Betz 14:0060a9850c5f 997 }
Davide Aliprandi 4:21603d68bcf7 998 }
Davide Aliprandi 4:21603d68bcf7 999
Wolfgang Betz 1:f90318e0923b 1000 #endif