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
unzen.cpp
- Committer:
- shorie
- Date:
- 2016-05-03
- Revision:
- 3:707608830793
- Parent:
- 2:6613e62da521
- Child:
- 4:d89a1e2b4b03
File content as of revision 3:707608830793:
#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 ;
tx_int_buffer[process_index][j++] = i << 26;
tx_int_buffer[process_index][j++] = i << 26 ;
}
}
// 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_48 )
{
data[ADDL] = 0x17; data[DATA] = 0x00;
i2c->write( addr, data, 3 ); // R17:Converter control, CONVSR = 0
}
if ( fs == Fs_96 )
{
data[ADDL] = 0x17; data[DATA] = 0x06;
i2c->write( addr, data, 3 ); // R17:Converter control, CONVSR = 6
}
if ( fs == Fs_32 )
{
data[ADDL] = 0x17; data[DATA] = 0x05;
i2c->write( addr, data, 3 ); // R17:Converter control, CONVSR = 5
}
// 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] = 0x9; i2c->write( addr, data, 3 ); // R27:MIXER 6
// set input gain
set_line_input_gain( 0, 0 ); // unmute
set_line_output_gain( 0, 0, true ); // unmute
set_hp_output_gain( 0, 0, true ); // unmute
}
#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 = (left_gain+15)/3 ; // See table 31 LINNG
level = max( level, 0 );
level = min( level, 7 );
data[DATA] = SET_INPUT_GAIN( level );
data[ADDL] = 0x0a; i2c->write( addr, data, 3 ); // R4: mixer 1 enable
// set right gain
level = (right_gain+15)/3 ; // See table 31 LINNG
level = max( level, 0 );
level = min( level, 7 );
data[DATA] = SET_INPUT_GAIN( level );
data[ADDL] = 0x0c; i2c->write( addr, data, 3 ); // R4: mixer 1 enable
}
}
#define SET_LO_GAIN( x ) ((x<<2)|2)
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, 3 ); // R31: LOUTVOL
data[ADDL] = 0x26; data[DATA] = 0x01; i2c->write( addr, data, 3 ); // 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_LO_GAIN(left ); i2c->write( addr, data, 3 ); // R31: LOUTVOL
data[ADDL] = 0x26; data[DATA] = SET_LO_GAIN(right); i2c->write( addr, data, 3 ); // R32: LOUTVOL
}
}
#define SET_HP_GAIN( x ) ((x<<2)|3)
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, 3 ); // R29: LHPVOL
data[ADDL] = 0x24; data[DATA] = 0x01; i2c->write( addr, data, 3 ); // 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, 3 ); // R29: LHPVOL
data[ADDL] = 0x24; data[DATA] = SET_HP_GAIN(right); i2c->write( addr, data, 3 ); // R30: LHPVOL & HP MODE
}
}
}