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:
Tue Nov 29 14:43:26 2016 +0100
Revision:
1:f90318e0923b
Child:
5:74da3773bf43
Child:
2:0c9ce59aee25
Rename & adjust

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 1:f90318e0923b 14
Wolfgang Betz 1:f90318e0923b 15 // #define DEBUG_STDIO 1 // betzw - TODO: temporarily enable debug printfs
Wolfgang Betz 1:f90318e0923b 16
Wolfgang Betz 1:f90318e0923b 17 #ifndef DEBUG_STDIO
Wolfgang Betz 1:f90318e0923b 18 # define DEBUG_STDIO 0
Wolfgang Betz 1:f90318e0923b 19 #endif
Wolfgang Betz 1:f90318e0923b 20
Wolfgang Betz 1:f90318e0923b 21 #if DEBUG_STDIO
Wolfgang Betz 1:f90318e0923b 22 # include <stdio.h>
Wolfgang Betz 1:f90318e0923b 23 # define DEBUG_PRINTF(...) do { printf(__VA_ARGS__); } while(0)
Wolfgang Betz 1:f90318e0923b 24 #else
Wolfgang Betz 1:f90318e0923b 25 # define DEBUG_PRINTF(...) {}
Wolfgang Betz 1:f90318e0923b 26 #endif
Wolfgang Betz 1:f90318e0923b 27
Wolfgang Betz 1:f90318e0923b 28 typedef enum {
Wolfgang Betz 1:f90318e0923b 29 I2S_TRANSFER_TYPE_TX = 1,
Wolfgang Betz 1:f90318e0923b 30 I2S_TRANSFER_TYPE_RX = 2,
Wolfgang Betz 1:f90318e0923b 31 I2S_TRANSFER_TYPE_TXRX = 3,
Wolfgang Betz 1:f90318e0923b 32 } transfer_type_t;
Wolfgang Betz 1:f90318e0923b 33
Wolfgang Betz 1:f90318e0923b 34 typedef struct {
Wolfgang Betz 1:f90318e0923b 35 DMA_HandleTypeDef tx_dma_handle;
Wolfgang Betz 1:f90318e0923b 36 DMA_HandleTypeDef rx_dma_handle;
Wolfgang Betz 1:f90318e0923b 37 } dma_handles_t;
Wolfgang Betz 1:f90318e0923b 38
Wolfgang Betz 1:f90318e0923b 39 #define I2S_NUM (5) // betzw: this approach wastes quite a bit of memory - TO BE IMPROVED!?!?
Wolfgang Betz 1:f90318e0923b 40
Wolfgang Betz 1:f90318e0923b 41 static I2S_HandleTypeDef I2sHandle[I2S_NUM];
Wolfgang Betz 1:f90318e0923b 42 static DMA_HandleTypeDef DMaHandles[I2S_NUM][NUM_OF_DIRECTIONS];
Wolfgang Betz 1:f90318e0923b 43
Wolfgang Betz 1:f90318e0923b 44 static void init_i2s(i2s_t *obj)
Wolfgang Betz 1:f90318e0923b 45 {
Wolfgang Betz 1:f90318e0923b 46 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 47
Wolfgang Betz 1:f90318e0923b 48 __HAL_I2S_DISABLE(handle);
Wolfgang Betz 1:f90318e0923b 49 HAL_I2S_Init(handle);
Wolfgang Betz 1:f90318e0923b 50 __HAL_I2S_ENABLE(handle);
Wolfgang Betz 1:f90318e0923b 51 }
Wolfgang Betz 1:f90318e0923b 52
Wolfgang Betz 1:f90318e0923b 53 static void init_dmas(i2s_t *obj)
Wolfgang Betz 1:f90318e0923b 54 {
Wolfgang Betz 1:f90318e0923b 55 DMA_HandleTypeDef *primary_handle = NULL;
Wolfgang Betz 1:f90318e0923b 56 DMA_HandleTypeDef *secondary_handle = NULL;
Wolfgang Betz 1:f90318e0923b 57 DMA_HandleTypeDef *hdmatx = NULL;
Wolfgang Betz 1:f90318e0923b 58
Wolfgang Betz 1:f90318e0923b 59 switch(obj->dma.dma_direction) {
Wolfgang Betz 1:f90318e0923b 60 case DMA_TX:
Wolfgang Betz 1:f90318e0923b 61 if(obj->dma.dma[DMA_TX] != NULL) {
Wolfgang Betz 1:f90318e0923b 62 hdmatx = primary_handle = &DMaHandles[obj->i2s.module][DMA_TX];
Wolfgang Betz 1:f90318e0923b 63 }
Wolfgang Betz 1:f90318e0923b 64 if(obj->dma.dma[DMA_RX] != NULL) {
Wolfgang Betz 1:f90318e0923b 65 secondary_handle = &DMaHandles[obj->i2s.module][DMA_RX];
Wolfgang Betz 1:f90318e0923b 66 }
Wolfgang Betz 1:f90318e0923b 67 break;
Wolfgang Betz 1:f90318e0923b 68 case DMA_RX:
Wolfgang Betz 1:f90318e0923b 69 default:
Wolfgang Betz 1:f90318e0923b 70 if(obj->dma.dma[DMA_RX] != NULL) {
Wolfgang Betz 1:f90318e0923b 71 primary_handle = &DMaHandles[obj->i2s.module][DMA_RX];
Wolfgang Betz 1:f90318e0923b 72 }
Wolfgang Betz 1:f90318e0923b 73 if(obj->dma.dma[DMA_TX] != NULL) {
Wolfgang Betz 1:f90318e0923b 74 hdmatx = secondary_handle = &DMaHandles[obj->i2s.module][DMA_TX];
Wolfgang Betz 1:f90318e0923b 75 }
Wolfgang Betz 1:f90318e0923b 76 break;
Wolfgang Betz 1:f90318e0923b 77 }
Wolfgang Betz 1:f90318e0923b 78
Wolfgang Betz 1:f90318e0923b 79 if(primary_handle != NULL) {
Wolfgang Betz 1:f90318e0923b 80 __HAL_DMA_DISABLE(primary_handle);
Wolfgang Betz 1:f90318e0923b 81 HAL_DMA_Init(primary_handle);
Wolfgang Betz 1:f90318e0923b 82
Wolfgang Betz 1:f90318e0923b 83 if(hdmatx == primary_handle) {
Wolfgang Betz 1:f90318e0923b 84 __HAL_LINKDMA(&I2sHandle[obj->i2s.module], hdmatx, *primary_handle);
Wolfgang Betz 1:f90318e0923b 85 } else {
Wolfgang Betz 1:f90318e0923b 86 __HAL_LINKDMA(&I2sHandle[obj->i2s.module], hdmarx, *primary_handle);
Wolfgang Betz 1:f90318e0923b 87 }
Wolfgang Betz 1:f90318e0923b 88 }
Wolfgang Betz 1:f90318e0923b 89
Wolfgang Betz 1:f90318e0923b 90 if(secondary_handle != NULL) {
Wolfgang Betz 1:f90318e0923b 91 __HAL_DMA_DISABLE(secondary_handle);
Wolfgang Betz 1:f90318e0923b 92 HAL_DMA_Init(secondary_handle);
Wolfgang Betz 1:f90318e0923b 93
Wolfgang Betz 1:f90318e0923b 94 if(hdmatx == secondary_handle) {
Wolfgang Betz 1:f90318e0923b 95 __HAL_LINKDMA(&I2sHandle[obj->i2s.module], hdmatx, *secondary_handle);
Wolfgang Betz 1:f90318e0923b 96 } else {
Wolfgang Betz 1:f90318e0923b 97 __HAL_LINKDMA(&I2sHandle[obj->i2s.module], hdmarx, *secondary_handle);
Wolfgang Betz 1:f90318e0923b 98 }
Wolfgang Betz 1:f90318e0923b 99 }
Wolfgang Betz 1:f90318e0923b 100 }
Wolfgang Betz 1:f90318e0923b 101
Wolfgang Betz 1:f90318e0923b 102 static inline uint32_t i2s_get_mode(i2s_mode_t mode, uint8_t *direction) {
Wolfgang Betz 1:f90318e0923b 103 switch(mode) {
Wolfgang Betz 1:f90318e0923b 104 case SLAVE_TX:
Wolfgang Betz 1:f90318e0923b 105 *direction = DMA_TX;
Wolfgang Betz 1:f90318e0923b 106 return I2S_MODE_SLAVE_TX;
Wolfgang Betz 1:f90318e0923b 107 case SLAVE_RX:
Wolfgang Betz 1:f90318e0923b 108 *direction = DMA_RX;
Wolfgang Betz 1:f90318e0923b 109 return I2S_MODE_SLAVE_RX;
Wolfgang Betz 1:f90318e0923b 110 case MASTER_TX:
Wolfgang Betz 1:f90318e0923b 111 *direction = DMA_TX;
Wolfgang Betz 1:f90318e0923b 112 return I2S_MODE_MASTER_TX;
Wolfgang Betz 1:f90318e0923b 113 case MASTER_RX:
Wolfgang Betz 1:f90318e0923b 114 default:
Wolfgang Betz 1:f90318e0923b 115 *direction = DMA_RX;
Wolfgang Betz 1:f90318e0923b 116 return I2S_MODE_MASTER_RX;
Wolfgang Betz 1:f90318e0923b 117 }
Wolfgang Betz 1:f90318e0923b 118 }
Wolfgang Betz 1:f90318e0923b 119
Wolfgang Betz 1:f90318e0923b 120 static inline uint32_t i2s_get_priority(i2s_dma_prio_t priority) {
Wolfgang Betz 1:f90318e0923b 121 switch(priority) {
Wolfgang Betz 1:f90318e0923b 122 case LOW:
Wolfgang Betz 1:f90318e0923b 123 return DMA_PRIORITY_LOW;
Wolfgang Betz 1:f90318e0923b 124 case URGENT:
Wolfgang Betz 1:f90318e0923b 125 return DMA_PRIORITY_VERY_HIGH;
Wolfgang Betz 1:f90318e0923b 126 case HIGH:
Wolfgang Betz 1:f90318e0923b 127 return DMA_PRIORITY_HIGH;
Wolfgang Betz 1:f90318e0923b 128 default:
Wolfgang Betz 1:f90318e0923b 129 return DMA_PRIORITY_MEDIUM;
Wolfgang Betz 1:f90318e0923b 130 }
Wolfgang Betz 1:f90318e0923b 131 }
Wolfgang Betz 1:f90318e0923b 132
Wolfgang Betz 1:f90318e0923b 133 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 134 // DMA declarations
Wolfgang Betz 1:f90318e0923b 135 DMA_HandleTypeDef *primary_handle = &DMaHandles[obj->i2s.module][obj->dma.dma_direction];
Wolfgang Betz 1:f90318e0923b 136 DMA_HandleTypeDef *secondary_handle = NULL;
Wolfgang Betz 1:f90318e0923b 137
Wolfgang Betz 1:f90318e0923b 138 // DMA initialization & configuration
Wolfgang Betz 1:f90318e0923b 139 dma_init();
Wolfgang Betz 1:f90318e0923b 140 obj->dma.dma[DMA_TX] = obj->dma.dma[DMA_RX] = NULL;
Wolfgang Betz 1:f90318e0923b 141
Wolfgang Betz 1:f90318e0923b 142 switch(obj->dma.dma_direction) {
Wolfgang Betz 1:f90318e0923b 143 case DMA_TX:
Wolfgang Betz 1:f90318e0923b 144 if(*use_tx) {
Wolfgang Betz 1:f90318e0923b 145 obj->dma.dma[DMA_TX] = dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_TX));
Wolfgang Betz 1:f90318e0923b 146 MBED_ASSERT(obj->dma.dma[DMA_TX] != DMA_ERROR_OUT_OF_CHANNELS);
Wolfgang Betz 1:f90318e0923b 147 }
Wolfgang Betz 1:f90318e0923b 148 break;
Wolfgang Betz 1:f90318e0923b 149 case DMA_RX:
Wolfgang Betz 1:f90318e0923b 150 default:
Wolfgang Betz 1:f90318e0923b 151 if(*use_rx) {
Wolfgang Betz 1:f90318e0923b 152 obj->dma.dma[DMA_RX] = dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_RX));
Wolfgang Betz 1:f90318e0923b 153 MBED_ASSERT(obj->dma.dma[DMA_RX] != DMA_ERROR_OUT_OF_CHANNELS);
Wolfgang Betz 1:f90318e0923b 154 }
Wolfgang Betz 1:f90318e0923b 155 break;
Wolfgang Betz 1:f90318e0923b 156 }
Wolfgang Betz 1:f90318e0923b 157
Wolfgang Betz 1:f90318e0923b 158 // Primary DMA configuration
Wolfgang Betz 1:f90318e0923b 159 if(obj->dma.dma[obj->dma.dma_direction] != NULL) {
Wolfgang Betz 1:f90318e0923b 160 primary_handle->Instance = obj->dma.dma[obj->dma.dma_direction]->dma_stream;
Wolfgang Betz 1:f90318e0923b 161 primary_handle->Init.Channel = obj->dma.dma[obj->dma.dma_direction]->channel_nr;
Wolfgang Betz 1:f90318e0923b 162 primary_handle->Init.Direction = (obj->dma.dma_direction == DMA_TX) ?
Wolfgang Betz 1:f90318e0923b 163 DMA_MEMORY_TO_PERIPH : DMA_PERIPH_TO_MEMORY;
Wolfgang Betz 1:f90318e0923b 164 primary_handle->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
Wolfgang Betz 1:f90318e0923b 165 primary_handle->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
Wolfgang Betz 1:f90318e0923b 166 primary_handle->Init.MemBurst = DMA_MBURST_SINGLE;
Wolfgang Betz 1:f90318e0923b 167 primary_handle->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
Wolfgang Betz 1:f90318e0923b 168 primary_handle->Init.MemInc = DMA_MINC_ENABLE;
Wolfgang Betz 1:f90318e0923b 169 primary_handle->Init.Mode = (circular ? DMA_CIRCULAR : DMA_NORMAL);
Wolfgang Betz 1:f90318e0923b 170 primary_handle->Init.PeriphBurst = DMA_PBURST_SINGLE;
Wolfgang Betz 1:f90318e0923b 171 primary_handle->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
Wolfgang Betz 1:f90318e0923b 172 primary_handle->Init.PeriphInc = DMA_PINC_DISABLE;
Wolfgang Betz 1:f90318e0923b 173 primary_handle->Init.Priority = i2s_get_priority(prio);
Wolfgang Betz 1:f90318e0923b 174 }
Wolfgang Betz 1:f90318e0923b 175
Wolfgang Betz 1:f90318e0923b 176 // Allocate secondary DMA channel (if full-duplex)
Wolfgang Betz 1:f90318e0923b 177 if(obj->i2s.pin_fdpx != NC) {
Wolfgang Betz 1:f90318e0923b 178 switch(obj->dma.dma_direction) {
Wolfgang Betz 1:f90318e0923b 179 case DMA_TX:
Wolfgang Betz 1:f90318e0923b 180 if(*use_rx) {
Wolfgang Betz 1:f90318e0923b 181 obj->dma.dma[DMA_RX] = dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_RX));
Wolfgang Betz 1:f90318e0923b 182 secondary_handle = &DMaHandles[obj->i2s.module][DMA_RX];
Wolfgang Betz 1:f90318e0923b 183 MBED_ASSERT(obj->dma.dma[DMA_RX] != DMA_ERROR_OUT_OF_CHANNELS);
Wolfgang Betz 1:f90318e0923b 184 }
Wolfgang Betz 1:f90318e0923b 185 break;
Wolfgang Betz 1:f90318e0923b 186 case DMA_RX:
Wolfgang Betz 1:f90318e0923b 187 default:
Wolfgang Betz 1:f90318e0923b 188 if(*use_tx) {
Wolfgang Betz 1:f90318e0923b 189 obj->dma.dma[DMA_TX] = dma_channel_allocate(MAKE_CAP(obj->dma.dma_device, DMA_TX));
Wolfgang Betz 1:f90318e0923b 190 secondary_handle = &DMaHandles[obj->i2s.module][DMA_TX];
Wolfgang Betz 1:f90318e0923b 191 MBED_ASSERT(obj->dma.dma[DMA_TX] != DMA_ERROR_OUT_OF_CHANNELS);
Wolfgang Betz 1:f90318e0923b 192 }
Wolfgang Betz 1:f90318e0923b 193 break;
Wolfgang Betz 1:f90318e0923b 194 }
Wolfgang Betz 1:f90318e0923b 195 }
Wolfgang Betz 1:f90318e0923b 196
Wolfgang Betz 1:f90318e0923b 197 // Secondary DMA configuration
Wolfgang Betz 1:f90318e0923b 198 if(secondary_handle != NULL) {
Wolfgang Betz 1:f90318e0923b 199 uint8_t secondary_dma_direction = (obj->dma.dma_direction == DMA_TX) ? DMA_RX : DMA_TX;
Wolfgang Betz 1:f90318e0923b 200
Wolfgang Betz 1:f90318e0923b 201 secondary_handle->Instance = obj->dma.dma[secondary_dma_direction]->dma_stream;
Wolfgang Betz 1:f90318e0923b 202 secondary_handle->Init.Channel = obj->dma.dma[secondary_dma_direction]->channel_nr_fd;
Wolfgang Betz 1:f90318e0923b 203 secondary_handle->Init.Direction = (secondary_dma_direction == DMA_TX) ?
Wolfgang Betz 1:f90318e0923b 204 DMA_MEMORY_TO_PERIPH : DMA_PERIPH_TO_MEMORY;
Wolfgang Betz 1:f90318e0923b 205 secondary_handle->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
Wolfgang Betz 1:f90318e0923b 206 secondary_handle->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
Wolfgang Betz 1:f90318e0923b 207 secondary_handle->Init.MemBurst = DMA_MBURST_SINGLE;
Wolfgang Betz 1:f90318e0923b 208 secondary_handle->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
Wolfgang Betz 1:f90318e0923b 209 secondary_handle->Init.MemInc = DMA_MINC_ENABLE;
Wolfgang Betz 1:f90318e0923b 210 secondary_handle->Init.Mode = (circular ? DMA_CIRCULAR : DMA_NORMAL);
Wolfgang Betz 1:f90318e0923b 211 secondary_handle->Init.PeriphBurst = DMA_PBURST_SINGLE;
Wolfgang Betz 1:f90318e0923b 212 secondary_handle->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
Wolfgang Betz 1:f90318e0923b 213 secondary_handle->Init.PeriphInc = DMA_PINC_DISABLE;
Wolfgang Betz 1:f90318e0923b 214 secondary_handle->Init.Priority = i2s_get_priority(prio);
Wolfgang Betz 1:f90318e0923b 215 }
Wolfgang Betz 1:f90318e0923b 216
Wolfgang Betz 1:f90318e0923b 217 if(obj->dma.dma[DMA_TX] == NULL) *use_tx = false;
Wolfgang Betz 1:f90318e0923b 218 if(obj->dma.dma[DMA_RX] == NULL) *use_rx = false;
Wolfgang Betz 1:f90318e0923b 219
Wolfgang Betz 1:f90318e0923b 220 // don't do anything, if the buffers aren't valid
Wolfgang Betz 1:f90318e0923b 221 if (!use_tx && !use_rx) {
Wolfgang Betz 1:f90318e0923b 222 DEBUG_PRINTF("I2S%u: No DMAs to init\n", obj->i2s.module+1);
Wolfgang Betz 1:f90318e0923b 223 return;
Wolfgang Betz 1:f90318e0923b 224 }
Wolfgang Betz 1:f90318e0923b 225
Wolfgang Betz 1:f90318e0923b 226 DEBUG_PRINTF("I2S%u: DMA(s) Init\n", obj->i2s.module+1);
Wolfgang Betz 1:f90318e0923b 227 init_dmas(obj);
Wolfgang Betz 1:f90318e0923b 228 }
Wolfgang Betz 1:f90318e0923b 229
Wolfgang Betz 1:f90318e0923b 230 static void dma_i2s_free(i2s_t *obj, uint8_t direction) {
Wolfgang Betz 1:f90318e0923b 231 const struct dma_stream_s *stream = obj->dma.dma[direction];
Wolfgang Betz 1:f90318e0923b 232
Wolfgang Betz 1:f90318e0923b 233 MBED_ASSERT(stream != NULL);
Wolfgang Betz 1:f90318e0923b 234
Wolfgang Betz 1:f90318e0923b 235 // disable irq
Wolfgang Betz 1:f90318e0923b 236 NVIC_DisableIRQ(stream->dma_stream_irq);
Wolfgang Betz 1:f90318e0923b 237
Wolfgang Betz 1:f90318e0923b 238 // free channel
Wolfgang Betz 1:f90318e0923b 239 dma_channel_free((void*)stream);
Wolfgang Betz 1:f90318e0923b 240 obj->dma.dma[direction] = NULL;
Wolfgang Betz 1:f90318e0923b 241 }
Wolfgang Betz 1:f90318e0923b 242
Wolfgang Betz 1:f90318e0923b 243 void i2s_init(i2s_t *obj, PinName data, PinName sclk, PinName wsel, PinName fdpx, PinName mclk, i2s_mode_t mode)
Wolfgang Betz 1:f90318e0923b 244 {
Wolfgang Betz 1:f90318e0923b 245 uint8_t dma_dev = 0, dma_direction = 0;
Wolfgang Betz 1:f90318e0923b 246
Wolfgang Betz 1:f90318e0923b 247 // Determine the I2S/SPI to use
Wolfgang Betz 1:f90318e0923b 248 SPIName i2s_data = (SPIName)pinmap_peripheral(data, PinMap_I2S_DATA);
Wolfgang Betz 1:f90318e0923b 249 SPIName i2s_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_I2S_SCLK);
Wolfgang Betz 1:f90318e0923b 250
Wolfgang Betz 1:f90318e0923b 251 SPIName i2s_wsel = (SPIName)pinmap_peripheral(wsel, PinMap_I2S_WSEL);
Wolfgang Betz 1:f90318e0923b 252 SPIName i2s_fdpx = (SPIName)pinmap_peripheral(fdpx, PinMap_I2S_FDPX);
Wolfgang Betz 1:f90318e0923b 253
Wolfgang Betz 1:f90318e0923b 254 SPIName i2s_mclk = (SPIName)pinmap_peripheral(mclk, PinMap_I2S_MCLK);
Wolfgang Betz 1:f90318e0923b 255
Wolfgang Betz 1:f90318e0923b 256 SPIName i2s_merge1 = (SPIName)pinmap_merge(i2s_data, i2s_sclk);
Wolfgang Betz 1:f90318e0923b 257 SPIName i2s_merge2 = (SPIName)pinmap_merge(i2s_wsel, i2s_fdpx);
Wolfgang Betz 1:f90318e0923b 258
Wolfgang Betz 1:f90318e0923b 259 SPIName i2s_merge3 = (SPIName)pinmap_merge(i2s_merge1, i2s_merge2);
Wolfgang Betz 1:f90318e0923b 260 SPIName instance = (SPIName)pinmap_merge(i2s_merge3, i2s_mclk);
Wolfgang Betz 1:f90318e0923b 261 MBED_ASSERT(instance != (SPIName)NC);
Wolfgang Betz 1:f90318e0923b 262
Wolfgang Betz 1:f90318e0923b 263 // Enable I2S/SPI clock and set the right module number
Wolfgang Betz 1:f90318e0923b 264 switch(instance) {
Wolfgang Betz 1:f90318e0923b 265 #if defined(I2S1ext_BASE)
Wolfgang Betz 1:f90318e0923b 266 case SPI_1:
Wolfgang Betz 1:f90318e0923b 267 __SPI1_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 268 obj->i2s.module = 0;
Wolfgang Betz 1:f90318e0923b 269 dma_dev = DMA_SPI1;
Wolfgang Betz 1:f90318e0923b 270 break;
Wolfgang Betz 1:f90318e0923b 271 #endif
Wolfgang Betz 1:f90318e0923b 272 #if defined(I2S2ext_BASE)
Wolfgang Betz 1:f90318e0923b 273 case SPI_2:
Wolfgang Betz 1:f90318e0923b 274 __SPI2_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 275 obj->i2s.module = 1;
Wolfgang Betz 1:f90318e0923b 276 dma_dev = DMA_SPI2;
Wolfgang Betz 1:f90318e0923b 277 break;
Wolfgang Betz 1:f90318e0923b 278 #endif
Wolfgang Betz 1:f90318e0923b 279 #if defined(I2S3ext_BASE)
Wolfgang Betz 1:f90318e0923b 280 case SPI_3:
Wolfgang Betz 1:f90318e0923b 281 __SPI3_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 282 obj->i2s.module = 2;
Wolfgang Betz 1:f90318e0923b 283 dma_dev = DMA_SPI3;
Wolfgang Betz 1:f90318e0923b 284 break;
Wolfgang Betz 1:f90318e0923b 285 #endif
Wolfgang Betz 1:f90318e0923b 286 #if defined(I2S4ext_BASE)
Wolfgang Betz 1:f90318e0923b 287 case SPI_4:
Wolfgang Betz 1:f90318e0923b 288 __SPI4_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 289 obj->i2s.module = 3;
Wolfgang Betz 1:f90318e0923b 290 dma_dev = DMA_SPI4;
Wolfgang Betz 1:f90318e0923b 291 break;
Wolfgang Betz 1:f90318e0923b 292 #endif
Wolfgang Betz 1:f90318e0923b 293 #if defined(I2S5ext_BASE)
Wolfgang Betz 1:f90318e0923b 294 case SPI_5:
Wolfgang Betz 1:f90318e0923b 295 __SPI5_CLK_ENABLE();
Wolfgang Betz 1:f90318e0923b 296 obj->i2s.module = 4;
Wolfgang Betz 1:f90318e0923b 297 dma_dev = DMA_SPI5;
Wolfgang Betz 1:f90318e0923b 298 break;
Wolfgang Betz 1:f90318e0923b 299 #endif
Wolfgang Betz 1:f90318e0923b 300 default:
Wolfgang Betz 1:f90318e0923b 301 MBED_ASSERT(0);
Wolfgang Betz 1:f90318e0923b 302 break;
Wolfgang Betz 1:f90318e0923b 303 }
Wolfgang Betz 1:f90318e0923b 304
Wolfgang Betz 1:f90318e0923b 305 // Save DMA device
Wolfgang Betz 1:f90318e0923b 306 obj->dma.dma_device = dma_dev;
Wolfgang Betz 1:f90318e0923b 307
Wolfgang Betz 1:f90318e0923b 308 // Configure the I2S pins
Wolfgang Betz 1:f90318e0923b 309 pinmap_pinout(data, PinMap_I2S_DATA);
Wolfgang Betz 1:f90318e0923b 310 pinmap_pinout(wsel, PinMap_I2S_WSEL);
Wolfgang Betz 1:f90318e0923b 311 pinmap_pinout(sclk, PinMap_I2S_SCLK);
Wolfgang Betz 1:f90318e0923b 312 pinmap_pinout(fdpx, PinMap_I2S_FDPX);
Wolfgang Betz 1:f90318e0923b 313 pinmap_pinout(mclk, PinMap_I2S_MCLK);
Wolfgang Betz 1:f90318e0923b 314
Wolfgang Betz 1:f90318e0923b 315 obj->i2s.pin_wsel = wsel;
Wolfgang Betz 1:f90318e0923b 316 obj->i2s.pin_data = data;
Wolfgang Betz 1:f90318e0923b 317 obj->i2s.pin_sclk = sclk;
Wolfgang Betz 1:f90318e0923b 318 obj->i2s.pin_fdpx = fdpx;
Wolfgang Betz 1:f90318e0923b 319 obj->i2s.pin_mclk = mclk;
Wolfgang Betz 1:f90318e0923b 320
Wolfgang Betz 1:f90318e0923b 321 /* Configure PLLI2S */
Wolfgang Betz 1:f90318e0923b 322 static bool first_time = true;
Wolfgang Betz 1:f90318e0923b 323 if(first_time) {
Wolfgang Betz 1:f90318e0923b 324 RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
Wolfgang Betz 1:f90318e0923b 325
Wolfgang Betz 1:f90318e0923b 326 /* Get RTCClockSelection */
Wolfgang Betz 1:f90318e0923b 327 HAL_RCCEx_GetPeriphCLKConfig(&PeriphClkInitStruct);
Wolfgang Betz 1:f90318e0923b 328
Wolfgang Betz 1:f90318e0923b 329 /* Set default configuration */
Wolfgang Betz 1:f90318e0923b 330 PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;
Wolfgang Betz 1:f90318e0923b 331 PeriphClkInitStruct.PLLI2S.PLLI2SN = 271; // betzw: use values which are suggested in Table 90. of the
Wolfgang Betz 1:f90318e0923b 332 PeriphClkInitStruct.PLLI2S.PLLI2SR = 2; // reference manual for master clock enabled & 44100Hz
Wolfgang Betz 1:f90318e0923b 333 #ifdef NDEBUG
Wolfgang Betz 1:f90318e0923b 334 HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
Wolfgang Betz 1:f90318e0923b 335 #else
Wolfgang Betz 1:f90318e0923b 336 HAL_StatusTypeDef ret = HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
Wolfgang Betz 1:f90318e0923b 337 #endif
Wolfgang Betz 1:f90318e0923b 338 MBED_ASSERT(ret == HAL_OK);
Wolfgang Betz 1:f90318e0923b 339 first_time = false;
Wolfgang Betz 1:f90318e0923b 340 }
Wolfgang Betz 1:f90318e0923b 341
Wolfgang Betz 1:f90318e0923b 342 // initialize the handle for this master!
Wolfgang Betz 1:f90318e0923b 343 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 344
Wolfgang Betz 1:f90318e0923b 345 handle->Instance = (SPI_TypeDef *)(instance);
Wolfgang Betz 1:f90318e0923b 346 handle->Init.Mode = i2s_get_mode(mode, &dma_direction);
Wolfgang Betz 1:f90318e0923b 347 handle->Init.Standard = I2S_STANDARD_PCM_SHORT;
Wolfgang Betz 1:f90318e0923b 348 handle->Init.DataFormat = I2S_DATAFORMAT_16B;
Wolfgang Betz 1:f90318e0923b 349 handle->Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE; // betzw: always enable master clock to avoid frequency dis-alignment between I2S devices
Wolfgang Betz 1:f90318e0923b 350 handle->Init.AudioFreq = I2S_AUDIOFREQ_44K;
Wolfgang Betz 1:f90318e0923b 351 handle->Init.CPOL = I2S_CPOL_LOW;
Wolfgang Betz 1:f90318e0923b 352 handle->Init.ClockSource = I2S_CLOCK_PLL;
Wolfgang Betz 1:f90318e0923b 353 handle->Init.FullDuplexMode = (fdpx == NC) ? I2S_FULLDUPLEXMODE_DISABLE : I2S_FULLDUPLEXMODE_ENABLE;
Wolfgang Betz 1:f90318e0923b 354
Wolfgang Betz 1:f90318e0923b 355 // Save primary DMA direction
Wolfgang Betz 1:f90318e0923b 356 obj->dma.dma_direction = dma_direction;
Wolfgang Betz 1:f90318e0923b 357
Wolfgang Betz 1:f90318e0923b 358 DEBUG_PRINTF("I2S%u: Init\n", obj->i2s.module+1);
Wolfgang Betz 1:f90318e0923b 359
Wolfgang Betz 1:f90318e0923b 360 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 361 }
Wolfgang Betz 1:f90318e0923b 362
Wolfgang Betz 1:f90318e0923b 363 void i2s_free(i2s_t *obj)
Wolfgang Betz 1:f90318e0923b 364 {
Wolfgang Betz 1:f90318e0923b 365 // Reset I2S and disable clock
Wolfgang Betz 1:f90318e0923b 366 switch(obj->i2s.module) {
Wolfgang Betz 1:f90318e0923b 367 #if defined(I2S1ext_BASE)
Wolfgang Betz 1:f90318e0923b 368 case 0:
Wolfgang Betz 1:f90318e0923b 369 __SPI1_FORCE_RESET();
Wolfgang Betz 1:f90318e0923b 370 __SPI1_RELEASE_RESET();
Wolfgang Betz 1:f90318e0923b 371 __SPI1_CLK_DISABLE();
Wolfgang Betz 1:f90318e0923b 372 break;
Wolfgang Betz 1:f90318e0923b 373 #endif
Wolfgang Betz 1:f90318e0923b 374 #if defined(I2S2ext_BASE)
Wolfgang Betz 1:f90318e0923b 375 case 1:
Wolfgang Betz 1:f90318e0923b 376 __SPI2_FORCE_RESET();
Wolfgang Betz 1:f90318e0923b 377 __SPI2_RELEASE_RESET();
Wolfgang Betz 1:f90318e0923b 378 __SPI2_CLK_DISABLE();
Wolfgang Betz 1:f90318e0923b 379 break;
Wolfgang Betz 1:f90318e0923b 380 #endif
Wolfgang Betz 1:f90318e0923b 381 #if defined(I2S3ext_BASE)
Wolfgang Betz 1:f90318e0923b 382 case 2:
Wolfgang Betz 1:f90318e0923b 383 __SPI3_FORCE_RESET();
Wolfgang Betz 1:f90318e0923b 384 __SPI3_RELEASE_RESET();
Wolfgang Betz 1:f90318e0923b 385 __SPI3_CLK_DISABLE();
Wolfgang Betz 1:f90318e0923b 386 break;
Wolfgang Betz 1:f90318e0923b 387 #endif
Wolfgang Betz 1:f90318e0923b 388 #if defined(I2S4ext_BASE)
Wolfgang Betz 1:f90318e0923b 389 case 3:
Wolfgang Betz 1:f90318e0923b 390 __SPI4_FORCE_RESET();
Wolfgang Betz 1:f90318e0923b 391 __SPI4_RELEASE_RESET();
Wolfgang Betz 1:f90318e0923b 392 __SPI4_CLK_DISABLE();
Wolfgang Betz 1:f90318e0923b 393 break;
Wolfgang Betz 1:f90318e0923b 394 #endif
Wolfgang Betz 1:f90318e0923b 395 #if defined(I2S5ext_BASE)
Wolfgang Betz 1:f90318e0923b 396 case 4:
Wolfgang Betz 1:f90318e0923b 397 __SPI5_FORCE_RESET();
Wolfgang Betz 1:f90318e0923b 398 __SPI5_RELEASE_RESET();
Wolfgang Betz 1:f90318e0923b 399 __SPI5_CLK_DISABLE();
Wolfgang Betz 1:f90318e0923b 400 break;
Wolfgang Betz 1:f90318e0923b 401 #endif
Wolfgang Betz 1:f90318e0923b 402 default:
Wolfgang Betz 1:f90318e0923b 403 MBED_ASSERT(0);
Wolfgang Betz 1:f90318e0923b 404 break;
Wolfgang Betz 1:f90318e0923b 405 }
Wolfgang Betz 1:f90318e0923b 406
Wolfgang Betz 1:f90318e0923b 407 // betzw - TODO: what about 'PLLI2S'?!?
Wolfgang Betz 1:f90318e0923b 408 // for the moment we leave it enabled!
Wolfgang Betz 1:f90318e0923b 409
Wolfgang Betz 1:f90318e0923b 410 // Configure GPIOs
Wolfgang Betz 1:f90318e0923b 411 pin_function(obj->i2s.pin_wsel, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 412 pin_function(obj->i2s.pin_data, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 413 pin_function(obj->i2s.pin_sclk, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 414 pin_function(obj->i2s.pin_fdpx, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 415 pin_function(obj->i2s.pin_mclk, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
Wolfgang Betz 1:f90318e0923b 416
Wolfgang Betz 1:f90318e0923b 417 DEBUG_PRINTF("I2S%u: Free\n", obj->i2s.module+1);
Wolfgang Betz 1:f90318e0923b 418 }
Wolfgang Betz 1:f90318e0923b 419
Wolfgang Betz 1:f90318e0923b 420 void i2s_format(i2s_t *obj, int dbits, int fbits, int polarity)
Wolfgang Betz 1:f90318e0923b 421 {
Wolfgang Betz 1:f90318e0923b 422 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 423
Wolfgang Betz 1:f90318e0923b 424 // Save new values
Wolfgang Betz 1:f90318e0923b 425 if (fbits == 16) { // format MUST be 16B
Wolfgang Betz 1:f90318e0923b 426 handle->Init.DataFormat = I2S_DATAFORMAT_16B;
Wolfgang Betz 1:f90318e0923b 427 } else { // format may NOT be 16B
Wolfgang Betz 1:f90318e0923b 428 switch (dbits) {
Wolfgang Betz 1:f90318e0923b 429 case 16:
Wolfgang Betz 1:f90318e0923b 430 handle->Init.DataFormat = I2S_DATAFORMAT_16B_EXTENDED;
Wolfgang Betz 1:f90318e0923b 431 break;
Wolfgang Betz 1:f90318e0923b 432 case 24:
Wolfgang Betz 1:f90318e0923b 433 handle->Init.DataFormat = I2S_DATAFORMAT_24B;
Wolfgang Betz 1:f90318e0923b 434 break;
Wolfgang Betz 1:f90318e0923b 435 case 32:
Wolfgang Betz 1:f90318e0923b 436 default:
Wolfgang Betz 1:f90318e0923b 437 handle->Init.DataFormat = I2S_DATAFORMAT_32B;
Wolfgang Betz 1:f90318e0923b 438 break;
Wolfgang Betz 1:f90318e0923b 439 }
Wolfgang Betz 1:f90318e0923b 440 }
Wolfgang Betz 1:f90318e0923b 441
Wolfgang Betz 1:f90318e0923b 442 handle->Init.CPOL = (polarity == 0) ? I2S_CPOL_LOW : I2S_CPOL_HIGH;
Wolfgang Betz 1:f90318e0923b 443
Wolfgang Betz 1:f90318e0923b 444 DEBUG_PRINTF("I2S%u: Format: %u (%u, %u), %u (%u)\n", obj->i2s.module+1,
Wolfgang Betz 1:f90318e0923b 445 (unsigned int)handle->Init.DataFormat, (unsigned int)dbits, (unsigned int)fbits,
Wolfgang Betz 1:f90318e0923b 446 (unsigned int)handle->Init.CPOL, (unsigned int)polarity);
Wolfgang Betz 1:f90318e0923b 447
Wolfgang Betz 1:f90318e0923b 448 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 449 }
Wolfgang Betz 1:f90318e0923b 450
Wolfgang Betz 1:f90318e0923b 451 void i2s_set_mode(i2s_t *obj, i2s_mode_t mode)
Wolfgang Betz 1:f90318e0923b 452 {
Wolfgang Betz 1:f90318e0923b 453 uint8_t dma_direction;
Wolfgang Betz 1:f90318e0923b 454 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 455
Wolfgang Betz 1:f90318e0923b 456 handle->Init.Mode = i2s_get_mode(mode, &dma_direction);
Wolfgang Betz 1:f90318e0923b 457
Wolfgang Betz 1:f90318e0923b 458 // Save primary DMA direction
Wolfgang Betz 1:f90318e0923b 459 obj->dma.dma_direction = dma_direction;
Wolfgang Betz 1:f90318e0923b 460
Wolfgang Betz 1:f90318e0923b 461 DEBUG_PRINTF("I2S%u: Mode: %u (%u)\n", obj->i2s.module+1,
Wolfgang Betz 1:f90318e0923b 462 (unsigned int)handle->Init.Mode, (unsigned int)mode);
Wolfgang Betz 1:f90318e0923b 463
Wolfgang Betz 1:f90318e0923b 464 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 465 }
Wolfgang Betz 1:f90318e0923b 466
Wolfgang Betz 1:f90318e0923b 467 void i2s_set_protocol(i2s_t *obj, i2s_bitorder_t protocol)
Wolfgang Betz 1:f90318e0923b 468 {
Wolfgang Betz 1:f90318e0923b 469 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 470
Wolfgang Betz 1:f90318e0923b 471 switch (protocol) {
Wolfgang Betz 1:f90318e0923b 472 case PHILIPS:
Wolfgang Betz 1:f90318e0923b 473 handle->Init.Standard = I2S_STANDARD_PHILIPS;
Wolfgang Betz 1:f90318e0923b 474 break;
Wolfgang Betz 1:f90318e0923b 475 case MSB:
Wolfgang Betz 1:f90318e0923b 476 handle->Init.Standard = I2S_STANDARD_MSB;
Wolfgang Betz 1:f90318e0923b 477 break;
Wolfgang Betz 1:f90318e0923b 478 case LSB:
Wolfgang Betz 1:f90318e0923b 479 handle->Init.Standard = I2S_STANDARD_LSB;
Wolfgang Betz 1:f90318e0923b 480 break;
Wolfgang Betz 1:f90318e0923b 481 case PCM_SHORT:
Wolfgang Betz 1:f90318e0923b 482 handle->Init.Standard = I2S_STANDARD_PCM_SHORT;
Wolfgang Betz 1:f90318e0923b 483 break;
Wolfgang Betz 1:f90318e0923b 484 case PCM_LONG:
Wolfgang Betz 1:f90318e0923b 485 default:
Wolfgang Betz 1:f90318e0923b 486 handle->Init.Standard = I2S_STANDARD_PCM_LONG;
Wolfgang Betz 1:f90318e0923b 487 break;
Wolfgang Betz 1:f90318e0923b 488 }
Wolfgang Betz 1:f90318e0923b 489
Wolfgang Betz 1:f90318e0923b 490 DEBUG_PRINTF("I2S%u: Protocol: %u (%u)\n", obj->i2s.module+1,
Wolfgang Betz 1:f90318e0923b 491 (unsigned int)handle->Init.Standard, (unsigned int)protocol);
Wolfgang Betz 1:f90318e0923b 492
Wolfgang Betz 1:f90318e0923b 493 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 494 }
Wolfgang Betz 1:f90318e0923b 495
Wolfgang Betz 1:f90318e0923b 496 void i2s_audio_frequency(i2s_t *obj, uint32_t hz)
Wolfgang Betz 1:f90318e0923b 497 {
Wolfgang Betz 1:f90318e0923b 498 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 499
Wolfgang Betz 1:f90318e0923b 500 if (IS_I2S_AUDIO_FREQ(hz) && (hz != I2S_AUDIOFREQ_DEFAULT)) {
Wolfgang Betz 1:f90318e0923b 501 handle->Init.AudioFreq = hz;
Wolfgang Betz 1:f90318e0923b 502 } else if (hz < I2S_AUDIOFREQ_8K) {
Wolfgang Betz 1:f90318e0923b 503 handle->Init.AudioFreq = I2S_AUDIOFREQ_8K;
Wolfgang Betz 1:f90318e0923b 504 } else {
Wolfgang Betz 1:f90318e0923b 505 handle->Init.AudioFreq = I2S_AUDIOFREQ_192K;
Wolfgang Betz 1:f90318e0923b 506 }
Wolfgang Betz 1:f90318e0923b 507
Wolfgang Betz 1:f90318e0923b 508 DEBUG_PRINTF("I2S%u: Audio frequency: %u (%u)\n", obj->i2s.module+1,
Wolfgang Betz 1:f90318e0923b 509 (unsigned int)handle->Init.AudioFreq, (unsigned int)hz);
Wolfgang Betz 1:f90318e0923b 510
Wolfgang Betz 1:f90318e0923b 511 init_i2s(obj);
Wolfgang Betz 1:f90318e0923b 512 }
Wolfgang Betz 1:f90318e0923b 513
Wolfgang Betz 1:f90318e0923b 514 uint8_t i2s_get_module(i2s_t *obj)
Wolfgang Betz 1:f90318e0923b 515 {
Wolfgang Betz 1:f90318e0923b 516 return obj->i2s.module;
Wolfgang Betz 1:f90318e0923b 517 }
Wolfgang Betz 1:f90318e0923b 518
Wolfgang Betz 1:f90318e0923b 519 static void i2s_start_asynch_transfer(i2s_t *obj, transfer_type_t transfer_type,
Wolfgang Betz 1:f90318e0923b 520 void *tx, void *rx, int length)
Wolfgang Betz 1:f90318e0923b 521 {
Wolfgang Betz 1:f90318e0923b 522 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 523 obj->i2s.transfer_type = transfer_type;
Wolfgang Betz 1:f90318e0923b 524
Wolfgang Betz 1:f90318e0923b 525 // the HAL expects number of transfers instead of number of bytes
Wolfgang Betz 1:f90318e0923b 526 int words;
Wolfgang Betz 1:f90318e0923b 527 switch(handle->Init.DataFormat) {
Wolfgang Betz 1:f90318e0923b 528 case I2S_DATAFORMAT_16B:
Wolfgang Betz 1:f90318e0923b 529 case I2S_DATAFORMAT_16B_EXTENDED:
Wolfgang Betz 1:f90318e0923b 530 words = length / 2;
Wolfgang Betz 1:f90318e0923b 531 if(words > 0xFFFC) words = 0xFFFC; // truncate in order to respect max DMA length
Wolfgang Betz 1:f90318e0923b 532 break;
Wolfgang Betz 1:f90318e0923b 533 case I2S_DATAFORMAT_24B:
Wolfgang Betz 1:f90318e0923b 534 case I2S_DATAFORMAT_32B:
Wolfgang Betz 1:f90318e0923b 535 default:
Wolfgang Betz 1:f90318e0923b 536 words = length / 4;
Wolfgang Betz 1:f90318e0923b 537 if(words > 0x7FFC) words = 0x7FFC; // truncate in order to respect max DMA length
Wolfgang Betz 1:f90318e0923b 538 break;
Wolfgang Betz 1:f90318e0923b 539 }
Wolfgang Betz 1:f90318e0923b 540
Wolfgang Betz 1:f90318e0923b 541 // enable the right hal transfer
Wolfgang Betz 1:f90318e0923b 542 int rc = 0;
Wolfgang Betz 1:f90318e0923b 543 switch(transfer_type) {
Wolfgang Betz 1:f90318e0923b 544 case I2S_TRANSFER_TYPE_TXRX:
Wolfgang Betz 1:f90318e0923b 545 // enable the interrupts
Wolfgang Betz 1:f90318e0923b 546 NVIC_EnableIRQ(obj->dma.dma[DMA_TX]->dma_stream_irq);
Wolfgang Betz 1:f90318e0923b 547 NVIC_EnableIRQ(obj->dma.dma[DMA_RX]->dma_stream_irq);
Wolfgang Betz 1:f90318e0923b 548 // trigger DMA transfers
Wolfgang Betz 1:f90318e0923b 549 rc = HAL_I2SEx_TransmitReceive_DMA(handle, (uint16_t*)tx, (uint16_t*)rx, (uint16_t)words);
Wolfgang Betz 1:f90318e0923b 550 break;
Wolfgang Betz 1:f90318e0923b 551 case I2S_TRANSFER_TYPE_TX:
Wolfgang Betz 1:f90318e0923b 552 // enable the interrupt
Wolfgang Betz 1:f90318e0923b 553 NVIC_EnableIRQ(obj->dma.dma[DMA_TX]->dma_stream_irq);
Wolfgang Betz 1:f90318e0923b 554 // trigger DMA transfer
Wolfgang Betz 1:f90318e0923b 555 rc = HAL_I2S_Transmit_DMA(handle, (uint16_t*)tx, (uint16_t)words);
Wolfgang Betz 1:f90318e0923b 556 break;
Wolfgang Betz 1:f90318e0923b 557 case I2S_TRANSFER_TYPE_RX:
Wolfgang Betz 1:f90318e0923b 558 // enable the interrupt
Wolfgang Betz 1:f90318e0923b 559 NVIC_EnableIRQ(obj->dma.dma[DMA_RX]->dma_stream_irq);
Wolfgang Betz 1:f90318e0923b 560 // trigger DMA transfer
Wolfgang Betz 1:f90318e0923b 561 rc = HAL_I2S_Receive_DMA(handle, (uint16_t*)rx, (uint16_t)words);
Wolfgang Betz 1:f90318e0923b 562 break;
Wolfgang Betz 1:f90318e0923b 563 }
Wolfgang Betz 1:f90318e0923b 564
Wolfgang Betz 1:f90318e0923b 565 if (rc) {
Wolfgang Betz 1:f90318e0923b 566 DEBUG_PRINTF("I2S%u: RC=%d\n", obj->i2s.module+1, rc);
Wolfgang Betz 1:f90318e0923b 567 }
Wolfgang Betz 1:f90318e0923b 568
Wolfgang Betz 1:f90318e0923b 569 return;
Wolfgang Betz 1:f90318e0923b 570 }
Wolfgang Betz 1:f90318e0923b 571
Wolfgang Betz 1:f90318e0923b 572 // asynchronous API
Wolfgang Betz 1:f90318e0923b 573 void i2s_transfer(i2s_t *obj,
Wolfgang Betz 1:f90318e0923b 574 void *tx, int tx_length,
Wolfgang Betz 1:f90318e0923b 575 void *rx, int rx_length,
Wolfgang Betz 1:f90318e0923b 576 bool circular, i2s_dma_prio_t prio,
Wolfgang Betz 1:f90318e0923b 577 uint32_t handler_tx, uint32_t handler_rx, uint32_t event)
Wolfgang Betz 1:f90318e0923b 578 {
Wolfgang Betz 1:f90318e0923b 579 // check which use-case we have
Wolfgang Betz 1:f90318e0923b 580 bool use_tx = (tx != NULL && tx_length > 0);
Wolfgang Betz 1:f90318e0923b 581 bool use_rx = (rx != NULL && rx_length > 0);
Wolfgang Betz 1:f90318e0923b 582
Wolfgang Betz 1:f90318e0923b 583 // Init DMAs
Wolfgang Betz 1:f90318e0923b 584 dma_i2s_init(obj, &use_tx, &use_rx, circular, prio);
Wolfgang Betz 1:f90318e0923b 585
Wolfgang Betz 1:f90318e0923b 586 // don't do anything, if the buffers aren't valid
Wolfgang Betz 1:f90318e0923b 587 if (!use_tx && !use_rx)
Wolfgang Betz 1:f90318e0923b 588 return;
Wolfgang Betz 1:f90318e0923b 589
Wolfgang Betz 1:f90318e0923b 590 // copy the buffers to the I2S object
Wolfgang Betz 1:f90318e0923b 591 obj->tx_buff.buffer = tx;
Wolfgang Betz 1:f90318e0923b 592 obj->tx_buff.length = tx_length;
Wolfgang Betz 1:f90318e0923b 593 obj->tx_buff.pos = 0;
Wolfgang Betz 1:f90318e0923b 594 obj->tx_buff.width = 16;
Wolfgang Betz 1:f90318e0923b 595
Wolfgang Betz 1:f90318e0923b 596 obj->rx_buff.buffer = rx;
Wolfgang Betz 1:f90318e0923b 597 obj->rx_buff.length = rx_length;
Wolfgang Betz 1:f90318e0923b 598 obj->rx_buff.pos = 0;
Wolfgang Betz 1:f90318e0923b 599 obj->rx_buff.width = obj->tx_buff.width;
Wolfgang Betz 1:f90318e0923b 600
Wolfgang Betz 1:f90318e0923b 601 obj->i2s.event = event;
Wolfgang Betz 1:f90318e0923b 602
Wolfgang Betz 1:f90318e0923b 603 DEBUG_PRINTF("I2S%u: Transfer: %u, %u\n", obj->i2s.module+1, tx_length, rx_length);
Wolfgang Betz 1:f90318e0923b 604
Wolfgang Betz 1:f90318e0923b 605 // register the thunking handler
Wolfgang Betz 1:f90318e0923b 606 if(use_tx) {
Wolfgang Betz 1:f90318e0923b 607 NVIC_SetVector(obj->dma.dma[DMA_TX]->dma_stream_irq, handler_tx);
Wolfgang Betz 1:f90318e0923b 608 }
Wolfgang Betz 1:f90318e0923b 609 if(use_rx) {
Wolfgang Betz 1:f90318e0923b 610 NVIC_SetVector(obj->dma.dma[DMA_RX]->dma_stream_irq, handler_rx);
Wolfgang Betz 1:f90318e0923b 611 }
Wolfgang Betz 1:f90318e0923b 612
Wolfgang Betz 1:f90318e0923b 613 // enable the right hal transfer
Wolfgang Betz 1:f90318e0923b 614 if (use_tx && use_rx) {
Wolfgang Betz 1:f90318e0923b 615 int size = (tx_length < rx_length)? tx_length : rx_length;
Wolfgang Betz 1:f90318e0923b 616 i2s_start_asynch_transfer(obj, I2S_TRANSFER_TYPE_TXRX, tx, rx, size);
Wolfgang Betz 1:f90318e0923b 617 } else if (use_tx) {
Wolfgang Betz 1:f90318e0923b 618 i2s_start_asynch_transfer(obj, I2S_TRANSFER_TYPE_TX, tx, NULL, tx_length);
Wolfgang Betz 1:f90318e0923b 619 } else if (use_rx) {
Wolfgang Betz 1:f90318e0923b 620 i2s_start_asynch_transfer(obj, I2S_TRANSFER_TYPE_RX, NULL, rx, rx_length);
Wolfgang Betz 1:f90318e0923b 621 }
Wolfgang Betz 1:f90318e0923b 622 }
Wolfgang Betz 1:f90318e0923b 623
Wolfgang Betz 1:f90318e0923b 624 uint32_t i2s_irq_handler_asynch(i2s_t *obj, uint8_t direction)
Wolfgang Betz 1:f90318e0923b 625 {
Wolfgang Betz 1:f90318e0923b 626 direction = (direction == I2S_TX_EVENT) ? DMA_TX : DMA_RX;
Wolfgang Betz 1:f90318e0923b 627
Wolfgang Betz 1:f90318e0923b 628 // use the right instance
Wolfgang Betz 1:f90318e0923b 629 I2S_HandleTypeDef *i2s_handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 630 DMA_HandleTypeDef *dma_handle = (direction == DMA_TX) ? i2s_handle->hdmatx : i2s_handle->hdmarx;
Wolfgang Betz 1:f90318e0923b 631
Wolfgang Betz 1:f90318e0923b 632 MBED_ASSERT(dma_handle != NULL);
Wolfgang Betz 1:f90318e0923b 633
Wolfgang Betz 1:f90318e0923b 634 int event = 0;
Wolfgang Betz 1:f90318e0923b 635
Wolfgang Betz 1:f90318e0923b 636 // call the Cube handler, this will update the handle
Wolfgang Betz 1:f90318e0923b 637 HAL_DMA_IRQHandler(dma_handle);
Wolfgang Betz 1:f90318e0923b 638
Wolfgang Betz 1:f90318e0923b 639 switch(HAL_I2S_GetState(i2s_handle)) {
Wolfgang Betz 1:f90318e0923b 640 case HAL_I2S_STATE_READY: {
Wolfgang Betz 1:f90318e0923b 641 // adjust buffer positions (betzw - TODO: to be checked for DMA transfers!!!)
Wolfgang Betz 1:f90318e0923b 642 int tx_size = (i2s_handle->TxXferSize - i2s_handle->TxXferCount);
Wolfgang Betz 1:f90318e0923b 643 int rx_size = (i2s_handle->RxXferSize - i2s_handle->RxXferCount);
Wolfgang Betz 1:f90318e0923b 644
Wolfgang Betz 1:f90318e0923b 645 // take data format into consideration
Wolfgang Betz 1:f90318e0923b 646 switch(i2s_handle->Init.DataFormat) {
Wolfgang Betz 1:f90318e0923b 647 case I2S_DATAFORMAT_16B:
Wolfgang Betz 1:f90318e0923b 648 case I2S_DATAFORMAT_16B_EXTENDED:
Wolfgang Betz 1:f90318e0923b 649 tx_size *= 2;
Wolfgang Betz 1:f90318e0923b 650 rx_size *= 2;
Wolfgang Betz 1:f90318e0923b 651 break;
Wolfgang Betz 1:f90318e0923b 652 case I2S_DATAFORMAT_24B:
Wolfgang Betz 1:f90318e0923b 653 case I2S_DATAFORMAT_32B:
Wolfgang Betz 1:f90318e0923b 654 default:
Wolfgang Betz 1:f90318e0923b 655 tx_size *= 4;
Wolfgang Betz 1:f90318e0923b 656 rx_size *= 4;
Wolfgang Betz 1:f90318e0923b 657 break;
Wolfgang Betz 1:f90318e0923b 658 }
Wolfgang Betz 1:f90318e0923b 659
Wolfgang Betz 1:f90318e0923b 660 // adjust buffer positions
Wolfgang Betz 1:f90318e0923b 661 if (obj->i2s.transfer_type != I2S_TRANSFER_TYPE_RX) {
Wolfgang Betz 1:f90318e0923b 662 obj->tx_buff.pos += tx_size;
Wolfgang Betz 1:f90318e0923b 663 }
Wolfgang Betz 1:f90318e0923b 664 if (obj->i2s.transfer_type != I2S_TRANSFER_TYPE_TX) {
Wolfgang Betz 1:f90318e0923b 665 obj->rx_buff.pos += rx_size;
Wolfgang Betz 1:f90318e0923b 666 }
Wolfgang Betz 1:f90318e0923b 667
Wolfgang Betz 1:f90318e0923b 668 if (i2s_handle->TxXferCount > 0) {
Wolfgang Betz 1:f90318e0923b 669 DEBUG_PRINTF("I2S%u: TxXferCount: %u\n", obj->i2s.module+1, i2s_handle->TxXferCount);
Wolfgang Betz 1:f90318e0923b 670 }
Wolfgang Betz 1:f90318e0923b 671 if (i2s_handle->RxXferCount > 0) {
Wolfgang Betz 1:f90318e0923b 672 DEBUG_PRINTF("I2S%u: RxXferCount: %u\n", obj->i2s.module+1, i2s_handle->RxXferCount);
Wolfgang Betz 1:f90318e0923b 673 }
Wolfgang Betz 1:f90318e0923b 674 }
Wolfgang Betz 1:f90318e0923b 675 /* no break */
Wolfgang Betz 1:f90318e0923b 676
Wolfgang Betz 1:f90318e0923b 677 case HAL_I2S_STATE_BUSY_TX:
Wolfgang Betz 1:f90318e0923b 678 case HAL_I2S_STATE_BUSY_RX:
Wolfgang Betz 1:f90318e0923b 679 case HAL_I2S_STATE_BUSY_TX_RX: {
Wolfgang Betz 1:f90318e0923b 680 int error = HAL_I2S_GetError(i2s_handle);
Wolfgang Betz 1:f90318e0923b 681
Wolfgang Betz 1:f90318e0923b 682 if(error != HAL_I2S_ERROR_NONE) {
Wolfgang Betz 1:f90318e0923b 683 // something went wrong and the transfer has definitely completed
Wolfgang Betz 1:f90318e0923b 684 event = ((direction == DMA_TX) ? I2S_EVENT_TX_ERROR : I2S_EVENT_RX_ERROR) | I2S_EVENT_INTERNAL_TRANSFER_COMPLETE;
Wolfgang Betz 1:f90318e0923b 685
Wolfgang Betz 1:f90318e0923b 686 if (error & HAL_I2S_ERROR_OVR) {
Wolfgang Betz 1:f90318e0923b 687 // buffer overrun
Wolfgang Betz 1:f90318e0923b 688 event |= I2S_EVENT_RX_OVERFLOW;
Wolfgang Betz 1:f90318e0923b 689 }
Wolfgang Betz 1:f90318e0923b 690
Wolfgang Betz 1:f90318e0923b 691 if (error & HAL_I2S_ERROR_UDR) {
Wolfgang Betz 1:f90318e0923b 692 // buffer underrun
Wolfgang Betz 1:f90318e0923b 693 event |= I2S_EVENT_TX_UNDERRUN;
Wolfgang Betz 1:f90318e0923b 694 }
Wolfgang Betz 1:f90318e0923b 695
Wolfgang Betz 1:f90318e0923b 696 // cleanup DMA (after error)
Wolfgang Betz 1:f90318e0923b 697 dma_i2s_free(obj, direction);
Wolfgang Betz 1:f90318e0923b 698 } else { // no error detected
Wolfgang Betz 1:f90318e0923b 699 HAL_DMA_StateTypeDef dma_state = HAL_DMA_GetState(dma_handle);
Wolfgang Betz 1:f90318e0923b 700
Wolfgang Betz 1:f90318e0923b 701 switch(dma_state) {
Wolfgang Betz 1:f90318e0923b 702 case HAL_DMA_STATE_READY_HALF_MEM0:
Wolfgang Betz 1:f90318e0923b 703 case HAL_DMA_STATE_READY_HALF_MEM1:
Wolfgang Betz 1:f90318e0923b 704 event = ((direction == DMA_TX) ? I2S_EVENT_TX_HALF_COMPLETE : I2S_EVENT_RX_HALF_COMPLETE);
Wolfgang Betz 1:f90318e0923b 705 break;
Wolfgang Betz 1:f90318e0923b 706 case HAL_DMA_STATE_READY_MEM0:
Wolfgang Betz 1:f90318e0923b 707 case HAL_DMA_STATE_READY_MEM1:
Wolfgang Betz 1:f90318e0923b 708 event = ((direction == DMA_TX) ? I2S_EVENT_TX_COMPLETE : I2S_EVENT_RX_COMPLETE);
Wolfgang Betz 1:f90318e0923b 709
Wolfgang Betz 1:f90318e0923b 710 if(dma_handle->Init.Mode != DMA_CIRCULAR) {
Wolfgang Betz 1:f90318e0923b 711 if (!i2s_active(obj)) { // Check for full-duplex transfer complete!
Wolfgang Betz 1:f90318e0923b 712 event |= I2S_EVENT_INTERNAL_TRANSFER_COMPLETE;
Wolfgang Betz 1:f90318e0923b 713 }
Wolfgang Betz 1:f90318e0923b 714
Wolfgang Betz 1:f90318e0923b 715 // cleanup DMA (because we are done)
Wolfgang Betz 1:f90318e0923b 716 dma_i2s_free(obj, direction);
Wolfgang Betz 1:f90318e0923b 717 }
Wolfgang Betz 1:f90318e0923b 718 break;
Wolfgang Betz 1:f90318e0923b 719 default:
Wolfgang Betz 1:f90318e0923b 720 printf("betzw(%s, %d): dma_state=0x%x\r\n", __func__, __LINE__, (int)dma_state);
Wolfgang Betz 1:f90318e0923b 721 MBED_ASSERT(0);
Wolfgang Betz 1:f90318e0923b 722 break;
Wolfgang Betz 1:f90318e0923b 723 }
Wolfgang Betz 1:f90318e0923b 724 }
Wolfgang Betz 1:f90318e0923b 725 }
Wolfgang Betz 1:f90318e0923b 726 break;
Wolfgang Betz 1:f90318e0923b 727
Wolfgang Betz 1:f90318e0923b 728 default:
Wolfgang Betz 1:f90318e0923b 729 // nothing to do?!?
Wolfgang Betz 1:f90318e0923b 730 break;
Wolfgang Betz 1:f90318e0923b 731 }
Wolfgang Betz 1:f90318e0923b 732
Wolfgang Betz 1:f90318e0923b 733 if (event) DEBUG_PRINTF("I2S%u: Event: 0x%x\n", obj->i2s.module+1, event);
Wolfgang Betz 1:f90318e0923b 734
Wolfgang Betz 1:f90318e0923b 735 return (event & (obj->i2s.event | I2S_EVENT_INTERNAL_TRANSFER_COMPLETE));
Wolfgang Betz 1:f90318e0923b 736 }
Wolfgang Betz 1:f90318e0923b 737
Wolfgang Betz 1:f90318e0923b 738 uint8_t i2s_active(i2s_t *obj)
Wolfgang Betz 1:f90318e0923b 739 {
Wolfgang Betz 1:f90318e0923b 740 I2S_HandleTypeDef *handle = &I2sHandle[obj->i2s.module];
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 1:f90318e0923b 749 return -1;
Wolfgang Betz 1:f90318e0923b 750 }
Wolfgang Betz 1:f90318e0923b 751 }
Wolfgang Betz 1:f90318e0923b 752
Wolfgang Betz 1:f90318e0923b 753 void i2s_abort_asynch(i2s_t *obj)
Wolfgang Betz 1:f90318e0923b 754 {
Wolfgang Betz 1:f90318e0923b 755 I2S_HandleTypeDef *i2s_handle = &I2sHandle[obj->i2s.module];
Wolfgang Betz 1:f90318e0923b 756
Wolfgang Betz 1:f90318e0923b 757 // Stop transfer
Wolfgang Betz 1:f90318e0923b 758 HAL_I2S_DMAStop(i2s_handle);
Wolfgang Betz 1:f90318e0923b 759
Wolfgang Betz 1:f90318e0923b 760 if(obj->dma.dma[DMA_TX] != NULL) {
Wolfgang Betz 1:f90318e0923b 761 DMA_HandleTypeDef *dma_handle_tx = &DMaHandles[obj->i2s.module][DMA_TX];
Wolfgang Betz 1:f90318e0923b 762
Wolfgang Betz 1:f90318e0923b 763 // disable interrupt & free resource
Wolfgang Betz 1:f90318e0923b 764 dma_i2s_free(obj, DMA_TX);
Wolfgang Betz 1:f90318e0923b 765
Wolfgang Betz 1:f90318e0923b 766 //clean up
Wolfgang Betz 1:f90318e0923b 767 __HAL_DMA_DISABLE(dma_handle_tx);
Wolfgang Betz 1:f90318e0923b 768 HAL_DMA_DeInit(dma_handle_tx);
Wolfgang Betz 1:f90318e0923b 769 HAL_DMA_Init(dma_handle_tx);
Wolfgang Betz 1:f90318e0923b 770 __HAL_DMA_ENABLE(dma_handle_tx);
Wolfgang Betz 1:f90318e0923b 771 }
Wolfgang Betz 1:f90318e0923b 772 if(obj->dma.dma[DMA_RX] != NULL) {
Wolfgang Betz 1:f90318e0923b 773 DMA_HandleTypeDef *dma_handle_rx = &DMaHandles[obj->i2s.module][DMA_RX];
Wolfgang Betz 1:f90318e0923b 774
Wolfgang Betz 1:f90318e0923b 775 // disable interrupt & free resource
Wolfgang Betz 1:f90318e0923b 776 dma_i2s_free(obj, DMA_RX);
Wolfgang Betz 1:f90318e0923b 777
Wolfgang Betz 1:f90318e0923b 778 //clean up
Wolfgang Betz 1:f90318e0923b 779 __HAL_DMA_DISABLE(dma_handle_rx);
Wolfgang Betz 1:f90318e0923b 780 HAL_DMA_DeInit(dma_handle_rx);
Wolfgang Betz 1:f90318e0923b 781 HAL_DMA_Init(dma_handle_rx);
Wolfgang Betz 1:f90318e0923b 782 __HAL_DMA_ENABLE(dma_handle_rx);
Wolfgang Betz 1:f90318e0923b 783 }
Wolfgang Betz 1:f90318e0923b 784
Wolfgang Betz 1:f90318e0923b 785 // clean-up I2S
Wolfgang Betz 1:f90318e0923b 786 __HAL_I2S_DISABLE(i2s_handle);
Wolfgang Betz 1:f90318e0923b 787 HAL_I2S_DeInit(i2s_handle);
Wolfgang Betz 1:f90318e0923b 788 HAL_I2S_Init(i2s_handle);
Wolfgang Betz 1:f90318e0923b 789 __HAL_I2S_ENABLE(i2s_handle);
Wolfgang Betz 1:f90318e0923b 790 }
Wolfgang Betz 1:f90318e0923b 791
Wolfgang Betz 1:f90318e0923b 792 #endif