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:
Wed Sep 27 11:23:28 2017 +0000
Revision:
14:9043626add45
Parent:
13:83c2aaf4a338
doc updates

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 10:49bb33f71d32 35
aidan1971 3:62c03088f256 36 /** SGTL5000 namespace
aidan1971 3:62c03088f256 37 */
aidan1971 0:8f28f25e3435 38 namespace SGTL5000
aidan1971 0:8f28f25e3435 39 {
aidan1971 0:8f28f25e3435 40
aidan1971 10:49bb33f71d32 41
aidan1971 3:62c03088f256 42 /*! SGTL5000 codec driver class
aidan1971 3:62c03088f256 43 */
aidan1971 3:62c03088f256 44 /*! Class for NXP SGTL5000 codec instance.
aidan1971 11:392c09372ae1 45 * Supports dual codecs. One using I2S TX&RX channel_0 the other I2S TX&RX channel_1. The instance created for codec1 (I2S channel_0 CODEC CS = LOW) is the master,
aidan1971 11:392c09372ae1 46 all stream ctrl functions (start, stop, pause & resume) are synchronous to this master codec and must be initiated by the master codec object.
aidan1971 3:62c03088f256 47 * @code
aidan1971 3:62c03088f256 48 * #include 'SGTL5000.h'
aidan1971 3:62c03088f256 49 *
aidan1971 3:62c03088f256 50 * SGTL5000::SGTL5000 codec(I2C_SDA, I2C_SCL);
aidan1971 3:62c03088f256 51 *
aidan1971 3:62c03088f256 52 * static q31_t *RX_AudioL = NULL;
aidan1971 3:62c03088f256 53 * static q31_t *RX_AudioR = NULL;
aidan1971 3:62c03088f256 54 * static q31_t *TX_AudioL = NULL;
aidan1971 3:62c03088f256 55 * static q31_t *TX_AudioR = NULL;
aidan1971 3:62c03088f256 56 *
aidan1971 3:62c03088f256 57 * const uint32_t I2S_FIFO_BS = 4;
aidan1971 3:62c03088f256 58 *
aidan1971 3:62c03088f256 59 *
aidan1971 3:62c03088f256 60 * uint32_t main()
aidan1971 3:62c03088f256 61 * {
aidan1971 14:9043626add45 62 * codec.init();
aidan1971 3:62c03088f256 63 * 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 64 * codec.modify_i2c(SGTL5000_ANA_HP_CTRL, 0x18, SGTL5000_ANA_HP_CTRL_HP_VOL_LEFT_MASK);
aidan1971 14:9043626add45 65 *
aidan1971 3:62c03088f256 66 * codec.attach_SYNC_NB((uint32_t)&I2S_SYNC_ISR);
aidan1971 11:392c09372ae1 67 * codec.sample_rate(96);
aidan1971 3:62c03088f256 68 * 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 69 * }
aidan1971 3:62c03088f256 70 *
aidan1971 3:62c03088f256 71 * void I2S_SYNC_ISR(void)
aidan1971 3:62c03088f256 72 * {
aidan1971 3:62c03088f256 73 * for(uint32_t i = 0; i < (I2S_FIFO_BS >> 1); ++i)
aidan1971 3:62c03088f256 74 * {
aidan1971 3:62c03088f256 75 * TX_AudioL[i] = RX_AudioL[i];
aidan1971 3:62c03088f256 76 * TX_AudioR[i] = RX_AudioR[i];
aidan1971 3:62c03088f256 77 * }
aidan1971 3:62c03088f256 78 * }
aidan1971 3:62c03088f256 79 @endcode
aidan1971 11:392c09372ae1 80 *
aidan1971 11:392c09372ae1 81 * To implement dual CODECs
aidan1971 11:392c09372ae1 82 * @code
aidan1971 11:392c09372ae1 83 * #include 'SGTL5000.h'
aidan1971 11:392c09372ae1 84 *
aidan1971 11:392c09372ae1 85 * SGTL5000::SGTL5000 codec1_ctrl(I2C_SDA, I2C_SCL);
aidan1971 11:392c09372ae1 86 * SGTL5000::SGTL5000 codec2(I2C_SDA, I2C_SCL);
aidan1971 11:392c09372ae1 87 *
aidan1971 11:392c09372ae1 88 * static q31_t *RX_AudioL1 = NULL;
aidan1971 11:392c09372ae1 89 * static q31_t *RX_AudioR1 = NULL;
aidan1971 11:392c09372ae1 90 * static q31_t *TX_AudioL1 = NULL;
aidan1971 11:392c09372ae1 91 * static q31_t *TX_AudioR1 = NULL;
aidan1971 11:392c09372ae1 92 * static q31_t *RX_AudioL2 = NULL;
aidan1971 11:392c09372ae1 93 * static q31_t *RX_AudioR2 = NULL;
aidan1971 11:392c09372ae1 94 * static q31_t *TX_AudioL2 = NULL;
aidan1971 11:392c09372ae1 95 * static q31_t *TX_AudioR2 = NULL;
aidan1971 11:392c09372ae1 96 *
aidan1971 11:392c09372ae1 97 * const uint32_t I2S_FIFO_BS = 4;
aidan1971 11:392c09372ae1 98 *
aidan1971 11:392c09372ae1 99 *
aidan1971 11:392c09372ae1 100 * uint32_t main()
aidan1971 11:392c09372ae1 101 * {
aidan1971 14:9043626add45 102 * codec1_ctrl.init();
aidan1971 14:9043626add45 103 * codec2.init();
aidan1971 11:392c09372ae1 104 * codec1_ctrl.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 11:392c09372ae1 105 * codec1_ctrl.modify_i2c(SGTL5000_ANA_HP_CTRL, 0x18, SGTL5000_ANA_HP_CTRL_HP_VOL_LEFT_MASK);
aidan1971 11:392c09372ae1 106 * codec2.modify_i2c(SGTL5000_ANA_HP_CTRL, 0x01, 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 11:392c09372ae1 107 * codec2.modify_i2c(SGTL5000_ANA_HP_CTRL, 0x01, SGTL5000_ANA_HP_CTRL_HP_VOL_LEFT_MASK); // Seperate codec settings.
aidan1971 14:9043626add45 108 *
aidan1971 11:392c09372ae1 109 * codec1_ctrl.attach_SYNC_NB((uint32_t)&I2S_SYNC_ISR);
aidan1971 11:392c09372ae1 110 * codec1_ctrl.sample_rate(96);
aidan1971 11:392c09372ae1 111 * codec1_ctrl.start_SYNC((uint32_t)&RX_AudioL1, (uint32_t)&RX_AudioR1, (uint32_t)&TX_AudioL1, (uint32_t)&TX_AudioR1, I2S_FIFO_BS, true, true, false, false, 14, 15,
aidan1971 11:392c09372ae1 112 * (uint32_t)&RX_AudioL2, (uint32_t)&RX_AudioR2, (uint32_t)&TX_AudioL2, (uint32_t)&TX_AudioR2)
aidan1971 11:392c09372ae1 113 * }
aidan1971 11:392c09372ae1 114 *
aidan1971 11:392c09372ae1 115 * void I2S_SYNC_ISR(void)
aidan1971 11:392c09372ae1 116 * {
aidan1971 11:392c09372ae1 117 * for(uint32_t i = 0; i < (I2S_FIFO_BS >> 1); ++i)
aidan1971 11:392c09372ae1 118 * {
aidan1971 11:392c09372ae1 119 * // CODEC 1
aidan1971 11:392c09372ae1 120 * TX_AudioL1[i] = RX_AudioL1[i];
aidan1971 11:392c09372ae1 121 * TX_AudioR1[i] = RX_AudioR1[i];
aidan1971 11:392c09372ae1 122 *
aidan1971 11:392c09372ae1 123 * // CODEC 2
aidan1971 11:392c09372ae1 124 * TX_AudioL2[i] = RX_AudioL2[i];
aidan1971 11:392c09372ae1 125 * TX_AudioR2[i] = RX_AudioR2[i];
aidan1971 11:392c09372ae1 126 * }
aidan1971 11:392c09372ae1 127 * }
aidan1971 11:392c09372ae1 128 @endcode
aidan1971 3:62c03088f256 129 */
aidan1971 0:8f28f25e3435 130 class SGTL5000
aidan1971 0:8f28f25e3435 131
aidan1971 0:8f28f25e3435 132 {
aidan1971 0:8f28f25e3435 133 public:
aidan1971 3:62c03088f256 134 //Constructor
aidan1971 3:62c03088f256 135 /*!
aidan1971 0:8f28f25e3435 136 @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 11:392c09372ae1 137 multiple instances. However currently only a single object for each CODEC should only be instantiated. It is possible to instantiate more, but care must be taken.
aidan1971 11:392c09372ae1 138 After the init() function is called, state within the class becomes indpendent of the object that modified it.
aidan1971 11:392c09372ae1 139 The class is wrapped in the SGTL5000 namespace to avoid collisions with statics needed by the ISRs. Only the CODEC using CTRL_ADR0_CS = 0 can be used to manage
aidan1971 11:392c09372ae1 140 the I2S setup and data flow, such as sample_rate, attach, start, stop etc. If a second CODEC is available then its data flow is locked to the 1st,
aidan1971 11:392c09372ae1 141 TX & RX FIFO buffers of both CODECs will be synchronised and only one DMA channel is used to TX data to both codecs and one DMA channel to RX data from both codecs.
aidan1971 12:9ce7f3828c6a 142
aidan1971 12:9ce7f3828c6a 143 In SYNC mode FIFO buffers depths are synchronised to bring DMA transfers as close as possible to each other. After both TX & RX DMA transfers are complete, user code is called.
aidan1971 12:9ce7f3828c6a 144 Therefore, please note, there will always be a minimum delay of 1 I2S sample between TX & RX DMA transfers. In most circumstances this is irrelevant, but needs to be considered.
aidan1971 12:9ce7f3828c6a 145 For example; if the codecs run at 48KHz, and a FIFO depth of 8 samples is implemented. User code will be called every 83.3uS. At the end of this 83.3uS period there will be a short period
aidan1971 12:9ce7f3828c6a 146 equal to the length of time needed to transfer 1 channel sample (@48Khz this will be (1/48000)/2 = 10.42uS + the time required to swap pointers ~ 800nS. Therefore ~ 11.3uS).
aidan1971 12:9ce7f3828c6a 147 During this period just before user code is called again, the data in the transfer buffers should not be read or written. It is suggested that upon entry into user code, all TX data is first written out
aidan1971 12:9ce7f3828c6a 148 followed by processing of RX data, which must complete in less than (83.3 - 11.3 = 72uS). If the sample rate changes this period changes, getting shorter as the sample rate increases.
aidan1971 12:9ce7f3828c6a 149 However the pointer swaps take a fixed time, dependent only on system core clock frequency.
aidan1971 12:9ce7f3828c6a 150 If this behaviour needs to ber avoided, run the TX & RX streams independently. However this then increases the overhead associated with IRQs and the user will need to
aidan1971 12:9ce7f3828c6a 151 manage synchronisation between TX & RX streams.
aidan1971 0:8f28f25e3435 152
aidan1971 0:8f28f25e3435 153 @param i2c_sda i2c Serial data pin (D18 Teensy 3.2 header / PTB3 MK20DX256)
aidan1971 0:8f28f25e3435 154 @param i2c_scl i2c Serial clock pin (D19 Teensy 3.2 header / PTB2 MK20DX256)
aidan1971 0:8f28f25e3435 155 @param i2c_freq Frequency in Hz at which the i2c codec interface clocks data
aidan1971 0:8f28f25e3435 156 @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 10:49bb33f71d32 157 @param _ctrl_IRQn A system IRQ number used to control the codec. All time sensitive commands are elevated to highest IRQ priority using this IRQ number.
aidan1971 10:49bb33f71d32 158 Note: This is only used by the master codec (which is the codec with CS pin LOW). All commands to control data flow must be issued through the master codec object.
aidan1971 10:49bb33f71d32 159 This includes setting sample rate. Both codecs are linked by default at the same rate. Setting the master codecs rate also sets the same rate for the 2nd codec.
aidan1971 10:49bb33f71d32 160 However each codec instance has fully independent access to all the other codec internal features, through its respective object.
aidan1971 0:8f28f25e3435 161
aidan1971 0:8f28f25e3435 162
aidan1971 0:8f28f25e3435 163 // Pin Configs for i2s hardcoded as follows to match Teensy Audio Shield
aidan1971 0:8f28f25e3435 164 i2s_mclk i2s master clock (D11 Teensy 3.2 header / PTC6 MK20DX256)
aidan1971 0:8f28f25e3435 165 i2s_bclk i2s bit clock (D9 Teensy 3.2 header / PTC3 MK20DX256)
aidan1971 0:8f28f25e3435 166 i2s_fs i2s Frame Sync / L/R clock / WordSelect (D23 Teensy 3.2 header / PTC2 MK20DX256)
aidan1971 0:8f28f25e3435 167 i2s_rx i2s tx_data (from bus master perspective) (D22 Teensy 3.2 header / PTC1 MK20DX256)
aidan1971 0:8f28f25e3435 168 i2s_tx i2s rx_data (from bus master perspective) (D13 Teensy 3.2 header /PTC5 MK20DX256)
aidan1971 0:8f28f25e3435 169
aidan1971 0:8f28f25e3435 170 */
aidan1971 10:49bb33f71d32 171 SGTL5000(PinName i2c_sda, PinName i2c_scl, int _i2c_freq = 100000, bool i2c_ctrl_adr0_cs = 0, IRQn _ctrl_IRQn = Reserved109_IRQn);
aidan1971 0:8f28f25e3435 172
aidan1971 3:62c03088f256 173 /*!
aidan1971 3:62c03088f256 174 @brief Read 16bit register of SGTL5000
aidan1971 3:62c03088f256 175 @param reg_addr 16bit address of the codec control register
aidan1971 3:62c03088f256 176 @param data 16bit data to read from the address
aidan1971 3:62c03088f256 177 @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 10:49bb33f71d32 178 @param _i2c_addr Default = 0. If none zero, overrides the address associated with the current object.
aidan1971 3:62c03088f256 179 @returns 0 = register data, -1 = fail
aidan1971 3:62c03088f256 180 */
aidan1971 10:49bb33f71d32 181 int32_t read_i2c(uint32_t reg_addr, uint32_t mask = 0xFFFF, int _i2c_addr = 0);
aidan1971 6:4ab5aaeaa064 182
aidan1971 3:62c03088f256 183 /*!
aidan1971 3:62c03088f256 184 @brief Write 16bit register of SGTL5000
aidan1971 3:62c03088f256 185 @param reg_addr 16bit address of the codec control register
aidan1971 3:62c03088f256 186 @param data 16bit data to write into the address
aidan1971 10:49bb33f71d32 187 @param _i2c_addr Default = 0. If none zero, overrides the address associated with the current object.
aidan1971 3:62c03088f256 188 @returns 0 = success, -1 = fail
aidan1971 3:62c03088f256 189 */
aidan1971 10:49bb33f71d32 190 int32_t write_i2c(uint32_t reg_addr, uint32_t data, int _i2c_addr = 0);
aidan1971 6:4ab5aaeaa064 191
aidan1971 3:62c03088f256 192 /*!
aidan1971 3:62c03088f256 193 @brief Modify masked bits within 16bit register of SGTL5000
aidan1971 3:62c03088f256 194 @param reg_addr 16bit address of the codec control register
aidan1971 3:62c03088f256 195 @param data 16bit data to write into the address
aidan1971 3:62c03088f256 196 @param mask 16bit mask of the bits to modify.
aidan1971 3:62c03088f256 197 The function automatically shifts the data to the position of the first masked bit.
aidan1971 10:49bb33f71d32 198 @param _i2c_addr Default = 0. If none zero, overrides the address associated with the current object.
aidan1971 3:62c03088f256 199 @returns 0 = success, -1 = fail
aidan1971 3:62c03088f256 200 */
aidan1971 10:49bb33f71d32 201 int32_t modify_i2c(uint32_t reg_addr, uint32_t data, uint32_t mask, int _i2c_addr = 0);
aidan1971 6:4ab5aaeaa064 202
aidan1971 3:62c03088f256 203 /*!
aidan1971 0:8f28f25e3435 204 @brief Attach a callback function to TX
aidan1971 3:62c03088f256 205 @param func Address of the user function to be called from the TX FIFO triggered ISR.
aidan1971 3:62c03088f256 206 This is blocking. If the user function does not complete before the next DMA completes the system will likely crash,
aidan1971 3:62c03088f256 207 however using this function avoids the latency of an IRQ stack push.
aidan1971 3:62c03088f256 208 @returns 0 = success, -1 = fail.
aidan1971 3:62c03088f256 209 Fails if already attached, must detach first.
aidan1971 0:8f28f25e3435 210 */
aidan1971 0:8f28f25e3435 211 int32_t attach_TX(Callback<void()> func);
aidan1971 6:4ab5aaeaa064 212
aidan1971 3:62c03088f256 213 /*!
aidan1971 3:62c03088f256 214 @brief Attach an ISR function to DMA TX
aidan1971 10:49bb33f71d32 215 @param user_ISR User function address pointer to be assigned as the NVIC vector for the DMA TX FIFO triggered user_ISR.
aidan1971 0:8f28f25e3435 216 @param irq_pri Set the system wide priority of the user_ISR.
aidan1971 0:8f28f25e3435 217 @param sw_irq The IRQ assigned. Default uses Reserved54_IRQn. See "MK20DX256.h" for available.
aidan1971 0:8f28f25e3435 218 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 219 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 220 across the whole system needs consideration.
aidan1971 0:8f28f25e3435 221 */
aidan1971 10:49bb33f71d32 222 int32_t attach_TX_NB(void* user_ISR, uint32_t irq_pri = 1, IRQn sw_irq = Reserved54_IRQn);
aidan1971 6:4ab5aaeaa064 223
aidan1971 3:62c03088f256 224 /*!
aidan1971 0:8f28f25e3435 225 @brief Stop TX channel and flag as detached.
aidan1971 13:83c2aaf4a338 226 During running stream, the callback based function can not be changed. It must therefore be deteched first. However changes to the NB IRQ based attachment can have the vector changed on-the-fly
aidan1971 0:8f28f25e3435 227 */
aidan1971 8:9fdf8501d14b 228 int32_t detach_TX(void);
aidan1971 0:8f28f25e3435 229
aidan1971 3:62c03088f256 230 /*!
aidan1971 10:49bb33f71d32 231 @brief Disables I2S TX function. This stops all DMA requests and supresses any IRQs from the driver and tristates the inbound CODEC I2S interface.
aidan1971 10:49bb33f71d32 232 It also stops bit clocks and word sync clocks.
aidan1971 10:49bb33f71d32 233 Note: Stopping the TX will also stop the RX stream because the RX is synchronous to the TX function. It is recommended that TX is the last enabled and first disabled.
aidan1971 0:8f28f25e3435 234 */
aidan1971 8:9fdf8501d14b 235 int32_t stop_TX(void);
aidan1971 6:4ab5aaeaa064 236
aidan1971 3:62c03088f256 237 /*!
aidan1971 10:49bb33f71d32 238 @brief Pauses I2S TX channels. Halts the TX stream(s) by masking all data words.
aidan1971 10:49bb33f71d32 239 This can be used to suspend the codec when a user wishes to run critical tasks where IRQs must be suppressed. To restart call the resume function.
aidan1971 10:49bb33f71d32 240 */
aidan1971 10:49bb33f71d32 241 int32_t pause_TX(void);
aidan1971 10:49bb33f71d32 242
aidan1971 10:49bb33f71d32 243 /*!
aidan1971 10:49bb33f71d32 244 @brief Resumes a paused I2S TX channels. Resumes the TX stream(s) by un-masking all data words.
aidan1971 10:49bb33f71d32 245 */
aidan1971 10:49bb33f71d32 246 int32_t resume_TX(void);
aidan1971 10:49bb33f71d32 247
aidan1971 10:49bb33f71d32 248 /*!
aidan1971 0:8f28f25e3435 249 @brief Starts the codec I2S interface and begins transferring TX buffers. Transfers use DMA.
aidan1971 10:49bb33f71d32 250 @param _BufTX_L_safe A pointer address to the TX Left channel_0 data.
aidan1971 11:392c09372ae1 251 The address pointed to by the users pointer is managed by the library and changes to implement a double buffer.
aidan1971 0:8f28f25e3435 252 It is suggested that a suitable declaration in the users code would be in the form: 'q31_t *TX_AudioL = NULL;'
aidan1971 0:8f28f25e3435 253 To pass into the class, dereference this pointer and cast as uint32_t, as follows: 'codec.start_SYNC((uint32_t)&TX_AudioL .....'
aidan1971 10:49bb33f71d32 254 @param _BufTX_R_safe A pointer address to the TX Right channel_0 data.
aidan1971 9:40e0ff8c2ba2 255 @param _block_size 2 | 4 | 8 words of both Left and Right channels combined.
aidan1971 0:8f28f25e3435 256 This defines the number of samples that are transferred to the TX FIFO each time a FIFO demand is detected.
aidan1971 9:40e0ff8c2ba2 257 @param _packed_TX If true 2 * 16bit words for wire transmission are expected packed into a single 32bit word.
aidan1971 4:91354c908416 258 If False each 32bit word from the user should contain a single 16bit word for transmission.
aidan1971 9:40e0ff8c2ba2 259 @param _TX_shift True = The MS16bits of TX buffer are sent to the TX FIFO. Default = true.
aidan1971 0:8f28f25e3435 260 False = The LS16bits of TX buffer are sent to the TX FIFO.
aidan1971 4:91354c908416 261 If packed is true, then shift has no relevance.
aidan1971 9:40e0ff8c2ba2 262 @param _tx_DMAch Defines the system DMA channel to assign to the TX transfer. Default is 15.
aidan1971 0:8f28f25e3435 263 15 is used as default to avoid using channels 0 - 3 which are the only channels available for gated triggers.
aidan1971 0:8f28f25e3435 264 Gated triggering is not needed, so these 4 channels are avoided.
aidan1971 9:40e0ff8c2ba2 265 @param _DMA_irq_pri Default = 0. Highest priority. This is the priority of the I2S TX DMA demands.
aidan1971 10:49bb33f71d32 266 @param _BufTX_L_safe2 A pointer address to the TX Left channel_1 data.
aidan1971 10:49bb33f71d32 267 @param _BufTX_R_safe2 A pointer address to the TX Right channel_1 data.
aidan1971 3:62c03088f256 268 @returns 0 = success, -1 = fail
aidan1971 3:62c03088f256 269 Fails on variable sanity checks.
aidan1971 0:8f28f25e3435 270 */
aidan1971 9:40e0ff8c2ba2 271 int32_t start_TX(uint32_t _BufTX_L_safe, uint32_t _BufTX_R_safe,
aidan1971 10:49bb33f71d32 272 uint32_t _block_size = 4, bool _packed_TX = false, bool _TX_shift = true, uint32_t _TX_DMAch = 15, uint32_t _DMA_irq_pri = 0, uint32_t _BufTX_L_safe2 = NULL, uint32_t _BufTX_R_safe2 = NULL);
aidan1971 0:8f28f25e3435 273
aidan1971 3:62c03088f256 274 /*!
aidan1971 0:8f28f25e3435 275 @brief Attach a callback function to RX
aidan1971 0:8f28f25e3435 276 @param func User function to be called from the RX FIFO triggered ISR.
aidan1971 0:8f28f25e3435 277 This is blocking. If the user function does not complete before the next DMA completes the system will crash,
aidan1971 0:8f28f25e3435 278 however using this function avoids the latency of a stack push.
aidan1971 3:62c03088f256 279 @returns 0 = success, -1 = fail.
aidan1971 3:62c03088f256 280 Fails if already attached, must detach first.
aidan1971 0:8f28f25e3435 281 */
aidan1971 0:8f28f25e3435 282 int32_t attach_RX(Callback<void()> func);
aidan1971 6:4ab5aaeaa064 283
aidan1971 3:62c03088f256 284 /*!
aidan1971 3:62c03088f256 285 @brief Attach an ISR function to DMA RX
aidan1971 10:49bb33f71d32 286 @param user_ISR User function address pointer to be assigned as the NVIC vector for the DMA RX FIFO triggered user_ISR.
aidan1971 0:8f28f25e3435 287 @param irq_pri Set the system wide priority of the user_ISR.
aidan1971 0:8f28f25e3435 288 @param sw_irq The IRQ assigned. Default uses Reserved55_IRQn. See "MK20DX256.h" for available.
aidan1971 0:8f28f25e3435 289 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 290 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 291 across the whole system needs consideration.
aidan1971 0:8f28f25e3435 292 */
aidan1971 10:49bb33f71d32 293 int32_t attach_RX_NB(void* user_ISR, uint32_t irq_pri = 1, IRQn sw_irq = Reserved55_IRQn);
aidan1971 6:4ab5aaeaa064 294
aidan1971 3:62c03088f256 295 /*!
aidan1971 0:8f28f25e3435 296 @brief Stop RX channel and flag as detached.
aidan1971 13:83c2aaf4a338 297 During running stream, the callback based function can not be changed. It must therefore be deteched first. However changes to the NB IRQ based attachment can have the vector changed on-the-fly
aidan1971 0:8f28f25e3435 298 */
aidan1971 8:9fdf8501d14b 299 int32_t detach_RX(void);
aidan1971 0:8f28f25e3435 300
aidan1971 3:62c03088f256 301 /*!
aidan1971 10:49bb33f71d32 302 @brief Disables I2S RX function. Stops all DMA requests and supresses any IRQs from the driver and tristates the outbound CODEC I2S interface(s).
aidan1971 10:49bb33f71d32 303 Note: Bit clock and Word Sync clock will continue as long as TX is running (started).
aidan1971 0:8f28f25e3435 304 */
aidan1971 8:9fdf8501d14b 305 int32_t stop_RX(void);
aidan1971 6:4ab5aaeaa064 306
aidan1971 3:62c03088f256 307 /*!
aidan1971 10:49bb33f71d32 308 @brief Pauses I2S RX channels. Halts the RX stream(s) by masking all data words.
aidan1971 10:49bb33f71d32 309 This can be used to suspend the codec when a user wishes to run critical tasks where IRQs must be suppressed. To restart call the resume function.
aidan1971 10:49bb33f71d32 310 */
aidan1971 10:49bb33f71d32 311 int32_t pause_RX(void);
aidan1971 10:49bb33f71d32 312
aidan1971 10:49bb33f71d32 313 /*!
aidan1971 10:49bb33f71d32 314 @brief Resumes a paused I2S RX channels. Resumes the RX stream(s) by un-masking all data words.
aidan1971 10:49bb33f71d32 315 */
aidan1971 10:49bb33f71d32 316 int32_t resume_RX(void);
aidan1971 10:49bb33f71d32 317
aidan1971 10:49bb33f71d32 318 /*!
aidan1971 0:8f28f25e3435 319 @brief Starts the codec I2S interface and begins transferring RX buffers. Transfers use DMA.
aidan1971 10:49bb33f71d32 320 @param _BufRX_L_safe A pointer address to the RX Left channel_0 data.
aidan1971 11:392c09372ae1 321 The address pointed to by the users pointer is managed by the library and changes to implement a double buffer.
aidan1971 0:8f28f25e3435 322 It is suggested that a suitable declaration in the users code would be in the form: 'q31_t *RX_AudioL = NULL;'
aidan1971 0:8f28f25e3435 323 To pass into the class, dereference this pointer and cast as uint32_t, as follows: 'codec.start_SYNC((uint32_t)&RX_AudioL .....'
aidan1971 10:49bb33f71d32 324 @param _BufRX_R_safe A pointer address to the RX Right channel_0 data.
aidan1971 9:40e0ff8c2ba2 325 @param _block_size 2 | 4 | 8 words of both Left and Right channels combined.
aidan1971 0:8f28f25e3435 326 This defines the number of samples that are transferred to the RX FIFO each time a FIFO demand is detected.
aidan1971 9:40e0ff8c2ba2 327 @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 328 If False a single 16bit word from the wire is placed into a single 32bit word towards the user.
aidan1971 9:40e0ff8c2ba2 329 @param _RX_shift True = The 16bits of RX FIFO data are shifted to the MSBs of the RX buffer. Default = true
aidan1971 0:8f28f25e3435 330 False = The 16bits of RX FIFO data are placed in the LSBs of the RX buffer
aidan1971 0:8f28f25e3435 331 Note: If data is not shifted, the 32bit word delivered to the user will not be sign extended.
aidan1971 4:91354c908416 332 If packed is true, then shift has no relevance.
aidan1971 9:40e0ff8c2ba2 333 @param _rx_DMAch Defines the system DMA channel to assign to the RX transfer. Default is 14.
aidan1971 0:8f28f25e3435 334 14 is used as default to avoid using channels 0 - 3 which are the only channels available for gated triggers.
aidan1971 0:8f28f25e3435 335 Gated triggering is not needed, so these 4 channels are avoided.
aidan1971 9:40e0ff8c2ba2 336 @param _DMA_irq_pri Default = 0. Highest priority. This is the priority of the I2S RX DMA demands.
aidan1971 10:49bb33f71d32 337 @param _BufRX_L_safe2 A pointer address to the RX Left channel_1 data.
aidan1971 10:49bb33f71d32 338 @param _BufRX_R_safe2 A pointer address to the RX Right channel_1 data.
aidan1971 3:62c03088f256 339 @returns 0 = success, -1 = fail
aidan1971 3:62c03088f256 340 Fails on variable sanity checks.
aidan1971 0:8f28f25e3435 341 */
aidan1971 9:40e0ff8c2ba2 342 int32_t start_RX(uint32_t _BufRX_L_safe, uint32_t _BufRX_R_safe,
aidan1971 10:49bb33f71d32 343 uint32_t _block_size = 4, bool _packed_RX = false, bool _RX_shift = true, uint32_t _RX_DMAch = 14, uint32_t _DMA_irq_pri = 0, uint32_t _BufRX_L_safe2 = NULL, uint32_t _BufRX_R_safe2 = NULL);
aidan1971 0:8f28f25e3435 344
aidan1971 3:62c03088f256 345 /*!
aidan1971 0:8f28f25e3435 346 @brief Attach a callback function to DMA SYNC
aidan1971 0:8f28f25e3435 347 @param func User function to be called from the DMA SYNC FIFO triggered ISR.
aidan1971 0:8f28f25e3435 348 This is blocking. If the user function does not complete before the next DMA triggered IRQ the system will crash,
aidan1971 0:8f28f25e3435 349 however using this function avoids the latency of a stack push.
aidan1971 3:62c03088f256 350 @returns 0 = success, -1 = fail.
aidan1971 3:62c03088f256 351 Fails if already attached, must detach first.
aidan1971 0:8f28f25e3435 352 */
aidan1971 0:8f28f25e3435 353 int32_t attach_SYNC(Callback<void()> func);
aidan1971 6:4ab5aaeaa064 354
aidan1971 10:49bb33f71d32 355
aidan1971 3:62c03088f256 356 /*!
aidan1971 0:8f28f25e3435 357 @brief Attach a ISR function to DMA SYNC
aidan1971 10:49bb33f71d32 358 @param user_ISR User function address pointer to be assigned as the NVIC vector for the DMA SYNC FIFO triggered user_ISR.
aidan1971 0:8f28f25e3435 359 @param irq_pri Set the system wide priority of the user_ISR.
aidan1971 0:8f28f25e3435 360 @param sw_irq The IRQ assigned. Default uses Reserved53_IRQn. See "MK20DX256.h" for available.
aidan1971 0:8f28f25e3435 361 This creates a non-blocking call, which tests to see if the users ISR has completed before calling again.
aidan1971 0:8f28f25e3435 362 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 363 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 364 across the whole system needs consideration.
aidan1971 0:8f28f25e3435 365 */
aidan1971 10:49bb33f71d32 366 int32_t attach_SYNC_NB(void* user_ISR, uint32_t irq_pri = 1, IRQn sw_irq = Reserved53_IRQn);
aidan1971 0:8f28f25e3435 367
aidan1971 3:62c03088f256 368 /*!
aidan1971 0:8f28f25e3435 369 @brief Stop both TX & RX channels and flag as detached.
aidan1971 13:83c2aaf4a338 370 During running stream, the callback based function can not be changed. It must therefore be deteched first. However changes to the NB IRQ based attachment can have the vector changed on-the-fly
aidan1971 0:8f28f25e3435 371 */
aidan1971 8:9fdf8501d14b 372 int32_t detach_SYNC(void);
aidan1971 0:8f28f25e3435 373
aidan1971 3:62c03088f256 374 /**
aidan1971 0:8f28f25e3435 375 @brief Starts the codec I2S interface and begins transferring RX and TX buffers. Transfers use DMA.
aidan1971 10:49bb33f71d32 376 @param _BufRX_L_safe A pointer address to the RX Left channel_0 data.
aidan1971 11:392c09372ae1 377 The address pointed to by the users pointer is managed by the library and changes to implement a double buffer.
aidan1971 0:8f28f25e3435 378 It is suggested that a suitable declaration in the users code would be in the form: 'q31_t *RX_AudioL = NULL;'
aidan1971 0:8f28f25e3435 379 To pass into the class, dereference this pointer and cast as uint32_t, as follows: 'codec.start_SYNC((uint32_t)&RX_AudioL .....'
aidan1971 10:49bb33f71d32 380 @param _BufRX_R_safe A pointer address to the RX Right channel_0 data.
aidan1971 10:49bb33f71d32 381 @param _BufTX_L_safe A pointer address to the TX Left channel_0 data.
aidan1971 10:49bb33f71d32 382 @param _BufTX_R_safe A pointer address to the TX Right channel_0 data.
aidan1971 9:40e0ff8c2ba2 383 @param _block_size 2 | 4 | 8 words of both Left and Right channels combined.
aidan1971 0:8f28f25e3435 384 This defines the number of samples that are transferred to both FIFOs each time a FIFO demand is detected.
aidan1971 9:40e0ff8c2ba2 385 @param _packed_TX If true the 2 * 16bit words for wire transmission are expected packed into a single 32bit word.
aidan1971 4:91354c908416 386 If False each 32bit word from the user should contain a single 16bit word for transmission.
aidan1971 9:40e0ff8c2ba2 387 @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 388 If False a single 16bit word from the wire is placed into a single 32bit word towards the user.
aidan1971 0:8f28f25e3435 389 @param _RX_shift True = The 16bits of RX FIFO data are shifted to the MSBs of the RX buffer. Default = true
aidan1971 0:8f28f25e3435 390 False = The 16bits of RX FIFO data are placed in the LSBs of the RX buffer.
aidan1971 0:8f28f25e3435 391 Note: If data is not shifted, the 32bit word delivered to the user will not be sign extended.
aidan1971 4:91354c908416 392 If RX packed is true, then shift has no relevance.
aidan1971 0:8f28f25e3435 393 @param _TX_shift True = The MS16bits of TX buffer are sent to the TX FIFO. Default = true.
aidan1971 0:8f28f25e3435 394 False = The LS16bits of TX buffer are sent to the TX FIFO.
aidan1971 4:91354c908416 395 If TX packed is true, then shift has no relevance.
aidan1971 0:8f28f25e3435 396 @param _RX_DMAch Defines the system DMA channel to assign to the RX transfer. Default is 14.
aidan1971 0:8f28f25e3435 397 @param _TX_DMAch Defines the system DMA channel to assign to the TX transfer. Default is 15.
aidan1971 0:8f28f25e3435 398 14 & 15 are used as default to avoid using channels 0 - 3 which are the only channels available for gated triggers.
aidan1971 0:8f28f25e3435 399 Gated triggering is not needed, so these 4 channels are avoided.
aidan1971 9:40e0ff8c2ba2 400 @param _DMA_irq_pri Default = 0. Highest priority. This is the priority of the I2S DMA demands.
aidan1971 10:49bb33f71d32 401 @param _BufRX_L_safe2 A pointer address to the RX Left channel_1 data.
aidan1971 10:49bb33f71d32 402 @param _BufRX_R_safe2 A pointer address to the RX Right channel_1 data.
aidan1971 10:49bb33f71d32 403 @param _BufTX_L_safe2 A pointer address to the TX Left channel_1 data.
aidan1971 10:49bb33f71d32 404 @param _BufTX_R_safe2 A pointer address to the TX Right channel_1 data.
aidan1971 3:62c03088f256 405 @returns 0 = success, -1 = fail
aidan1971 3:62c03088f256 406 Fails on variable sanity checks.
aidan1971 0:8f28f25e3435 407 */
aidan1971 9:40e0ff8c2ba2 408 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 10:49bb33f71d32 409 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, uint32_t _BufRX_L_safe2 = NULL, uint32_t _BufRX_R_safe2 = NULL, uint32_t _BufTX_L_safe2 = NULL, uint32_t _BufTX_R_safe2 = NULL);
aidan1971 0:8f28f25e3435 410
aidan1971 3:62c03088f256 411 /*!
aidan1971 10:49bb33f71d32 412 @brief Stops I2S TX & RX channels. Stops all DMA requests and supresses any IRQs from the driver and tristates the CODEC I2S interface.
aidan1971 0:8f28f25e3435 413 */
aidan1971 8:9fdf8501d14b 414 int32_t stop_SYNC(void);
aidan1971 0:8f28f25e3435 415
aidan1971 3:62c03088f256 416 /*!
aidan1971 10:49bb33f71d32 417 @brief Pauses I2S RX & TX channels. Halts the RX & TX stream(s) by masking all data words.
aidan1971 10:49bb33f71d32 418 This can be used to suspend the codec when a user wishes to run critical tasks where IRQs must be suppressed. To restart call the resume function.
aidan1971 10:49bb33f71d32 419 */
aidan1971 10:49bb33f71d32 420 int32_t pause_SYNC(void);
aidan1971 10:49bb33f71d32 421
aidan1971 10:49bb33f71d32 422 /*!
aidan1971 10:49bb33f71d32 423 @brief Resumes a paused I2S RX & TX channels. Resumes the RX & TX stream(s) by un-masking all data words.
aidan1971 10:49bb33f71d32 424 */
aidan1971 10:49bb33f71d32 425 int32_t resume_SYNC(void);
aidan1971 10:49bb33f71d32 426
aidan1971 10:49bb33f71d32 427 /*!
aidan1971 10:49bb33f71d32 428 @brief Set codec and I2S Sampling frequency
aidan1971 0:8f28f25e3435 429 @param rate 8, 11, 12, 16, 22, 24, 32, 44, 48, 96, 192
aidan1971 0:8f28f25e3435 430 Base sampling rate of the codec
aidan1971 0:8f28f25e3435 431
aidan1971 0:8f28f25e3435 432 In all cases the SGTL5000 is programmed to use MCLK 256 times faster than sampling freq.
aidan1971 0:8f28f25e3435 433 MCU MCLK output = MCLK_Input((FRACT + 1)/(DIVIDE + 1))
aidan1971 0:8f28f25e3435 434 MCU MCLK Divide Register ratio is therefore = (Fs * 256)/PLL Clk
aidan1971 10:49bb33f71d32 435 The Teensy 3.1 & 3.2 have PLL freq @ 96MHz. However 120Mhz is supported dependent on the global 'SystemCoreClock' variable indicating this.
aidan1971 0:8f28f25e3435 436
aidan1971 3:62c03088f256 437 Note: To achieve some of these rates the codec SYS_FS is adjusted.
aidan1971 0:8f28f25e3435 438 This needs to be considered for several internal codec processes such as filter co-efficients and AVC.
aidan1971 3:62c03088f256 439 @returns 0 = success, -1 = fail
aidan1971 0:8f28f25e3435 440 */
aidan1971 10:49bb33f71d32 441 int32_t sample_rate(uint32_t rate);
aidan1971 10:49bb33f71d32 442
aidan1971 8:9fdf8501d14b 443 /*!
aidan1971 8:9fdf8501d14b 444 @brief Initialise codec.
aidan1971 10:49bb33f71d32 445 Resets the codec and sends initial default configuration data to the codec over I2C.
aidan1971 8:9fdf8501d14b 446 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 447 Failure to initialize will prevent operation of the codec. However it possible to attach and detach functions before init.
aidan1971 8:9fdf8501d14b 448 @returns 0 = success, -1 = fail
aidan1971 8:9fdf8501d14b 449 */
aidan1971 8:9fdf8501d14b 450 int32_t init(void);
aidan1971 10:49bb33f71d32 451
aidan1971 3:62c03088f256 452 /*!
aidan1971 3:62c03088f256 453 @brief Read debug data from the codec
aidan1971 3:62c03088f256 454 @param index 0-15
aidan1971 10:49bb33f71d32 455 @param finished a simple semaphore, indicating that debug data should be aquired again. (Can be used in combination with the internal bool SGTL5000::debug_read, to gate data collection.)
aidan1971 3:62c03088f256 456 Just a simple way for user code to grab running variables if you need it.
aidan1971 3:62c03088f256 457 @returns 0 = success, -1 = fail
aidan1971 3:62c03088f256 458 */
aidan1971 10:49bb33f71d32 459 int32_t read_debug(uint32_t index, bool finished = false);
aidan1971 10:49bb33f71d32 460 static bool debug_read;
aidan1971 0:8f28f25e3435 461
aidan1971 0:8f28f25e3435 462
aidan1971 0:8f28f25e3435 463 protected:
aidan1971 6:4ab5aaeaa064 464 static uint32_t debug[16];
aidan1971 10:49bb33f71d32 465 static void t_stamp_start(void);
aidan1971 10:49bb33f71d32 466 static void t_stamp_stop(void);
aidan1971 10:49bb33f71d32 467 static uint32_t t1;
aidan1971 10:49bb33f71d32 468 static uint32_t proc_time;
aidan1971 10:49bb33f71d32 469 static uint32_t SYST_CVAL;// = 0xE000E018; // Address of SysTick current value register
aidan1971 0:8f28f25e3435 470
aidan1971 0:8f28f25e3435 471
aidan1971 0:8f28f25e3435 472 private:
aidan1971 10:49bb33f71d32 473
aidan1971 10:49bb33f71d32 474 static IRQn CODEC_CTRL_IRQ; // Default IRQ used to elevate priority of user commands.
aidan1971 10:49bb33f71d32 475 static uint32_t ctrl_command; // Command translation
aidan1971 10:49bb33f71d32 476 #define STOP_SYNC 0x1
aidan1971 10:49bb33f71d32 477 #define STOP_TX 0x2
aidan1971 10:49bb33f71d32 478 #define STOP_RX 0x3
aidan1971 10:49bb33f71d32 479 #define PAUSE_TX 0x4
aidan1971 10:49bb33f71d32 480 #define PAUSE_RX 0x5
aidan1971 10:49bb33f71d32 481 #define PAUSE_SYNC 0x6
aidan1971 10:49bb33f71d32 482 #define RESUME_TX 0x7
aidan1971 10:49bb33f71d32 483 #define RESUME_RX 0x8
aidan1971 10:49bb33f71d32 484 #define RESUME_SYNC 0x9
aidan1971 10:49bb33f71d32 485
aidan1971 10:49bb33f71d32 486 static void stream_ctrl_ISR(void); // High priority control commands trigger by user through software ISR
aidan1971 10:49bb33f71d32 487
aidan1971 10:49bb33f71d32 488
aidan1971 7:d65476c153a4 489 I2C mI2C; // Create I2C instance
aidan1971 10:49bb33f71d32 490
aidan1971 10:49bb33f71d32 491 int i2c_addr;
aidan1971 0:8f28f25e3435 492
aidan1971 10:49bb33f71d32 493 int32_t init_i2s(void); // Configure I2S Default Settings
aidan1971 0:8f28f25e3435 494
aidan1971 8:9fdf8501d14b 495 int32_t init_codec(void); // Configure codec Default Settings
aidan1971 0:8f28f25e3435 496
aidan1971 0:8f28f25e3435 497 void init_DMA(void); // Configure SYNC DMA settings on MK20DX256
aidan1971 0:8f28f25e3435 498
aidan1971 10:49bb33f71d32 499 static void SYNC_TX_dma_ISR(void);
aidan1971 6:4ab5aaeaa064 500
aidan1971 10:49bb33f71d32 501 static void SYNC_RX_dma_ISR(void);
aidan1971 0:8f28f25e3435 502
aidan1971 10:49bb33f71d32 503 static void SYNC_pointer_swap(void);
aidan1971 0:8f28f25e3435 504
aidan1971 10:49bb33f71d32 505 static void TX_dma_ISR(void); // Handle TX DMA transfers complete.
aidan1971 6:4ab5aaeaa064 506
aidan1971 10:49bb33f71d32 507 static void RX_dma_ISR(void); // Handle RX DMA transfers complete using Callback
aidan1971 0:8f28f25e3435 508
aidan1971 9:40e0ff8c2ba2 509 static void tx_I2S_WS_ISR(void); // Handle TX word start allignment
aidan1971 0:8f28f25e3435 510
aidan1971 9:40e0ff8c2ba2 511 static void rx_I2S_WS_ISR(void); // Handle RX word start allignment
aidan1971 0:8f28f25e3435 512
aidan1971 9:40e0ff8c2ba2 513 static void sync_I2S_WS_ISR(void); // Handle SYNC word start allignment
aidan1971 0:8f28f25e3435 514
aidan1971 0:8f28f25e3435 515
aidan1971 10:49bb33f71d32 516 //const uint32_t DMA_INT_ADDR = 0x40008024; // Hard code the DMA->INT address its faster when inline assembler optimises
aidan1971 6:4ab5aaeaa064 517
aidan1971 10:49bb33f71d32 518
aidan1971 10:49bb33f71d32 519 static volatile uint32_t * volatile BufRX_L_safe; // Define statics for ISRs
aidan1971 10:49bb33f71d32 520 static volatile uint32_t * volatile BufRX_R_safe;
aidan1971 10:49bb33f71d32 521 static volatile uint32_t * volatile BufTX_L_safe;
aidan1971 10:49bb33f71d32 522 static volatile uint32_t * volatile BufTX_R_safe;
aidan1971 10:49bb33f71d32 523 static volatile uint32_t * volatile BufRX_L_safe2; // Define statics for ISRs
aidan1971 10:49bb33f71d32 524 static volatile uint32_t * volatile BufRX_R_safe2;
aidan1971 10:49bb33f71d32 525 static volatile uint32_t * volatile BufTX_L_safe2;
aidan1971 10:49bb33f71d32 526 static volatile uint32_t * volatile BufTX_R_safe2;
aidan1971 10:49bb33f71d32 527 static uint32_t BufRX_L_safeA; // Precalculated double buffer addresses
aidan1971 10:49bb33f71d32 528 static uint32_t BufRX_R_safeA;
aidan1971 10:49bb33f71d32 529 static uint32_t BufTX_L_safeA;
aidan1971 10:49bb33f71d32 530 static uint32_t BufTX_R_safeA;
aidan1971 10:49bb33f71d32 531 static uint32_t BufRX_L_safeB; // Precalculated double buffer addresses
aidan1971 10:49bb33f71d32 532 static uint32_t BufRX_R_safeB;
aidan1971 10:49bb33f71d32 533 static uint32_t BufTX_L_safeB;
aidan1971 10:49bb33f71d32 534 static uint32_t BufTX_R_safeB;
aidan1971 10:49bb33f71d32 535 static uint32_t BufRX_L_safeA2; // Precalculated double buffer addresses
aidan1971 10:49bb33f71d32 536 static uint32_t BufRX_R_safeA2;
aidan1971 10:49bb33f71d32 537 static uint32_t BufTX_L_safeA2;
aidan1971 10:49bb33f71d32 538 static uint32_t BufTX_R_safeA2;
aidan1971 10:49bb33f71d32 539 static uint32_t BufRX_L_safeB2; // Precalculated double buffer addresses
aidan1971 10:49bb33f71d32 540 static uint32_t BufRX_R_safeB2;
aidan1971 10:49bb33f71d32 541 static uint32_t BufTX_L_safeB2;
aidan1971 10:49bb33f71d32 542 static uint32_t BufTX_R_safeB2;
aidan1971 10:49bb33f71d32 543 static uint32_t I2S_RX_Buffer[16];
aidan1971 10:49bb33f71d32 544 static uint32_t I2S_TX_Buffer[16];
aidan1971 10:49bb33f71d32 545 static uint32_t I2S_RX_Buffer2[16];
aidan1971 10:49bb33f71d32 546 static uint32_t I2S_TX_Buffer2[16];
aidan1971 10:49bb33f71d32 547 static uint32_t active_RX_DMAch_bm;
aidan1971 10:49bb33f71d32 548 static uint32_t active_TX_DMAch_bm;
aidan1971 10:49bb33f71d32 549 static uint32_t sync_dma_irq_acks;
aidan1971 0:8f28f25e3435 550 static IRQn SYNC_swIRQ;
aidan1971 0:8f28f25e3435 551 static IRQn TX_swIRQ;
aidan1971 0:8f28f25e3435 552 static IRQn RX_swIRQ;
aidan1971 0:8f28f25e3435 553 static Callback<void()> TX_user_func;
aidan1971 0:8f28f25e3435 554 static Callback<void()> RX_user_func;
aidan1971 0:8f28f25e3435 555 static Callback<void()> SYNC_user_func;
aidan1971 9:40e0ff8c2ba2 556 static uint32_t db_phase_sync;
aidan1971 9:40e0ff8c2ba2 557 static uint32_t db_phase_tx;
aidan1971 9:40e0ff8c2ba2 558 static uint32_t db_phase_rx;
aidan1971 10:49bb33f71d32 559 static uint32_t SYNC_attach_type;
aidan1971 10:49bb33f71d32 560 static uint32_t TX_attach_type;
aidan1971 10:49bb33f71d32 561 static uint32_t RX_attach_type;
aidan1971 10:49bb33f71d32 562 static bool i2s_configured;
aidan1971 10:49bb33f71d32 563 static bool codec2_active;
aidan1971 10:49bb33f71d32 564 static bool codec1_active;
aidan1971 10:49bb33f71d32 565 static uint32_t dump;
aidan1971 10:49bb33f71d32 566 static uint32_t NULL_DMA_TX;
aidan1971 10:49bb33f71d32 567 static uint32_t NULL_DMA_RX;
aidan1971 10:49bb33f71d32 568 static uint32_t RX_DMAch;
aidan1971 10:49bb33f71d32 569 static uint32_t TX_DMAch;
aidan1971 10:49bb33f71d32 570 static bool SYNC_run;
aidan1971 10:49bb33f71d32 571 static bool TX_run;
aidan1971 10:49bb33f71d32 572 static bool RX_run;
aidan1971 0:8f28f25e3435 573
aidan1971 10:49bb33f71d32 574 int i2c_freq;
aidan1971 6:4ab5aaeaa064 575 uint32_t TX_block_size;
aidan1971 6:4ab5aaeaa064 576 uint32_t RX_block_size;
aidan1971 0:8f28f25e3435 577 uint32_t TX_bs_bytes;
aidan1971 0:8f28f25e3435 578 uint32_t RX_bs_bytes;
aidan1971 10:49bb33f71d32 579 bool ctrl_codec;
aidan1971 8:9fdf8501d14b 580 bool codec_configured;
aidan1971 9:40e0ff8c2ba2 581 bool codec_I2S_active;
aidan1971 10:49bb33f71d32 582
aidan1971 0:8f28f25e3435 583 bool SYNC_attached;
aidan1971 0:8f28f25e3435 584 bool TX_attached;
aidan1971 0:8f28f25e3435 585 bool RX_attached;
aidan1971 0:8f28f25e3435 586 bool TX_shift;
aidan1971 0:8f28f25e3435 587 bool RX_shift;
aidan1971 4:91354c908416 588 bool packed_RX;
aidan1971 4:91354c908416 589 bool packed_TX;
aidan1971 10:49bb33f71d32 590
aidan1971 10:49bb33f71d32 591
aidan1971 0:8f28f25e3435 592 };
aidan1971 0:8f28f25e3435 593 }
aidan1971 0:8f28f25e3435 594 #endif