I am attempting to get the ECU module in the VoLIB to work on TMS320C6A8168 processor.
But it does not seem to work.I feel like ECU buffer problems.I want to consult on how to initialize the ECU module(ECU buffer).Or give me some suggestions to make the ECU work properly.
Here I write some code:
#define siuMakeID(mid,chnum) ((tuint)(mid)<<8|(tuint)(chnum))
#define SIU_MAX_FRAME_LENGTH 80 /* 10ms maximum frame duration */#define SIU_MAX_ECU_FILTER_LENGTH 1024 /* maximum echo tail in taps */#define SIU_MAX_ECU_FLTSEG 3 /* maximum number of filter segments */#define SIU_MAX_ECU_FLTSEG_LENGTH 256 /* maximum taps for all filter segments */#define SIU_MAX_SYSTEM_DELAY 320 /* maximum extra system delay in samples */
#define SIU_VOICE_HEAP_SIZE 2048tword siu_voice_heap[SIU_VOICE_HEAP_SIZE];
//void *cheap;void *vheap;
/* Module ID's */#define SIU_MID_SIU 0x01 /* SIU module */#define SIU_MID_VCU 0x02 /* VCU module */#define SIU_MID_VCA 0x03 /* VCA modules */#define SIU_MID_PIU 0x04 /* PIU module */#define SIU_MID_ECU 0x05 /* ECU module */ /* 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
struct ecu_inst_params{ tuint ID;
void *ecu_Inst; /* Signal limiter Instance */ ecomemBuffer_t *ecu_buffers; ecuConfig_t ecuCfg; ecuControl_t ecuCtl; ecuNewConfig_t ecuCfgNew;
tint ecu_rx_buffer[80]; tint ecu_tx_buffer[80]; tint ecu_ec_buffer[80];
};
struct ecu_inst_params ys_ecu_inst[64];
void my_exception(tuint _id, tuint _type, tuint _code, tuint _length, tuint *data){ System_printf("id: %x, type: %d, code: %d, len: %d", _id, _type, _code, _length);}ecuContext_t ecuContext = { (vfnptr)my_exception, NULL, /* Debug streaming function pointer */ NULL, NULL, /* Search filter swapping function */ NULL,//ecu_send_out, /* Send out function pointer */ NULL,//piuReceiveIn, /* 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 */};
typedef struct { Fract ecu_buf_1[512]; Fract ecu_buf_2[512]; linSample ecu_buf_3[80]; linSample ecu_buf_4[2048]; linSample ecu_buf_5[4096]; Fract ecu_buf_6[2048]; Fract ecu_buf_14[2048];}ecu_buf_t;ecu_buf_t ecu_buf[64];
void ecu_set_buffer(const ecomemBuffer_t *bufs, ecomemBuffer_t *ecuBufs, tint ecuNbufs, int inst_num){ int i;
for (i = 0; i < ecuNbufs; i++) { ecuBufs[i] = bufs[i]; if (i == ecu_FG_FLTSEG) { /* FG Filter */ ecuBufs[i].base = &(ecu_buf[inst_num].ecu_buf_1[0]);; ecuBufs[i].size = sizeof(ecu_buf[inst_num].ecu_buf_1); } else if (i == ecu_BG_FLTSEG) { /* BG Filter */ ecuBufs[i].base = &(ecu_buf[inst_num].ecu_buf_2[0]);; ecuBufs[i].size = sizeof(ecu_buf[inst_num].ecu_buf_2); } else if (i == ecu_BG_E_BUF) { /* BG Error Buffer IRAM */ ecuBufs[i].base = &(ecu_buf[inst_num].ecu_buf_3[0]);; ecuBufs[i].size = sizeof(ecu_buf[inst_num].ecu_buf_3); } else if (i == ecu_RECEIVE_IN) { /* ECU's recv-in buffer is aligned! */ ecuBufs[i].volat = FALSE; ecuBufs[i].base = &(ecu_buf[inst_num].ecu_buf_4[0]);; ecuBufs[i].size = sizeof(ecu_buf[inst_num].ecu_buf_4); } else if (i == ecu_EXPAND_DL_BUF) { /* ECU's recv-in buffer is aligned! */ ecuBufs[i].volat = TRUE; ecuBufs[i].base = &(ecu_buf[inst_num].ecu_buf_5[0]);; ecuBufs[i].size = sizeof(ecu_buf[inst_num].ecu_buf_5); } else if (i == ecu_BG_UPDATE_BUF) { /* BG Work Buffer IRAM */ if (ecuBufs[i].size > 0) { ecuBufs[i].base = &(ecu_buf[inst_num].ecu_buf_6[0]);; ecuBufs[i].size = sizeof(ecu_buf[inst_num].ecu_buf_6);
} 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 = &(ecu_buf[inst_num].ecu_buf_14[0]);; ecuBufs[i].size = sizeof(ecu_buf[inst_num].ecu_buf_14); } else { if (ecuBufs[i].size > 0) { ecuBufs[i].volat = FALSE; ecuBufs[i].base = (mhmAlloc (vheap, bufs[i].size)); } else { /* no buffer allocated if size zero or less */ ecuBufs[i].base = NULL; ecuBufs[i].size = 0; } } }
}
int ys_ecu_new(int chan){ tint stat, ecuNbufs; const ecomemBuffer_t *bufs;
stat = ecuGetSizes (&ecuNbufs, &bufs, (void *)NULL); if (stat != ecu_NOERR) { Log_print1(Diags_EXIT,"[+X] ecuGetSizes failed >return %d\n",stat); return stat; }
ys_ecu_inst[chan].ecu_buffers = (ecomemBuffer_t*)calloc (ecuNbufs,sizeof(ecomemBuffer_t)); if(ys_ecu_inst[chan].ecu_buffers == NULL) { Log_print0(Diags_EXIT,"[+X] the ecu_buffers allocated failed \n"); return -1; } vheap = mhmCreate (siu_voice_heap, SIU_VOICE_HEAP_SIZE,0); ecu_set_buffer(bufs, ys_ecu_inst[chan].ecu_buffers, ecuNbufs, chan);
ys_ecu_inst[chan].ecuCfgNew.ID = siuMakeID (SIU_MID_ECU, chan); stat = ecuNew (&(ys_ecu_inst[chan].ecu_Inst), ecuNbufs, ys_ecu_inst[chan].ecu_buffers, &(ys_ecu_inst[chan].ecuCfgNew));
if (stat != ecu_NOERR) { Log_print2(Diags_EXIT, "[+X] ecuNew %d failed > return %d\n", chan, stat); return stat; }
return 0;}
int ys_ecu_open(int chan){ ecuConfigParam_t cfgParam;
ys_ecu_inst[chan].ecuCfg.cfgParam = &cfgParam; ys_ecu_inst[chan].ecuCfg.y2x_delay = 40; /* One frame default y2x delay */ ys_ecu_inst[chan].ecuCfg.samples_per_frame = 10*8; /* 5ms default frame duration */ ys_ecu_inst[chan].ecuCfg.pcm_zero = 0;//(0x55D5); ys_ecu_inst[chan].ecuCfg.pcm_expand_tbl = NULL;//&_a2lin[0];
cfgParam.filter_length = SIU_MAX_ECU_FILTER_LENGTH ; /* 128ms default ECU tail */ cfgParam.noise_level = 0; /* Use default (-70) if fixed */ cfgParam.config_bitfield = ecu_ENABLE_ECHO_CANCELLER | /* ENABLE ECU, ENABLE NLP, ENABLE UPDATE */ 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.nlp_aggress = 0; /* balance performance */ cfgParam.cn_config = 0; /* pink noise */
ecuOpen (ys_ecu_inst[chan].ecu_Inst, &(ys_ecu_inst[chan].ecuCfg)); return 0;}
int ecu_init(){ int chan; int res; memset(ys_ecu_inst, 0, sizeof(struct ecu_inst_params) * 64); for (chan=0; chan<64; chan++) { res = ys_ecu_new(chan); if(res != 0){ Log_print1(Diags_EXIT, "[+X] ys_ecu_new faild> return (0x%x)", res); return res; }
ys_ecu_open(chan);
int ys_ecu_process(int chan, int codec, short* rx, short * tx, short * ec){ int i;
for(i = 0; i <80; i ++){ ys_ecu_inst[chan].ecu_rx_buffer[i] = rx[i]; ys_ecu_inst[chan].ecu_tx_buffer[i] = tx[i]; }
ecuSendIn(ys_ecu_inst[chan].ecu_Inst, ys_ecu_inst[chan].ecu_rx_buffer, ys_ecu_inst[chan].ecu_tx_buffer, ys_ecu_inst[chan].ecu_ec_buffer);
for(i = 0; i <80; i ++){ ec[i] =ys_ecu_inst[chan].ecu_ec_buffer[i]; } return 0;}
Hi Tiger,
It looks as though you are using either muaTblUlawCmpr() or something similar to compress the samples. While this is the first step to create packed samples for the ECU "vrecv_in" buffer, the samples at this point are compressed, but still stored as the lower 8-bits of a 16-bit "tint". This will produce the delay-line pattern you see since every other 8-bits, as read by the ECU, will be PCM zero. You can achieve proper compression in the following manner:
linSample rinLinear[N]; tint rinCompr[N]; tword rinBuffer[N]; tint length = N; tint i; /* Compress U-law delay line samples */ muaTblUlawCmpr (length, rinLinear, rinCompr);
/* Pack samples for delay line compression */ for (i=0; i<length; i++) { rinBuffer[i] = rinCompr[i] & 0xFF; }
Note that "rinBuffer" is of type "tword". This represents the atomic type on a platform (8-bits on C6000).
Please let me know if this helps, I believe it will.
Regards,Charlie
Hi Charlie,
My manner is same as your manner. I see that rinBuffer(tword, 8-bit) have no PCM zero. But data in Far-end expanded delay line buffer have a PCM zero every couple samples. I think that rinBuffer and Far-end delay buffer are correct. The problem is that Far-end delay buffer is expanded to Far-end expanded delay line buffer.
u-law compress: muaTblUlawCmpr()
u-law expand: pcm_zero = 0xFFFF; pcm_expand_tbl = &muaTblUlaw[0];
The echo is cancelled by comparing the data in sinBuffer and Far-end expanded delay line buffer.
Far-end delay buffer is expanded to Far-end expanded delay line buffer by &muaTblUlaw[0].
Can you explain how data is stored in Far-end expanded delay line buffer ?
Can you give me a example about data in Far-end delay buffer and Far-end expanded delay line buffer ?
I don't konw how ecuSendIn( ) to process the rinBuffer and produce FG filter coefficients.
Input (sinBuffer, rinBuffer) and configuration are right . The all buffer is also allocated properly.
Why FG filter coefficients is 0 and Far-end expanded delay line buffer is incorrect ?
Just to re-iterate what Charlie said. The Transmit buffer requires two samples to be packed into each single 16-bit word.
Here is the code I used for the filling the transmit buffer.
ulaw1 = mulaw_compress( transmitData[ii]); ulaw2 = mulaw_compress( transmitData[ii+1]); tx_buffer[index] = ( ( ulaw1 << 8 ) & 0xff00 ) | ( ulaw2 & 0xff );
Where mulaw_compress() converts a linear PCM sample into a mulaw sample.
Hi Paul,
I tried the way what you said, but the result is unchanged. All FG filter coefficients is still 0 and ECU’s search filter buffer is also 0.
ecuGetPerformance() return struct ecuUpdateStat_t:
attempt_update:1 attempt_search: 0 erle_bypass: 0 xtone_bypass: 1 other_bypass: 0
xidle: 0 double_talk: 0 dt_cps: 0 dt_cpt: 0 nlp: 2 divergence: 0
srch_divergence: 0 fg_switch: 0 bg_switch: 0 openloop_found: 0 numseg_change: 0
segment_change: 0 converge_exit: 0 txbssat_events: 0 rxbssat_events: 0
When NLP is enable, the sout_buffer is 0 whatever data is in tx_buffer and rx_buffer.
I think that buffer alloaction is incorrect, but the buffer align and size is right. Moreover, the ecuNew() return true.
I have tried the manner you said. The sout_buffer is still same as sin_buffer.
While the code is running, I can see that there is no data being put into the Far-end expanded delay line and that the Foreground Filter segment coefficients are not updating.
I see that ecuContext.expand_ptr is not updating. The value is always 0xB700409E and ecuContext.rxout_buf_base is 0xB7004000.
The ecuContext.pack_ptr is updating.
Can you tell me how Far-end delay line is expanded to Far-end expanded delay line by pcm_expand_tbl ?
I have allocated all the memory as requested by the ecuGetSizes function and confirmed the correct size and allignment on the memory blocks I pass into ecuNew.
I doubt whether ECU is compatible with C674 dsp or C6A816x platform. It is possible that a bug exist when ECU is used in C674 or C6A816x platform.
Regards,
Tiger
This thread appears to be a duplicate of http://e2e.ti.com/support/embedded/bios/f/355/p/199331/716381.aspx#716381. I am marking this as Answered with the understanding that the other thread will continue.
Dave
Hi CharlieF,
I can run ECU code in CCS project. I new a ccs project and add my code to this project. I compare output pcm flile with input file, the echo can be cancelled.
When I add the same code to EZSDK, the ECU can't cancel echo. In EZSDK, Codec Engine is used to call the ECU API and process voice data.
The voice data are read from app part., then codec part get the data to process. In codec, ECU APIs are called. Scale example of Codecs is packed to call ECU API.
The EZSDK version is 5.02. CCS version is 5.2.1.00018 .
I can see the delay line expand buffer data is wrong when I set rinBuffer(u law) to 0xFF.
delay line expand buffer:
0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124 0 -32124