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:
Thu Dec 22 11:10:10 2016 +0100
Revision:
9:c4c2240e06d6
Parent:
8:561d7ee70ef6
Child:
10:1a612c2e4a85
Separate platform-independent from platform-dependent code

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 9:c4c2240e06d6 788 /** Compute the real frequency of a given I2S objects.
Wolfgang Betz 9:c4c2240e06d6 789 *
Wolfgang Betz 9:c4c2240e06d6 790 * @param dev_i2s reference to the I2S object.
Wolfgang Betz 9:c4c2240e06d6 791 * @return the computed real frequency.
Wolfgang Betz 9:c4c2240e06d6 792 */
Wolfgang Betz 9:c4c2240e06d6 793 static float i2s_compute_real_frequency(i2s_t *dev_i2s)
Wolfgang Betz 9:c4c2240e06d6 794 {
Wolfgang Betz 9:c4c2240e06d6 795 uint32_t i2sclk = 0U, i2sdiv = 2U, i2sodd = 0U, packetlength = 1U, tmp = 0U;
Wolfgang Betz 9:c4c2240e06d6 796 I2S_HandleTypeDef *hi2s;
Wolfgang Betz 9:c4c2240e06d6 797
Wolfgang Betz 9:c4c2240e06d6 798 /* Get the I2S handle. */
Wolfgang Betz 9:c4c2240e06d6 799 hi2s = i2s_get_handle(dev_i2s);
Wolfgang Betz 9:c4c2240e06d6 800
Wolfgang Betz 9:c4c2240e06d6 801 /* Check the frame length (For the Prescaler computing). */
Wolfgang Betz 9:c4c2240e06d6 802 if (hi2s->Init.DataFormat != I2S_DATAFORMAT_16B)
Wolfgang Betz 9:c4c2240e06d6 803 {
Wolfgang Betz 9:c4c2240e06d6 804 /* Packet length is 32 bits */
Wolfgang Betz 9:c4c2240e06d6 805 packetlength = 2U;
Wolfgang Betz 9:c4c2240e06d6 806 }
Wolfgang Betz 9:c4c2240e06d6 807
Wolfgang Betz 9:c4c2240e06d6 808 /* Get I2S source Clock frequency. */
Wolfgang Betz 9:c4c2240e06d6 809 i2sclk = I2S_GetInputClock(hi2s);
Wolfgang Betz 9:c4c2240e06d6 810
Wolfgang Betz 9:c4c2240e06d6 811 /* Compute the Real divider depending on the MCLK output state, with a floating point. */
Wolfgang Betz 9:c4c2240e06d6 812 if (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE)
Wolfgang Betz 9:c4c2240e06d6 813 {
Wolfgang Betz 9:c4c2240e06d6 814 /* MCLK output is enabled. */
Wolfgang Betz 9:c4c2240e06d6 815 tmp = (uint32_t)(((((i2sclk / 256U) * 10U) / hi2s->Init.AudioFreq)) + 5U);
Wolfgang Betz 9:c4c2240e06d6 816 }
Wolfgang Betz 9:c4c2240e06d6 817 else
Wolfgang Betz 9:c4c2240e06d6 818 {
Wolfgang Betz 9:c4c2240e06d6 819 /* MCLK output is disabled. */
Wolfgang Betz 9:c4c2240e06d6 820 tmp = (uint32_t)(((((i2sclk / (32U * packetlength)) * 10U) / hi2s->Init.AudioFreq)) + 5U);
Wolfgang Betz 9:c4c2240e06d6 821 }
Wolfgang Betz 9:c4c2240e06d6 822
Wolfgang Betz 9:c4c2240e06d6 823 /* Remove the flatting point. */
Wolfgang Betz 9:c4c2240e06d6 824 tmp = tmp / 10U;
Wolfgang Betz 9:c4c2240e06d6 825
Wolfgang Betz 9:c4c2240e06d6 826 /* Check the parity of the divider. */
Wolfgang Betz 9:c4c2240e06d6 827 i2sodd = (uint32_t)(tmp & (uint32_t)1U);
Wolfgang Betz 9:c4c2240e06d6 828
Wolfgang Betz 9:c4c2240e06d6 829 /* Compute the i2sdiv prescaler. */
Wolfgang Betz 9:c4c2240e06d6 830 i2sdiv = (uint32_t)((tmp - i2sodd) / 2U);
Wolfgang Betz 9:c4c2240e06d6 831
Wolfgang Betz 9:c4c2240e06d6 832 /* Test if the divider is 1 or 0 or greater than 0xFF. */
Wolfgang Betz 9:c4c2240e06d6 833 if ((i2sdiv < 2U) || (i2sdiv > 0xFFU))
Wolfgang Betz 9:c4c2240e06d6 834 {
Wolfgang Betz 9:c4c2240e06d6 835 /* Set the default values. */
Wolfgang Betz 9:c4c2240e06d6 836 i2sdiv = 2U;
Wolfgang Betz 9:c4c2240e06d6 837 i2sodd = 0U;
Wolfgang Betz 9:c4c2240e06d6 838 }
Wolfgang Betz 9:c4c2240e06d6 839
Wolfgang Betz 9:c4c2240e06d6 840 /* Compute the I2S frequencies. */
Wolfgang Betz 9:c4c2240e06d6 841 uint32_t format_factor = (hi2s->Init.DataFormat == I2S_DATAFORMAT_16B ? 16 : 32);
Wolfgang Betz 9:c4c2240e06d6 842 uint32_t mclk_factor = (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE ? (format_factor == 16 ? 8 : 4) : 1);
Wolfgang Betz 9:c4c2240e06d6 843 float f = i2sclk / (2 * format_factor * ((2 * i2sdiv) + i2sodd) * mclk_factor);
Wolfgang Betz 9:c4c2240e06d6 844
Wolfgang Betz 9:c4c2240e06d6 845 return f;
Wolfgang Betz 9:c4c2240e06d6 846 }
Wolfgang Betz 9:c4c2240e06d6 847
Wolfgang Betz 9:c4c2240e06d6 848 /** Computes the two-div-plus-odd factor of a given I2S objects
Wolfgang Betz 9:c4c2240e06d6 849 * on a desired frequency.
Wolfgang Betz 9:c4c2240e06d6 850 *
Wolfgang Betz 9:c4c2240e06d6 851 * @param dev_i2s reference to the I2S object.
Wolfgang Betz 9:c4c2240e06d6 852 * @frequency the desired frequency.
Wolfgang Betz 9:c4c2240e06d6 853 * @return the computed two-div-plus-odd factor.
Wolfgang Betz 9:c4c2240e06d6 854 */
Wolfgang Betz 9:c4c2240e06d6 855 static float i2s_compute_magic_factor(i2s_t *dev_i2s, float f)
Davide Aliprandi 4:21603d68bcf7 856 {
Wolfgang Betz 9:c4c2240e06d6 857 uint32_t i2sclk = 0U;
Wolfgang Betz 9:c4c2240e06d6 858 I2S_HandleTypeDef *hi2s;
Wolfgang Betz 9:c4c2240e06d6 859
Wolfgang Betz 9:c4c2240e06d6 860 /* Get the I2S handle. */
Wolfgang Betz 9:c4c2240e06d6 861 hi2s = i2s_get_handle(dev_i2s);
Wolfgang Betz 9:c4c2240e06d6 862
Wolfgang Betz 9:c4c2240e06d6 863 /* Get I2S source Clock frequency. */
Wolfgang Betz 9:c4c2240e06d6 864 i2sclk = I2S_GetInputClock(hi2s);
Wolfgang Betz 9:c4c2240e06d6 865 /* Compute the I2S frequencies. */
Wolfgang Betz 9:c4c2240e06d6 866 uint32_t format_factor = (hi2s->Init.DataFormat == I2S_DATAFORMAT_16B ? 16 : 32);
Wolfgang Betz 9:c4c2240e06d6 867 uint32_t mclk_factor = (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE ? (format_factor == 16 ? 8 : 4) : 1);
Wolfgang Betz 9:c4c2240e06d6 868 float mf = i2sclk / (2 * format_factor * f * mclk_factor);
Wolfgang Betz 9:c4c2240e06d6 869
Wolfgang Betz 9:c4c2240e06d6 870 return mf;
Wolfgang Betz 9:c4c2240e06d6 871 }
Wolfgang Betz 9:c4c2240e06d6 872
Wolfgang Betz 9:c4c2240e06d6 873 /** Compute the desired frequency of a given I2S objects, given the magic
Wolfgang Betz 9:c4c2240e06d6 874 * factor.
Wolfgang Betz 9:c4c2240e06d6 875 *
Wolfgang Betz 9:c4c2240e06d6 876 * @param dev_i2s reference to the I2S object.
Wolfgang Betz 9:c4c2240e06d6 877 * @param mf the two-div-plus-odd factor.
Wolfgang Betz 9:c4c2240e06d6 878 * @return the computed desired frequency.
Wolfgang Betz 9:c4c2240e06d6 879 */
Wolfgang Betz 9:c4c2240e06d6 880 static float i2s_compute_desired_frequency(i2s_t *dev_i2s, float mf)
Wolfgang Betz 9:c4c2240e06d6 881 {
Wolfgang Betz 9:c4c2240e06d6 882 uint32_t i2sclk = 0U;
Wolfgang Betz 9:c4c2240e06d6 883 I2S_HandleTypeDef *hi2s;
Wolfgang Betz 9:c4c2240e06d6 884
Wolfgang Betz 9:c4c2240e06d6 885 /* Get the I2S handle. */
Wolfgang Betz 9:c4c2240e06d6 886 hi2s = i2s_get_handle(dev_i2s);
Wolfgang Betz 9:c4c2240e06d6 887
Wolfgang Betz 9:c4c2240e06d6 888 /* Get I2S source Clock frequency. */
Wolfgang Betz 9:c4c2240e06d6 889 i2sclk = I2S_GetInputClock(hi2s);
Wolfgang Betz 9:c4c2240e06d6 890
Wolfgang Betz 9:c4c2240e06d6 891 /* Compute the I2S frequencies. */
Wolfgang Betz 9:c4c2240e06d6 892 uint32_t format_factor = (hi2s->Init.DataFormat == I2S_DATAFORMAT_16B ? 16 : 32);
Wolfgang Betz 9:c4c2240e06d6 893 uint32_t mclk_factor = (hi2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE ? (format_factor == 16 ? 8 : 4) : 1);
Wolfgang Betz 9:c4c2240e06d6 894 float f = i2sclk / (2 * format_factor * mf * mclk_factor);
Wolfgang Betz 9:c4c2240e06d6 895
Wolfgang Betz 9:c4c2240e06d6 896 return f;
Wolfgang Betz 9:c4c2240e06d6 897 }
Wolfgang Betz 9:c4c2240e06d6 898
Wolfgang Betz 9:c4c2240e06d6 899 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 900 {
Wolfgang Betz 9:c4c2240e06d6 901 if (*freq_i2s_1 == *freq_i2s_2)
Wolfgang Betz 9:c4c2240e06d6 902 return 0;
Wolfgang Betz 9:c4c2240e06d6 903
Wolfgang Betz 9:c4c2240e06d6 904 /* Compute the real frequencies. */
Wolfgang Betz 9:c4c2240e06d6 905 float f1 = i2s_compute_real_frequency(dev_i2s_1);
Wolfgang Betz 9:c4c2240e06d6 906 float f2 = i2s_compute_real_frequency(dev_i2s_2);
Wolfgang Betz 9:c4c2240e06d6 907
Wolfgang Betz 9:c4c2240e06d6 908 //printf("REAL: %f %f\r\n", f1, f2);
Wolfgang Betz 9:c4c2240e06d6 909
Wolfgang Betz 9:c4c2240e06d6 910 /* Compute the desired frequencies so that they are multiple one of the
Wolfgang Betz 9:c4c2240e06d6 911 other. */
Wolfgang Betz 9:c4c2240e06d6 912 float q;
Wolfgang Betz 9:c4c2240e06d6 913 if (f1 < f2)
Wolfgang Betz 9:c4c2240e06d6 914 q = f2 / f1;
Wolfgang Betz 9:c4c2240e06d6 915 else
Wolfgang Betz 9:c4c2240e06d6 916 q = f1 / f2;
Wolfgang Betz 9:c4c2240e06d6 917 float r = q - (uint32_t) q;
Wolfgang Betz 9:c4c2240e06d6 918
Wolfgang Betz 9:c4c2240e06d6 919 if (r > 0)
Wolfgang Betz 9:c4c2240e06d6 920 {
Wolfgang Betz 9:c4c2240e06d6 921 if (f1 < f2)
Wolfgang Betz 9:c4c2240e06d6 922 {
Wolfgang Betz 9:c4c2240e06d6 923 float mf = i2s_compute_magic_factor(dev_i2s_1, f2 / 2);
Wolfgang Betz 9:c4c2240e06d6 924 r = mf - (uint32_t) mf;
Wolfgang Betz 9:c4c2240e06d6 925 if (r > 0)
Wolfgang Betz 9:c4c2240e06d6 926 {
Wolfgang Betz 9:c4c2240e06d6 927 if (f2 > *freq_i2s_2)
Wolfgang Betz 9:c4c2240e06d6 928 f1 = i2s_compute_desired_frequency(dev_i2s_1, ((uint32_t) mf) + 1);
Wolfgang Betz 9:c4c2240e06d6 929 else
Wolfgang Betz 9:c4c2240e06d6 930 f1 = i2s_compute_desired_frequency(dev_i2s_1, ((uint32_t) mf) - 1);
Wolfgang Betz 9:c4c2240e06d6 931 f2 = 2 * f1;
Wolfgang Betz 9:c4c2240e06d6 932 }
Wolfgang Betz 9:c4c2240e06d6 933 else
Wolfgang Betz 9:c4c2240e06d6 934 f1 = f2 / 2;
Wolfgang Betz 9:c4c2240e06d6 935 }
Wolfgang Betz 9:c4c2240e06d6 936 else
Wolfgang Betz 9:c4c2240e06d6 937 {
Wolfgang Betz 9:c4c2240e06d6 938 float mf = i2s_compute_magic_factor(dev_i2s_2, f1 / 2);
Wolfgang Betz 9:c4c2240e06d6 939 r = mf - (uint32_t) mf;
Wolfgang Betz 9:c4c2240e06d6 940 if (r > 0)
Wolfgang Betz 9:c4c2240e06d6 941 {
Wolfgang Betz 9:c4c2240e06d6 942 if (f1 > *freq_i2s_1)
Wolfgang Betz 9:c4c2240e06d6 943 f2 = i2s_compute_desired_frequency(dev_i2s_2, ((uint32_t) mf) + 1);
Wolfgang Betz 9:c4c2240e06d6 944 else
Wolfgang Betz 9:c4c2240e06d6 945 f2 = i2s_compute_desired_frequency(dev_i2s_2, ((uint32_t) mf) - 1);
Wolfgang Betz 9:c4c2240e06d6 946 f1 = 2 * f2;
Wolfgang Betz 9:c4c2240e06d6 947 }
Wolfgang Betz 9:c4c2240e06d6 948 else
Wolfgang Betz 9:c4c2240e06d6 949 f2 = f1 / 2;
Wolfgang Betz 9:c4c2240e06d6 950 }
Wolfgang Betz 9:c4c2240e06d6 951 }
Wolfgang Betz 9:c4c2240e06d6 952
Wolfgang Betz 9:c4c2240e06d6 953 //printf("DESIRED: %f %f\r\n", f1, f2);
Wolfgang Betz 9:c4c2240e06d6 954
Wolfgang Betz 9:c4c2240e06d6 955 /* Return the desired frequencies. */
Wolfgang Betz 9:c4c2240e06d6 956 *freq_i2s_1 = (uint32_t)f1;
Wolfgang Betz 9:c4c2240e06d6 957 *freq_i2s_2 = (uint32_t)f2;
Wolfgang Betz 9:c4c2240e06d6 958
Wolfgang Betz 9:c4c2240e06d6 959 return 0;
Davide Aliprandi 4:21603d68bcf7 960 }
Davide Aliprandi 4:21603d68bcf7 961
Wolfgang Betz 1:f90318e0923b 962 #endif