Hi,
I am trying to implement a Echo Cancellation Algorithm on my DSP. I am using bios_6_76_03_01 on AM5728's DSP. I am using rin.pcm and sin.pcm vectors provided by the test project. The code is based on the project provided by Stan Sidorov on this post: https://e2e.ti.com/support/processors/f/791/t/391242#pi320966=2
I am also pasting my ecu_test.c code below which includes all the code related to ECU below. I have tried playing with the config_bitfield but the result is either an unchanged sout, or a completely silent sout.
- How can I properly use the ECU for C66 DSP? Is there a better alternative for Echo Cancellation applications?
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ti/mas/util/ecomem.h> #include <ti/mas/ecu/ecu.h> #include <ti/mas/util/mua.h> #include <ti/mas/vpe/pcm.h> #include <ti/mas/mhm/mhm.h> #include <xdc/runtime/Log.h> #include <xdc/runtime/Diags.h> #include "app.h" #define SIU_VOICE_HEAP_SIZE 2048 tword siu_voice_heap[SIU_VOICE_HEAP_SIZE]; void *vheap; #define siuMakeID(mid,chnum) ((tuint)(mid)<<8|(tuint)(chnum)) #define SIU_MID_ECU 0x05 // ECU module //.............................................................................. //.............................................................................. //.............................................................................. #define FRAME_SIZE 80 // N of samples in the frame #define SIU_MAX_FRAME_LENGTH FRAME_SIZE // 10ms maximum frame duration */ #define SIU_MAX_ECU_FILTER_LENGTH 256 // 1024 - 128 ms tail search filter #define SIU_MAX_ECU_FLTSEG 3 // Maximum of 3 individual filter segments #define SIU_MAX_ECU_FLTSEG_LENGTH 256 // 32 mS filter length #define SIU_MAX_SYSTEM_DELAY 40 // maximum extra system delay in samples #define IRAM_ECU_MAX_FLTSEG_LENGTH SIU_MAX_ECU_FLTSEG_LENGTH #define IRAM_ECU_BLOCK_LENGTH SIU_MAX_SYSTEM_DELAY #define IRAM_ECU_SRCH_FILTER_LENGTH SIU_MAX_ECU_FILTER_LENGTH #define ecu_SIM_DLINE_SAMPLES_PER_WORD 2 // Delay line compression related /* NOTE: The following limits the maximum frame size to 2 ECU blocks, (i.e., 10ms or 11ms)*/ #define ecu_DELAY_LINE_LENGTH (IRAM_ECU_SRCH_FILTER_LENGTH + 2*IRAM_ECU_BLOCK_LENGTH + SIU_MAX_SYSTEM_DELAY + SIU_MAX_FRAME_LENGTH) #define IRAM_ECU_EXPAND_LENGTH (ecu_DELAY_LINE_LENGTH - IRAM_ECU_BLOCK_LENGTH) #define IRAM_PIU_ECU_RECEIVE_LENGTH (ecu_DELAY_LINE_LENGTH/ecu_SIM_DLINE_SAMPLES_PER_WORD) #define IRAM_ECU_BG_WORK_LENGTH IRAM_ECU_SRCH_FILTER_LENGTH /* changed from 8*/ /* 1024 for search filter length */ #define IRAM_ECU_BG_E_LENGTH IRAM_ECU_BLOCK_LENGTH /* linSample */ #define IRAM_ECU_BG_FLTSEG_LENGTH IRAM_ECU_MAX_FLTSEG_LENGTH /* Fract */ #define IRAM_ECU_FG_FLTSEG_LENGTH IRAM_ECU_MAX_FLTSEG_LENGTH /* Fract */ /* Buffer numbers. Ensure that these coincide with #defines in ecuinit.c */ #define ecu_FG_FLTSEG 1 #define ecu_BG_FLTSEG 2 #define ecu_BG_E_BUF 3 #define ecu_RECEIVE_IN 4 #define ecu_EXPAND_DL_BUF 5 #define ecu_BG_UPDATE_BUF 6 #define ecu_SEARCH_FILTER_BUF 14 //.............................................................................. //.............................................................................. //.............................................................................. //.............................................................................. typedef struct ecu_inst_params_t { void *ecu_Inst; /* Signal limiter Instance */ ecomemBuffer_t *ecu_buffers; ecuConfig_t ecuCfg; ecuControl_t ecuCtl; ecuNewConfig_t ecuCfgNew; } ecu_inst_params_t; struct ecu_inst_params_t ecu_instance; void DebugInfo (tuint _id, tuint _type, tuint _code, tuint _length, tuint *_data) { //printf("EXC-id:%x, Type: %d, Code: %d len:%d", _id, _type, _code,_length); Log_print4(Diags_ENTRY | Diags_INFO, "EXC-id:%x, Type: %d, Code: %d len:%d", _id, _type, _code,_length); } ecuContext_t ecuContext = { (vfnptr) DebugInfo, /* Void function pointer to SIU exception handler */ NULL, /* Debug streaming function pointer */ NULL, NULL, /* Search filter swapping function */ NULL, /* Send out function pointer */ NULL, /* Receive out function pointer */ SIU_MAX_FRAME_LENGTH, /* Maximum number of samples per frame */ SIU_MAX_ECU_FILTER_LENGTH, /* Maximum filter length in taps */ SIU_MAX_ECU_FLTSEG_LENGTH, /* Maximum filter segment buffer length in taps */ SIU_MAX_ECU_FLTSEG, /* Maximum allowed active filter segments */ SIU_MAX_SYSTEM_DELAY + SIU_MAX_FRAME_LENGTH, /* Maximum y2x delay in samples */ 0L, /* Bitfield representing those portions of the delay line already expanded. */ NULL, /* Pointer to base of the scratch delay line */ NULL, /* TDM aligned pointer within scratch delay line */ NULL, /* TDM aligned pointer within packed delay line */ }; linSample ecu_pcm_expand[IRAM_ECU_EXPAND_LENGTH];//[2048]; tword piu_ecu_receive[IRAM_PIU_ECU_RECEIVE_LENGTH]; Fract ecu_srch_filter[IRAM_ECU_SRCH_FILTER_LENGTH]; Fract ecu_bg_work[IRAM_ECU_BG_WORK_LENGTH]; linSample ecu_bg_e[IRAM_ECU_BG_E_LENGTH]; Fract ecu_bg_filter[IRAM_ECU_BG_FLTSEG_LENGTH]; Fract ecu_fg_filter[IRAM_ECU_FG_FLTSEG_LENGTH]; typedef struct { linSample *ecu_pcm_expand_ptr; tword *piu_ecu_receive_ptr; Fract *ecu_srch_filter_ptr; Fract *ecu_bg_work_ptr; linSample *ecu_bg_e_ptr; Fract *ecu_bg_filter_ptr; Fract *ecu_fg_filter_ptr; } iramSeg_t; iramSeg_t iramSeg; iramSeg_t iramSeg = { &ecu_pcm_expand[0], &piu_ecu_receive[0], &ecu_srch_filter[0], &ecu_bg_work[0], &ecu_bg_e[0], &ecu_bg_filter[0], &ecu_fg_filter[0] }; //.............................................................................. //.............................................................................. //.............................................................................. //****************************************************************************** // FRAMEWORK BUFFERS //****************************************************************************** linSample sin[FRAME_SIZE]; linSample rin[FRAME_SIZE]; linSample sout[FRAME_SIZE]; linSample rout[FRAME_SIZE]; tword scompr[FRAME_SIZE]; tword rcompr[FRAME_SIZE]; tint rinCompr[FRAME_SIZE]; tint sinCompr[FRAME_SIZE]; //.............................................................................. //.............................................................................. //.............................................................................. //****************************************************************************** // ECU FUNCTIONS //****************************************************************************** void ecu_set_buffer(const ecomemBuffer_t *bufs, ecomemBuffer_t *ecuBufs, tint ecuNbufs) { int i; for (i = 0; i < ecuNbufs; i++) { ecuBufs[i] = bufs[i]; if (i == ecu_FG_FLTSEG) { /* FG Filter */ ecuBufs[i].base = iramSeg.ecu_fg_filter_ptr; ecuBufs[i].size = IRAM_ECU_FG_FLTSEG_LENGTH*sizeof(Fract); } else if (i == ecu_BG_FLTSEG) { /* BG Filter */ ecuBufs[i].base = iramSeg.ecu_bg_filter_ptr; ecuBufs[i].size = IRAM_ECU_BG_FLTSEG_LENGTH*sizeof(Fract); } else if (i == ecu_BG_E_BUF) { /* BG Error Buffer IRAM */ ecuBufs[i].base = iramSeg.ecu_bg_e_ptr; ecuBufs[i].size = IRAM_ECU_BG_E_LENGTH*sizeof(linSample); } else if (i == ecu_RECEIVE_IN) { /* ECU's recv-in buffer is aligned! */ ecuBufs[i].volat = FALSE; ecuBufs[i].base = iramSeg.piu_ecu_receive_ptr; ecuBufs[i].size = IRAM_PIU_ECU_RECEIVE_LENGTH*sizeof(linSample); } else if (i == ecu_EXPAND_DL_BUF) { /* ECU's recv-in buffer is aligned! */ ecuBufs[i].volat = TRUE; ecuBufs[i].base = iramSeg.ecu_pcm_expand_ptr; ecuBufs[i].size = IRAM_ECU_EXPAND_LENGTH*sizeof(linSample); } else if (i == ecu_BG_UPDATE_BUF) { /* BG Work Buffer IRAM */ if (ecuBufs[i].size > 0) { ecuBufs[i].base = iramSeg.ecu_bg_work_ptr; ecuBufs[i].size = IRAM_ECU_BG_WORK_LENGTH*sizeof(Fract); } else { /* Float version may not use this buffer */ ecuBufs[i].base = NULL; ecuBufs[i].size = 0; } } else if (i == ecu_SEARCH_FILTER_BUF) { /* Search filter buffer IRAM */ ecuBufs[i].volat = FALSE; ecuBufs[i].base = iramSeg.ecu_srch_filter_ptr; ecuBufs[i].size = IRAM_ECU_SRCH_FILTER_LENGTH*sizeof(Fract); } else { if (ecuBufs[i].size > 0) { ecuBufs[i].volat = FALSE; ecuBufs[i].base = malloc(bufs[i].size); } else { /* no buffer allocated if size zero or less */ ecuBufs[i].base = NULL; ecuBufs[i].size = 0; } } } } //.............................................................................. //.............................................................................. //.............................................................................. void ecu_new() { tint stat, ecuNbufs; const ecomemBuffer_t *bufs; ecu_instance.ecu_Inst = NULL; stat = ecuGetSizes(&ecuNbufs, &bufs, (void *) NULL); if (stat != ecu_NOERR) { Log_print0(Diags_ENTRY | Diags_INFO, "ecuGetSizes fail\n"); } if((ecu_instance.ecu_buffers = (ecomemBuffer_t*) calloc(ecuNbufs, sizeof(ecomemBuffer_t))) == NULL) { Log_print0(Diags_ENTRY | Diags_INFO, "no memory\n"); } ecu_set_buffer(bufs, ecu_instance.ecu_buffers, ecuNbufs); ecu_instance.ecuCfgNew.ID = siuMakeID (SIU_MID_ECU, 1); stat = ecuNew(&(ecu_instance.ecu_Inst), ecuNbufs, ecu_instance.ecu_buffers, &(ecu_instance.ecuCfgNew)); if (stat != ecu_NOERR) { Log_print0(Diags_ENTRY | Diags_INFO, "ecuNew fail\n"); } } //.............................................................................. //.............................................................................. //.............................................................................. void ecu_open() { ecuConfigParam_t cfgParam; ecu_instance.ecuCfg.cfgParam = &cfgParam; // Start off with 0 to ensure causality, adjust once everything is working to // preserve entire 128ms tail ecu_instance.ecuCfg.y2x_delay = 0; /* One frame default y2x delay */ ecu_instance.ecuCfg.samples_per_frame = 10 * 8; /* 10ms default frame duration */ ecu_instance.ecuCfg.pcm_zero = (0x55D5);// A-law zero:0x55D5 , U-law zero:0xFFFF ecu_instance.ecuCfg.pcm_expand_tbl = &muaTblAlaw[0];// &muaTblUlaw[0];//&;//muaTblAlaw cfgParam.filter_length = SIU_MAX_ECU_FILTER_LENGTH; /* 128ms default ECU tail */ // Enable adaptive CNG level, 4-wire detection and clear all filters before use cfgParam.config_bitfield = ecu_ENABLE_ECHO_CANCELLER | ecu_ENABLE_UPDATE | ecu_ENABLE_NLP | ecu_ENABLE_AUTO_UPDATE | ecu_ENABLE_SEARCH | ecu_ENABLE_CNG_ADAPT | ecu_ENABLE_OPNLP_DETECT ; cfgParam.config_bitfield1 = ecu_ENABLE_NLP_PHASE_RND; cfgParam.noise_level = 0; /* Use default (-70) if fixed */ cfgParam.nlp_aggress = 0; /* balance performance */ cfgParam.cn_config = 0; /* pink noise */ ecuOpen(ecu_instance.ecu_Inst, &(ecu_instance.ecuCfg)); } //.............................................................................. //.............................................................................. //.............................................................................. void ecu_init() { int i; ecu_instance.ecu_Inst = NULL; memset(ecu_instance.ecu_buffers, 0, sizeof(ecu_instance.ecu_buffers)); ecu_new(); ecu_open(); for (i = 0; i < FRAME_SIZE; i++) { sin[i] = 0; rin[i] = 0; sout[i] = 0; rout[i] = 0; scompr[i] = 0; rcompr[i] = 0; rinCompr[i] = 0; sinCompr[i] = 0; } } void echo_cancel(int16_t* input_rin, int16_t* input_sin, int16_t* output_sout) { int i; // FRAMEWORK and ECU memcpy(sin, input_sin, FRAME_SIZE*sizeof(int16_t)); memcpy(rin, input_rin, FRAME_SIZE*sizeof(int16_t)); /* Compress A-law delay line samples */ muaTblAlawCmpr (FRAME_SIZE, rin, rinCompr); for (i = 0; i < FRAME_SIZE; i++) { rcompr[i] = rinCompr[i] & 0xFF; } ecuSendIn(ecu_instance.ecu_Inst, sin, rcompr, sout); memcpy(output_sout, sout, FRAME_SIZE*sizeof(int16_t)); }