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 Feb 13 11:53:21 2017 +0100
Revision:
24:b78825180506
Parent:
23:6ebde375d2d1
Child:
26:468cdd70cd3e
Avoid two warnings

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