| struct fir_filter { | struct fir_filter { | ||||
| short *coeffs; | short *coeffs; | ||||
| short num_coeffs; | |||||
| short num_coeffs; // num_coeffs must be an even number, 4 or higher | |||||
| }; | }; | ||||
| // index of current filter. Start with the low pass. | // index of current filter. Start with the low pass. |
| coeff_p = cp; | coeff_p = cp; | ||||
| // Initialize FIR instance (ARM DSP Math Library) | // Initialize FIR instance (ARM DSP Math Library) | ||||
| if (coeff_p && (coeff_p != FIR_PASSTHRU) && n_coeffs <= FIR_MAX_COEFFS) { | if (coeff_p && (coeff_p != FIR_PASSTHRU) && n_coeffs <= FIR_MAX_COEFFS) { | ||||
| arm_fir_init_q15(&fir_inst, n_coeffs, (q15_t *)coeff_p, | |||||
| &StateQ15[0], AUDIO_BLOCK_SAMPLES); | |||||
| if (arm_fir_init_q15(&fir_inst, n_coeffs, (q15_t *)coeff_p, | |||||
| &StateQ15[0], AUDIO_BLOCK_SAMPLES) != ARM_MATH_SUCCESS) { | |||||
| // n_coeffs must be an even number, 4 or larger | |||||
| coeff_p = NULL; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| void end(void) { | void end(void) { |
| <p>Receive 16 bit quad (4) channel audio from two | <p>Receive 16 bit quad (4) channel audio from two | ||||
| <a href="http://www.pjrc.com/store/teensy3_audio.html" target="_blank">audio shields</a> | <a href="http://www.pjrc.com/store/teensy3_audio.html" target="_blank">audio shields</a> | ||||
| or another I2S devices, using I2S master mode.</p> | or another I2S devices, using I2S master mode.</p> | ||||
| <p align=center><img src="img/audioshield_quad_in.jpg"></p> | |||||
| </div> | </div> | ||||
| <h3>Audio Connections</h3> | <h3>Audio Connections</h3> | ||||
| <table class=doc align=center cellpadding=3> | <table class=doc align=center cellpadding=3> | ||||
| <h3>Summary</h3> | <h3>Summary</h3> | ||||
| <div class=tooltipinfo> | <div class=tooltipinfo> | ||||
| <p>Transmit quad (4) channel 16 bit audio, using I2S master mode.</p> | <p>Transmit quad (4) channel 16 bit audio, using I2S master mode.</p> | ||||
| <p align=center><img src="img/audioshield_quad_out.jpg"></p> | |||||
| </div> | </div> | ||||
| <h3>Audio Connections</h3> | <h3>Audio Connections</h3> | ||||
| <table class=doc align=center cellpadding=3> | <table class=doc align=center cellpadding=3> | ||||
| <h3>Functions</h3> | <h3>Functions</h3> | ||||
| <p class=func><span class=keyword>delay</span>(channel, milliseconds);</p> | <p class=func><span class=keyword>delay</span>(channel, milliseconds);</p> | ||||
| <p class=desc>Set output channel (0 to 7) to delay the signals by | <p class=desc>Set output channel (0 to 7) to delay the signals by | ||||
| milliseconds. The maximum delay is approx 333 ms. The actual delay | |||||
| milliseconds. The maximum delay is approx 425 ms. The actual delay | |||||
| is rounded to the nearest sample. Each channel can be configured for | is rounded to the nearest sample. Each channel can be configured for | ||||
| any delay. There is no requirement to configure the "taps" in increasing | any delay. There is no requirement to configure the "taps" in increasing | ||||
| delay order. | delay order. | ||||
| <h3>Functions</h3> | <h3>Functions</h3> | ||||
| <p class=func><span class=keyword>delay</span>(channel, milliseconds);</p> | <p class=func><span class=keyword>delay</span>(channel, milliseconds);</p> | ||||
| <p class=desc>Set output channel (0 to 7) to delay the signals by | <p class=desc>Set output channel (0 to 7) to delay the signals by | ||||
| milliseconds. The maximum delay is approx 333 ms. The actual delay | |||||
| milliseconds. The maximum delay is approx 1.5 seconds for each 23LC1024 chip. | |||||
| The actual delay | |||||
| is rounded to the nearest sample. Each channel can be configured for | is rounded to the nearest sample. Each channel can be configured for | ||||
| any delay. There is no requirement to configure the "taps" in increasing | any delay. There is no requirement to configure the "taps" in increasing | ||||
| delay order. | delay order. | ||||
| <h3>Examples</h3> | <h3>Examples</h3> | ||||
| <p class=exam>File > Examples > Audio > Effects > Filter_FIR | <p class=exam>File > Examples > Audio > Effects > Filter_FIR | ||||
| </p> | </p> | ||||
| <h3>Known Issues</h3> | |||||
| <p>Your filter's impulse response array must have an even length. If you have | |||||
| add odd number of taps, you must add an extra zero to increase the length | |||||
| to an even number. | |||||
| </p> | |||||
| <p>The minimum number of taps is 4. If you use less, add extra zeros to increase | |||||
| the length to 4. | |||||
| </p> | |||||
| <p>The impulse response must be given in reverse order. Many filters have | |||||
| symetrical impluse response, making this a non-issue. If your filter has | |||||
| a non-symetrical response, make sure the data is in reverse time order. | |||||
| </p> | |||||
| <h3>Notes</h3> | <h3>Notes</h3> | ||||
| <p>FIR filters requires more CPU time than Biquad (IIR), but they can | <p>FIR filters requires more CPU time than Biquad (IIR), but they can | ||||
| implement filters with better phase response. | implement filters with better phase response. | ||||
| supported filter length is 200 points. | supported filter length is 200 points. | ||||
| </p> | </p> | ||||
| <p>The free | <p>The free | ||||
| <a href="http://t-filter.appspot.com/fir/index.html" target="_blank"> TFilter Design Tool</a> | |||||
| <a href="http://t-filter.engineerjs.com/" target="_blank"> TFilter Design Tool</a> | |||||
| can be used to create the impulse response array. Be sure to set the sampling | can be used to create the impulse response array. Be sure to set the sampling | ||||
| frequency to 44117 HZ (it defaults to only 2000 Hz) and the output type to "int" (16 bit). | frequency to 44117 HZ (it defaults to only 2000 Hz) and the output type to "int" (16 bit). | ||||
| </p> | </p> |
| bool AudioInputI2SQuad::update_responsibility = false; | bool AudioInputI2SQuad::update_responsibility = false; | ||||
| DMAChannel AudioInputI2SQuad::dma(false); | DMAChannel AudioInputI2SQuad::dma(false); | ||||
| #if defined(__MK20DX256__) | |||||
| #if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
| void AudioInputI2SQuad::begin(void) | void AudioInputI2SQuad::begin(void) | ||||
| { | { |
| { | { | ||||
| "name": "Audio", | |||||
| "frameworks": "Arduino", | |||||
| "platforms": "Teensy", | |||||
| "keywords": "sound, audio, FFT, filter, effect", | |||||
| "description": "Teensy Audio Library", | |||||
| "url": "http://www.pjrc.com/teensy/td_libs_Audio.html", | |||||
| "downloadUrl": "https://github.com/PaulStoffregen/Audio/archive/master.zip", | |||||
| "version": "1.03", | |||||
| "exclude": "extras", | |||||
| "authors": | |||||
| { | |||||
| "name": "Paul Stoffregen", | |||||
| "maintainer": true | |||||
| }, | |||||
| "repository": | |||||
| { | |||||
| "type": "git", | |||||
| "url": "https://github.com/PaulStoffregen/Audio" | |||||
| }, | |||||
| "dependencies": | |||||
| { | |||||
| "name": "SerialFlash", | |||||
| "frameworks": "arduino" | |||||
| }, | |||||
| "name": "Audio", | |||||
| "frameworks": "Arduino", | |||||
| "platforms": "Teensy", | |||||
| "keywords": "sound, audio, FFT, filter, effect", | |||||
| "description": "Teensy Audio Library", | |||||
| "url": "http://www.pjrc.com/teensy/td_libs_Audio.html", | |||||
| "version": "1.03", | |||||
| "exclude": "extras", | |||||
| "authors": | |||||
| { | |||||
| "name": "Paul Stoffregen", | |||||
| "maintainer": true | |||||
| }, | |||||
| "repository": | |||||
| { | |||||
| "type": "git", | |||||
| "url": "https://github.com/PaulStoffregen/Audio" | |||||
| }, | |||||
| "dependencies": | |||||
| { | |||||
| "name": "SerialFlash", | |||||
| "frameworks": "arduino" | |||||
| }, | |||||
| "examples": [ | "examples": [ | ||||
| "examples/*/*.ino", | "examples/*/*.ino", | ||||
| "examples/*/*/*.ino" | "examples/*/*/*.ino" |
| * SOFTWARE. | * SOFTWARE. | ||||
| */ | */ | ||||
| #if defined(__MK20DX128__) || defined(__MK20DX256__) | |||||
| #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
| .cpu cortex-m4 | .cpu cortex-m4 | ||||
| .syntax unified | .syntax unified |
| #include "output_dac.h" | #include "output_dac.h" | ||||
| #include "utility/pdb.h" | #include "utility/pdb.h" | ||||
| #if defined(__MK20DX256__) | |||||
| #if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
| DMAMEM static uint16_t dac_buffer[AUDIO_BLOCK_SAMPLES*2]; | DMAMEM static uint16_t dac_buffer[AUDIO_BLOCK_SAMPLES*2]; | ||||
| audio_block_t * AudioOutputAnalog::block_left_1st = NULL; | audio_block_t * AudioOutputAnalog::block_left_1st = NULL; |
| #elif F_CPU == 168000000 | #elif F_CPU == 168000000 | ||||
| #define MCLK_MULT 8 | #define MCLK_MULT 8 | ||||
| #define MCLK_DIV 119 | #define MCLK_DIV 119 | ||||
| #elif F_CPU == 180000000 | |||||
| #define MCLK_MULT 16 | |||||
| #define MCLK_DIV 255 | |||||
| #elif F_CPU == 192000000 | |||||
| #define MCLK_MULT 1 | |||||
| #define MCLK_DIV 17 | |||||
| #elif F_CPU == 16000000 | #elif F_CPU == 16000000 | ||||
| #define MCLK_MULT 12 | #define MCLK_MULT 12 | ||||
| #define MCLK_DIV 17 | #define MCLK_DIV 17 | ||||
| // enable MCLK output | // enable MCLK output | ||||
| I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE; | I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE; | ||||
| while (I2S0_MCR & I2S_MCR_DUF) ; | |||||
| I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1)); | I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1)); | ||||
| // configure transmitter | // configure transmitter |
| #include "output_i2s_quad.h" | #include "output_i2s_quad.h" | ||||
| #include "memcpy_audio.h" | #include "memcpy_audio.h" | ||||
| #if defined(__MK20DX256__) | |||||
| #if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
| audio_block_t * AudioOutputI2SQuad::block_ch1_1st = NULL; | audio_block_t * AudioOutputI2SQuad::block_ch1_1st = NULL; | ||||
| audio_block_t * AudioOutputI2SQuad::block_ch2_1st = NULL; | audio_block_t * AudioOutputI2SQuad::block_ch2_1st = NULL; | ||||
| #elif F_CPU == 168000000 | #elif F_CPU == 168000000 | ||||
| #define MCLK_MULT 8 | #define MCLK_MULT 8 | ||||
| #define MCLK_DIV 119 | #define MCLK_DIV 119 | ||||
| #elif F_CPU == 180000000 | |||||
| #define MCLK_MULT 16 | |||||
| #define MCLK_DIV 255 | |||||
| #elif F_CPU == 192000000 | |||||
| #define MCLK_MULT 1 | |||||
| #define MCLK_DIV 17 | |||||
| #elif F_CPU == 16000000 | #elif F_CPU == 16000000 | ||||
| #define MCLK_MULT 12 | #define MCLK_MULT 12 | ||||
| #define MCLK_DIV 17 | #define MCLK_DIV 17 | ||||
| // enable MCLK output | // enable MCLK output | ||||
| I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE; | I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE; | ||||
| while (I2S0_MCR & I2S_MCR_DUF) ; | |||||
| I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1)); | I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1)); | ||||
| // configure transmitter | // configure transmitter |
| #elif F_CPU == 168000000 | #elif F_CPU == 168000000 | ||||
| #define MCLK_MULT 8 | #define MCLK_MULT 8 | ||||
| #define MCLK_DIV 119 | #define MCLK_DIV 119 | ||||
| #elif F_CPU == 180000000 | |||||
| #define MCLK_MULT 16 | |||||
| #define MCLK_DIV 255 | |||||
| #elif F_CPU == 192000000 | |||||
| #define MCLK_MULT 1 | |||||
| #define MCLK_DIV 17 | |||||
| #elif F_CPU == 16000000 | #elif F_CPU == 16000000 | ||||
| #define MCLK_MULT 12 | #define MCLK_MULT 12 | ||||
| #define MCLK_DIV 17 | #define MCLK_DIV 17 | ||||
| // enable MCLK output | // enable MCLK output | ||||
| I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE; | I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE; | ||||
| while (I2S0_MCR & I2S_MCR_DUF) ; | |||||
| I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1)); | I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1)); | ||||
| // configure transmitter | // configure transmitter |
| return out; | return out; | ||||
| } | } | ||||
| //get Q from PSR | |||||
| static inline uint32_t get_q_psr(void) __attribute__((always_inline, unused)); | |||||
| static inline uint32_t get_q_psr(void) | |||||
| { | |||||
| uint32_t out; | |||||
| asm volatile("mrs %0, APSR" : "=r" (out)); | |||||
| return (out & 0x8000000)>>27; | |||||
| } | |||||
| //clear Q BIT in PSR | |||||
| static inline void clr_q_psr(void) __attribute__((always_inline, unused)); | |||||
| static inline void clr_q_psr(void) | |||||
| { | |||||
| uint32_t t; | |||||
| asm volatile("mrs %0,APSR " : "=r" (t)); | |||||
| asm volatile("bfc %0, #27, #1" : "=r" (t)); | |||||
| asm volatile("msr APSR_nzcvq,%0" : "=r" (t)); | |||||
| } | |||||
| #endif | #endif |