Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: unzen_sample_LPC4088_quickstart
Diff: unzen.cpp
- Revision:
- 2:6613e62da521
- Parent:
- 1:9710fb328a08
- Child:
- 3:707608830793
diff -r 9710fb328a08 -r 6613e62da521 unzen.cpp
--- 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