Library to control and transfer data from NXP SGTL5000. As used on the Teensy Audio Shield. It uses DMA to transfer I2S FIFO data.

The Library now supports dual codecs. Allowing all 4 channels of the Teensy I2S interface to RX and TX data to separate SGTL5000 devices.

The ISR routines that handles pointer swaps for double buffering has been fully coded in assembler to reduce overhead and now takes < 800nS per FIFO transfer when using all 4 channels.

Support added for all typical sample rates and system Clock speeds of 96Mhz or 120Mhz.

Pause and Resume functions added to allow quick and simple suppression of IRQs and stream halting and restart. This required software triggered IRQ, in order to ensure accurate word sync control.

Committer:
aidan1971
Date:
Sat Jul 15 13:15:08 2017 +0000
Revision:
9:40e0ff8c2ba2
Parent:
8:9fdf8501d14b
Child:
10:49bb33f71d32
Changed the stop functions to suspend IRQs and DMA requests, also the codec's I2S interface is disabled. During start, the MCUs I2S state machine is now reset, before acquiring sync.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
aidan1971 3:62c03088f256 1 /*!
aidan1971 0:8f28f25e3435 2 @ author Aidan Walton, aidan.walton@gmail.com
aidan1971 0:8f28f25e3435 3
aidan1971 0:8f28f25e3435 4 @section LICENSE
aidan1971 0:8f28f25e3435 5 * Permission is hereby granted, free of charge, to any person obtaining a copy
aidan1971 0:8f28f25e3435 6 * of this software and associated documentation files (the "Software"), to deal
aidan1971 0:8f28f25e3435 7 * in the Software without restriction, including without limitation the rights
aidan1971 0:8f28f25e3435 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
aidan1971 0:8f28f25e3435 9 * copies of the Software, and to permit persons to whom the Software is
aidan1971 0:8f28f25e3435 10 * furnished to do so, subject to the following conditions:
aidan1971 0:8f28f25e3435 11 *
aidan1971 0:8f28f25e3435 12 * The above copyright notice, development funding notice, and this permission
aidan1971 0:8f28f25e3435 13 * notice shall be included in all copies or substantial portions of the Software.
aidan1971 0:8f28f25e3435 14 *
aidan1971 0:8f28f25e3435 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
aidan1971 0:8f28f25e3435 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
aidan1971 0:8f28f25e3435 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
aidan1971 0:8f28f25e3435 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
aidan1971 0:8f28f25e3435 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
aidan1971 0:8f28f25e3435 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
aidan1971 0:8f28f25e3435 21 * THE SOFTWARE.
aidan1971 0:8f28f25e3435 22
aidan1971 0:8f28f25e3435 23 @section DESCRIPTION
aidan1971 0:8f28f25e3435 24 Library for NXP SGTL5000 Codec
aidan1971 0:8f28f25e3435 25 */
aidan1971 0:8f28f25e3435 26
aidan1971 0:8f28f25e3435 27 #ifndef MBED_SGTL5000_H
aidan1971 0:8f28f25e3435 28 #define MBED_SGTL5000_H
aidan1971 0:8f28f25e3435 29
aidan1971 0:8f28f25e3435 30 #include "mbed.h"
aidan1971 0:8f28f25e3435 31 #include "platform.h"
aidan1971 0:8f28f25e3435 32 #include "Callback.h"
aidan1971 0:8f28f25e3435 33 #include "sgtl5000_defs.h"
aidan1971 0:8f28f25e3435 34
aidan1971 3:62c03088f256 35 /** SGTL5000 namespace
aidan1971 3:62c03088f256 36 */
aidan1971 0:8f28f25e3435 37 namespace SGTL5000
aidan1971 0:8f28f25e3435 38 {
aidan1971 0:8f28f25e3435 39
aidan1971 3:62c03088f256 40 /*! SGTL5000 codec driver class
aidan1971 3:62c03088f256 41 */
aidan1971 3:62c03088f256 42 /*! Class for NXP SGTL5000 codec instance.
aidan1971 3:62c03088f256 43 * @code
aidan1971 3:62c03088f256 44 * #include 'SGTL5000.h'
aidan1971 3:62c03088f256 45 *
aidan1971 3:62c03088f256 46 * SGTL5000::SGTL5000 codec(I2C_SDA, I2C_SCL);
aidan1971 3:62c03088f256 47 *
aidan1971 3:62c03088f256 48 * static q31_t *RX_AudioL = NULL;
aidan1971 3:62c03088f256 49 * static q31_t *RX_AudioR = NULL;
aidan1971 3:62c03088f256 50 * static q31_t *TX_AudioL = NULL;
aidan1971 3:62c03088f256 51 * static q31_t *TX_AudioR = NULL;
aidan1971 3:62c03088f256 52 *
aidan1971 3:62c03088f256 53 * const uint32_t I2S_FIFO_BS = 4;
aidan1971 3:62c03088f256 54 *
aidan1971 3:62c03088f256 55 *
aidan1971 3:62c03088f256 56 * uint32_t main()
aidan1971 3:62c03088f256 57 * {
aidan1971 3:62c03088f256 58 * codec.modify_i2c(SGTL5000_ANA_HP_CTRL, 0x18, SGTL5000_ANA_HP_CTRL_HP_VOL_RIGHT_MASK); // Headphone volume control with 0.5 dB steps.0x00 = +12 dB, 0x01 = +11.5 dB, 0x18 = 0 dB,...0x7F = -51.5 dB
aidan1971 3:62c03088f256 59 * codec.modify_i2c(SGTL5000_ANA_HP_CTRL, 0x18, SGTL5000_ANA_HP_CTRL_HP_VOL_LEFT_MASK);
aidan1971 6:4ab5aaeaa064 60 *
aidan1971 3:62c03088f256 61 * codec.attach_SYNC_NB((uint32_t)&I2S_SYNC_ISR);
aidan1971 3:62c03088f256 62 * codec.freq(96);
aidan1971 3:62c03088f256 63 * codec.start_SYNC((uint32_t)&RX_AudioL, (uint32_t)&RX_AudioR, (uint32_t)&TX_AudioL, (uint32_t)&TX_AudioR, I2S_FIFO_BS)
aidan1971 3:62c03088f256 64 * }
aidan1971 3:62c03088f256 65 *
aidan1971 3:62c03088f256 66 * void I2S_SYNC_ISR(void)
aidan1971 3:62c03088f256 67 * {
aidan1971 3:62c03088f256 68 * for(uint32_t i = 0; i < (I2S_FIFO_BS >> 1); ++i)
aidan1971 3:62c03088f256 69 * {
aidan1971 3:62c03088f256 70 * TX_AudioL[i] = RX_AudioL[i];
aidan1971 3:62c03088f256 71 * TX_AudioR[i] = RX_AudioR[i];
aidan1971 3:62c03088f256 72 * }
aidan1971 3:62c03088f256 73 * }
aidan1971 3:62c03088f256 74 @endcode
aidan1971 3:62c03088f256 75 */
aidan1971 0:8f28f25e3435 76 class SGTL5000
aidan1971 0:8f28f25e3435 77
aidan1971 0:8f28f25e3435 78 {
aidan1971 0:8f28f25e3435 79 public:
aidan1971 3:62c03088f256 80 //Constructor
aidan1971 3:62c03088f256 81 /*!
aidan1971 0:8f28f25e3435 82 @brief Create an SGTL5000 object defined on the I2C port using DMA transfers of I2S data. The class is not defined as a singleton, as future development may require
aidan1971 3:62c03088f256 83 multiple instances. However currently it should only be instantiated once. The class is wrapped in the SGTL5000 namespace to avoid collisions with statics
aidan1971 3:62c03088f256 84 needed by the ISRs.
aidan1971 0:8f28f25e3435 85
aidan1971 0:8f28f25e3435 86 @param i2c_sda i2c Serial data pin (D18 Teensy 3.2 header / PTB3 MK20DX256)
aidan1971 0:8f28f25e3435 87 @param i2c_scl i2c Serial clock pin (D19 Teensy 3.2 header / PTB2 MK20DX256)
aidan1971 0:8f28f25e3435 88 @param i2c_freq Frequency in Hz at which the i2c codec interface clocks data
aidan1971 0:8f28f25e3435 89 @param i2c_ctrl_adr0_cs State on SGTL5000 CTRL_ADR0_CS pin i2c addr = 0n01010(R/W) :R/W = 1 to write R/W = 0 to read, n = 0 pull down / n = 1 pull up on CTRL_ADR0_CS pin of SGTL5000)
aidan1971 0:8f28f25e3435 90
aidan1971 0:8f28f25e3435 91
aidan1971 0:8f28f25e3435 92 // Pin Configs for i2s hardcoded as follows to match Teensy Audio Shield
aidan1971 0:8f28f25e3435 93 i2s_mclk i2s master clock (D11 Teensy 3.2 header / PTC6 MK20DX256)
aidan1971 0:8f28f25e3435 94 i2s_bclk i2s bit clock (D9 Teensy 3.2 header / PTC3 MK20DX256)
aidan1971 0:8f28f25e3435 95 i2s_fs i2s Frame Sync / L/R clock / WordSelect (D23 Teensy 3.2 header / PTC2 MK20DX256)
aidan1971 0:8f28f25e3435 96 i2s_rx i2s tx_data (from bus master perspective) (D22 Teensy 3.2 header / PTC1 MK20DX256)
aidan1971 0:8f28f25e3435 97 i2s_tx i2s rx_data (from bus master perspective) (D13 Teensy 3.2 header /PTC5 MK20DX256)
aidan1971 0:8f28f25e3435 98
aidan1971 0:8f28f25e3435 99 */
aidan1971 9:40e0ff8c2ba2 100 SGTL5000(PinName i2c_sda, PinName i2c_scl, int _i2c_freq = 100000, bool i2c_ctrl_adr0_cs = 0);
aidan1971 0:8f28f25e3435 101
aidan1971 3:62c03088f256 102 /*!
aidan1971 3:62c03088f256 103 @brief Read 16bit register of SGTL5000
aidan1971 3:62c03088f256 104 @param reg_addr 16bit address of the codec control register
aidan1971 3:62c03088f256 105 @param data 16bit data to read from the address
aidan1971 3:62c03088f256 106 @param mask 16bit mask applied over the data read from the codec. The final returned value is the register data automatically shifted to the position of the first masked bit.
aidan1971 3:62c03088f256 107 @returns 0 = register data, -1 = fail
aidan1971 3:62c03088f256 108 */
aidan1971 3:62c03088f256 109 int32_t read_i2c(uint32_t reg_addr, uint32_t mask = 0xFFFF);
aidan1971 6:4ab5aaeaa064 110
aidan1971 3:62c03088f256 111 /*!
aidan1971 3:62c03088f256 112 @brief Write 16bit register of SGTL5000
aidan1971 3:62c03088f256 113 @param reg_addr 16bit address of the codec control register
aidan1971 3:62c03088f256 114 @param data 16bit data to write into the address
aidan1971 3:62c03088f256 115 @returns 0 = success, -1 = fail
aidan1971 3:62c03088f256 116 */
aidan1971 3:62c03088f256 117 int32_t write_i2c(uint32_t reg_addr, uint32_t data);
aidan1971 6:4ab5aaeaa064 118
aidan1971 3:62c03088f256 119 /*!
aidan1971 3:62c03088f256 120 @brief Modify masked bits within 16bit register of SGTL5000
aidan1971 3:62c03088f256 121 @param reg_addr 16bit address of the codec control register
aidan1971 3:62c03088f256 122 @param data 16bit data to write into the address
aidan1971 3:62c03088f256 123 @param mask 16bit mask of the bits to modify.
aidan1971 3:62c03088f256 124 The function automatically shifts the data to the position of the first masked bit.
aidan1971 3:62c03088f256 125 @returns 0 = success, -1 = fail
aidan1971 3:62c03088f256 126 */
aidan1971 6:4ab5aaeaa064 127 int32_t modify_i2c(uint32_t reg_addr, uint32_t data, uint32_t mask);
aidan1971 6:4ab5aaeaa064 128
aidan1971 3:62c03088f256 129 /*!
aidan1971 0:8f28f25e3435 130 @brief Attach a callback function to TX
aidan1971 3:62c03088f256 131 @param func Address of the user function to be called from the TX FIFO triggered ISR.
aidan1971 3:62c03088f256 132 This is blocking. If the user function does not complete before the next DMA completes the system will likely crash,
aidan1971 3:62c03088f256 133 however using this function avoids the latency of an IRQ stack push.
aidan1971 3:62c03088f256 134 @returns 0 = success, -1 = fail.
aidan1971 3:62c03088f256 135 Fails if already attached, must detach first.
aidan1971 0:8f28f25e3435 136 */
aidan1971 0:8f28f25e3435 137 int32_t attach_TX(Callback<void()> func);
aidan1971 6:4ab5aaeaa064 138
aidan1971 3:62c03088f256 139 /*!
aidan1971 3:62c03088f256 140 @brief Attach an ISR function to DMA TX
aidan1971 3:62c03088f256 141 @param user_ISR Address of the user function to be assigned as the NVIC vector for the DMA TX FIFO triggered user_ISR.
aidan1971 0:8f28f25e3435 142 @param irq_pri Set the system wide priority of the user_ISR.
aidan1971 0:8f28f25e3435 143 @param sw_irq The IRQ assigned. Default uses Reserved54_IRQn. See "MK20DX256.h" for available.
aidan1971 0:8f28f25e3435 144 This is non-blocking provided the priority of the IRQ associated with user_ISR is lower than the priority of the DMA triggered ISR.
aidan1971 0:8f28f25e3435 145 It can be useful to use a non-blocking call, however this involves the extra time needed to push the stack and manageing IRQ priorities
aidan1971 0:8f28f25e3435 146 across the whole system needs consideration.
aidan1971 0:8f28f25e3435 147 */
aidan1971 8:9fdf8501d14b 148 int32_t attach_TX_NB(uint32_t user_ISR, uint32_t irq_pri = 1, IRQn sw_irq = Reserved54_IRQn);
aidan1971 6:4ab5aaeaa064 149
aidan1971 3:62c03088f256 150 /*!
aidan1971 0:8f28f25e3435 151 @brief Stop TX channel and flag as detached.
aidan1971 0:8f28f25e3435 152 During running stream, the callback based function can not be changed. However changes to the NB IRQ based attachment can have the vector changed on-the-fly
aidan1971 0:8f28f25e3435 153 */
aidan1971 8:9fdf8501d14b 154 int32_t detach_TX(void);
aidan1971 0:8f28f25e3435 155
aidan1971 3:62c03088f256 156 /*!
aidan1971 9:40e0ff8c2ba2 157 @brief Stops i2s TX channel. Stops all DMA requests and supresses any IRQs from the driver.
aidan1971 9:40e0ff8c2ba2 158 This can be used to suspend the codec when a user wishes to run critical tasks where IRQs must be disabled. To restart call the start function again.
aidan1971 0:8f28f25e3435 159 */
aidan1971 8:9fdf8501d14b 160 int32_t stop_TX(void);
aidan1971 6:4ab5aaeaa064 161
aidan1971 3:62c03088f256 162 /*!
aidan1971 0:8f28f25e3435 163 @brief Starts the codec I2S interface and begins transferring TX buffers. Transfers use DMA.
aidan1971 9:40e0ff8c2ba2 164 @param _BufTX_L_safe A pointer address to the TX Left channel data.
aidan1971 0:8f28f25e3435 165 The pointer address is managed by the driver and changes to implement a double buffer.
aidan1971 0:8f28f25e3435 166 It is suggested that a suitable declaration in the users code would be in the form: 'q31_t *TX_AudioL = NULL;'
aidan1971 0:8f28f25e3435 167 Although volatile is not strictly necessary both the pointer address and the data pointed to, are changing outside the flow of the user code.
aidan1971 0:8f28f25e3435 168 To pass into the class, dereference this pointer and cast as uint32_t, as follows: 'codec.start_SYNC((uint32_t)&TX_AudioL .....'
aidan1971 9:40e0ff8c2ba2 169 @param _BufTX_R_safe A pointer address to the TX Right channel data.
aidan1971 9:40e0ff8c2ba2 170 @param _block_size 2 | 4 | 8 words of both Left and Right channels combined.
aidan1971 0:8f28f25e3435 171 This defines the number of samples that are transferred to the TX FIFO each time a FIFO demand is detected.
aidan1971 9:40e0ff8c2ba2 172 @param _packed_TX If true 2 * 16bit words for wire transmission are expected packed into a single 32bit word.
aidan1971 4:91354c908416 173 If False each 32bit word from the user should contain a single 16bit word for transmission.
aidan1971 9:40e0ff8c2ba2 174 @param _TX_shift True = The MS16bits of TX buffer are sent to the TX FIFO. Default = true.
aidan1971 0:8f28f25e3435 175 False = The LS16bits of TX buffer are sent to the TX FIFO.
aidan1971 4:91354c908416 176 If packed is true, then shift has no relevance.
aidan1971 9:40e0ff8c2ba2 177 @param _tx_DMAch Defines the system DMA channel to assign to the TX transfer. Default is 15.
aidan1971 0:8f28f25e3435 178 15 is used as default to avoid using channels 0 - 3 which are the only channels available for gated triggers.
aidan1971 0:8f28f25e3435 179 Gated triggering is not needed, so these 4 channels are avoided.
aidan1971 9:40e0ff8c2ba2 180 @param _DMA_irq_pri Default = 0. Highest priority. This is the priority of the I2S TX DMA demands.
aidan1971 3:62c03088f256 181 @returns 0 = success, -1 = fail
aidan1971 3:62c03088f256 182 Fails on variable sanity checks.
aidan1971 0:8f28f25e3435 183 */
aidan1971 9:40e0ff8c2ba2 184 int32_t start_TX(uint32_t _BufTX_L_safe, uint32_t _BufTX_R_safe,
aidan1971 9:40e0ff8c2ba2 185 uint32_t _block_size = 4, bool _packed_TX = false, bool _TX_shift = true, uint32_t _TX_DMAch = 15, uint32_t _DMA_irq_pri = 0);
aidan1971 0:8f28f25e3435 186
aidan1971 3:62c03088f256 187 /*!
aidan1971 0:8f28f25e3435 188 @brief Attach a callback function to RX
aidan1971 0:8f28f25e3435 189 @param func User function to be called from the RX FIFO triggered ISR.
aidan1971 0:8f28f25e3435 190 This is blocking. If the user function does not complete before the next DMA completes the system will crash,
aidan1971 0:8f28f25e3435 191 however using this function avoids the latency of a stack push.
aidan1971 3:62c03088f256 192 @returns 0 = success, -1 = fail.
aidan1971 3:62c03088f256 193 Fails if already attached, must detach first.
aidan1971 0:8f28f25e3435 194 */
aidan1971 0:8f28f25e3435 195 int32_t attach_RX(Callback<void()> func);
aidan1971 6:4ab5aaeaa064 196
aidan1971 3:62c03088f256 197 /*!
aidan1971 3:62c03088f256 198 @brief Attach an ISR function to DMA RX
aidan1971 0:8f28f25e3435 199 @param user_ISR User function to be assigned as the NVIC vector for the DMA RX FIFO triggered user_ISR.
aidan1971 0:8f28f25e3435 200 @param irq_pri Set the system wide priority of the user_ISR.
aidan1971 0:8f28f25e3435 201 @param sw_irq The IRQ assigned. Default uses Reserved55_IRQn. See "MK20DX256.h" for available.
aidan1971 0:8f28f25e3435 202 This is non-blocking provided the priority of the IRQ associated with user_ISR is lower than the priority of the DMA triggered ISR.
aidan1971 0:8f28f25e3435 203 It can be useful to use a non-blocking call, however this involves the extra time needed to push the stack and manageing IRQ priorities
aidan1971 0:8f28f25e3435 204 across the whole system needs consideration.
aidan1971 0:8f28f25e3435 205 */
aidan1971 8:9fdf8501d14b 206 int32_t attach_RX_NB(uint32_t user_ISR, uint32_t irq_pri = 1, IRQn sw_irq = Reserved55_IRQn);
aidan1971 6:4ab5aaeaa064 207
aidan1971 3:62c03088f256 208 /*!
aidan1971 0:8f28f25e3435 209 @brief Stop RX channel and flag as detached.
aidan1971 9:40e0ff8c2ba2 210 During running stream, the callback based function can not be changed. However changes to the NB IRQ based attachment can have the vector changed on-the-fly
aidan1971 0:8f28f25e3435 211 */
aidan1971 8:9fdf8501d14b 212 int32_t detach_RX(void);
aidan1971 0:8f28f25e3435 213
aidan1971 3:62c03088f256 214 /*!
aidan1971 9:40e0ff8c2ba2 215 @brief Stops i2s RX channel. Stops all DMA requests and supresses any IRQs from the driver.
aidan1971 9:40e0ff8c2ba2 216 This can be used to suspend the codec when a user wishes to run critical tasks where IRQs must be disabled. To restart call the start function again.
aidan1971 0:8f28f25e3435 217 */
aidan1971 8:9fdf8501d14b 218 int32_t stop_RX(void);
aidan1971 6:4ab5aaeaa064 219
aidan1971 3:62c03088f256 220 /*!
aidan1971 0:8f28f25e3435 221 @brief Starts the codec I2S interface and begins transferring RX buffers. Transfers use DMA.
aidan1971 9:40e0ff8c2ba2 222 @param _BufRX_L_safe A pointer address to the RX Left channel data.
aidan1971 0:8f28f25e3435 223 The pointer address is managed by the driver and changes to implement a double buffer.
aidan1971 0:8f28f25e3435 224 It is suggested that a suitable declaration in the users code would be in the form: 'q31_t *RX_AudioL = NULL;'
aidan1971 0:8f28f25e3435 225 To pass into the class, dereference this pointer and cast as uint32_t, as follows: 'codec.start_SYNC((uint32_t)&RX_AudioL .....'
aidan1971 9:40e0ff8c2ba2 226 @param _BufRX_R_safe A pointer address to the RX Right channel data.
aidan1971 9:40e0ff8c2ba2 227 @param _block_size 2 | 4 | 8 words of both Left and Right channels combined.
aidan1971 0:8f28f25e3435 228 This defines the number of samples that are transferred to the RX FIFO each time a FIFO demand is detected.
aidan1971 9:40e0ff8c2ba2 229 @param _packed_RX If true the 2 * 16bit words from the codec are packed into a single 32bit word towards the user. This allows user code to use SIMD operations on the data
aidan1971 4:91354c908416 230 If False a single 16bit word from the wire is placed into a single 32bit word towards the user.
aidan1971 9:40e0ff8c2ba2 231 @param _RX_shift True = The 16bits of RX FIFO data are shifted to the MSBs of the RX buffer. Default = true
aidan1971 0:8f28f25e3435 232 False = The 16bits of RX FIFO data are placed in the LSBs of the RX buffer
aidan1971 0:8f28f25e3435 233 Note: If data is not shifted, the 32bit word delivered to the user will not be sign extended.
aidan1971 4:91354c908416 234 If packed is true, then shift has no relevance.
aidan1971 9:40e0ff8c2ba2 235 @param _rx_DMAch Defines the system DMA channel to assign to the RX transfer. Default is 14.
aidan1971 0:8f28f25e3435 236 14 is used as default to avoid using channels 0 - 3 which are the only channels available for gated triggers.
aidan1971 0:8f28f25e3435 237 Gated triggering is not needed, so these 4 channels are avoided.
aidan1971 9:40e0ff8c2ba2 238 @param _DMA_irq_pri Default = 0. Highest priority. This is the priority of the I2S RX DMA demands.
aidan1971 3:62c03088f256 239 @returns 0 = success, -1 = fail
aidan1971 3:62c03088f256 240 Fails on variable sanity checks.
aidan1971 0:8f28f25e3435 241 */
aidan1971 9:40e0ff8c2ba2 242 int32_t start_RX(uint32_t _BufRX_L_safe, uint32_t _BufRX_R_safe,
aidan1971 9:40e0ff8c2ba2 243 uint32_t _block_size = 4, bool _packed_RX = false, bool _RX_shift = true, uint32_t _RX_DMAch = 14, uint32_t _DMA_irq_pri = 0);
aidan1971 0:8f28f25e3435 244
aidan1971 3:62c03088f256 245 /*!
aidan1971 0:8f28f25e3435 246 @brief Attach a callback function to DMA SYNC
aidan1971 0:8f28f25e3435 247 @param func User function to be called from the DMA SYNC FIFO triggered ISR.
aidan1971 0:8f28f25e3435 248 This is blocking. If the user function does not complete before the next DMA triggered IRQ the system will crash,
aidan1971 0:8f28f25e3435 249 however using this function avoids the latency of a stack push.
aidan1971 3:62c03088f256 250 @returns 0 = success, -1 = fail.
aidan1971 3:62c03088f256 251 Fails if already attached, must detach first.
aidan1971 0:8f28f25e3435 252 */
aidan1971 0:8f28f25e3435 253 int32_t attach_SYNC(Callback<void()> func);
aidan1971 6:4ab5aaeaa064 254
aidan1971 3:62c03088f256 255 /*!
aidan1971 0:8f28f25e3435 256 @brief Attach a ISR function to DMA SYNC
aidan1971 0:8f28f25e3435 257 @param user_ISR User function to be assigned as the NVIC vector for the DMA SYNC FIFO triggered user_ISR.
aidan1971 0:8f28f25e3435 258 @param irq_pri Set the system wide priority of the user_ISR.
aidan1971 0:8f28f25e3435 259 @param sw_irq The IRQ assigned. Default uses Reserved53_IRQn. See "MK20DX256.h" for available.
aidan1971 0:8f28f25e3435 260 This creates a non-blocking call, which tests to see if the users ISR has completed before calling again.
aidan1971 0:8f28f25e3435 261 It requires that the priority of the IRQ associated with user_ISR is lower than the priority of the DMA triggered ISR.
aidan1971 0:8f28f25e3435 262 It can be useful to use a non-blocking call, however this involves the extra time needed to push the stack and manageing IRQ priorities
aidan1971 0:8f28f25e3435 263 across the whole system needs consideration.
aidan1971 0:8f28f25e3435 264 */
aidan1971 8:9fdf8501d14b 265 int32_t attach_SYNC_NB(uint32_t user_ISR, uint32_t irq_pri = 1, IRQn sw_irq = Reserved53_IRQn);
aidan1971 0:8f28f25e3435 266
aidan1971 3:62c03088f256 267 /*!
aidan1971 0:8f28f25e3435 268 @brief Stop both TX & RX channels and flag as detached.
aidan1971 0:8f28f25e3435 269 During running stream, the callback based function can not be changed. However changes to the NB IRQ based attachment can have the vector changed on-the-fly
aidan1971 0:8f28f25e3435 270 */
aidan1971 8:9fdf8501d14b 271 int32_t detach_SYNC(void);
aidan1971 0:8f28f25e3435 272
aidan1971 3:62c03088f256 273 /**
aidan1971 0:8f28f25e3435 274 @brief Starts the codec I2S interface and begins transferring RX and TX buffers. Transfers use DMA.
aidan1971 9:40e0ff8c2ba2 275 @param _BufRX_L_safe A pointer address to the RX Left channel data.
aidan1971 0:8f28f25e3435 276 The pointer address is managed by the driver and changes to implement a double buffer.
aidan1971 0:8f28f25e3435 277 It is suggested that a suitable declaration in the users code would be in the form: 'q31_t *RX_AudioL = NULL;'
aidan1971 0:8f28f25e3435 278 To pass into the class, dereference this pointer and cast as uint32_t, as follows: 'codec.start_SYNC((uint32_t)&RX_AudioL .....'
aidan1971 9:40e0ff8c2ba2 279 @param _BufRX_R_safe A pointer address to the RX Right channel data.
aidan1971 9:40e0ff8c2ba2 280 @param _BufTX_L_safe A pointer address to the TX Left channel data.
aidan1971 9:40e0ff8c2ba2 281 @param _BufTX_R_safe A pointer address to the TX Right channel data.
aidan1971 9:40e0ff8c2ba2 282 @param _block_size 2 | 4 | 8 words of both Left and Right channels combined.
aidan1971 0:8f28f25e3435 283 This defines the number of samples that are transferred to both FIFOs each time a FIFO demand is detected.
aidan1971 9:40e0ff8c2ba2 284 @param _packed_TX If true the 2 * 16bit words for wire transmission are expected packed into a single 32bit word.
aidan1971 4:91354c908416 285 If False each 32bit word from the user should contain a single 16bit word for transmission.
aidan1971 9:40e0ff8c2ba2 286 @param _packed_RX If true the 2 * 16bit words from the codec are packed into a single 32bit word towards the user. This allows user code to use SIMD operations on the data
aidan1971 4:91354c908416 287 If False a single 16bit word from the wire is placed into a single 32bit word towards the user.
aidan1971 0:8f28f25e3435 288 @param _RX_shift True = The 16bits of RX FIFO data are shifted to the MSBs of the RX buffer. Default = true
aidan1971 0:8f28f25e3435 289 False = The 16bits of RX FIFO data are placed in the LSBs of the RX buffer.
aidan1971 0:8f28f25e3435 290 Note: If data is not shifted, the 32bit word delivered to the user will not be sign extended.
aidan1971 4:91354c908416 291 If RX packed is true, then shift has no relevance.
aidan1971 0:8f28f25e3435 292 @param _TX_shift True = The MS16bits of TX buffer are sent to the TX FIFO. Default = true.
aidan1971 0:8f28f25e3435 293 False = The LS16bits of TX buffer are sent to the TX FIFO.
aidan1971 4:91354c908416 294 If TX packed is true, then shift has no relevance.
aidan1971 0:8f28f25e3435 295 @param _RX_DMAch Defines the system DMA channel to assign to the RX transfer. Default is 14.
aidan1971 0:8f28f25e3435 296 @param _TX_DMAch Defines the system DMA channel to assign to the TX transfer. Default is 15.
aidan1971 0:8f28f25e3435 297 14 & 15 are used as default to avoid using channels 0 - 3 which are the only channels available for gated triggers.
aidan1971 0:8f28f25e3435 298 Gated triggering is not needed, so these 4 channels are avoided.
aidan1971 9:40e0ff8c2ba2 299 @param _DMA_irq_pri Default = 0. Highest priority. This is the priority of the I2S DMA demands.
aidan1971 3:62c03088f256 300 @returns 0 = success, -1 = fail
aidan1971 3:62c03088f256 301 Fails on variable sanity checks.
aidan1971 0:8f28f25e3435 302 */
aidan1971 9:40e0ff8c2ba2 303 int32_t start_SYNC(uint32_t _BufRX_L_safe, uint32_t _BufRX_R_safe, uint32_t _BufTX_L_safe, uint32_t _BufTX_R_safe,
aidan1971 9:40e0ff8c2ba2 304 uint32_t _block_size = 4, bool _packed_RX = false, bool _packed_TX = false, bool _RX_shift = true, bool _TX_shift = true, uint32_t _RX_DMAch = 14, uint32_t _TX_DMAch = 15, uint32_t _DMA_irq_pri = 0);
aidan1971 0:8f28f25e3435 305
aidan1971 3:62c03088f256 306 /*!
aidan1971 9:40e0ff8c2ba2 307 @brief Stops i2s TX & RX channels. Stops all DMA requests and supresses any IRQs from the driver.
aidan1971 9:40e0ff8c2ba2 308 This can be used to suspend the codec when a user wishes to run critical tasks where IRQs must be disabled. To restart call the start function again.
aidan1971 0:8f28f25e3435 309 */
aidan1971 8:9fdf8501d14b 310 int32_t stop_SYNC(void);
aidan1971 0:8f28f25e3435 311
aidan1971 3:62c03088f256 312 /*!
aidan1971 0:8f28f25e3435 313 @brief Set codec and i2s Sampling frequency
aidan1971 0:8f28f25e3435 314 @param rate 8, 11, 12, 16, 22, 24, 32, 44, 48, 96, 192
aidan1971 0:8f28f25e3435 315 Base sampling rate of the codec
aidan1971 0:8f28f25e3435 316
aidan1971 0:8f28f25e3435 317 In all cases the SGTL5000 is programmed to use MCLK 256 times faster than sampling freq.
aidan1971 0:8f28f25e3435 318 MCU MCLK output = MCLK_Input((FRACT + 1)/(DIVIDE + 1))
aidan1971 0:8f28f25e3435 319 MCU MCLK Divide Register ratio is therefore = (Fs * 256)/PLL Clk
aidan1971 0:8f28f25e3435 320 The Teensy 3.1 & 3.2 have PLL freq @ 96MHz
aidan1971 0:8f28f25e3435 321
aidan1971 3:62c03088f256 322 Note: To achieve some of these rates the codec SYS_FS is adjusted.
aidan1971 0:8f28f25e3435 323 This needs to be considered for several internal codec processes such as filter co-efficients and AVC.
aidan1971 3:62c03088f256 324 @returns 0 = success, -1 = fail
aidan1971 0:8f28f25e3435 325 */
aidan1971 0:8f28f25e3435 326 int32_t freq(uint32_t rate);
aidan1971 8:9fdf8501d14b 327
aidan1971 8:9fdf8501d14b 328 /*!
aidan1971 8:9fdf8501d14b 329 @brief Initialise codec.
aidan1971 8:9fdf8501d14b 330 Sends initial default configuration data to the codec over I2C.
aidan1971 8:9fdf8501d14b 331 This function must be called after instantiation and before most other functions. It allows control over when I2C communications with the codec takes place.
aidan1971 8:9fdf8501d14b 332 Failure to initialize will prevent operation of the codec. However it possible to attach and detach functions before init.
aidan1971 8:9fdf8501d14b 333 @returns 0 = success, -1 = fail
aidan1971 8:9fdf8501d14b 334 */
aidan1971 8:9fdf8501d14b 335 int32_t init(void);
aidan1971 8:9fdf8501d14b 336
aidan1971 3:62c03088f256 337 /*!
aidan1971 3:62c03088f256 338 @brief Read debug data from the codec
aidan1971 3:62c03088f256 339 @param index 0-15
aidan1971 3:62c03088f256 340 Just a simple way for user code to grab running variables if you need it.
aidan1971 3:62c03088f256 341 @returns 0 = success, -1 = fail
aidan1971 3:62c03088f256 342 */
aidan1971 8:9fdf8501d14b 343 int32_t read_debug(uint32_t index);
aidan1971 0:8f28f25e3435 344
aidan1971 0:8f28f25e3435 345
aidan1971 0:8f28f25e3435 346 protected:
aidan1971 6:4ab5aaeaa064 347 static uint32_t debug[16];
aidan1971 0:8f28f25e3435 348
aidan1971 0:8f28f25e3435 349
aidan1971 0:8f28f25e3435 350 private:
aidan1971 7:d65476c153a4 351 I2C mI2C; // Create I2C instance
aidan1971 0:8f28f25e3435 352 int i2c_addr;
aidan1971 0:8f28f25e3435 353
aidan1971 0:8f28f25e3435 354 void init_i2s(void); // Configure I2S Default Settings
aidan1971 0:8f28f25e3435 355
aidan1971 8:9fdf8501d14b 356 int32_t init_codec(void); // Configure codec Default Settings
aidan1971 0:8f28f25e3435 357
aidan1971 0:8f28f25e3435 358 void init_DMA(void); // Configure SYNC DMA settings on MK20DX256
aidan1971 0:8f28f25e3435 359
aidan1971 6:4ab5aaeaa064 360 static void tx_dma_ISR_NB(void); // Handle TX DMA transfers complete using IRQs to user
aidan1971 6:4ab5aaeaa064 361
aidan1971 6:4ab5aaeaa064 362 static void rx_dma_ISR_NB(void); // Handle RX DMA transfers complete using IRQs to user
aidan1971 6:4ab5aaeaa064 363
aidan1971 6:4ab5aaeaa064 364 static void sync_dma_ISR_NB(void); // Handle SYNC DMA transfers complete using IRQs to user
aidan1971 0:8f28f25e3435 365
aidan1971 6:4ab5aaeaa064 366 static void tx_dma_ISR(void); // Handle TX DMA transfers complete using Callback
aidan1971 0:8f28f25e3435 367
aidan1971 6:4ab5aaeaa064 368 static void rx_dma_ISR(void); // Handle RX DMA transfers complete using Callback
aidan1971 6:4ab5aaeaa064 369
aidan1971 6:4ab5aaeaa064 370 static void sync_dma_ISR(void); // Handle SYNC DMA transfers complete using Callback
aidan1971 0:8f28f25e3435 371
aidan1971 9:40e0ff8c2ba2 372 static void tx_I2S_WS_ISR(void); // Handle TX word start allignment
aidan1971 0:8f28f25e3435 373
aidan1971 9:40e0ff8c2ba2 374 static void rx_I2S_WS_ISR(void); // Handle RX word start allignment
aidan1971 0:8f28f25e3435 375
aidan1971 9:40e0ff8c2ba2 376 static void sync_I2S_WS_ISR(void); // Handle SYNC word start allignment
aidan1971 0:8f28f25e3435 377
aidan1971 0:8f28f25e3435 378
aidan1971 6:4ab5aaeaa064 379
aidan1971 6:4ab5aaeaa064 380 static uint32_t *BufRX_L_safe; // Define statics for ISRs
aidan1971 0:8f28f25e3435 381 static uint32_t *BufRX_R_safe;
aidan1971 0:8f28f25e3435 382 static uint32_t *BufTX_L_safe;
aidan1971 0:8f28f25e3435 383 static uint32_t *BufTX_R_safe;
aidan1971 0:8f28f25e3435 384 static uint32_t RX_DMAch;
aidan1971 0:8f28f25e3435 385 static uint32_t TX_DMAch;
aidan1971 0:8f28f25e3435 386 static IRQn SYNC_swIRQ;
aidan1971 0:8f28f25e3435 387 static IRQn TX_swIRQ;
aidan1971 0:8f28f25e3435 388 static IRQn RX_swIRQ;
aidan1971 0:8f28f25e3435 389 static Callback<void()> TX_user_func;
aidan1971 0:8f28f25e3435 390 static Callback<void()> RX_user_func;
aidan1971 0:8f28f25e3435 391 static Callback<void()> SYNC_user_func;
aidan1971 9:40e0ff8c2ba2 392 static uint32_t db_phase_sync;
aidan1971 9:40e0ff8c2ba2 393 static uint32_t db_phase_tx;
aidan1971 9:40e0ff8c2ba2 394 static uint32_t db_phase_rx;
aidan1971 9:40e0ff8c2ba2 395
aidan1971 9:40e0ff8c2ba2 396 int i2c_freq;
aidan1971 0:8f28f25e3435 397
aidan1971 6:4ab5aaeaa064 398 uint32_t I2S_RX_Buffer[16];
aidan1971 6:4ab5aaeaa064 399 uint32_t I2S_TX_Buffer[16];
aidan1971 6:4ab5aaeaa064 400 uint32_t SYNC_attach_type;
aidan1971 6:4ab5aaeaa064 401 uint32_t TX_attach_type;
aidan1971 6:4ab5aaeaa064 402 uint32_t RX_attach_type;
aidan1971 6:4ab5aaeaa064 403 uint32_t TX_block_size;
aidan1971 6:4ab5aaeaa064 404 uint32_t RX_block_size;
aidan1971 0:8f28f25e3435 405 uint32_t TX_bs_bytes;
aidan1971 0:8f28f25e3435 406 uint32_t RX_bs_bytes;
aidan1971 8:9fdf8501d14b 407 bool codec_configured;
aidan1971 9:40e0ff8c2ba2 408 bool codec_I2S_active;
aidan1971 0:8f28f25e3435 409 bool SYNC_run;
aidan1971 0:8f28f25e3435 410 bool TX_run;
aidan1971 0:8f28f25e3435 411 bool RX_run;
aidan1971 0:8f28f25e3435 412 bool SYNC_attached;
aidan1971 0:8f28f25e3435 413 bool TX_attached;
aidan1971 0:8f28f25e3435 414 bool RX_attached;
aidan1971 0:8f28f25e3435 415 bool TX_shift;
aidan1971 0:8f28f25e3435 416 bool RX_shift;
aidan1971 4:91354c908416 417 bool packed_RX;
aidan1971 4:91354c908416 418 bool packed_TX;
aidan1971 0:8f28f25e3435 419 };
aidan1971 0:8f28f25e3435 420 }
aidan1971 0:8f28f25e3435 421 #endif