ADSP-21584: Random math errors, root cause from interrupt?

I am running an ADSP-2158x and noticed some issues. This was narrowed down to two locations in code involving math operations; I'll attach one of them as an example. Every once in a while the values will calculate higher than expected. This isn't isolated to a single cycle, and it usually reads consistently high for at least a second... we are performing the calculations every 2.5 ms.

Specifically the line "WDcosSum += WDcos400Hz[i] * input[i];" will give us different answers despite both the two input values being held constant.

We have a single interrupt being ran and was wondering if there was anything there that could be the issue, though I'm not seeing anything... plus it seems to be caused by a very specific lines in the interrupt c code itself (when commenting out the "for(int i = 0; i < 4; i++) {" section it seems to work fine). 

I've included the code performing the calculations and the interrupt code in the attached. I assume it is an issue with the registers coming into and out of the interrupt, and the same issue appears on multiple processors so I don't think it is hardware related. I can provide disassembly if needed. 

Has anyone experienced this before? I'm hope it is something I'm missing before needing to go to the disassembly level to try to trace this...

Attach.txt
================================> function performing the operations; all variables are global
float32_t waveformDistortion(float32_t * input)
{
   if(zWDinputCaptureFlag) {
      zWDinputCaptureFlag = 0;
      for(int i = 0; i < WD_NUMPOINTS; i++) {
         zWDinput[i] = input[i];
      }
   }
   WDsinSum = 0.0;
   WDcosSum = 0.0;
   WDsumOfSquares = 0.0;

   for (int i = 0; i < WD_NUMPOINTS; i++) {
      WDsinSum += WDsin400Hz[i] * input[i];
      WDcosSum += WDcos400Hz[i] * input[i];
      WDsumOfSquares += input[i] * input[i];
   }
   WDsinMean = WDsinSum * 2.0/WD_NUMPOINTS;
   WDcosMean = WDcosSum * 2.0/WD_NUMPOINTS;
   WDrms400Hz = SquareRoot(WDsinMean*WDsinMean + WDcosMean*WDcosMean) * 0.7071067812;
   WDrmsAll = SquareRoot(WDsumOfSquares / WD_NUMPOINTS);

   return SquareRoot(WDrmsAll*WDrmsAll - WDrms400Hz*WDrms400Hz) / WDrms400Hz * 100.0;
}

================================> interrupt C function
void foregroundProcess(void)
{
   ForegroundSymmComponents();
   estFreq = FreqPLL(&angle_PLL, &freqPLL_LPF, &VLPI_PLL, &Vxyz);
   for(int i = 0; i < 4; i++) {
      register volatile struct DacStruct* p = &DAC[i];
      register int tmpi;

      switch(p->type) {
      case NOT_USED:    // Likely catches most cases so put first for speed
         DacBuffer[i] = 0;
         break;
      case IEEE_FLOAT:
         if (p->zero == 0) {
            tmpi = (int)((*(float *)p->addr + p->offset) * p->gain);
            DacBuffer[i] = (unsigned int)max(min(tmpi,4095),0);
         }
         else {
            DacBuffer[i] = 2048;
         }
         break;
      case UNSIGNED_16:
         if (p->zero == 0) {
            tmpi = (int)(((float)(*(unsigned short*)p->addr) + p->offset) * p->gain);
            DacBuffer[i] = (unsigned int)max(min(tmpi,4095),0);
         }
         else {
            DacBuffer[i] = 0;
         }
         break;
      case SIGNED_16:
         if (p->zero == 0) {
            tmpi = (int)(((float)(*(short*)p->addr) + p->offset) * p->gain);
            DacBuffer[i] = (unsigned int)max(min(tmpi,4095),0);
         }
         else {
            DacBuffer[i] = 2048;
         }
         break;
      case UNSIGNED_32:
         if (p->zero == 0) {
            tmpi = (int)(((float)(*(unsigned int*)p->addr) + p->offset) * p->gain);
            DacBuffer[i] = (unsigned int)max(min(tmpi,4095),0);
         }
         else {
            DacBuffer[i] = 0;
         }
         break;
      case SIGNED_32:
         if (p->zero == 0) {
            tmpi = (int)(((float)(*(int*)p->addr) + p->offset) * p->gain);
            DacBuffer[i] = (unsigned int)max(min(tmpi,4095),0);
         }
         else {
            DacBuffer[i] = 2048;
         }
         break;
      default:    // Invalid type
         break;
      }
   }
   *(unsigned short*)(DAC_ADDRESS) = DacBuffer[0];
   *(unsigned short*)(DAC_ADDRESS + 2) = DacBuffer[1];
   *(unsigned short*)(DAC_ADDRESS + 4) = DacBuffer[2];
   *(unsigned short*)(DAC_ADDRESS + 6) = DacBuffer[3];
   if ( (StopForegndWatchdog != STOP_P1F_WATCHDOG) && !zStopPDSPWD0_10kHz) {
      *pREG_PORTE_DATA_TGL = BITM_PORT_DATA_PX15;
   }
} /* foregroundProcess */

================================> ISR branching to the C code
__TMZHI: // 0x2C: Timer Zero High Priority Interrupt
   jump ForegroundProcessHandler (db);
      nop; //BIT SET MODE1 0x000004F8; // enable secondary dags and work registers
      nop; 
   rti;
   
   <<snip>>
   
ForegroundProcessHandler:
#if 1 
BIT SET MODE1 0x000004F8; // enable secondary dags and work registers
nop;

   CJUMP foregroundProcess. (db);
      DM(i7,m7) = R2;
      DM(i7,m7) = PC;
      
   BIT CLR MODE1 0x000004F8; // disable secondary dags and work registers      
   nop; 
#else
#if defined(DEBUG) /* Toggle register for timing checking */
puts = R0;
R0 = 0x8000;
dm(REG_PORTE_DATA_TGL) = R0;
R0 = gets(1);
alter(1);
#endif
#endif   

   RTI (db);
      nop;
      nop;
ForegroundProcessHandler.end:


  • 0
    •  Analog Employees 
    on Aug 14, 2019 9:15 AM

    Hi,

    Apologies for the delay. Can you please let me know the answer for the below questions.

    1) Can you please explain your application in brief?
    2) What is the input given to these functions?
    3) Why are you using ISR to update DAC buffers? Is it possible to replace it as normal function?
    4) Can you able to use flag synchronization method to update DAC buffers from ISR and normal function?
    5) Can you share the minimal project to replicate the issue in our side?
    6) Is it possible for you to connect in simulator mode and check if you could see the similar issue? This is isolate any hardware related issues.
    7) Which version of CCES are you using?
    8) Can you let us know where the variables are mapped? Is it L1/L2/L3?
    9) In the below lines of code, is there any specific reason you are using 'register'? Can you attempt with normal declaration and see how it behaves?
        register volatile struct DacStruct* p = &DAC[i];
        register int tmpi;

    Regards,
    Anand Selvaraj.