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