Add ddr pdm mics
This commit is contained in:
@@ -4,12 +4,13 @@ TARGET = RPI_HAT_60QFN.xn
|
||||
|
||||
# The flags passed to xcc when building the application
|
||||
XCC_FLAGS = -fcomment-asm -Xmapper --map -Xmapper MAPFILE -Os -report \
|
||||
-g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[1]
|
||||
-g -Wno-unused-function -Wno-timing -DXUD_SERIES_SUPPORT=XUD_X200_SERIES -DUSB_TILE=tile[1] \
|
||||
-D MIC_ARRAY_CH0=PIN0 -D MIC_ARRAY_CH1=PIN4
|
||||
|
||||
# The USED_MODULES variable lists other module used by the application. These
|
||||
# modules will extend the SOURCE_DIRS, INCLUDE_DIRS and LIB_DIRS variables.
|
||||
# Modules are expected to be in the directory above the BASE_DIR directory.
|
||||
USED_MODULES = lib_xua lib_i2s lib_xud lib_i2c lib_gpio
|
||||
USED_MODULES = lib_xua lib_i2s lib_xud lib_i2c lib_mic_array_ddr
|
||||
|
||||
#=============================================================================
|
||||
# The following part of the Makefile includes the common build infrastructure
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "i2s.h"
|
||||
#include "i2c.h"
|
||||
#include "gpio.h"
|
||||
#include "mic_array.h"
|
||||
|
||||
#define DEBUG_UNIT XUA_APP
|
||||
#define DEBUG_PRINT_ENABLE_XUA_APP 1
|
||||
@@ -37,12 +38,19 @@ on tile[1]: in port p_mclk_in_usb = XS1_PORT_1A;
|
||||
on tile[1]: in port p_for_mclk_count= XS1_PORT_16A; // Extra port for counting master clock ticks
|
||||
on tile[1]: clock clk_usb_mclk = XS1_CLKBLK_3; // Master clock
|
||||
|
||||
|
||||
// Clock-block declarations
|
||||
on tile[0]:clock clk_audio_bclk = XS1_CLKBLK_2; // Bit clock
|
||||
on tile[0]:clock clk_audio_mclk = XS1_CLKBLK_3; // Master clock
|
||||
on tile[0]: clock clk_audio_bclk = XS1_CLKBLK_2; // Bit clock
|
||||
on tile[0]: clock clk_audio_mclk = XS1_CLKBLK_3; // Master clock
|
||||
//XUD uses XS1_CLKBLK_4, XS1_CLKBLK_5 on tile[1]
|
||||
|
||||
//Mic array resources
|
||||
on tile[0]: out port p_pdm_clk = XS1_PORT_1L;
|
||||
on tile[0]: in buffered port:32 p_pdm_mics = XS1_PORT_4E;
|
||||
|
||||
on tile[0]: clock pdmclk = XS1_CLKBLK_4;
|
||||
on tile[0]: clock pdmclk6 = XS1_CLKBLK_5;
|
||||
|
||||
|
||||
// Endpoint type tables - informs XUD what the transfer types for each Endpoint in use and also
|
||||
// if the endpoint wishes to be informed of USB bus resets
|
||||
|
||||
@@ -51,10 +59,12 @@ XUD_EpType epTypeTableIn[] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_
|
||||
|
||||
void XUA_Buffer_lite(chanend c_ep0_out, chanend c_ep0_in, chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, in port p_for_mclk_count, streaming chanend c_aud_host);
|
||||
[[distributable]]
|
||||
void AudioHub(server i2s_frame_callback_if i2s, streaming chanend c_aud, client i2c_master_if ?i2c, client output_gpio_if dac_reset);
|
||||
void AudioHub(server i2s_frame_callback_if i2s, streaming chanend c_audio, streaming chanend (&?c_ds_output)[1]);
|
||||
void setup_audio_gpio(out port p_gpio);
|
||||
void AudioHwConfigure(unsigned samFreq, client i2c_master_if i_i2c);
|
||||
void XUA_Endpoint0_select(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl,
|
||||
chanend ?c_mix_ctl, chanend ?c_clk_ctl, chanend ?c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, ?dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_);
|
||||
void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics);
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -67,17 +77,26 @@ int main()
|
||||
|
||||
interface i2s_frame_callback_if i_i2s;
|
||||
interface i2c_master_if i_i2c[1];
|
||||
interface output_gpio_if i_gpio[1];
|
||||
|
||||
streaming chan c_audio; //We use the channel buffering (48B across switch each way)
|
||||
streaming chan c_ds_output[1];
|
||||
|
||||
par
|
||||
{
|
||||
on tile[0]: {
|
||||
//Set the GPIOs needed for audio
|
||||
setup_audio_gpio(p_gpio);
|
||||
c_audio <: 0; //Signal that we can now do i2c setup
|
||||
c_audio :> int _; //Now wait until i2c has finished mclk setup
|
||||
|
||||
const unsigned micDiv = MCLK_48/3072000;
|
||||
mic_array_setup_ddr(pdmclk, pdmclk6, p_mclk_in, p_pdm_clk, p_pdm_mics, micDiv);
|
||||
|
||||
par {
|
||||
i2s_frame_master(i_i2s, p_i2s_dac, 1, p_i2s_adc, 1, p_bclk, p_lrclk, p_mclk_in, clk_audio_bclk);
|
||||
[[distribute]]AudioHub(i_i2s, c_audio, null, i_gpio[0]);
|
||||
[[distribute]]output_gpio(i_gpio, 1, p_gpio, null);
|
||||
[[distribute]]AudioHub(i_i2s, c_audio, c_ds_output);
|
||||
pdm_mic(c_ds_output[0], p_pdm_mics);
|
||||
|
||||
}
|
||||
}
|
||||
on tile[1]:{
|
||||
@@ -86,11 +105,13 @@ int main()
|
||||
set_port_clock(p_for_mclk_count, clk_usb_mclk); // Clock the "count" port from the clock block
|
||||
start_clock(clk_usb_mclk); // Set the clock off running
|
||||
|
||||
//Setup DAC and then return so we do not use a thread
|
||||
//Setup DAC over i2c and then return so we do not use a thread
|
||||
c_audio :> int _; //Wait for reset asserted from other tile to complete
|
||||
par{
|
||||
i2c_master(i_i2c, 1, p_scl, p_sda, 100);
|
||||
AudioHwConfigure(DEFAULT_FREQ, i_i2c[0]);
|
||||
}
|
||||
c_audio <: 0; //Signal to tile[0] that clock is good
|
||||
|
||||
debug_printf("XUD SPEED: %d\n", (AUDIO_CLASS == 1) ? XUD_SPEED_FS : XUD_SPEED_HS); //FS = 1, HS = 2
|
||||
par{
|
||||
|
||||
@@ -5,21 +5,47 @@
|
||||
#define DEBUG_UNIT XUA_AUDIO_HUB
|
||||
#define DEBUG_PRINT_ENABLE_XUA_AUDIO_HUB 1
|
||||
#include "debug_print.h"
|
||||
#include "mic_array.h"
|
||||
|
||||
|
||||
void mic_array_decimator_set_samprate(const unsigned samplerate, int fir_gain_compen[], int * unsafe fir_coefs[], int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[]);
|
||||
|
||||
|
||||
void setup_audio_gpio(out port p_gpio){
|
||||
// Reset DAC and disable MUTE
|
||||
p_gpio <: 0x0;
|
||||
delay_milliseconds(1);
|
||||
p_gpio <: 0x1;
|
||||
delay_milliseconds(1);
|
||||
}
|
||||
|
||||
|
||||
//Globally declared for 64b alignment
|
||||
int mic_decimator_fir_data_array[8][THIRD_STAGE_COEFS_PER_STAGE * PDM_MAX_DECIMATION] = {{0}};
|
||||
mic_array_frame_time_domain mic_audio_frame[2];
|
||||
|
||||
[[distributable]]
|
||||
void AudioHub(server i2s_frame_callback_if i2s,
|
||||
streaming chanend c_audio_hub,
|
||||
client i2c_master_if ?i_i2c,
|
||||
client output_gpio_if dac_reset)
|
||||
streaming chanend c_audio,
|
||||
streaming chanend (&?c_ds_output)[1])
|
||||
{
|
||||
int32_t samples_out[NUM_USB_CHAN_OUT] = {0};
|
||||
int32_t samples_in[NUM_USB_CHAN_IN] = {0};
|
||||
|
||||
// Reset DAC
|
||||
dac_reset.output(0);
|
||||
delay_milliseconds(1);
|
||||
dac_reset.output(1);
|
||||
#if XUA_NUM_PDM_MICS > 0
|
||||
unsigned buffer;
|
||||
int output[XUA_NUM_PDM_MICS] = {0};
|
||||
const unsigned decimatorCount = 1; // Supports up to 4 mics
|
||||
mic_array_decimator_conf_common_t dcc;
|
||||
int * unsafe fir_coefs[7];
|
||||
mic_array_decimator_config_t dc[1];
|
||||
int fir_gain_compen[7];
|
||||
mic_array_frame_time_domain * unsafe current;
|
||||
|
||||
mic_array_decimator_set_samprate(DEFAULT_FREQ, fir_gain_compen, fir_coefs, mic_decimator_fir_data_array[0], &dcc, dc);
|
||||
mic_array_decimator_configure(c_ds_output, decimatorCount, dc);
|
||||
mic_array_init_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc);
|
||||
#endif
|
||||
|
||||
|
||||
while (1) {
|
||||
@@ -42,10 +68,16 @@ void AudioHub(server i2s_frame_callback_if i2s,
|
||||
case i2s.restart_check() -> i2s_restart_t restart:
|
||||
restart = I2S_NO_RESTART; // Keep on looping
|
||||
timer tmr; int t0, t1; tmr :> t0;
|
||||
for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub :> samples_out[i];
|
||||
for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio_hub <: samples_in[i];
|
||||
// for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio :> samples_out[i];
|
||||
// for (int i = 0; i < NUM_USB_CHAN_IN; i++) c_audio <: samples_in[i];
|
||||
//tmr :> t1; debug_printf("%d\n", t1 - t0);
|
||||
//delay_microseconds(10); //Test backpressure tolerance
|
||||
//delay_microseconds(15); //Test backpressure tolerance
|
||||
|
||||
current = mic_array_get_next_time_domain_frame(c_ds_output, decimatorCount, buffer, mic_audio_frame, dc);
|
||||
unsafe {
|
||||
samples_out[0] = current->data[0][0];
|
||||
samples_out[1] = current->data[1][0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
75
examples/xua_lite_example/src/pdm_mic.xc
Normal file
75
examples/xua_lite_example/src/pdm_mic.xc
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "xua.h"
|
||||
#if (XUA_NUM_PDM_MICS > 0)
|
||||
|
||||
#include <platform.h>
|
||||
#include <xs1.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <xclib.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mic_array.h"
|
||||
|
||||
|
||||
void mic_array_decimator_set_samprate(const unsigned samplerate, int fir_gain_compen[], int * unsafe fir_coefs[], int mic_decimator_fir_data_array[], mic_array_decimator_conf_common_t *dcc, mic_array_decimator_config_t dc[])
|
||||
{
|
||||
unsigned decimationfactor = 96000/samplerate;
|
||||
unsafe
|
||||
{
|
||||
fir_gain_compen[0] = 0;
|
||||
fir_gain_compen[1] = FIR_COMPENSATOR_DIV_2; //48kHz
|
||||
fir_gain_compen[2] = FIR_COMPENSATOR_DIV_4;
|
||||
fir_gain_compen[3] = FIR_COMPENSATOR_DIV_6; //16kHz
|
||||
fir_gain_compen[4] = FIR_COMPENSATOR_DIV_8;
|
||||
fir_gain_compen[5] = 0;
|
||||
fir_gain_compen[6] = FIR_COMPENSATOR_DIV_12;
|
||||
|
||||
fir_coefs[0] = 0;
|
||||
fir_coefs[1] = (int * unsafe)g_third_stage_div_2_fir;
|
||||
fir_coefs[2] = (int * unsafe)g_third_stage_div_4_fir;
|
||||
fir_coefs[3] = (int * unsafe)g_third_stage_div_6_fir;
|
||||
fir_coefs[4] = (int * unsafe)g_third_stage_div_8_fir;
|
||||
fir_coefs[5] = 0;
|
||||
fir_coefs[6] = (int * unsafe)g_third_stage_div_12_fir;
|
||||
|
||||
//dcc = {MIC_ARRAY_MAX_FRAME_SIZE_LOG2, 1, 0, 0, decimationfactor, fir_coefs[decimationfactor/2], 0, 0, DECIMATOR_NO_FRAME_OVERLAP, 2};
|
||||
dcc->frame_size_log2 = MIC_ARRAY_MAX_FRAME_SIZE_LOG2;
|
||||
dcc->apply_dc_offset_removal = 1;
|
||||
dcc->index_bit_reversal = 0;
|
||||
dcc->windowing_function = null;
|
||||
dcc->output_decimation_factor = decimationfactor;
|
||||
dcc->coefs = fir_coefs[decimationfactor/2];
|
||||
dcc->apply_mic_gain_compensation = 0;
|
||||
dcc->fir_gain_compensation = fir_gain_compen[decimationfactor/2];
|
||||
dcc->buffering_type = DECIMATOR_NO_FRAME_OVERLAP;
|
||||
dcc->number_of_frame_buffers = 2;
|
||||
|
||||
//dc[0] = {&dcc, mic_decimator_fir_data[0], {0, 0, 0, 0}, 4};
|
||||
dc[0].dcc = dcc;
|
||||
dc[0].data = mic_decimator_fir_data_array;
|
||||
dc[0].mic_gain_compensation[0]=0;
|
||||
dc[0].mic_gain_compensation[1]=0;
|
||||
dc[0].mic_gain_compensation[2]=0;
|
||||
dc[0].mic_gain_compensation[3]=0;
|
||||
dc[0].channel_count = 4;
|
||||
}
|
||||
}
|
||||
|
||||
#if MAX_FREQ > 48000
|
||||
#error MAX_FREQ > 48000 NOT CURRENTLY SUPPORTED
|
||||
#endif
|
||||
|
||||
void pdm_mic(streaming chanend c_ds_output, in buffered port:32 p_pdm_mics)
|
||||
{
|
||||
streaming chan c_4x_pdm_mic_0;
|
||||
assert((MCLK_48 / 3072000) == (MCLK_441 / 2822400));
|
||||
par
|
||||
{
|
||||
mic_array_pdm_rx(p_pdm_mics, c_4x_pdm_mic_0, null);
|
||||
mic_array_decimate_to_pcm_4ch(c_4x_pdm_mic_0, c_ds_output, MIC_ARRAY_NO_INTERNAL_CHANS);
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -20,15 +20,21 @@
|
||||
#define PRODUCT_STR_A1 "XUA Lite Class 1"
|
||||
#define PID_AUDIO_1 1
|
||||
#define PID_AUDIO_2 2
|
||||
#define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example) */
|
||||
#define XUA_DFU_EN 0 /* Disable DFU (for simplicity of example) */
|
||||
|
||||
#define INPUT_FORMAT_COUNT 1
|
||||
#define STREAM_FORMAT_INPUT_1_RESOLUTION_BITS 16
|
||||
#define OUTPUT_FORMAT_COUNT 1
|
||||
#define STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS 16
|
||||
|
||||
#define OUTPUT_VOLUME_CONTROL 0
|
||||
#define INPUT_VOLUME_CONTROL 0
|
||||
|
||||
#define UAC_FORCE_FEEDBACK_EP 1
|
||||
#define XUA_LITE 1 // Use simple/optimised USB buffer tasks
|
||||
#define XUA_LITE 1 // Use simple/optimised USB buffer tasks
|
||||
#define AUDIO_CLASS 1
|
||||
|
||||
#define XUA_NUM_PDM_MICS 4 // It's actually 2 but we run 4ch and ignore 2
|
||||
#define PDM_MAX_DECIMATION (96000/(MIN_FREQ))
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user