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:
Wed Jul 12 15:24:49 2017 +0200
Revision:
31:bb4bac0874da
Parent:
27:c2fc3330d0df
Merge branch 'master' into betzw_wb

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