First Publish. Works fine.
Dependents: unzen_sample_nucleo_f746 unzen_delay_sample_nucleo_f746 skeleton_unzen_nucleo_f746 ifmag_noise_canceller ... more
Nucleo F746ZG用のオーディオ・フレームワークです。フレームワーク地震の詳細は『雲仙』オーディオ・フレームワークを参照してください。
参考リンク
- skeleton_unzen_nucleo_f746 Nucleo F746ZGおよびUI基板を使う場合のスケルトンプログラム。F746を使う方はここから読み始めると良いでしょう。
unzen.cpp
- Committer:
- shorie
- Date:
- 2016-05-04
- Revision:
- 4:d89a1e2b4b03
- Parent:
- 3:707608830793
- Child:
- 5:1cbfb7a9cd0c
File content as of revision 4:d89a1e2b4b03:
#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] = rx_int_buffer[process_index][i]; j++; // tx_int_buffer[process_index][j] = rx_int_buffer[process_index][j]; j++; tx_int_buffer[process_index][j++] = i << 27; tx_int_buffer[process_index][j++] = i << 27 ; } } // 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 // 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 || fs == Fs_32 ) { 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 ); } // Additional clock setting for 96kHz if ( fs == Fs_48 || fs == Fs_441) { data[ADDL] = 0x17; data[DATA] = 0x00; i2c->write( addr, data, 3 ); // R17:Converter control, CONVSR = 0 } else if ( fs == Fs_96 ) { data[ADDL] = 0x17; data[DATA] = 0x06; i2c->write( addr, data, 3 ); // R17:Converter control, CONVSR = 6 } else if ( fs == Fs_32 ) { data[ADDL] = 0x17; data[DATA] = 0x05; i2c->write( addr, data, 3 ); // R17:Converter control, CONVSR = 5 } // Initialize all register as reset. for ( int i=0x08; i<0x17; i++ ) data[ADDL] = i; data[DATA] = 0x00; i2c->write( addr, data, 3 ); // R2:Dig Mic ... R18:Converter 1 for ( int i=0x18; 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] = 0x20; i2c->write( addr, data, 3 ); // R19:ADC Control. HPF on for ( int i=0x1A; i<0x23; 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<0x28; 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<0x2d; 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 **** // 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 // both channel ADC ON, HPF on data[ADDL] = 0x19; data[DATA] = 0x23; i2c->write( addr, data, 3 ); // R19:ADC Control // Playback Power Management data[ADDL] = 0x29; data[DATA] = 0x3; i2c->write( addr, data, 3 ); // R35:Left/Right Playback Enable // 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] = 0x09; 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 ); // mute set_hp_output_gain( 0, 0, true ); // mute } #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]; int left, right; data[0] = 0x40; // Upper address of register 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 { // set left gain left = (left_gain+15)/3 ; // See table 31 LINNG left = max( left, 0 ); left = min( left, 7 ); data[DATA] = SET_INPUT_GAIN( left ); data[ADDL] = 0x0a; i2c->write( addr, data, 3 ); // R4: mixer 1 enable // set right gain right = (right_gain+15)/3 ; // See table 31 LINNG right = max( right, 0 ); right = min( right, 7 ); data[DATA] = SET_INPUT_GAIN( right ); 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 } } }