Forums

adsp 21161 ifft problem

Started by Klaus Koch November 8, 2003
Hi,

I'm working with a Analog Devices 21161 EZKIT board. I'm a beginner on 
the dsp subject and having problems with fft / inverse fft.

I used the talkthrough - example provided with the visual dsp environment 
to fill a buffer with the audio signal coming from line-in input. After 
filling it, it will be repeated infinite.  My idea now was to fft this 
buffer after it has been filled and then do a inverse fft. I thought if 
doing the fft / inverse, the signal should be the same like the original 
input signal (?). But this does not seem to be the case and I just don't 
know what is going wrong.

Could please someone take a look at the following code, especially at the 
fftBuffer() function or post an example for doing a fft / ifft for the 
21161 or a similar kit ?

Regards,
Klaus Koch


-------------------------------------------------------------------------
Main.h
 
/////////////////////////////////////////////////////////////////////////
#include "ADDS_21161_EzKit.h"

#include <def21161.h>
#include <signal.h>
#include <filter.h>

////////////////////////////////////////////////////////////////////////
int             buffer_size         = 0x20000;

int             buffer_in_index     = 0;
float*          pbuffer_in_data;

int             buffer_out_index    = 0;
float*          pbuffer_out_data;

int             buffer_fft_size     = 4096;
complex_float*  pbuffer_fft_in_data;
complex_float*  pbuffer_fft_out_data;

/////////////////////////////////////////////////////////////////////////
enum    TState {
        state_fill = 0,
        state_fft,
        state_play
};

int     state               = 0;

/////////////////////////////////////////////////////////////////////////
void    processSamples      (int);




-------------------------------------------------------------------------
Main.c
 
/////////////////////////////////////////////////////////////////////////
#include "Main.h"
 
/////////////////////////////////////////////////////////////////////////
void	main()
{
    	Setup_ADSP21161N();
	Setup_SDRAM();

	Setup_AD1836();
	Init_AD1852_DACs();

	Program_SPORT02_TDM_Registers();
	Program_SPORT02_DMA_Channels();

	interruptf(SIG_SP0I, processSamples);

	*(int *) SP02MCTL |= MCE;



	pbuffer_in_data        = (float*) 0x00200000;
	pbuffer_out_data       = (float*) ((long) pbuffer_in_data + 
(buffer_size * sizeof(float)));
	
	pbuffer_fft_in_data    = (complex_float*) ((long) pbuffer_out_data      
+ (buffer_size      * sizeof(float)));
	pbuffer_fft_out_data   = (complex_float*) ((long) 
pbuffer_fft_in_data   + (buffer_fft_size  * sizeof(complex_float)));
	
	

    while(state != state_fft);
    fftBuffer();
    state = state_play;   
 	
    while(true)
        asm("idle;");
}


 
/////////////////////////////////////////////////////////////////////////
void	processSamples(int sig_int)
{
    float   current_sample_left,
            current_sample_right;
    
            
	Receive_Samples();

	
    
	if(state == state_fill) {
	   pbuffer_in_data[buffer_in_index] = (Left_Channel_In1 / 2) + 
(Right_Channel_In1 / 2);
	   
	   if(++buffer_in_index >= buffer_size) {
	       state = state_fft;
	       buffer_in_index = 0;
	   }
	}
	
    
	else if(state == state_play) {
	   current_sample_left = pbuffer_out_data[buffer_out_index];
	   current_sample_right= pbuffer_in_data [buffer_out_index];
	   
	   Left_Channel_Out0   = 
	   Left_Channel_Out1   = current_sample_left;

	   Right_Channel_Out0  = 
	   Right_Channel_Out1  = current_sample_right;
	   
	   if(++buffer_out_index >= buffer_size)
	       buffer_out_index = 0;
	}
	
	
	Transmit_Samples();
}

 
/////////////////////////////////////////////////////////////////////////
void    fftBuffer() {
    int             fft_cnt,
                    cnt;

    complex_float*  pbuffer_result_data;

    for(fft_cnt = 0; fft_cnt < buffer_size; fft_cnt += buffer_fft_size) {
        // copy input buffer
        for(cnt = 0; cnt < buffer_fft_size; cnt++) {
            pbuffer_fft_in_data[cnt].re = pbuffer_in_data[fft_cnt + cnt];
            pbuffer_fft_in_data[cnt].im = 0;
        }
        
        // i/fft
        cfft4096(pbuffer_fft_in_data, pbuffer_fft_out_data);
        pbuffer_result_data = ifft4096(pbuffer_fft_out_data, 
pbuffer_fft_in_data);
        
        // write output buffer
        for(cnt = 0; cnt < buffer_fft_size; cnt++)
            pbuffer_out_data[fft_cnt + cnt] = pbuffer_result_data
[cnt].re;
    }
}
Hi Klaus,

a short glance to your code raises a question:

> void main() > { > ... > while(state != state_fft); > fftBuffer(); > state = state_play; > > while(true) > asm("idle;"); > }
If I interpret this right, it does the following: 1. wait until the ISR has filled the buffer 2. perform a fft on the buffer 3. set state -> play which circularly transmits the output buffer (during ISR) 4. wait -wait -wait ... am I missing something, or do you perform only a single fft on one buffer once?! I'd guess that this should read like:
> void main() > { > ... > while(true) { > while(state != state_fft); > fftBuffer(); > state = state_play; > asm("idle;"); > } > }
However, this code might lose a lot of samples, because it tries to do the fft/ifft in a single cycle (if it's thought to work on a streaming basis) Bernhard
Hello Bernhard,

the code I've posted performs the fft / ifft only once and then plays 
that transformed and inverse transformed sample infinitely. It doesn't 
operate on streamed data, It just fills the buffer, then does the fft 
and ifft and loops the original data on the left channel and the fft / 
ifft data on the right channel, so I can compare the two signals.

My problem was (which I forgot to mention) that the ifft data was 
totally noisy and "cracky". It sounded like the bitcrusher effect in 
Cubase.

A few hours ago I figured out what was going wrong: the fft / ifft from 
Analog Devices doesn't seem to operate on data located in external 
memory / sdram. If I define the fft buffers to be located in the 
internal memory everything works fine.

My question now is: is it possible to use the fft (cfft, rfft) / ifft 
from the adsp 21161 with data which is located in sdram ? Everytime I 
use the external ram for my buffers the fft routines work with, the 
signal gets completely crackled and noisy. Using internal ram everything 
works fine.

I've slightly rewritten the code. The buffer - definitions are as 
follows:

// seg_dmdata is mapped to sdram
section("seg_dmdata") float pbuffer_out_data[BUFFER_SIZE];
section("seg_dmdata") float pbuffer_in_data [BUFFER_SIZE];

// seg_fft is mapped to internal ram, e.g. seg_pmco
section("seg_fft") complex_float pbuffer_fft_in_data [BUFFER_FFT_SIZE];
section("seg_fft") complex_float pbuffer_fft_out_data[BUFFER_FFT_SIZE];

This works. Only the input buffers are in sdram. But if I define the 
pbuffer_fft_... data like this

// located in sdram
section("seg_dmdata") complex_float pbuffer_fft_in_data
[BUFFER_FFT_SIZE];
section("seg_dmdata") complex_float pbuffer_fft_out_data
[BUFFER_FFT_SIZE];

I get problems.

Maybe I can't locate the buffers in external ram because it's to slow 
for the optimized fft routines for 21161 (the help says they need to 
fetch data in one cycle) ? Is there a workaround for this problem or 
have I just done something wrong ? I just thought if it wouldn't be 
possible to use sdram data, why does Analog Devices provide fft 
functions for e.g. 65536 samples (which I can't use with internal memory 
data).

Thank you in advance,
Klaus




PS: here is the code once again (this variant works)


Main.h -----------------------------------------------------------------
 
////////////////////////////////////////////////////////////////////////
// headers
#include "ADDS_21161_EzKit.h"

#include <def21161.h>
#include <signal.h>
#include <filter.h>

#pragma align 1024

 
////////////////////////////////////////////////////////////////////////
// buffer
#define	BUFFER_SIZE			0x50000
#define	BUFFER_FFT_SIZE		2048

int     buffer_in_index     = 0,
        buffer_out_index    = 0;

section("seg_dmdata") float pbuffer_out_data[BUFFER_SIZE];
section("seg_dmdata") float pbuffer_in_data [BUFFER_SIZE];

section("seg_fft") complex_float pbuffer_fft_in_data [BUFFER_FFT_SIZE];
section("seg_fft") complex_float pbuffer_fft_out_data[BUFFER_FFT_SIZE];


 
////////////////////////////////////////////////////////////////////////
// states
enum    TState {
        state_fill = 0,
        state_fft,
        state_play
};

int     state               = 0;


 
////////////////////////////////////////////////////////////////////////
// forward declarations
void    processSamples      (int);
void    fftBuffer           ();







Main.c -----------------------------------------------------------------

 
////////////////////////////////////////////////////////////////////////
// headers
#include "Main.h"


 
////////////////////////////////////////////////////////////////////////
// main
void	main()
{
      /////////////////////////////////////////////////////////////////
	Setup_ADSP21161N();
	Setup_SDRAM();

	Setup_AD1836();
	Init_AD1852_DACs();

	Program_SPORT02_TDM_Registers();
	Program_SPORT02_DMA_Channels();

	interruptf(SIG_SP0I, processSamples);

	*(int *) SP02MCTL |= MCE;
	
      ////////////////////////////////////////////////////////////////
      while(state != state_fft);
      fftBuffer();
      state = state_play;   
 	
      while(true)
         asm("idle;");
}


 
////////////////////////////////////////////////////////////////////////
// isr
void	processSamples(int sig_int)
{
     float   current_sample_left,
             current_sample_right;
    
            
	Receive_Samples();

	
      /////////////////////////////////////////////////////////////////
	if(state == state_fill) {
	   pbuffer_in_data[buffer_in_index] = (Left_Channel_In1 / 2.) +                   
                                            (Right_Channel_In1 / 2.);
	   
	   if(++buffer_in_index >= BUFFER_SIZE) {
	       state = state_fft;
	       buffer_in_index = 0;
	   }
	}
	
      //////////////////////////////////////////////////////////////////
	else if(state == state_play) {
	   current_sample_left = pbuffer_out_data[buffer_out_index];
	   current_sample_right= pbuffer_in_data [buffer_out_index];
	   
	   Left_Channel_Out0   = 
	   Left_Channel_Out1   = current_sample_left;

	   Right_Channel_Out0  = 
	   Right_Channel_Out1  = current_sample_right;
	   
	   if(++buffer_out_index >= BUFFER_SIZE)
	       buffer_out_index = 0;
	}
	
	
	Transmit_Samples();
}

 
////////////////////////////////////////////////////////////////////////
// fft
void    fftBuffer() {
    int             fft_cnt = 0,
                    cnt;

    complex_float*  pbuffer_result_data;

    for(fft_cnt = 0; fft_cnt < BUFFER_SIZE; fft_cnt += BUFFER_FFT_SIZE)  
    {
        // copy input buffer
        for(cnt = 0; cnt < BUFFER_FFT_SIZE; cnt++) {
            pbuffer_fft_in_data[cnt].re=pbuffer_in_data[fft_cnt + cnt];
            pbuffer_fft_in_data[cnt].im=0;
        }
        
        // i/fft
        cfft2048(pbuffer_fft_in_data, pbuffer_fft_out_data);
        pbuffer_result_data = ifft2048(pbuffer_fft_out_data, 
                                       pbuffer_fft_in_data);
        
        // write output buffer
        for(cnt = 0; cnt < BUFFER_FFT_SIZE; cnt++)
            pbuffer_out_data[fft_cnt + cnt]=pbuffer_result_data[cnt].re;
    }
}
I haven't tried it, but you could be overtaxing the dsp if you are
performing the fft on external memory at 48k Fs.  just glancing at the
code, it looks like they are using both the pm and dm bus which
enables them to fetch and write in one cycle.  I haven't looked at the
sdram configuration on the chip, but I think it might be only tied to
the dm bus.  So if you put both on dm, external or not, you can't
read/write in one cycle.

my guess.  Are you using the ezkit?



Klaus Koch <klauskoch@gmx.com> wrote in message news:<Xns942FC3C28ABC5none@195.114.230.36>...
> Hello Bernhard, > > the code I've posted performs the fft / ifft only once and then plays > that transformed and inverse transformed sample infinitely. It doesn't > operate on streamed data, It just fills the buffer, then does the fft > and ifft and loops the original data on the left channel and the fft / > ifft data on the right channel, so I can compare the two signals. > > My problem was (which I forgot to mention) that the ifft data was > totally noisy and "cracky". It sounded like the bitcrusher effect in > Cubase. > > A few hours ago I figured out what was going wrong: the fft / ifft from > Analog Devices doesn't seem to operate on data located in external > memory / sdram. If I define the fft buffers to be located in the > internal memory everything works fine. > > My question now is: is it possible to use the fft (cfft, rfft) / ifft > from the adsp 21161 with data which is located in sdram ? Everytime I > use the external ram for my buffers the fft routines work with, the > signal gets completely crackled and noisy. Using internal ram everything > works fine. > > I've slightly rewritten the code. The buffer - definitions are as > follows: > > // seg_dmdata is mapped to sdram > section("seg_dmdata") float pbuffer_out_data[BUFFER_SIZE]; > section("seg_dmdata") float pbuffer_in_data [BUFFER_SIZE]; > > // seg_fft is mapped to internal ram, e.g. seg_pmco > section("seg_fft") complex_float pbuffer_fft_in_data [BUFFER_FFT_SIZE]; > section("seg_fft") complex_float pbuffer_fft_out_data[BUFFER_FFT_SIZE]; > > This works. Only the input buffers are in sdram. But if I define the > pbuffer_fft_... data like this > > // located in sdram > section("seg_dmdata") complex_float pbuffer_fft_in_data > [BUFFER_FFT_SIZE]; > section("seg_dmdata") complex_float pbuffer_fft_out_data > [BUFFER_FFT_SIZE]; > > I get problems. > > Maybe I can't locate the buffers in external ram because it's to slow > for the optimized fft routines for 21161 (the help says they need to > fetch data in one cycle) ? Is there a workaround for this problem or > have I just done something wrong ? I just thought if it wouldn't be > possible to use sdram data, why does Analog Devices provide fft > functions for e.g. 65536 samples (which I can't use with internal memory > data). > > Thank you in advance, > Klaus > > > > > PS: here is the code once again (this variant works) > > > Main.h ----------------------------------------------------------------- > > //////////////////////////////////////////////////////////////////////// > // headers > #include "ADDS_21161_EzKit.h" > > #include <def21161.h> > #include <signal.h> > #include <filter.h> > > #pragma align 1024 > > > //////////////////////////////////////////////////////////////////////// > // buffer > #define BUFFER_SIZE 0x50000 > #define BUFFER_FFT_SIZE 2048 > > int buffer_in_index = 0, > buffer_out_index = 0; > > section("seg_dmdata") float pbuffer_out_data[BUFFER_SIZE]; > section("seg_dmdata") float pbuffer_in_data [BUFFER_SIZE]; > > section("seg_fft") complex_float pbuffer_fft_in_data [BUFFER_FFT_SIZE]; > section("seg_fft") complex_float pbuffer_fft_out_data[BUFFER_FFT_SIZE]; > > > > //////////////////////////////////////////////////////////////////////// > // states > enum TState { > state_fill = 0, > state_fft, > state_play > }; > > int state = 0; > > > > //////////////////////////////////////////////////////////////////////// > // forward declarations > void processSamples (int); > void fftBuffer (); > > > > > > > > Main.c ----------------------------------------------------------------- > > > //////////////////////////////////////////////////////////////////////// > // headers > #include "Main.h" > > > > //////////////////////////////////////////////////////////////////////// > // main > void main() > { > ///////////////////////////////////////////////////////////////// > Setup_ADSP21161N(); > Setup_SDRAM(); > > Setup_AD1836(); > Init_AD1852_DACs(); > > Program_SPORT02_TDM_Registers(); > Program_SPORT02_DMA_Channels(); > > interruptf(SIG_SP0I, processSamples); > > *(int *) SP02MCTL |= MCE; > > //////////////////////////////////////////////////////////////// > while(state != state_fft); > fftBuffer(); > state = state_play; > > while(true) > asm("idle;"); > } > > > > //////////////////////////////////////////////////////////////////////// > // isr > void processSamples(int sig_int) > { > float current_sample_left, > current_sample_right; > > > Receive_Samples(); > > > ///////////////////////////////////////////////////////////////// > if(state == state_fill) { > pbuffer_in_data[buffer_in_index] = (Left_Channel_In1 / 2.) + > (Right_Channel_In1 / 2.); > > if(++buffer_in_index >= BUFFER_SIZE) { > state = state_fft; > buffer_in_index = 0; > } > } > > ////////////////////////////////////////////////////////////////// > else if(state == state_play) { > current_sample_left = pbuffer_out_data[buffer_out_index]; > current_sample_right= pbuffer_in_data [buffer_out_index]; > > Left_Channel_Out0 = > Left_Channel_Out1 = current_sample_left; > > Right_Channel_Out0 = > Right_Channel_Out1 = current_sample_right; > > if(++buffer_out_index >= BUFFER_SIZE) > buffer_out_index = 0; > } > > > Transmit_Samples(); > } > > > //////////////////////////////////////////////////////////////////////// > // fft > void fftBuffer() { > int fft_cnt = 0, > cnt; > > complex_float* pbuffer_result_data; > > for(fft_cnt = 0; fft_cnt < BUFFER_SIZE; fft_cnt += BUFFER_FFT_SIZE) > { > // copy input buffer > for(cnt = 0; cnt < BUFFER_FFT_SIZE; cnt++) { > pbuffer_fft_in_data[cnt].re=pbuffer_in_data[fft_cnt + cnt]; > pbuffer_fft_in_data[cnt].im=0; > } > > // i/fft > cfft2048(pbuffer_fft_in_data, pbuffer_fft_out_data); > pbuffer_result_data = ifft2048(pbuffer_fft_out_data, > pbuffer_fft_in_data); > > // write output buffer > for(cnt = 0; cnt < BUFFER_FFT_SIZE; cnt++) > pbuffer_out_data[fft_cnt + cnt]=pbuffer_result_data[cnt].re; > } > }