Part Number: AM5728
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));
}