First Publish. Works fine.
Dependents: unzen_sample_lpcxpresso_4337_callbacks
Diff: unzen.cpp
- 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