Il y avait des problèmes dans la libraire...

Dependents:   X_NUCLEO_CCA02M1

Fork of ST_I2S by ST

Committer:
Wolfgang Betz
Date:
Fri Jan 20 11:06:07 2017 +0100
Revision:
14:0060a9850c5f
Parent:
13:fa1b24df9025
Child:
15:13ee1f813328
Compromise proposal (no cleanup)

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 1:f90318e0923b 16 // #define DEBUG_STDIO 1 // betzw - TODO: temporarily enable debug printfs
Wolfgang Betz 1:f90318e0923b 17
Wolfgang Betz 1:f90318e0923b 18 #ifndef DEBUG_STDIO
Wolfgang Betz 1:f90318e0923b 19 # define DEBUG_STDIO 0
Wolfgang Betz 1:f90318e0923b 20 #endif
Wolfgang Betz 1:f90318e0923b 21
Wolfgang Betz 1:f90318e0923b 22 #if DEBUG_STDIO
Wolfgang Betz 1:f90318e0923b 23 # include <stdio.h>
Wolfgang Betz 1:f90318e0923b 24 # define DEBUG_PRINTF(...) do { printf(__VA_ARGS__); } while(0)
Wolfgang Betz 1:f90318e0923b 25 #else
Wolfgang Betz 1:f90318e0923b 26 # define DEBUG_PRINTF(...) {}
Wolfgang Betz 1:f90318e0923b 27 #endif
Wolfgang Betz 1:f90318e0923b 28
Wolfgang Betz 1:f90318e0923b 29 typedef enum {
Wolfgang Betz 1:f90318e0923b 30 I2S_TRANSFER_TYPE_TX = 1,
Wolfgang Betz 1:f90318e0923b 31 I2S_TRANSFER_TYPE_RX = 2,
Wolfgang Betz 1:f90318e0923b 32 I2S_TRANSFER_TYPE_TXRX = 3,
Wolfgang Betz 1:f90318e0923b 33 } transfer_type_t;
Wolfgang Betz 1:f90318e0923b 34
Wolfgang Betz 1:f90318e0923b 35 typedef struct {
Wolfgang Betz 1:f90318e0923b 36 DMA_HandleTypeDef tx_dma_handle;
Wolfgang Betz 1:f90318e0923b 37 DMA_HandleTypeDef rx_dma_handle;
Wolfgang Betz 1:f90318e0923b 38 } dma_handles_t;
Wolfgang Betz 1:f90318e0923b 39
Wolfgang Betz 1:f90318e0923b 40 #define I2S_NUM (5) // betzw: this approach wastes quite a bit of memory - TO BE IMPROVED!?!?
Wolfgang Betz 1:f90318e0923b 41
Wolfgang Betz 1:f90318e0923b 42 static I2S_HandleTypeDef I2sHandle[I2S_NUM];
Wolfgang Betz 1:f90318e0923b 43 static DMA_HandleTypeDef DMaHandles[I2S_NUM][NUM_OF_DIRECTIONS];
Wolfgang Betz 1:f90318e0923b 44
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;
Davide Aliprandi 4:21603d68bcf7 329 PeriphClkInitStruct.PLLI2S.PLLI2SN = 271; // betzw: use values which are suggested in Table 91 of the
Davide Aliprandi 4:21603d68bcf7 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 8:561d7ee70ef6 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 1:f90318e0923b 405 // betzw - TODO: what about 'PLLI2S'?!?
Wolfgang Betz 1:f90318e0923b 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 1:f90318e0923b 633 // adjust buffer positions (betzw - TODO: to be checked for DMA transfers!!!)
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 1:f90318e0923b 712 printf("betzw(%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 1:f90318e0923b 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 14:0060a9850c5f 788 /** Computes the two-div-plus-odd factor of a given I2S objects
Wolfgang Betz 14:0060a9850c5f 789 * on a desired frequency.
Wolfgang Betz 9:c4c2240e06d6 790 *
Wolfgang Betz 9:c4c2240e06d6 791 * @param dev_i2s reference to the I2S object.
Wolfgang Betz 14:0060a9850c5f 792 * @param frequency the desired frequency.
Wolfgang Betz 14:0060a9850c5f 793 * @return the computed two-div-plus-odd factor.
Wolfgang Betz 9:c4c2240e06d6 794 */
Wolfgang Betz 14:0060a9850c5f 795 static float i2s_compute_magic_factor(i2s_t *dev_i2s, float frequency)
Wolfgang Betz 9:c4c2240e06d6 796 {
Wolfgang Betz 14:0060a9850c5f 797 float i2sclk;
Wolfgang Betz 14:0060a9850c5f 798 I2S_HandleTypeDef *hi2s;
Wolfgang Betz 14:0060a9850c5f 799
Wolfgang Betz 14:0060a9850c5f 800 /* Get the I2S handle. */
Wolfgang Betz 14:0060a9850c5f 801 hi2s = i2s_get_handle(dev_i2s);
Wolfgang Betz 14:0060a9850c5f 802
Wolfgang Betz 14:0060a9850c5f 803 /* Get I2S source Clock frequency. */
Wolfgang Betz 14:0060a9850c5f 804 i2sclk = (float)I2S_GetInputClock(hi2s);
Wolfgang Betz 14:0060a9850c5f 805 /* Compute the I2S frequencies. */
Wolfgang Betz 14:0060a9850c5f 806 float format_factor = (float)(hi2s->Init.DataFormat == I2S_DATAFORMAT_16B ? 16 : 32);
Wolfgang Betz 14:0060a9850c5f 807 float mclk_factor = (float)(hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE ? (format_factor == 16 ? 8 : 4) : 1);
Wolfgang Betz 14:0060a9850c5f 808 float mf = i2sclk / ((float)2.0 * format_factor * frequency * mclk_factor);
Wolfgang Betz 14:0060a9850c5f 809
Wolfgang Betz 14:0060a9850c5f 810 return mf;
Wolfgang Betz 14:0060a9850c5f 811 }
Wolfgang Betz 14:0060a9850c5f 812
Wolfgang Betz 14:0060a9850c5f 813 /** Computing the frequency of an I2S peripheral given a certain
Wolfgang Betz 14:0060a9850c5f 814 * two-div-plus-odd factor.
Wolfgang Betz 14:0060a9850c5f 815 *
Wolfgang Betz 14:0060a9850c5f 816 * @param obj reference to an i2s_t structure.
Wolfgang Betz 14:0060a9850c5f 817 * @param magic_factor the given two-div-plus-odd factor.
Wolfgang Betz 14:0060a9850c5f 818 * @return the computed frequency.
Wolfgang Betz 14:0060a9850c5f 819 */
Wolfgang Betz 14:0060a9850c5f 820 static uint32_t i2s_compute_frequency(i2s_t *obj, int32_t magic_factor)
Wolfgang Betz 14:0060a9850c5f 821 {
Wolfgang Betz 14:0060a9850c5f 822 float i2sclk;
Wolfgang Betz 14:0060a9850c5f 823 I2S_HandleTypeDef *hi2s;
Wolfgang Betz 14:0060a9850c5f 824
Wolfgang Betz 14:0060a9850c5f 825 /* Getting the I2S handle. */
Wolfgang Betz 14:0060a9850c5f 826 hi2s = i2s_get_handle(obj);
Wolfgang Betz 14:0060a9850c5f 827
Wolfgang Betz 14:0060a9850c5f 828 /* Getting the I2S source clock frequency. */
Wolfgang Betz 14:0060a9850c5f 829 i2sclk = (float)I2S_GetInputClock(hi2s);
Wolfgang Betz 14:0060a9850c5f 830
Wolfgang Betz 14:0060a9850c5f 831 /* Computing the frequencies. */
Wolfgang Betz 14:0060a9850c5f 832 float format_factor = (float)(hi2s->Init.DataFormat == I2S_DATAFORMAT_16B ? 16 : 32);
Wolfgang Betz 14:0060a9850c5f 833 float mclk_factor = (float)(hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE ? (format_factor == 16 ? 8 : 4) : 1);
Wolfgang Betz 14:0060a9850c5f 834 float f = i2sclk / ((float)2.0 * format_factor * (float)magic_factor * mclk_factor);
Wolfgang Betz 14:0060a9850c5f 835
Wolfgang Betz 14:0060a9850c5f 836 //printf("f = %d / (2 * %d * %f * %d) = %f\r\n", i2sclk, format_factor, magic_factor, mclk_factor, f);
Wolfgang Betz 14:0060a9850c5f 837
Wolfgang Betz 14:0060a9850c5f 838 /* Returning the computed frequency. */
Wolfgang Betz 14:0060a9850c5f 839 return (uint32_t)f;
Wolfgang Betz 14:0060a9850c5f 840 }
Wolfgang Betz 14:0060a9850c5f 841
Wolfgang Betz 14:0060a9850c5f 842 static uint32_t i2s_compute_closest_frequency(i2s_t *dev_i2s, uint32_t target_freq) {
Wolfgang Betz 9:c4c2240e06d6 843 uint32_t i2sclk = 0U, i2sdiv = 2U, i2sodd = 0U, packetlength = 1U, tmp = 0U;
Wolfgang Betz 9:c4c2240e06d6 844 I2S_HandleTypeDef *hi2s;
Wolfgang Betz 9:c4c2240e06d6 845
Wolfgang Betz 9:c4c2240e06d6 846 /* Get the I2S handle. */
Wolfgang Betz 9:c4c2240e06d6 847 hi2s = i2s_get_handle(dev_i2s);
Wolfgang Betz 9:c4c2240e06d6 848
Wolfgang Betz 9:c4c2240e06d6 849 /* Check the frame length (For the Prescaler computing). */
Wolfgang Betz 9:c4c2240e06d6 850 if (hi2s->Init.DataFormat != I2S_DATAFORMAT_16B)
Wolfgang Betz 9:c4c2240e06d6 851 {
Wolfgang Betz 9:c4c2240e06d6 852 /* Packet length is 32 bits */
Wolfgang Betz 9:c4c2240e06d6 853 packetlength = 2U;
Wolfgang Betz 9:c4c2240e06d6 854 }
Wolfgang Betz 9:c4c2240e06d6 855
Wolfgang Betz 9:c4c2240e06d6 856 /* Get I2S source Clock frequency. */
Wolfgang Betz 9:c4c2240e06d6 857 i2sclk = I2S_GetInputClock(hi2s);
Wolfgang Betz 9:c4c2240e06d6 858
Wolfgang Betz 9:c4c2240e06d6 859 /* Compute the Real divider depending on the MCLK output state, with a floating point. */
Wolfgang Betz 9:c4c2240e06d6 860 if (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE)
Wolfgang Betz 9:c4c2240e06d6 861 {
Wolfgang Betz 9:c4c2240e06d6 862 /* MCLK output is enabled. */
Wolfgang Betz 14:0060a9850c5f 863 tmp = (uint32_t)(((((i2sclk / 256U) * 10U) / target_freq)) + 5U);
Wolfgang Betz 9:c4c2240e06d6 864 }
Wolfgang Betz 9:c4c2240e06d6 865 else
Wolfgang Betz 9:c4c2240e06d6 866 {
Wolfgang Betz 9:c4c2240e06d6 867 /* MCLK output is disabled. */
Wolfgang Betz 14:0060a9850c5f 868 tmp = (uint32_t)(((((i2sclk / (32U * packetlength)) * 10U) / target_freq)) + 5U);
Wolfgang Betz 9:c4c2240e06d6 869 }
Wolfgang Betz 9:c4c2240e06d6 870
Wolfgang Betz 9:c4c2240e06d6 871 /* Remove the flatting point. */
Wolfgang Betz 9:c4c2240e06d6 872 tmp = tmp / 10U;
Wolfgang Betz 9:c4c2240e06d6 873
Wolfgang Betz 9:c4c2240e06d6 874 /* Check the parity of the divider. */
Wolfgang Betz 9:c4c2240e06d6 875 i2sodd = (uint32_t)(tmp & (uint32_t)1U);
Wolfgang Betz 9:c4c2240e06d6 876
Wolfgang Betz 9:c4c2240e06d6 877 /* Compute the i2sdiv prescaler. */
Wolfgang Betz 9:c4c2240e06d6 878 i2sdiv = (uint32_t)((tmp - i2sodd) / 2U);
Wolfgang Betz 9:c4c2240e06d6 879
Wolfgang Betz 9:c4c2240e06d6 880 /* Test if the divider is 1 or 0 or greater than 0xFF. */
Wolfgang Betz 9:c4c2240e06d6 881 if ((i2sdiv < 2U) || (i2sdiv > 0xFFU))
Wolfgang Betz 9:c4c2240e06d6 882 {
Wolfgang Betz 9:c4c2240e06d6 883 /* Set the default values. */
Wolfgang Betz 9:c4c2240e06d6 884 i2sdiv = 2U;
Wolfgang Betz 9:c4c2240e06d6 885 i2sodd = 0U;
Wolfgang Betz 9:c4c2240e06d6 886 }
Wolfgang Betz 9:c4c2240e06d6 887
Wolfgang Betz 9:c4c2240e06d6 888 /* Compute the I2S frequencies. */
Wolfgang Betz 9:c4c2240e06d6 889 uint32_t format_factor = (hi2s->Init.DataFormat == I2S_DATAFORMAT_16B ? 16 : 32);
Wolfgang Betz 9:c4c2240e06d6 890 uint32_t mclk_factor = (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE ? (format_factor == 16 ? 8 : 4) : 1);
Wolfgang Betz 13:fa1b24df9025 891 uint32_t f = (uint32_t)((float)i2sclk / (float)(2 * format_factor * ((2 * i2sdiv) + i2sodd) * mclk_factor));
Wolfgang Betz 9:c4c2240e06d6 892
Wolfgang Betz 9:c4c2240e06d6 893 return f;
Wolfgang Betz 9:c4c2240e06d6 894 }
Wolfgang Betz 9:c4c2240e06d6 895
Wolfgang Betz 14:0060a9850c5f 896 /** Compute the real frequency of a given I2S objects.
Wolfgang Betz 9:c4c2240e06d6 897 *
Wolfgang Betz 9:c4c2240e06d6 898 * @param dev_i2s reference to the I2S object.
Wolfgang Betz 14:0060a9850c5f 899 * @return the computed real frequency.
Wolfgang Betz 9:c4c2240e06d6 900 */
Wolfgang Betz 14:0060a9850c5f 901 static inline uint32_t i2s_compute_real_frequency(i2s_t *dev_i2s)
Davide Aliprandi 4:21603d68bcf7 902 {
Wolfgang Betz 9:c4c2240e06d6 903 I2S_HandleTypeDef *hi2s;
Wolfgang Betz 9:c4c2240e06d6 904
Wolfgang Betz 9:c4c2240e06d6 905 /* Get the I2S handle. */
Wolfgang Betz 9:c4c2240e06d6 906 hi2s = i2s_get_handle(dev_i2s);
Wolfgang Betz 9:c4c2240e06d6 907
Wolfgang Betz 14:0060a9850c5f 908 return i2s_compute_closest_frequency(dev_i2s, hi2s->Init.AudioFreq);
Wolfgang Betz 9:c4c2240e06d6 909 }
Wolfgang Betz 9:c4c2240e06d6 910
Wolfgang Betz 14:0060a9850c5f 911 /** Computing the harmonized frequencies of two I2S peripherals.
Wolfgang Betz 14:0060a9850c5f 912 *
Wolfgang Betz 14:0060a9850c5f 913 * @param[in] i2s_t_l reference to the i2s_t structure with the lower frequency.
Wolfgang Betz 14:0060a9850c5f 914 * @param[in] i2s_t_h reference to the i2s_t structure with the higher frequency.
Wolfgang Betz 14:0060a9850c5f 915 * @param[in|out] ptr_low_freq pointer to lower frequency.
Wolfgang Betz 14:0060a9850c5f 916 * @param[in|out] ptr_high_freq pointer to higher frequency.
Wolfgang Betz 14:0060a9850c5f 917 * @param[in] real_low_freq real higher frequency.
Wolfgang Betz 14:0060a9850c5f 918 * @param[in] real_high_freq real lower frequency.
Wolfgang Betz 14:0060a9850c5f 919 * @return "0" if the frequencies have been harmonized, "-1" otherwise.
Wolfgang Betz 14:0060a9850c5f 920 */
Wolfgang Betz 14:0060a9850c5f 921 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, uint32_t real_low_freq, uint32_t real_high_freq)
Wolfgang Betz 14:0060a9850c5f 922 {
Wolfgang Betz 14:0060a9850c5f 923 /* Returning if the two real frequencies are already multiple one of the other. */
Wolfgang Betz 14:0060a9850c5f 924 float division = (float)real_high_freq / (float)real_low_freq;
Wolfgang Betz 14:0060a9850c5f 925 float rest = (division - floorf(division));
Wolfgang Betz 14:0060a9850c5f 926 MBED_ASSERT(rest >= 0);
Wolfgang Betz 14:0060a9850c5f 927 if (rest == 0) {
Wolfgang Betz 14:0060a9850c5f 928 return 0;
Wolfgang Betz 14:0060a9850c5f 929 }
Wolfgang Betz 14:0060a9850c5f 930
Wolfgang Betz 14:0060a9850c5f 931 /* Computing the harmonized frequencies so that they are multiple one of the
Wolfgang Betz 14:0060a9850c5f 932 other by a certain factor. */
Wolfgang Betz 14:0060a9850c5f 933 uint32_t multiplier = ((rest >= 0.5) ? ((uint32_t)division + 1) : (uint32_t)division);
Wolfgang Betz 14:0060a9850c5f 934 float magic_factor = i2s_compute_magic_factor(i2s_t_l, (float)real_high_freq / (float)multiplier);
Wolfgang Betz 14:0060a9850c5f 935 uint32_t magic_factor_floor = (uint32_t)floorf(magic_factor);
Wolfgang Betz 14:0060a9850c5f 936
Wolfgang Betz 14:0060a9850c5f 937 if(real_high_freq > (*ptr_high_freq)) {
Wolfgang Betz 14:0060a9850c5f 938 if(magic_factor_floor <= 1) {
Wolfgang Betz 14:0060a9850c5f 939 return -1;
Wolfgang Betz 14:0060a9850c5f 940 }
Wolfgang Betz 14:0060a9850c5f 941 }
Wolfgang Betz 14:0060a9850c5f 942
Wolfgang Betz 14:0060a9850c5f 943 uint32_t new_low_freq = i2s_compute_frequency(i2s_t_l, magic_factor_floor + ((real_high_freq > (*ptr_high_freq)) ? 1 : -1));
Wolfgang Betz 14:0060a9850c5f 944 uint32_t new_high_freq = multiplier * new_low_freq; // betzw: potentially this high frequency might not be achievable!
Wolfgang Betz 14:0060a9850c5f 945 uint32_t real_new_high_freq = i2s_compute_closest_frequency(i2s_t_h, new_high_freq);
Wolfgang Betz 14:0060a9850c5f 946
Wolfgang Betz 14:0060a9850c5f 947 if(new_high_freq != real_new_high_freq) {
Wolfgang Betz 14:0060a9850c5f 948 return -1;
Wolfgang Betz 14:0060a9850c5f 949 }
Wolfgang Betz 14:0060a9850c5f 950
Wolfgang Betz 14:0060a9850c5f 951 *ptr_low_freq = new_low_freq;
Wolfgang Betz 14:0060a9850c5f 952 *ptr_high_freq = new_high_freq;
Wolfgang Betz 14:0060a9850c5f 953
Wolfgang Betz 14:0060a9850c5f 954 return 0;
Wolfgang Betz 14:0060a9850c5f 955 }
Wolfgang Betz 14:0060a9850c5f 956
Wolfgang Betz 14:0060a9850c5f 957 #if 0 // betzw
Wolfgang Betz 9:c4c2240e06d6 958 /** Compute the desired frequency of a given I2S objects, given the magic
Wolfgang Betz 9:c4c2240e06d6 959 * factor.
Wolfgang Betz 9:c4c2240e06d6 960 *
Wolfgang Betz 9:c4c2240e06d6 961 * @param dev_i2s reference to the I2S object.
Wolfgang Betz 9:c4c2240e06d6 962 * @param mf the two-div-plus-odd factor.
Wolfgang Betz 9:c4c2240e06d6 963 * @return the computed desired frequency.
Wolfgang Betz 9:c4c2240e06d6 964 */
Wolfgang Betz 9:c4c2240e06d6 965 static float i2s_compute_desired_frequency(i2s_t *dev_i2s, float mf)
Wolfgang Betz 9:c4c2240e06d6 966 {
Wolfgang Betz 9:c4c2240e06d6 967 uint32_t i2sclk = 0U;
Wolfgang Betz 9:c4c2240e06d6 968 I2S_HandleTypeDef *hi2s;
Wolfgang Betz 9:c4c2240e06d6 969
Wolfgang Betz 9:c4c2240e06d6 970 /* Get the I2S handle. */
Wolfgang Betz 9:c4c2240e06d6 971 hi2s = i2s_get_handle(dev_i2s);
Wolfgang Betz 9:c4c2240e06d6 972
Wolfgang Betz 9:c4c2240e06d6 973 /* Get I2S source Clock frequency. */
Wolfgang Betz 9:c4c2240e06d6 974 i2sclk = I2S_GetInputClock(hi2s);
Wolfgang Betz 9:c4c2240e06d6 975
Wolfgang Betz 9:c4c2240e06d6 976 /* Compute the I2S frequencies. */
Wolfgang Betz 9:c4c2240e06d6 977 uint32_t format_factor = (hi2s->Init.DataFormat == I2S_DATAFORMAT_16B ? 16 : 32);
Wolfgang Betz 9:c4c2240e06d6 978 uint32_t mclk_factor = (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE ? (format_factor == 16 ? 8 : 4) : 1);
Wolfgang Betz 9:c4c2240e06d6 979 float f = i2sclk / (2 * format_factor * mf * mclk_factor);
Wolfgang Betz 9:c4c2240e06d6 980
Wolfgang Betz 9:c4c2240e06d6 981 return f;
Wolfgang Betz 9:c4c2240e06d6 982 }
Wolfgang Betz 9:c4c2240e06d6 983
Wolfgang Betz 13:fa1b24df9025 984 static uint32_t i2s_compute_closest_frequency(i2s_t *dev_i2s, uint32_t target_freq, uint8_t *mclk_enabled) {
Wolfgang Betz 13:fa1b24df9025 985 uint32_t i2sclk = 0U, i2sdiv = 2U, i2sodd = 0U, packetlength = 1U, tmp = 0U;
Wolfgang Betz 13:fa1b24df9025 986 uint32_t f1, f2;
Wolfgang Betz 13:fa1b24df9025 987 I2S_HandleTypeDef *hi2s;
Wolfgang Betz 13:fa1b24df9025 988
Wolfgang Betz 13:fa1b24df9025 989 /* init mclk_enabled */
Wolfgang Betz 13:fa1b24df9025 990 *mclk_enabled = 0;
Wolfgang Betz 13:fa1b24df9025 991
Wolfgang Betz 13:fa1b24df9025 992 /* Get the I2S handle. */
Wolfgang Betz 13:fa1b24df9025 993 hi2s = i2s_get_handle(dev_i2s);
Wolfgang Betz 13:fa1b24df9025 994
Wolfgang Betz 13:fa1b24df9025 995 /* Check the frame length (For the Prescaler computing). */
Wolfgang Betz 13:fa1b24df9025 996 if (hi2s->Init.DataFormat != I2S_DATAFORMAT_16B)
Wolfgang Betz 13:fa1b24df9025 997 {
Wolfgang Betz 13:fa1b24df9025 998 /* Packet length is 32 bits */
Wolfgang Betz 13:fa1b24df9025 999 packetlength = 2U;
Wolfgang Betz 13:fa1b24df9025 1000 }
Wolfgang Betz 13:fa1b24df9025 1001
Wolfgang Betz 13:fa1b24df9025 1002 /* Get I2S source Clock frequency. */
Wolfgang Betz 13:fa1b24df9025 1003 i2sclk = I2S_GetInputClock(hi2s);
Wolfgang Betz 13:fa1b24df9025 1004
Wolfgang Betz 13:fa1b24df9025 1005 if(hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_DISABLE) { // betzw: one more degree of freedom, i.e. mclk can be enabled
Wolfgang Betz 13:fa1b24df9025 1006 /* MCLK output is disabled. */
Wolfgang Betz 13:fa1b24df9025 1007 tmp = (uint32_t)(((((i2sclk / (32U * packetlength)) * 10U) / target_freq)) + 5U);
Wolfgang Betz 13:fa1b24df9025 1008
Wolfgang Betz 13:fa1b24df9025 1009 /* Remove the flatting point. */
Wolfgang Betz 13:fa1b24df9025 1010 tmp = tmp / 10U;
Wolfgang Betz 13:fa1b24df9025 1011
Wolfgang Betz 13:fa1b24df9025 1012 /* Check the parity of the divider. */
Wolfgang Betz 13:fa1b24df9025 1013 i2sodd = (uint32_t)(tmp & (uint32_t)1U);
Wolfgang Betz 13:fa1b24df9025 1014
Wolfgang Betz 13:fa1b24df9025 1015 /* Compute the i2sdiv prescaler. */
Wolfgang Betz 13:fa1b24df9025 1016 i2sdiv = (uint32_t)((tmp - i2sodd) / 2U);
Wolfgang Betz 13:fa1b24df9025 1017
Wolfgang Betz 13:fa1b24df9025 1018 /* Test if the divider is 1 or 0 or greater than 0xFF. */
Wolfgang Betz 13:fa1b24df9025 1019 if ((i2sdiv < 2U) || (i2sdiv > 0xFFU))
Wolfgang Betz 13:fa1b24df9025 1020 {
Wolfgang Betz 13:fa1b24df9025 1021 /* Set the default values. */
Wolfgang Betz 13:fa1b24df9025 1022 i2sdiv = 2U;
Wolfgang Betz 13:fa1b24df9025 1023 i2sodd = 0U;
Wolfgang Betz 13:fa1b24df9025 1024 }
Wolfgang Betz 13:fa1b24df9025 1025
Wolfgang Betz 13:fa1b24df9025 1026 /* Compute the I2S frequency */
Wolfgang Betz 13:fa1b24df9025 1027 uint32_t format_factor = (hi2s->Init.DataFormat == I2S_DATAFORMAT_16B ? 16 : 32);
Wolfgang Betz 13:fa1b24df9025 1028 uint32_t mclk_factor = 1;
Wolfgang Betz 13:fa1b24df9025 1029 f1 = (uint32_t)((float)i2sclk / (float)(2 * format_factor * ((2 * i2sdiv) + i2sodd) * mclk_factor));
Wolfgang Betz 13:fa1b24df9025 1030
Wolfgang Betz 13:fa1b24df9025 1031 if(f1 == target_freq) return f1;
Wolfgang Betz 13:fa1b24df9025 1032
Wolfgang Betz 13:fa1b24df9025 1033 /* set mclk_enabled */
Wolfgang Betz 13:fa1b24df9025 1034 *mclk_enabled = 1;
Wolfgang Betz 13:fa1b24df9025 1035 }
Wolfgang Betz 13:fa1b24df9025 1036
Wolfgang Betz 13:fa1b24df9025 1037 /* Set mclk enabled */
Wolfgang Betz 13:fa1b24df9025 1038 hi2s->Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
Wolfgang Betz 13:fa1b24df9025 1039
Wolfgang Betz 13:fa1b24df9025 1040 /* MCLK output is enabled. */
Wolfgang Betz 13:fa1b24df9025 1041 tmp = (uint32_t)(((((i2sclk / 256U) * 10U) / target_freq)) + 5U);
Wolfgang Betz 13:fa1b24df9025 1042
Wolfgang Betz 13:fa1b24df9025 1043 /* Remove the flatting point. */
Wolfgang Betz 13:fa1b24df9025 1044 tmp = tmp / 10U;
Wolfgang Betz 13:fa1b24df9025 1045
Wolfgang Betz 13:fa1b24df9025 1046 /* Check the parity of the divider. */
Wolfgang Betz 13:fa1b24df9025 1047 i2sodd = (uint32_t)(tmp & (uint32_t)1U);
Wolfgang Betz 13:fa1b24df9025 1048
Wolfgang Betz 13:fa1b24df9025 1049 /* Compute the i2sdiv prescaler. */
Wolfgang Betz 13:fa1b24df9025 1050 i2sdiv = (uint32_t)((tmp - i2sodd) / 2U);
Wolfgang Betz 13:fa1b24df9025 1051
Wolfgang Betz 13:fa1b24df9025 1052 /* Test if the divider is 1 or 0 or greater than 0xFF. */
Wolfgang Betz 13:fa1b24df9025 1053 if ((i2sdiv < 2U) || (i2sdiv > 0xFFU))
Wolfgang Betz 13:fa1b24df9025 1054 {
Wolfgang Betz 13:fa1b24df9025 1055 /* Set the default values. */
Wolfgang Betz 13:fa1b24df9025 1056 i2sdiv = 2U;
Wolfgang Betz 13:fa1b24df9025 1057 i2sodd = 0U;
Wolfgang Betz 13:fa1b24df9025 1058 }
Wolfgang Betz 13:fa1b24df9025 1059
Wolfgang Betz 13:fa1b24df9025 1060 /* Compute the I2S frequency */
Wolfgang Betz 13:fa1b24df9025 1061 uint32_t format_factor = (hi2s->Init.DataFormat == I2S_DATAFORMAT_16B ? 16 : 32);
Wolfgang Betz 13:fa1b24df9025 1062 uint32_t mclk_factor = (format_factor == 16 ? 8 : 4);
Wolfgang Betz 13:fa1b24df9025 1063
Wolfgang Betz 13:fa1b24df9025 1064 f2 = (uint32_t)((float)i2sclk / (float)(2 * format_factor * ((2 * i2sdiv) + i2sodd) * mclk_factor));
Wolfgang Betz 13:fa1b24df9025 1065 if(f2 == target_freq) return f2;
Wolfgang Betz 13:fa1b24df9025 1066
Wolfgang Betz 13:fa1b24df9025 1067 /* return closest result */
Wolfgang Betz 13:fa1b24df9025 1068 uint32_t diff1, diff2;
Wolfgang Betz 13:fa1b24df9025 1069
Wolfgang Betz 13:fa1b24df9025 1070 if(*mclk_enabled != 0) {
Wolfgang Betz 13:fa1b24df9025 1071 if(target_freq > f1) diff1 = target_freq - f1;
Wolfgang Betz 13:fa1b24df9025 1072 else diff1 = f1 - target_freq;
Wolfgang Betz 13:fa1b24df9025 1073 } else { // no 'f1' available
Wolfgang Betz 13:fa1b24df9025 1074 return f2;
Wolfgang Betz 13:fa1b24df9025 1075 }
Wolfgang Betz 13:fa1b24df9025 1076
Wolfgang Betz 13:fa1b24df9025 1077 if(target_freq > f2) diff2 = target_freq - f2;
Wolfgang Betz 13:fa1b24df9025 1078 else diff2 = f2 - target_freq;
Wolfgang Betz 13:fa1b24df9025 1079
Wolfgang Betz 13:fa1b24df9025 1080 if(diff1 < diff2) {
Wolfgang Betz 13:fa1b24df9025 1081 /* reset mclk */
Wolfgang Betz 13:fa1b24df9025 1082 hi2s->Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
Wolfgang Betz 13:fa1b24df9025 1083
Wolfgang Betz 13:fa1b24df9025 1084 /* reset mclk_enabled */
Wolfgang Betz 13:fa1b24df9025 1085 *mclk_enabled = 0;
Wolfgang Betz 13:fa1b24df9025 1086
Wolfgang Betz 13:fa1b24df9025 1087 return f1;
Wolfgang Betz 13:fa1b24df9025 1088 }
Wolfgang Betz 13:fa1b24df9025 1089
Wolfgang Betz 13:fa1b24df9025 1090 return f2;
Wolfgang Betz 13:fa1b24df9025 1091 }
Wolfgang Betz 13:fa1b24df9025 1092
Wolfgang Betz 13:fa1b24df9025 1093 static inline void i2s_reset_mclk(i2s_t *dev_i2s) {
Wolfgang Betz 13:fa1b24df9025 1094 I2S_HandleTypeDef *hi2s;
Wolfgang Betz 13:fa1b24df9025 1095
Wolfgang Betz 13:fa1b24df9025 1096 /* Get the I2S handle. */
Wolfgang Betz 13:fa1b24df9025 1097 hi2s = i2s_get_handle(dev_i2s);
Wolfgang Betz 13:fa1b24df9025 1098
Wolfgang Betz 13:fa1b24df9025 1099 /* rest mclk enabled */
Wolfgang Betz 13:fa1b24df9025 1100 hi2s->Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
Wolfgang Betz 13:fa1b24df9025 1101 }
Wolfgang Betz 14:0060a9850c5f 1102 #endif // 0
Wolfgang Betz 13:fa1b24df9025 1103
Wolfgang Betz 9:c4c2240e06d6 1104 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 1105 {
Wolfgang Betz 14:0060a9850c5f 1106 /* Returning if the two set frequencies are not multiple one of the other. */
Wolfgang Betz 14:0060a9850c5f 1107 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 1108 return -1;
Wolfgang Betz 14:0060a9850c5f 1109 }
Wolfgang Betz 9:c4c2240e06d6 1110
Wolfgang Betz 14:0060a9850c5f 1111 /* Compute the real frequencies. */
Wolfgang Betz 14:0060a9850c5f 1112 uint32_t real_f1 = i2s_compute_real_frequency(dev_i2s_1);
Wolfgang Betz 14:0060a9850c5f 1113 uint32_t real_f2 = i2s_compute_real_frequency(dev_i2s_2);
Wolfgang Betz 14:0060a9850c5f 1114
Wolfgang Betz 14:0060a9850c5f 1115 /* Returning if the two real frequencies are already equal. */
Wolfgang Betz 14:0060a9850c5f 1116 if(real_f1 == real_f2) {
Wolfgang Betz 10:1a612c2e4a85 1117 return 0;
Wolfgang Betz 10:1a612c2e4a85 1118 }
Wolfgang Betz 10:1a612c2e4a85 1119
Wolfgang Betz 14:0060a9850c5f 1120 /* Computing the harmonized frequencies. */
Wolfgang Betz 14:0060a9850c5f 1121 if(real_f1 < real_f2) {
Wolfgang Betz 14:0060a9850c5f 1122 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 1123 } else {
Wolfgang Betz 14:0060a9850c5f 1124 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 1125 }
Wolfgang Betz 14:0060a9850c5f 1126
Wolfgang Betz 14:0060a9850c5f 1127 #if 0 // betzw
Wolfgang Betz 9:c4c2240e06d6 1128 //printf("REAL: %f %f\r\n", f1, f2);
Wolfgang Betz 9:c4c2240e06d6 1129
Wolfgang Betz 9:c4c2240e06d6 1130 /* Compute the desired frequencies so that they are multiple one of the
Wolfgang Betz 9:c4c2240e06d6 1131 other. */
Wolfgang Betz 13:fa1b24df9025 1132
Wolfgang Betz 13:fa1b24df9025 1133 /* figure out multiply value and i2s to adapt and it's target freq */
Wolfgang Betz 13:fa1b24df9025 1134 uint32_t multiplier;
Wolfgang Betz 13:fa1b24df9025 1135 i2s_t *target_dev;
Wolfgang Betz 13:fa1b24df9025 1136 uint32_t target_freq;
Wolfgang Betz 13:fa1b24df9025 1137
Wolfgang Betz 13:fa1b24df9025 1138 if(f1 > f2) {
Wolfgang Betz 13:fa1b24df9025 1139 multiplier = (uint32_t)((float)f1 / (float)f2);
Wolfgang Betz 13:fa1b24df9025 1140 target_freq = f2 * multiplier;
Wolfgang Betz 13:fa1b24df9025 1141 target_dev = dev_i2s_1;
Wolfgang Betz 13:fa1b24df9025 1142 } else {
Wolfgang Betz 13:fa1b24df9025 1143 multiplier = (uint32_t)((float)f2 / (float)f1);
Wolfgang Betz 13:fa1b24df9025 1144 target_freq = f1 * multiplier;
Wolfgang Betz 13:fa1b24df9025 1145 target_dev = dev_i2s_2;
Wolfgang Betz 13:fa1b24df9025 1146 }
Wolfgang Betz 13:fa1b24df9025 1147
Wolfgang Betz 13:fa1b24df9025 1148 if(multiplier == 1) { // nothing that can be reasonably done
Wolfgang Betz 13:fa1b24df9025 1149 return -1;
Wolfgang Betz 13:fa1b24df9025 1150 }
Wolfgang Betz 13:fa1b24df9025 1151
Wolfgang Betz 13:fa1b24df9025 1152 /* compute closest freq */
Wolfgang Betz 13:fa1b24df9025 1153 uint8_t mclk_enabled = 0;
Wolfgang Betz 13:fa1b24df9025 1154 uint32_t closest_freq = i2s_compute_closest_frequency(target_dev, target_freq, &mclk_enabled);
Wolfgang Betz 13:fa1b24df9025 1155
Wolfgang Betz 13:fa1b24df9025 1156 if(closest_freq == target_freq) {
Wolfgang Betz 13:fa1b24df9025 1157 if(target_dev == dev_i2s_1) {
Wolfgang Betz 14:0060a9850c5f 1158 /* Return the desired frequencies. */
Wolfgang Betz 14:0060a9850c5f 1159 *freq_i2s_1 = i2s_align_freq(closest_freq);
Wolfgang Betz 14:0060a9850c5f 1160 *freq_i2s_2 = i2s_align_freq(f2);
Wolfgang Betz 13:fa1b24df9025 1161 } else {
Wolfgang Betz 14:0060a9850c5f 1162 /* Return the desired frequencies. */
Wolfgang Betz 14:0060a9850c5f 1163 *freq_i2s_1 = i2s_align_freq(f1);
Wolfgang Betz 14:0060a9850c5f 1164 *freq_i2s_2 = i2s_align_freq(closest_freq);
Wolfgang Betz 13:fa1b24df9025 1165 }
Wolfgang Betz 13:fa1b24df9025 1166 return 0;
Wolfgang Betz 13:fa1b24df9025 1167 }
Wolfgang Betz 13:fa1b24df9025 1168
Wolfgang Betz 13:fa1b24df9025 1169 /* reset mclk */
Wolfgang Betz 13:fa1b24df9025 1170 if(mclk_enabled != 0) {
Wolfgang Betz 13:fa1b24df9025 1171 i2s_reset_mclk(target_dev);
Wolfgang Betz 13:fa1b24df9025 1172 }
Wolfgang Betz 13:fa1b24df9025 1173
Wolfgang Betz 13:fa1b24df9025 1174 /* try other way round */
Wolfgang Betz 13:fa1b24df9025 1175 if(target_dev == dev_i2s_1) {
Wolfgang Betz 13:fa1b24df9025 1176 target_dev = dev_i2s_2;
Wolfgang Betz 13:fa1b24df9025 1177 target_freq = (uint32_t)((float)f1 / (float)multiplier);
Wolfgang Betz 13:fa1b24df9025 1178 } else {
Wolfgang Betz 13:fa1b24df9025 1179 target_dev = dev_i2s_1;
Wolfgang Betz 13:fa1b24df9025 1180 target_freq = (uint32_t) ((float)f2 / (float)multiplier);
Wolfgang Betz 13:fa1b24df9025 1181 }
Wolfgang Betz 13:fa1b24df9025 1182
Wolfgang Betz 13:fa1b24df9025 1183 /* compute closest freq */
Wolfgang Betz 13:fa1b24df9025 1184 mclk_enabled = 0;
Wolfgang Betz 13:fa1b24df9025 1185 closest_freq = i2s_compute_closest_frequency(target_dev, target_freq, &mclk_enabled);
Wolfgang Betz 13:fa1b24df9025 1186
Wolfgang Betz 13:fa1b24df9025 1187 if(closest_freq == target_freq) {
Wolfgang Betz 13:fa1b24df9025 1188 if(target_dev == dev_i2s_1) {
Wolfgang Betz 14:0060a9850c5f 1189 /* Return the desired frequencies. */
Wolfgang Betz 14:0060a9850c5f 1190 *freq_i2s_1 = i2s_align_freq(closest_freq);
Wolfgang Betz 14:0060a9850c5f 1191 *freq_i2s_2 = i2s_align_freq(f2);
Wolfgang Betz 13:fa1b24df9025 1192 } else {
Wolfgang Betz 14:0060a9850c5f 1193 /* Return the desired frequencies. */
Wolfgang Betz 14:0060a9850c5f 1194 *freq_i2s_1 = i2s_align_freq(f1);
Wolfgang Betz 14:0060a9850c5f 1195 *freq_i2s_2 = i2s_align_freq(closest_freq);
Wolfgang Betz 13:fa1b24df9025 1196 }
Wolfgang Betz 13:fa1b24df9025 1197 return 0;
Wolfgang Betz 13:fa1b24df9025 1198 }
Wolfgang Betz 13:fa1b24df9025 1199
Wolfgang Betz 13:fa1b24df9025 1200 /* reset mclk */
Wolfgang Betz 13:fa1b24df9025 1201 if(mclk_enabled != 0) {
Wolfgang Betz 13:fa1b24df9025 1202 i2s_reset_mclk(target_dev);
Wolfgang Betz 13:fa1b24df9025 1203 }
Wolfgang Betz 13:fa1b24df9025 1204
Wolfgang Betz 13:fa1b24df9025 1205 /* return failure */
Wolfgang Betz 13:fa1b24df9025 1206 return -1;
Wolfgang Betz 13:fa1b24df9025 1207 #endif // 0
Davide Aliprandi 4:21603d68bcf7 1208 }
Davide Aliprandi 4:21603d68bcf7 1209
Wolfgang Betz 1:f90318e0923b 1210 #endif