Using DMA WITH DAC

Status
Not open for further replies.

Casio94

New member
Greetings Guys

I'm currently working on a direct conversion FM SDR.I have began by working on the fm demodulation part,which essentially reads of 128 pre-recorded IQ samples does the necessary DSP.The resulting output is an array of 32 16-bit integers centered around 2047(DC Value).The code does successfully demodulate baseband FM signals(I have printed the values to the serial terminal and played them in Matlab).I tried sending these values to the DAC via DMA by adapting some code I found on the forum with little luck.My code is attached herewith.I suspect that I am not either not placing the code in the correct place or misunderstanding how to incorporate the DMA and DAC.Any guidance will be greatly appreciated.

Code:
/* -------------------------------------------------------------------- */
/*--------------------FM_SDR DEMODULATION ALGORITHM-------------------- */
/*----------------------------------------------------------------------*/
    //(1) Get 128 samples of the form s[k] = a+jb (RAW IQ DATA)
    //(2) Copy I component to InputB and Q component to InputC and upsample by a factor of 2
    //(3) Clear bk and ck
    //(4) Copy I and Q to b[k] & c[k]
    //(5) FFT bk and Ck
    //(6) Multiply B[k] & C[k] with A[k]
    //(7) Set ifftflag to 1
    //(8)Take inverse fft of A[k]B[K] AND A[k]C[k] => Gives us time domain convolved output
    //(9)Transfer k E [128 256] from AxB[k] and AxC[k] to OutputA and OutputB buffers
    //(10)Use processed data to compute the following expression for all samples:
    //(11)y_demod[n] = (i[n](q'[n]) - q[n](i'[n]))/(i[n]^2 + q[n]^2)
    //(12)Collect 128 samples and repeat!!!
    // |=============================================================HINTS & FUTURE IMPROVEMENTS=====================================================================|
    // Downsampling by a factor of f_Sample/f_DAC and additional FIR filtering??????????=>Investigate after front-end is built if necessary implement 6th order FIR LPF.
    // Send processed data to DAC at 44.1E3 kHz!!!!!.Do not forget to add DC Bias to DAC Output followed by decoupling capacitor to speakers/amplifier(for audio),other data such as CW and Morse will be sent serially when the required demod. schemes are completed.
    //Bandwidth should be ~165-170kHz so both mono + stereo will be possible.
    //RAW RDS can be extracted if desired => nth order(6/7th order BPF at 57kHz) as proposed bandwidth is ~ 3x57kHz.
    //Investigate use of FAST_RFFT ->May reduce processing time by a min. of 50uS/128 ADC samples => Min. of 20kHz more bandwidth!!!!
   
/*-----------------------------------------------------------------------*/
/*-----------------AM_SDR_DEMODULATION ALGORITHM-------------------------*/
/*----------------(=========!!TO DO!!===========)------------------------*/ 
//NB:THIS SHOULD BE NOTABLY SIMPLER TO IMPLEMENT THAN FM => LARGER BANDWIDTH CAN BE ACHIEVED OWING TO REDUCED DSP TIME!!!!=>REMEMBER AND CAPTILIZE

/*-----------------------------------------------------------------------*/
/*-----------------CW_SDR_DEMODULATION ALGORITHM-------------------------*/
/*----------------(=========!!TO DO!!===========)------------------------*/
/*-----------------------------------------------------------------------*/
/*-----------------LSB&USB_SDR_DEMODULATION ALGORITHM-------------------------*/
/*----------------(=========!!TO DO!!===========)------------------------*/
#include "arm_math.h"
#include "math_helper.h"
#include "arm_const_structs.h"
#include "SdFat.h"
#include <DMAChannel.h>
/* ----------------------------------------------------------------------
* Defines each of the tests performed
* ---------------------------------------------------------------------*/
#define MAX_BLOCKSIZE   512
#define NUM_TAPS        32
#define DC_OFFSET       127.5
/* ----------------------------------------------------------------------
* Declare I/O buffers
* ------------------------------------------------------------------- */
float32_t Ak[MAX_BLOCKSIZE];        /* Input A */
float32_t Bk[MAX_BLOCKSIZE];        /* Input B */
float32_t Ck[MAX_BLOCKSIZE];
float32_t AxB[MAX_BLOCKSIZE * 2];   /* Output */
float32_t AxC[MAX_BLOCKSIZE * 2];
/* ----------------------------------------------------------------------
* Test input data for Floating point Convolution example for 32-blockSize
* ------------------------------------------------------------------- */
float32_t FIR_128_TAP_BPF_f32[256] ={-0.000283723267087997, 0,  -0.000290290943344975,  0,  0.000301189321326625, 0,  0.000316617777579883, 0,  -0.000336778716415289,  0,  -0.000361877893411611,  0,  0.000392124798790657, 0,  0.00042773310785065,  0,  -0.000468921206617346,  0,  -0.000515912802003418,  0,  0.000568937627089686, 0,  0.000628232253692209, 0,  -0.000694041026202697,  0,  -0.000766617132838579,  0,  0.000846223832981496, 0,  0.00093313586229789,  0,  -0.00102764104092475, 0,  -0.00113004211428895, 0,  0.0012406588612651, 0,  0.00135983051055364,  0,  -0.00148791851362049, 0,  -0.00162530973157952, 0,  0.0017724201044055, 0,  0.00192969888431859,  0,  -0.00209763353170622, 0,  -0.00227675539233821, 0,  0.00246764629992005,  0,  0.00267094627955749,  0,  -0.00288736256723321, 0,  -0.00311768021023803, 0,  0.00336277457673956,  0,  0.00362362618342634,  0,  -0.00390133835400266, 0,  -0.00419715835578936, 0,  0.00451250283720405,  0,  0.00484898861984088,  0,  -0.00520847020541099, 0,  -0.00559308576845541, 0,  0.00600531396134173,  0,  0.00644804461775425,  0,  -0.00692466749154768, 0,  -0.00743918463876092, 0,  0.00799635413726569,  0,  0.00860187584130664,  0,  -0.00926263425688625, 0,  -0.00998702014768913, 0,  0.010785362360065,  0,  0.011670516622864,  0,  -0.0126586822100837,  0,  -0.0137705564650335,  0,  0.0150330023693281, 0,  0.0164815164575361, 0,  -0.0181639842399921,  0,  -0.0201465814679796,  0,  0.0225234023835554, 0,  0.0254328842305388, 0,  -0.0290873711985721,  0,  -0.0338299679534549,  0,  0.0402534149485865, 0,  0.0494774638372458, 0,  -0.063901753180106, 0,  -0.0897655852658466,  0,  0.149946809227067,  0,  0.450347298556167,  0,  0.450347298556167,  0,  0.149946809227067,  0,  -0.0897655852658466,  0,  -0.063901753180106, 0,  0.0494774638372458, 0,  0.0402534149485865, 0,  -0.0338299679534549,  0,  -0.0290873711985721,  0,  0.0254328842305388, 0,  0.0225234023835554, 0,  -0.0201465814679796,  0,  -0.0181639842399921,  0,  0.0164815164575361, 0,  0.0150330023693281, 0,  -0.0137705564650335,  0,  -0.0126586822100837,  0,  0.011670516622864,  0,  0.010785362360065,  0,  -0.00998702014768913, 0,  -0.00926263425688625, 0,  0.00860187584130664,  0,  0.00799635413726569,  0,  -0.00743918463876092, 0,  -0.00692466749154768, 0,  0.00644804461775425,  0,  0.00600531396134173,  0,  -0.00559308576845541, 0,  -0.00520847020541099, 0,  0.00484898861984088,  0,  0.00451250283720405,  0,  -0.00419715835578936, 0,  -0.00390133835400266, 0,  0.00362362618342634,  0,  0.00336277457673956,  0,  -0.00311768021023803, 0,  -0.00288736256723321, 0,  0.00267094627955749,  0,  0.00246764629992005,  0,  -0.00227675539233821, 0,  -0.00209763353170622, 0,  0.00192969888431859,  0,  0.0017724201044055, 0,  -0.00162530973157952, 0,  -0.00148791851362049, 0,  0.00135983051055364,  0,  0.0012406588612651, 0,  -0.00113004211428895, 0,  -0.00102764104092475, 0,  0.00093313586229789,  0,  0.000846223832981496, 0,  -0.000766617132838579,  0,  -0.000694041026202697,  0,  0.000628232253692209, 0,  0.000568937627089686, 0,  -0.000515912802003418,  0,  -0.000468921206617346,  0,  0.00042773310785065,  0,  0.000392124798790657, 0,  -0.000361877893411611,  0,  -0.000336778716415289,  0,  0.000316617777579883, 0,  0.000301189321326625, 0,  -0.000290290943344975,  0,  -0.000283723267087997,  0};
float32_t testInputB_f32[256]={};
float32_t testInputC_f32[256]={};

float32_t firStateF32[MAX_BLOCKSIZE/4 + NUM_TAPS - 1];
float32_t DecimateFilter[NUM_TAPS]={-0.00156552057451955, -0.0015721358306938,  -0.00162554249834432, -0.00136475981408984, -0.000289068572379983,  0.00215718490748801,  0.00647496902313494,  0.0129956340058802, 0.0217826003507149, 0.0325698919071186, 0.044752049172766,  0.0574312427643976, 0.069517228693083,  0.0798660349133817, 0.0874357943056302, 0.0914343972464324, 0.0914343972464324, 0.0874357943056302, 0.0798660349133817, 0.069517228693083,  0.0574312427643976, 0.044752049172766,  0.0325698919071186, 0.0217826003507149, 0.0129956340058802, 0.00647496902313494,  0.00215718490748801,  -0.000289068572379983,  -0.00136475981408984, -0.00162554249834432, -0.0015721358306938,  -0.00156552057451955}; 
arm_fir_decimate_instance_f32 S;
float32_t Audio_Out[MAX_BLOCKSIZE/16]={};

float32_t OutputA[MAX_BLOCKSIZE/4];                   //Buffer to contained 
float32_t OutputB[MAX_BLOCKSIZE/4];

float32_t IF_I[MAX_BLOCKSIZE/4];
float32_t IF_Q[MAX_BLOCKSIZE/4];

float32_t X_1[MAX_BLOCKSIZE/4];
float32_t X_2[MAX_BLOCKSIZE/4];

float32_t Y_1[MAX_BLOCKSIZE/4];
float32_t Y_2[MAX_BLOCKSIZE/4];

float32_t Y_demod_Num[MAX_BLOCKSIZE/4];
float32_t Y_demod_Denom[MAX_BLOCKSIZE/4];

float32_t Y_DEMOD[MAX_BLOCKSIZE/4];

/* --------------------------------------------------------------------
******************** Declare Global variables**************************
-------------------------------------------------------------------- */
uint32_t srcALen = 256;       /* Length of Input A */
uint32_t srcBLen = 256;       /* Length of Input B */
uint32_t outLen;              /* Length of convolution output */
uint32_t ifftFlag = 0;        /*ifft/fft flag*/
uint32_t doBitReverse = 1;  

SdFatSdioEX sdEx;
File file;

const size_t BUF_DIM = 256;   //SAMPLE BUFFER SIZE
const size_t nb=256;

uint8_t buf[BUF_DIM];         //SAMPLE BUFFER
float32_t buf_float[BUF_DIM];
float32_t Norm[BUF_DIM/2];
uint8_t DAC_BUFF[32];
uint32_t blocks_read=0;

/* --------------------------------------------------------------------
******************** DMA&DAC VARIABLES**************************
-------------------------------------------------------------------- */
#define PDB_CONFIG     (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_PDBIE | PDB_SC_CONT | PDB_SC_DMAEN)
DMAChannel dma1(false);
const uint32_t pdb_freq = 41000; 

void setup()
{

  delay(3000);  //SAFETY DELAY -> PREVENT PROCESSOR FROM HANGING AT START
  Serial.begin(115200);

   if (!sdEx.begin()){}
     sdEx.chvol();
  if (!file.open("FM_TEST.bin", O_RDWR | O_CREAT)) {}
  else{}

  arm_status status;                                                      //CMSIS DSP STATUS FLAG 
  status = ARM_MATH_SUCCESS;
  outLen = srcALen + srcBLen - 1;                                         
  arm_fir_decimate_init_f32(&S,MAX_BLOCKSIZE/16,4,DecimateFilter,firStateF32,MAX_BLOCKSIZE/4);
  
  arm_fill_f32(0.0,testInputB_f32, MAX_BLOCKSIZE/2);
  arm_fill_f32(0.0,testInputC_f32, MAX_BLOCKSIZE/2);
  
                                                                         //START TIMER USED TO MEASURE PROCESSING TIME
  arm_fill_f32(0.0,  Ak, MAX_BLOCKSIZE);                                 //FILL FFT INPUT BUFFERS WITH ZEROs
  arm_fill_f32(0.0,  Bk, MAX_BLOCKSIZE);                                 //"                                 "
  arm_fill_f32(0.0,  Ck, MAX_BLOCKSIZE);                                 //"                                 "

  arm_fill_f32(0.0,  AxB,MAX_BLOCKSIZE*2);                               //CLEAR BUFFER TO HOLD FILTERED I SIGNAL FREQ. DOMAIN
  arm_fill_f32(0.0,  AxC,MAX_BLOCKSIZE*2);                               //CLEAR BUFFER TO HOLD FILTERED Q SIGNAL FREQ. DOMAIN

  arm_fill_f32(0.0,  OutputA,MAX_BLOCKSIZE/4);                           //CLEAR BUFFER TO HOLD CONVOLVED/IFFT OF FILTERED I SIGNAL 
  arm_fill_f32(0.0,  OutputB,MAX_BLOCKSIZE/4);                           //CLEAR BUFFER TO HOLD CONVOLVED/IFFT OF FILTERED Q SIGNAL

  arm_fill_f32(0.0,  IF_I,MAX_BLOCKSIZE/4);                              //CLEAR BUFFER TO HOLD PRE-FILTERED I SIGNAL
  arm_fill_f32(0.0,  IF_Q,MAX_BLOCKSIZE/4);                              //CLEAR BUFFER TO HOLD PRE-FILTERED Q SIGNAL

  arm_fill_f32(0.0,  X_1,MAX_BLOCKSIZE/4);                               //CLEAR BUFFER TO HOLD 1ST NUMERATOR TERM IN FINAL COMPUTATION
  arm_fill_f32(0.0,  X_2,MAX_BLOCKSIZE/4);                               //CLEAR BUFFER TO HOLD 2ND NUMERATOR TERM IN FINAL COMPUTATION

  arm_fill_f32(0.0,  Y_1,MAX_BLOCKSIZE/4);                               //CLEAR BUFFER TO HOLD 1ST DENOMINATOR TERM IN FINAL COMPUTATION
  arm_fill_f32(0.0,  Y_2,MAX_BLOCKSIZE/4);                               //CLEAR BUFFER TO HOLD 2ND DENOMINATOR TERM IN FINAL COMPUATION

  arm_fill_f32(0.0,  Y_demod_Num,MAX_BLOCKSIZE/4);                       //CLEAR BUFFER TO HOLD NUMERATOR IN FINAL COMPUTATION
  arm_fill_f32(0.0,  Y_demod_Denom,MAX_BLOCKSIZE/4);                     //CLEAR BUFFER TO HOLD DENOMINATOR IN FINAL COMPUTATION
  
  arm_copy_f32(FIR_128_TAP_BPF_f32,  Ak, MAX_BLOCKSIZE/2);               //FILL BUFFER WITH TIME DOMAIN FIR FILTER COEFFICIENTS
  arm_cfft_f32(&arm_cfft_sR_f32_len256, Ak,ifftFlag,doBitReverse);       //FFT OF FIR FILTER COEFFICIENTS
}

void loop()
{

  if(blocks_read<185937)
  {
                                                                         //START TIMER
    ifftFlag=0;                                                          //SET IFFT FLAG TO ZERO
    memset(buf, 0, sizeof(buf));                                         //CLEAR ADC/SD CARD BUFFER
    
    file.read(buf,nb);                                                   //READ 128 COMPLEX SAMPLES OF THE FORM s[k] = i[k]+j*q[k] WHERE i[k]='I SIGNAL' & q[k]= 'Q SIGNAL'
    
    for(int i=0;i<MAX_BLOCKSIZE/2;i++){buf_float[i]=buf[i]-127.5;}
    arm_cmplx_mag_f32(buf_float,Norm,128);
    
       for(int i=0;i<MAX_BLOCKSIZE/4;i++)
           {
               testInputB_f32[2*i]=buf_float[2*i]/Norm[i];               //Upsample i[k] by a factor of 2 & remove DC Offset
               testInputC_f32[2*i]=buf_float[2*i+1]/Norm[i];             //Upsample q[k] by a factor of 2 & remove DC Offset
           }
 
    arm_fill_f32(0.0,Norm,MAX_BLOCKSIZE/4);
    arm_fill_f32(0.0,buf_float,MAX_BLOCKSIZE/2);
    
    arm_copy_f32(testInputB_f32,  Bk, MAX_BLOCKSIZE/2);                  //FILL BUFFER WITH I ADC VALUES
    arm_copy_f32(testInputC_f32,  Ck, MAX_BLOCKSIZE/2);                  //FILL BUFFER WITH Q ADC VALUES

    arm_cfft_f32(&arm_cfft_sR_f32_len256, Bk,ifftFlag,doBitReverse);     //FFT OF I ADC VALUES        i[n]=>I[n]
    arm_cfft_f32(&arm_cfft_sR_f32_len256, Ck,ifftFlag,doBitReverse);     //FFT OF Q ADC VALUES        q[n]=>Q[n]
    arm_cmplx_mult_cmplx_f32(Ak, Bk, AxB, MAX_BLOCKSIZE/2);              // d/dn[I[n]] = I[n]xH[n]  
    arm_cmplx_mult_cmplx_f32(Ak, Ck, AxC, MAX_BLOCKSIZE/2);              // d/dn[Q[n]] = Q[n]xH[n]
    ifftFlag=1;
    
    arm_cfft_f32(&arm_cfft_sR_f32_len256,AxB,ifftFlag,doBitReverse);     //i'[n]=ifft(d/dn[I[n]] = I[n]xH[n])=fft^-1(d/dn[I[n]] = I[n]xH[n])
    arm_cfft_f32(&arm_cfft_sR_f32_len256,AxC,ifftFlag,doBitReverse);     //q'[n]=ifft(d/dn[Q[n]] = Q[n]xH[n])=fft^-1(d/dn[Q[n]] = Q[n]xH[n])
  
        for(int i=0;i<MAX_BLOCKSIZE/4;i++)
          {
              OutputA[i]=AxB[MAX_BLOCKSIZE/4 + 2*i];                            
              OutputB[i]=AxC[MAX_BLOCKSIZE/4 + 2*i];
              IF_I[i]=testInputB_f32[2*i];
              IF_Q[i]=testInputC_f32[2*i];
          }

    arm_mult_f32(IF_I,OutputB,X_1,MAX_BLOCKSIZE/4);                                     //i[n](q'[n])
    arm_mult_f32(IF_Q,OutputA,X_2,MAX_BLOCKSIZE/4);                                     //q[n](i'[n])

    arm_mult_f32(IF_I,IF_I,Y_1,MAX_BLOCKSIZE/4);                                        //(i[n])^2= i[n]xi[n]
    arm_mult_f32(IF_Q,IF_Q,Y_2,MAX_BLOCKSIZE/4);                                        //(q[n])^2= q[n]xq[n]

    arm_sub_f32(X_1,X_2,Y_demod_Num,MAX_BLOCKSIZE/4);                                   //i[n](q'[n]) - q[n](i'[n])
    arm_add_f32(Y_1,Y_2,Y_demod_Denom,MAX_BLOCKSIZE/4);                                 // i[n]^2 + q[n]^2
   
   for(int i=0;i<MAX_BLOCKSIZE/4;i++){Y_DEMOD[i]=Y_demod_Num[i]/Y_demod_Denom[i];}      // y_demod[n] = (i[n](q'[n]) - q[n](i'[n]))/(i[n]^2 + q[n]^2)
   arm_fir_decimate_f32(&S,Y_DEMOD,Audio_Out,MAX_BLOCKSIZE/4);
   for(int i=0;i<MAX_BLOCKSIZE/16;i++){DAC_BUFF[i]=1000*Audio_Out[i]+2047;}                  //SEND DEMODULATED DATA TO COMPARE TO MATLAB OUTPUT 
   SETUP_AND_START();
   
/*----THE MUNDANE TASK OF CLEARING BUFFERS IS PERFORMED HERE TO PREVENT OVERFLOW----*/
   
   arm_fill_f32(0.0,testInputB_f32, MAX_BLOCKSIZE/2);
   arm_fill_f32(0.0,testInputC_f32, MAX_BLOCKSIZE/2);
   arm_fill_f32(0.0,  Bk, MAX_BLOCKSIZE);                               
   arm_fill_f32(0.0,  Ck, MAX_BLOCKSIZE);                     

   arm_fill_f32(0.0,  AxB,MAX_BLOCKSIZE*2);
   arm_fill_f32(0.0,  AxC,MAX_BLOCKSIZE*2);

   arm_fill_f32(0.0,  OutputA,MAX_BLOCKSIZE/4);
   arm_fill_f32(0.0,  OutputB,MAX_BLOCKSIZE/4);

   arm_fill_f32(0.0,  IF_I,MAX_BLOCKSIZE/4);
   arm_fill_f32(0.0,  IF_Q,MAX_BLOCKSIZE/4);

   arm_fill_f32(0.0,  X_1,MAX_BLOCKSIZE/4);
   arm_fill_f32(0.0,  X_2,MAX_BLOCKSIZE/4);

   arm_fill_f32(0.0,  Y_1,MAX_BLOCKSIZE/4);
   arm_fill_f32(0.0,  Y_2,MAX_BLOCKSIZE/4);

   arm_fill_f32(0.0,  Y_demod_Num,MAX_BLOCKSIZE/4);
   arm_fill_f32(0.0,  Y_demod_Denom,MAX_BLOCKSIZE/4);

   arm_fill_f32(0.0,  Audio_Out,MAX_BLOCKSIZE/16);
/*----THE MUNDANE TASK OF CLEARING BUFFERS HAS NOW CONCLUDED-------*/
   
   blocks_read=blocks_read+1;                                                    //ADD 256 BYTES TO THE TOTAL NO# OF BYTES PROCESSED   
   
  }
}


void setup_pdb() {
  uint32_t mod = (F_BUS / pdb_freq);
    
  PDB0_MOD = (uint16_t)(mod-1);  
  PDB0_IDLY = 0;
  PDB0_SC = PDB_CONFIG | PDB_SC_LDOK;
  PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG;
  PDB0_CH0C1 = 0x0101;
}

// Setup DMA for DAC transfer - ref sin 
void setup_dma1() {
  dma1.disable();
  dma1.sourceBuffer(DAC_BUFF, sizeof(DAC_BUFF));
  dma1.transferSize(2);
  dma1.destination(*(volatile uint16_t *)&(DAC0_DAT0L));
  dma1.triggerAtHardwareEvent(DMAMUX_SOURCE_PDB);
  
  //dma_dac.transferCount(lut_size/3);
  //dma_dac_ref.interruptAtCompletion();
  //dma_dac.interruptAtHalf();

  dma1.enable();
  //dma_dac_ref1.attachInterrupt(dma_dac_ref_isr);
}





void SETUP_AND_START() {
  // setup DAC 
  SIM_SCGC2 |= SIM_SCGC2_DAC0
  DAC0_C0 = DAC_C0_DACEN; // 1.2V VDDA is DACREF_2
  DAC0_C0 |= DAC_C0_DACRFS; // 3.3V
  
  // slowly ramp up to DC voltage, approx 1/4 second
  for (int16_t i=0; i<=2048; i+=8) {
    *(int16_t *)&(DAC0_DAT0L) = i;
    delay(1);
  }
  // allocate the dma channels
  dma1.begin(true);
  setup_dma1();
  SIM_SCGC6 |= SIM_SCGC6_PDB; // enable PDB clock
  setup_pdb();
}
 
It looks like you're calling your setup routine from your main program loop, which would cause the DAC, PDB, and DMA modules to be repeatedly reset.
 
Status
Not open for further replies.
Back
Top