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