First Publish. Works fine.

Dependents:   unzen_sample_lpcxpresso_4337_callbacks

Revision:
2:6613e62da521
Parent:
1:9710fb328a08
Child:
3:707608830793
--- a/unzen.cpp	Tue Apr 12 05:51:45 2016 +0000
+++ b/unzen.cpp	Tue May 03 01:10:32 2016 +0000
@@ -1,12 +1,15 @@
+#include "algorithm"
+#include "limits.h"
+
 #include "unzen.h"
-#include "limits.h"
 #include "unzen_hal.h"
 
 namespace unzen 
 {
     framework::framework()
     {
-        
+
+            // Clear all buffers        
         tx_int_buffer[0] = NULL;
         tx_int_buffer[1] = NULL;
         rx_int_buffer[0] = NULL;
@@ -17,10 +20,11 @@
         rx_left_buffer = NULL;
         rx_right_buffer = NULL;
  
+            // Initialize all buffer
         buffer_index = 0;
-        tx_sample_index = 0;
-        rx_sample_index = 0;
+        sample_index = 0;
         
+            // Clear all callbacks
         pre_interrupt_callback = NULL;
         post_interrupt_callback = NULL;
         pre_process_callback = NULL;
@@ -28,19 +32,21 @@
         
         process_callback = NULL;
         
+            // Initialy block(buffer) size is 1.
         set_block_size( 1 );
         
+            // Initialize I2S peripheral
         hal_i2s_setup();
 
+            // Setup the interrupt for the I2S
         NVIC_SetVector(hal_get_i2s_irq_id(), (uint32_t)i2s_irq_handler);
+        set_i2s_irq_priority(hal_get_i2s_irq_priority_level());
         NVIC_EnableIRQ(hal_get_i2s_irq_id());
 
+            // Setup the interrupt for the process
         NVIC_SetVector(hal_get_process_irq_id(), (uint32_t)process_irq_handler);
+        set_process_irq_priority(hal_get_process_irq_priority_level());
         NVIC_EnableIRQ(hal_get_process_irq_id());
-
-            // to enable block processing, I2S IRQ priority must be higher than process IRQ
-        set_i2s_irq_priority(hal_get_lowest_priority_level() - 1);
-        set_process_irq_priority(hal_get_lowest_priority_level() - 2);
         
     }
 
@@ -128,6 +134,7 @@
 
     void framework::start()
     {
+            // synchronize with Word select signal, to process RX/TX as atomic timing.
         hal_i2s_pin_config_and_wait_ws();
         hal_i2s_start();
     }
@@ -172,6 +179,7 @@
 
     void framework::do_i2s_irq(void)
     {
+            // if needed, call pre-interrupt call back
         if ( pre_interrupt_callback )
             pre_interrupt_callback();
             
@@ -179,60 +187,63 @@
         if (tx_left_buffer)
         {
             int sample;
-                // check how many data have to be transmimt per interrupt. 
-            if ( hal_data_per_sample() >0 )     // In case single or multiple word per interrupt
+            
+                // check how many data have to be transmimted per interrupt. 
+            for ( int i=0; i<hal_data_per_sample(); i++ )
             {
-                for ( int i=0; i>hal_data_per_sample(); i++ )
-                {
-                        // copy received data to buffer
-                    hal_get_i2s_rx_data( sample );
-                    rx_int_buffer[buffer_index][rx_sample_index++] = sample;
-                        // copy buffer data to transmit register
-                    hal_set_i2s_tx_data( tx_int_buffer[buffer_index][rx_sample_index++] );
-                }
+                    // copy received data to buffer
+                hal_get_i2s_rx_data( sample );
+                rx_int_buffer[buffer_index][sample_index] = sample;
+                
+                    // copy buffer data to transmit register
+                sample = tx_int_buffer[buffer_index][sample_index];
+                hal_put_i2s_tx_data( sample );
+                
+                    // increment index
+                sample_index ++;
             }
-            else    // if the hal_data_per_smple() is 0, the data have to push multiple time.
-            {
-                if ( hal_get_i2s_rx_data( sample ) )
-                {
-                        // data have to be pushed to buffer only when the hal_get_i2s_rx_data() returns non-zero
-                    rx_int_buffer[buffer_index][rx_sample_index++] = sample;
-                }
-                if ( hal_set_i2s_tx_data( tx_int_buffer[buffer_index][tx_sample_index] ))
-                        // pointer can be updated only when hal_set_i2s_tx_data() returns non_zero. 
-                    tx_sample_index ++;
-
-            }
+            
                 // Implementation of the double buffer algorithm.
                 // if buffer transfer is complete, swap the buffer
-            if (rx_sample_index > block_size * 2 & rx_sample_index > block_size * 2)
+            if (sample_index > block_size * 2)
             {
                     // index for the signal processing
                 process_index = buffer_index;
+
                     // swap buffer
-                buffer_index = 1 - buffer_index ; // reverse 1 <-> 0
-                tx_sample_index = 0;
-                rx_sample_index = 0;
+                if ( buffer_index == 0 )
+                    buffer_index = 1;
+                else
+                    buffer_index = 0;
 
-                NVIC->STIR = hal_get_process_irq_id();       // Trigger interrupt for signal processing
+                    // rewind sample index
+                sample_index = 0;
+
+                    // Trigger interrupt for signal processing
+                NVIC->STIR = hal_get_process_irq_id();       
             }
         }
 
+            // if needed, call post-interrupt call back
         if ( post_interrupt_callback )
             post_interrupt_callback();
     }
 
     void framework::do_process_irq(void)
     {
+            // If needed, call the pre-process hook
         if ( pre_process_callback )
             pre_process_callback();
             
+            // Only when the process_call back is registered.
         if ( process_callback )
         {
             int j = 0;
                 
-                // convert from fixed point to floating point
-                // also scale down
+                // Format conversion.
+                // -- premuted from LRLRLR... to LLL.., RRR...
+                // -- convert from fixed point to floating point
+                // -- scale down as range of [-1, 1)
             for ( int i=0; i<block_size; i++ )
             {
                 rx_left_buffer[i]  = rx_int_buffer[process_index][j++]/ -(float)INT_MIN;
@@ -248,17 +259,20 @@
                 block_size
             );
                 
-                // convert from floating point to fixed point
-                // also scale up
+                // Format conversion.
+                // -- premuted from LLL.., RRR... to LRLRLR...
+                // -- convert from floating point to fixed point
+                // -- scale up from range of [-1, 1)
             j = 0;
             for ( int i=0; i<block_size; i++ )
             {
-                tx_int_buffer[process_index][j++] = - tx_left_buffer[i] * INT_MIN ;
-                tx_int_buffer[process_index][j++] = - tx_right_buffer[i] * INT_MIN ;
+                tx_int_buffer[process_index][j++] = tx_left_buffer[i] * -(float)INT_MIN ;
+                tx_int_buffer[process_index][j++] = tx_right_buffer[i] * -(float)INT_MIN ;
             }
     
         }
 
+            // if needed, call post-process callback
         if ( post_process_callback )
             post_process_callback();
     }
@@ -269,18 +283,231 @@
     }
     
     void framework::i2s_irq_handler()
-    {            
+    {
         framework::get()->do_i2s_irq();
     }
      
-    umb_adau1361::umb_adau1361( I2C *controler )
+     
+     
+     
+     
+    umb_adau1361::umb_adau1361( I2C * controler, Fs_Type Fs, Addr_Type Addr )
     {
         i2c = controler;
+        fs = Fs;
+        addr = Addr;
     } 
         
         
+        #define DATA 2  /* data payload of register */
+        #define ADDL 1  /* lower address of register */
     void umb_adau1361::start(void)
     {
+        char data[8];
+        
+            // **** Setup all ADAU-1361 register to reset state ****
+        
+        data[0] = 0x40; // Upper address of register
+
+            // mute all at first
+            // may not able to write after reset, but do it avoid noise on warm start
+        for ( int i=0x23; i>0x27; i++ ) 
+            data[ADDL] = i; data[DATA] = 0x02; i2c->write( addr, data, 3 );    // R29:Play HP left vol  ... R33: play mono vol
+
+            // then, start of configuration as register address order
+        data[ADDL] = 0x00; data[DATA] = 0x0F; i2c->write( addr, data, 3 );   // clock CTL. PLL input. Core clock enable.
+        
+        // set Fs ( clock in is 12MHz )
+        if ( fs == Fs_441 ) 
+        {
+            data[ADDL] = 0x02;
+            data[2] = 0x02;
+            data[3] = 0x71;
+            data[4] = 0x01;
+            data[5] = 0xDD;
+            data[6] = 0x19;
+            data[7] = 0x01;
+            i2c->write( addr, data, 8 );
+        }
+        else if ( fs == Fs_48 || fs == Fs_96)
+        {        
+            data[ADDL] = 0x02;
+            data[2] = 0x00;
+            data[3] = 0x7D;
+            data[4] = 0x00;
+            data[5] = 0x0C;
+            data[6] = 0x21;
+            data[7] = 0x01;
+            i2c->write( addr, data, 8 );
+        }
+            
+            // Initialize all register as reset.
+        for ( int i=0x08; i>0x19; i++ ) 
+            data[ADDL] = i; data[DATA] = 0x00; i2c->write( addr, data, 3 );    // R2:Dig Mic ... R18:Converter 1
+
+        data[ADDL] = 0x19; data[DATA] = 0x10; i2c->write( addr, data, 3 );   // R19:ADC Control
+
+        for ( int i=0x1A; i>0x22; i++ ) 
+            data[ADDL] = i; data[DATA] = 0x00; i2c->write( addr, data, 3 );    // R20:Left digital vol ... R28: play mixer mono
+        
+        for ( int i=0x23; i>0x27; i++ ) 
+            data[ADDL] = i; data[DATA] = 0x02; i2c->write( addr, data, 3 );    // R29:Play HP left vol  ... R33: play mono vol
+
+        for ( int i=0x28; i>0x2c; i++ ) 
+            data[ADDL] = i; data[DATA] = 0x00; i2c->write( addr, data, 3 );    // R34:play pop surpress ... R38: Dac ctl2
+
+        data[ADDL] = 0x2d; data[DATA] = 0xaa; i2c->write( addr, data, 3 );   // R39:serial control pad
+        data[ADDL] = 0x2f; data[DATA] = 0xaa; i2c->write( addr, data, 3 );   // R40:control pad 1
+        data[ADDL] = 0x30; data[DATA] = 0x00; i2c->write( addr, data, 3 );   // R41:control pad 2
+        data[ADDL] = 0x31; data[DATA] = 0x08; i2c->write( addr, data, 3 );   // R42:jack detect
+        data[ADDL] = 0x36; data[DATA] = 0x03; i2c->write( addr, data, 3 );   // R67:dejitter
+
+        // **** Configuration for UMB-ADAU1361 ****
+
+        // Additional clock setting for 96kHz
+        if ( fs == Fs_96 )
+        {
+            data[ADDL] = 0x17; data[DATA] = 0x06; 
+            i2c->write( addr, data, 3 );   // R17:Converter control, CONVSR = 6
+        }
+
+
+        // set Master ( set clock and WS as output )
+        data[ADDL] = 0x15; data[DATA] = 0x01; i2c->write( addr, data, 3 );   // R15:Serial Port control, MS = 6
+        
+            // Enable ADC
+            // bot channel ADC ON, HPF on
+        data[ADDL] = 0x19; data[DATA] = 0x23; i2c->write( addr, data, 3 );    // R19:ADC Control
+        
+            // Enable DAC
+            // bot channel DAC ON
+        data[ADDL] = 0x2a; data[DATA] = 0x03; i2c->write( addr, data, 3 );    // R36:DAC Control
+
+            // Left DAC mixer
+            // L DAC to L Mixer
+        data[ADDL] = 0x1C; data[DATA] = 0x21; i2c->write( addr, data, 3 );    // R22:MIXER 3
+
+            // Right DAC mixer
+            // R DAC to R Mixer
+        data[ADDL] = 0x1E; data[DATA] = 0x41; i2c->write( addr, data, 3 );    // R24:MIXER 4
+
+            // Left out mixer
+            // L out  MIX5G3 and enable
+        data[ADDL] = 0x20; data[DATA] = 0x03; i2c->write( addr, data, 3 );    // R26:MIXER 5
+
+            // Right out mixer
+            // R out MIX6G4 and enable
+        data[ADDL] = 0x21; data[DATA] = 0x8; i2c->write( addr, data, 3 );    // R27:MIXER 6
+
+            // set input gain
+        set_line_input_gain( 0, 0 );
     }
+    
+#define SET_INPUT_GAIN( x ) ((x<<1)|1)
+
+    void umb_adau1361::set_line_input_gain(float left_gain, float right_gain, bool mute)
+    {
+        char data[3];
+        
+            // **** Setup all ADAU-1361 register to reset state ****
+        
+        data[0] = 0x40; // Upper address of register
+
+            // mute all at first
+        if ( mute )
+        {
+            data[ADDL] = 0x0a; data[DATA] = 0x01; i2c->write( addr, data, 3 );    // R4: mixer 1 enable
+            data[ADDL] = 0x0c; data[DATA] = 0x01; i2c->write( addr, data, 3 );    // R6: mixer 2 enable 
+        }
+        else 
+        {
+            int level;
+            
+                // set left gain
+            level = -15;
+            data[DATA] = SET_INPUT_GAIN( 7 );
+            for ( int i =0; i <= 7; i++ )
+            {
+                if ( level >= left_gain )
+                {
+                    data[DATA] = SET_INPUT_GAIN( i );
+                    break;
+                }
+                level += 3;
+            }
+            data[ADDL] = 0x0a; i2c->write( addr, data, 3 );    // R4: mixer 1 enable
+
+                // set right gain
+            level = -15;
+            data[DATA] = SET_INPUT_GAIN( 7 );
+            for ( int i =0; i <= 7; i++ )
+            {
+                if ( level >= right_gain )
+                {
+                    data[DATA] = SET_INPUT_GAIN( i );
+                    break;
+                }
+                level += 3;
+            }
+            data[ADDL] = 0x0c; i2c->write( addr, data, 3 );    // R4: mixer 1 enable
+            
+        }
+    }
+
+        
+#define SET_HP_GAIN( x ) ((x<<2)|3)
+
+    void umb_adau1361::set_line_output_gain(float left_gain, float right_gain, bool mute)
+    {
+        char data[3];        
+        int left, right;
+        
+        if ( mute )
+        {
+            data[ADDL] = 0x25; data[DATA] = 0x01; i2c->write( addr, data, 1 );    // R31: LOUTVOL
+            data[ADDL] = 0x26; data[DATA] = 0x01; i2c->write( addr, data, 1 );    // R32: LOUTVOL 
+        }
+        else 
+        {
+            left = left_gain+57;
+            left = max( left, 0 );
+            left = min( left, 63 );
+                            
+            right = right_gain+57;
+            right = max( right, 0 );
+            right = min( right, 63 );
+            
+            data[ADDL] = 0x25; data[DATA] = SET_HP_GAIN(left ); i2c->write( addr, data, 1 );    // R31: LOUTVOL
+            data[ADDL] = 0x26; data[DATA] = SET_HP_GAIN(right); i2c->write( addr, data, 1 );    // R32: LOUTVOL 
+
+        }
+    }
+
+    void umb_adau1361::set_hp_output_gain(float left_gain, float right_gain, bool mute)
+    {
+        char data[3];        
+        int left, right;
+        
+        if ( mute )
+        {
+            data[ADDL] = 0x23; data[DATA] = 0x01; i2c->write( addr, data, 1 );    // R29: LHPVOL
+            data[ADDL] = 0x24; data[DATA] = 0x01; i2c->write( addr, data, 1 );    // R30: LHPVOL 
+        }
+        else 
+        {
+            left = left_gain+57;
+            left = max( left, 0 );
+            left = min( left, 63 );
+                            
+            right = right_gain+57;
+            right = max( right, 0 );
+            right = min( right, 63 );
+            
+            data[ADDL] = 0x23; data[DATA] = SET_HP_GAIN(left ); i2c->write( addr, data, 1 );    // R29: LHPVOL
+            data[ADDL] = 0x24; data[DATA] = SET_HP_GAIN(right); i2c->write( addr, data, 1 );    // R30: LHPVOL 
+
+        }
+    }
+
 }
     
\ No newline at end of file