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