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.

Revision:
9:40e0ff8c2ba2
Parent:
8:9fdf8501d14b
Child:
10:49bb33f71d32
--- a/sgtl5000.h	Fri Jul 07 11:38:57 2017 +0000
+++ b/sgtl5000.h	Sat Jul 15 13:15:08 2017 +0000
@@ -97,7 +97,7 @@
     i2s_tx             i2s rx_data (from bus master perspective) (D13 Teensy 3.2 header /PTC5 MK20DX256)
 
     */
-    SGTL5000(PinName i2c_sda, PinName i2c_scl, int i2c_freq = 100000, bool i2c_ctrl_adr0_cs = 0);
+    SGTL5000(PinName i2c_sda, PinName i2c_scl, int _i2c_freq = 100000, bool i2c_ctrl_adr0_cs = 0);
 
     /*!
     @brief  Read 16bit register of SGTL5000
@@ -154,34 +154,35 @@
     int32_t detach_TX(void);
 
     /*!
-    @brief Stops i2s TX channel but maintains clocking.
+    @brief Stops i2s TX channel. Stops all DMA requests and supresses any IRQs from the driver.
+           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.
     */
     int32_t stop_TX(void);
 
     /*!
     @brief  Starts the codec I2S interface and begins transferring TX buffers. Transfers use DMA.
-    @param  BufTX_L_safe    A pointer address to the TX Left channel data.
+    @param  _BufTX_L_safe   A pointer address to the TX Left channel data.
                             The pointer address is managed by the driver and changes to implement a double buffer.
                             It is suggested that a suitable declaration in the users code would be in the form: 'q31_t *TX_AudioL = NULL;'
                             Although volatile is not strictly necessary both the pointer address and the data pointed to, are changing outside the flow of the user code.
                             To pass into the class, dereference this pointer and cast as uint32_t, as follows: 'codec.start_SYNC((uint32_t)&TX_AudioL .....'
-    @param  BufTX_R_safe    A pointer address to the TX Right channel data.
-    @param  block_size      2 | 4 | 8 words of both Left and Right channels combined.
+    @param  _BufTX_R_safe   A pointer address to the TX Right channel data.
+    @param  _block_size     2 | 4 | 8 words of both Left and Right channels combined.
                             This defines the number of samples that are transferred to the TX FIFO each time a FIFO demand is detected.
-    @param  packed_TX       If true 2 * 16bit words for wire transmission are expected packed into a single 32bit word.
+    @param  _packed_TX      If true 2 * 16bit words for wire transmission are expected packed into a single 32bit word.
                             If False each 32bit word from the user should contain a single 16bit word for transmission.
-    @param  TX_shift        True = The MS16bits of TX buffer are sent to the TX FIFO.   Default = true.
+    @param  _TX_shift       True = The MS16bits of TX buffer are sent to the TX FIFO.   Default = true.
                             False = The LS16bits of TX buffer are sent to the TX FIFO.
                             If packed is true, then shift has no relevance.
-    @param  tx_DMAch        Defines the system DMA channel to assign to the TX transfer. Default is 15.
+    @param  _tx_DMAch       Defines the system DMA channel to assign to the TX transfer. Default is 15.
                             15 is used as default to avoid using channels 0 - 3 which are the only channels available for gated triggers.
                             Gated triggering is not needed, so these 4 channels are avoided.
-    @param  DMA_irq_pri     Default = 0. Highest priority. This is the priority of the I2S TX DMA demands.
+    @param  _DMA_irq_pri    Default = 0. Highest priority. This is the priority of the I2S TX DMA demands.
     @returns                0 = success, -1 = fail
                             Fails on variable sanity checks.
     */
-    int32_t start_TX(uint32_t BufTX_L_safe, uint32_t BufTX_R_safe,
-                     uint32_t block_size = 4, bool _packed_TX = false, bool _TX_shift = true,  uint32_t _TX_DMAch = 15, uint32_t DMA_irq_pri = 0);
+    int32_t start_TX(uint32_t _BufTX_L_safe, uint32_t _BufTX_R_safe,
+                     uint32_t _block_size = 4, bool _packed_TX = false, bool _TX_shift = true,  uint32_t _TX_DMAch = 15, uint32_t _DMA_irq_pri = 0);
 
     /*!
     @brief Attach a callback function to RX
@@ -206,39 +207,40 @@
 
     /*!
     @brief Stop RX channel and flag as detached.
-                        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
+           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
     */
     int32_t detach_RX(void);
 
     /*!
-    @brief Stops i2s RX channel but maintains clocking.
+    @brief Stops i2s RX channel. Stops all DMA requests and supresses any IRQs from the driver.
+           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.
     */
     int32_t stop_RX(void);
 
     /*!
     @brief  Starts the codec I2S interface and begins transferring RX buffers. Transfers use DMA.
-    @param  BufRX_L_safe    A pointer address to the RX Left channel data.
+    @param  _BufRX_L_safe   A pointer address to the RX Left channel data.
                             The pointer address is managed by the driver and changes to implement a double buffer.
                             It is suggested that a suitable declaration in the users code would be in the form: 'q31_t *RX_AudioL = NULL;'
                             To pass into the class, dereference this pointer and cast as uint32_t, as follows: 'codec.start_SYNC((uint32_t)&RX_AudioL .....'
-    @param  BufRX_R_safe    A pointer address to the RX Right channel data.
-    @param  block_size      2 | 4 | 8 words of both Left and Right channels combined.
+    @param  _BufRX_R_safe   A pointer address to the RX Right channel data.
+    @param  _block_size     2 | 4 | 8 words of both Left and Right channels combined.
                             This defines the number of samples that are transferred to the RX FIFO each time a FIFO demand is detected.
-    @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
+    @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
                             If False a single 16bit word from the wire is placed into a single 32bit word towards the user.
-    @param  RX_shift        True = The 16bits of RX FIFO data are shifted to the MSBs of the RX buffer. Default = true
+    @param  _RX_shift       True = The 16bits of RX FIFO data are shifted to the MSBs of the RX buffer. Default = true
                             False = The 16bits of RX FIFO data are placed in the LSBs of the RX buffer
                             Note: If data is not shifted, the 32bit word delivered to the user will not be sign extended.
                             If packed is true, then shift has no relevance.
-    @param  rx_DMAch        Defines the system DMA channel to assign to the RX transfer. Default is 14.
+    @param  _rx_DMAch       Defines the system DMA channel to assign to the RX transfer. Default is 14.
                             14 is used as default to avoid using channels 0 - 3 which are the only channels available for gated triggers.
                             Gated triggering is not needed, so these 4 channels are avoided.
-    @param  DMA_irq_pri     Default = 0. Highest priority. This is the priority of the I2S RX DMA demands.
+    @param  _DMA_irq_pri    Default = 0. Highest priority. This is the priority of the I2S RX DMA demands.
     @returns                0 = success, -1 = fail
                             Fails on variable sanity checks.
     */
-    int32_t start_RX(uint32_t BufRX_L_safe, uint32_t BufRX_R_safe,
-                     uint32_t block_size = 4, bool _packed_RX = false, bool _RX_shift = true,  uint32_t _RX_DMAch = 14, uint32_t DMA_irq_pri = 0);
+    int32_t start_RX(uint32_t _BufRX_L_safe, uint32_t _BufRX_R_safe,
+                     uint32_t _block_size = 4, bool _packed_RX = false, bool _RX_shift = true,  uint32_t _RX_DMAch = 14, uint32_t _DMA_irq_pri = 0);
 
     /*!
     @brief Attach a callback function to DMA SYNC
@@ -270,18 +272,18 @@
 
     /**
     @brief  Starts the codec I2S interface and begins transferring RX and TX buffers. Transfers use DMA.
-    @param  BufRX_L_safe    A pointer address to the RX Left channel data.
+    @param  _BufRX_L_safe   A pointer address to the RX Left channel data.
                             The pointer address is managed by the driver and changes to implement a double buffer.
                             It is suggested that a suitable declaration in the users code would be in the form: 'q31_t *RX_AudioL = NULL;'
                             To pass into the class, dereference this pointer and cast as uint32_t, as follows: 'codec.start_SYNC((uint32_t)&RX_AudioL .....'
-    @param  BufRX_L_safe    A pointer address to the RX Right channel data.
-    @param  BufRX_L_safe    A pointer address to the TX Left channel data.
-    @param  BufRX_L_safe    A pointer address to the TX Right channel data.
-    @param  block_size      2 | 4 | 8 words of both Left and Right channels combined.
+    @param  _BufRX_R_safe   A pointer address to the RX Right channel data.
+    @param  _BufTX_L_safe   A pointer address to the TX Left channel data.
+    @param  _BufTX_R_safe   A pointer address to the TX Right channel data.
+    @param  _block_size     2 | 4 | 8 words of both Left and Right channels combined.
                             This defines the number of samples that are transferred to both FIFOs each time a FIFO demand is detected.
-    @param  packed_TX       If true the 2 * 16bit words for wire transmission are expected packed into a single 32bit word.
+    @param  _packed_TX      If true the 2 * 16bit words for wire transmission are expected packed into a single 32bit word.
                             If False each 32bit word from the user should contain a single 16bit word for transmission.
-    @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
+    @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
                             If False a single 16bit word from the wire is placed into a single 32bit word towards the user.
     @param  _RX_shift       True = The 16bits of RX FIFO data are shifted to the MSBs of the RX buffer. Default = true
                             False = The 16bits of RX FIFO data are placed in the LSBs of the RX buffer.
@@ -294,15 +296,16 @@
     @param  _TX_DMAch       Defines the system DMA channel to assign to the TX transfer. Default is 15.
                             14 & 15 are used as default to avoid using channels 0 - 3 which are the only channels available for gated triggers.
                             Gated triggering is not needed, so these 4 channels are avoided.
-    @param  DMA_irq_pri     Default = 0. Highest priority. This is the priority of the I2S DMA demands.
+    @param  _DMA_irq_pri    Default = 0. Highest priority. This is the priority of the I2S DMA demands.
     @returns                0 = success, -1 = fail
                             Fails on variable sanity checks.
     */
-    int32_t start_SYNC(uint32_t BufRX_L_safe, uint32_t BufRX_R_safe, uint32_t BufTX_L_safe, uint32_t BufTX_R_safe,
-                       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);
+    int32_t start_SYNC(uint32_t _BufRX_L_safe, uint32_t _BufRX_R_safe, uint32_t _BufTX_L_safe, uint32_t _BufTX_R_safe,
+                       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);
 
     /*!
-    @brief Stops i2s TX & RX channels but maintains clocking.
+    @brief Stops i2s TX & RX channels. Stops all DMA requests and supresses any IRQs from the driver.
+           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.
     */
     int32_t stop_SYNC(void);
 
@@ -366,11 +369,11 @@
 
     static void sync_dma_ISR(void);                                             // Handle SYNC DMA transfers complete using Callback
 
-    static void tx_I2S_ISR(void);                                               // Handle TX word start allignment
+    static void tx_I2S_WS_ISR(void);                                            // Handle TX word start allignment
 
-    static void rx_I2S_ISR(void);                                               // Handle RX word start allignment
+    static void rx_I2S_WS_ISR(void);                                            // Handle RX word start allignment
 
-    static void sync_I2S_ISR(void);                                             // Handle SYNC word start allignment
+    static void sync_I2S_WS_ISR(void);                                          // Handle SYNC word start allignment
 
 
 
@@ -386,6 +389,11 @@
     static Callback<void()> TX_user_func;
     static Callback<void()> RX_user_func;
     static Callback<void()> SYNC_user_func;
+    static uint32_t db_phase_sync;
+    static uint32_t db_phase_tx;
+    static uint32_t db_phase_rx;
+    
+    int i2c_freq;
 
     uint32_t I2S_RX_Buffer[16];
     uint32_t I2S_TX_Buffer[16];
@@ -397,6 +405,7 @@
     uint32_t TX_bs_bytes;
     uint32_t RX_bs_bytes;
     bool codec_configured;
+    bool codec_I2S_active;
     bool SYNC_run;
     bool TX_run;
     bool RX_run;