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

Dependents:   X_NUCLEO_CCA02M1

Fork of ST_I2S by ST

Committer:
Wolfgang Betz
Date:
Mon Mar 27 16:15:20 2017 +0200
Revision:
26:468cdd70cd3e
Parent:
24:b78825180506
Child:
27:c2fc3330d0df
Enable I2S w/o requirement for HAL patches

Who changed what in which revision?

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