First Publish. Works fine.

Dependents:   unzen_sample_lpcxpresso_4337_callbacks

unzen.cpp

Committer:
shorie
Date:
2016-05-03
Revision:
2:6613e62da521
Parent:
1:9710fb328a08
Child:
3:707608830793

File content as of revision 2:6613e62da521:

#include "algorithm"
#include "limits.h"

#include "unzen.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;
        rx_int_buffer[1] = NULL;
        
        tx_left_buffer = NULL;
        tx_right_buffer = NULL;
        rx_left_buffer = NULL;
        rx_right_buffer = NULL;
 
            // Initialize all buffer
        buffer_index = 0;
        sample_index = 0;
        
            // Clear all callbacks
        pre_interrupt_callback = NULL;
        post_interrupt_callback = NULL;
        pre_process_callback = NULL;
        post_process_callback = NULL;
        
        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());
        
    }

    error_type framework::set_block_size(  unsigned int new_block_size )
    {
        
        delete [] tx_int_buffer[0];
        delete [] tx_int_buffer[1];
        delete [] rx_int_buffer[0];
        delete [] rx_int_buffer[1];
        
        delete [] tx_left_buffer;
        delete [] tx_right_buffer;
        delete [] rx_left_buffer;
        delete [] rx_right_buffer;
        
        block_size = new_block_size;

        tx_int_buffer[0] = new int[ 2 * block_size ];
        tx_int_buffer[1] = new int[ 2 * block_size ];
        rx_int_buffer[0] = new int[ 2 * block_size ];
        rx_int_buffer[1] = new int[ 2 * block_size ];
        
        tx_left_buffer = new float[ block_size ];
        tx_right_buffer = new float[ block_size ];
        rx_left_buffer = new float[ block_size ];
        rx_right_buffer = new float[ block_size ];
 
            // error check
        if ( rx_int_buffer[0] == NULL |
             rx_int_buffer[1] == NULL |
             tx_int_buffer[0] == NULL |
             tx_int_buffer[1] == NULL |
             rx_right_buffer == NULL |
             tx_right_buffer == NULL |
             rx_left_buffer == NULL |
             tx_left_buffer == NULL )
        {   // if error, release all 
            delete [] tx_int_buffer[0];
            delete [] tx_int_buffer[1];
            delete [] rx_int_buffer[0];
            delete [] rx_int_buffer[1];
            
            delete [] tx_left_buffer;
            delete [] tx_right_buffer;
            delete [] rx_left_buffer;
            delete [] rx_right_buffer;
            
            tx_int_buffer[0] = NULL;
            tx_int_buffer[1] = NULL;
            rx_int_buffer[0] = NULL;
            rx_int_buffer[1] = NULL;
            
            tx_left_buffer = NULL;
            tx_right_buffer = NULL;
            rx_left_buffer = NULL;
            rx_right_buffer = NULL;
            
            return memory_allocation_error;
        }

            // clear blocks
        for ( int i=0; i<block_size*2; i++ )
        {

            tx_int_buffer[0][i] = 0;
            tx_int_buffer[1][i] = 0;
            rx_int_buffer[0][i] = 0;
            rx_int_buffer[1][i] = 0;
            
        }
            // clear blocks
        for ( int i=0; i<block_size ; i++ )
        {

            tx_left_buffer[i] = 0;
            tx_right_buffer[i] = 0;
            rx_left_buffer[i] = 0;
            rx_right_buffer[i] = 0;

        }
         
        return no_error;
    }

    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();
    }

    void framework::set_i2s_irq_priority( unsigned int pri )
    {
        NVIC_SetPriority(hal_get_process_irq_id(), pri);  // must be higher than PendSV of mbed-RTOS
        
    }
    
    void framework::set_process_irq_priority( unsigned int pri )
    {
        NVIC_SetPriority(hal_get_i2s_irq_id(), pri);      // must be higher than process IRQ

    }

    void framework::set_process_callback( void (* cb ) (float[], float[], float[], float[], unsigned int))
    { 
        process_callback = cb;
    }

    void framework::set_pre_interrupt_callback( void (* cb ) (void))
    { 
        pre_interrupt_callback = cb;
    }
    
    void framework::set_post_interrupt_callback( void (* cb ) (void))
    { 
        post_interrupt_callback = cb;
    }
    
    void framework::set_pre_process_callback( void (* cb ) (void))
    { 
        pre_process_callback = cb;
    }
    
    void framework::set_post_process_callback( void (* cb ) (void))
    { 
        post_process_callback = cb;
    }


    void framework::do_i2s_irq(void)
    {
            // if needed, call pre-interrupt call back
        if ( pre_interrupt_callback )
            pre_interrupt_callback();
            
            // irq is handled only when the buffer is correctly allocated    
        if (tx_left_buffer)
        {
            int sample;
            
                // check how many data have to be transmimted per interrupt. 
            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][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 ++;
            }
            
                // Implementation of the double buffer algorithm.
                // if buffer transfer is complete, swap the buffer
            if (sample_index > block_size * 2)
            {
                    // index for the signal processing
                process_index = buffer_index;

                    // swap buffer
                if ( buffer_index == 0 )
                    buffer_index = 1;
                else
                    buffer_index = 0;

                    // 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;
                
                // 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;
                rx_right_buffer[i] = rx_int_buffer[process_index][j++]/ -(float)INT_MIN;
            }
                
            process_callback
            (
                rx_left_buffer,
                rx_right_buffer,
                tx_left_buffer,
                tx_right_buffer,
                block_size
            );
                
                // 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] * -(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();
    }
    
    void framework::process_irq_handler()
    {
        framework::get()->do_process_irq();
    }
    
    void framework::i2s_irq_handler()
    {
        framework::get()->do_i2s_irq();
    }
     
     
     
     
     
    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 

        }
    }

}