This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM5728: Using VoLIB's ECU on C66 DSP

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  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));
}