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.
Hi folks,
I have a project that is based on a digital power library example, it uses the ASM ISR triggeredd periodically from a PWM to call macros to perform actions (such as read ADC).
I have added a long call (asm: LCR) to a C function that I hope would calculate some RMS measurements for me. This C function is an adaption of the TI SolarLib sine_analyser_with_pwr function.
For the most part my adaptions are just stripping out bits that I didnt need. However if this function is called from the ASM ISR this causes and illegal ISR to be vectored.
I have tracked this down to the IQ functions used within the sine analyser function (i.e. _IQ15rsmpy) but dont understand why this should be the case or how I could solve the issue...
Usage of IQ functions work correctly in other parts of my project that are not called from the ASM ISR, so I guess that there is some issue in the way the IQ functions get called in this case?? Anyone any knowledge why this should be the case??
Thanks
The relevant portion of the ASM ISR:
_DPL_ISR: ;(13 cycles to get to here from ISR trigger) ;CONTEXT_SAVE PUSH AR1H:AR0H PUSH XAR2 PUSH XAR3 PUSH XAR4 ;-- Comment these to save cycles -------- PUSH XAR5 PUSH XAR6 PUSH XAR7 ;---------------------------------------- PUSH XT NOP ;---------------------------------------- MOVW DP, #tsPtr CMP @tsPtr, #2 B TS2, EQ TS1: INC @tsPtr ;... Run some DPLib macros here LB TS_END TS2: ;... Other DPLib macros ADCDRV_1ch 12 LCR _updateSineAnalysis ; Run the function 'updateSineAnalysis()' CNTL_2P2Z 6 ;... Other DPLib macros MOVW DP, #tsPtr MOV @tsPtr,#1 TS_END: ;... ;---------------------------------------- ;=================================== EXIT_ISR ;=================================== ; Interrupt management before exit MOVW DP,#_EPwm1Regs.ETCLR MOV @_EPwm1Regs.ETCLR,#0x01 ; Clear EPWM1 Int flag MOVW DP,#_PieCtrlRegs.PIEACK MOV @_PieCtrlRegs.PIEACK, #0x4 ; Acknowledge PIE interrupt Group 3 ; Restore context & return POP XT ;-- Comment these to save cycles --- POP XAR7 POP XAR6 POP XAR5 ;----------------------------------- POP XAR4 POP XAR3 POP XAR2 POP AR1H:AR0H IRET
The altered sine analyser code:
typedef struct { int32_t Threshold; /* Input: Voltage level corresponding to zero i/p. */ int32_t sum_v_sq; /* Internal: Running sum for Vacc_rms calculation over one sine cycle. */ int32_t sum_i_sq; /* Internal: Running sum for Iacc_rms calculation over one sine cycle. */ int32_t vin_norm; /* Internal: Normalised value of the input voltage. */ int32_t iin_norm; /* Internal: Normalised value of the input current. */ int32_t inv_nsamples; /* Internal: 1/( No of samples in one cycle of the sine wave). */ int32_t inv_sqrt_nsamples; /* Internal: SQRT(1/( No. of samples in one cycle of the sine wave)). */ uint32_t nsamples; /* Internal: No of samples in one cycle of the sine wave. */ uint32_t nsamplesMin; /* Internal: Lower-bound for no of samples in one sine wave cycle. */ uint32_t nsamplesMax; /* Internal: Upper-bound for no of samples in one sine wave cycle. */ uint16_t prev_sign; /* Internal: Flag to detect ZCD. */ uint16_t curr_sign; /* Internal: Flag to detect ZCD. */ } sineAnalyserContext_t; #pragma DATA_SECTION (saContext, "SANAL_1ch_Struct") volatile sineAnalyserContext_t saContext; volatile int32_t *SANAL_1ch_VIn = 0; /* Analyser voltage input terminal. */ volatile int32_t *SANAL_1ch_IIn = 0; volatile int32_t *SANAL_1ch_VRms = 0; volatile int32_t *SANAL_1ch_IRms = 0; void updateSineAnalysis (void) { if (*SANAL_1ch_VIn > saContext.Threshold) { /* If the voltage is above the threshold, save the value and the sign. */ saContext.vin_norm = _IQtoIQ15(*SANAL_1ch_VIn); /* Take a sample from the voltage. */ saContext.iin_norm = _IQtoIQ15(*SANAL_1ch_IIn); /* Take a sample from the current. */ saContext.curr_sign = 1; /* Flag the current sign as positive. */ } else { /* If the voltage is below the threshold, save the absolute value and record the sign. */ saContext.vin_norm = _IQ15abs(_IQtoIQ15(*SANAL_1ch_VIn));/* Take an absolute sample from the voltage. */ saContext.iin_norm = _IQ15abs(_IQtoIQ15(*SANAL_1ch_IIn));/* Take an absolute sample from the current. */ saContext.curr_sign = 0; /* Clear the current sign flag. */ } if((saContext.prev_sign != saContext.curr_sign) && (saContext.curr_sign == 1)) { /* If the voltage has crossed the threshold going positive then the sample window is finished. */ /* Invert the number of samples, N (IQ15). */ saContext.inv_nsamples = _IQ15div(_IQ15(1.0), (saContext.nsamples << 15)); /* Get 1/√N (IQ15). */ saContext.inv_sqrt_nsamples = _IQ15isqrt(saContext.nsamples << 15); if(saContext.nsamplesMin < saContext.nsamples < saContext.nsamplesMax) { /* If N is valid, i.e. if there were no spurious samples before the threshold was crossed, calculate * the RMS values for the sample window. */ /* V_RMS = √∑V_2(N) / √N. */ *SANAL_1ch_VRms = _IQ15toIQ(_IQ15mpy(_IQ15sqrt(saContext.sum_v_sq), saContext.inv_sqrt_nsamples)); /* I_RMS = Round(√∑I_2(N) / √N). */ *SANAL_1ch_IRms = _IQ15toIQ(_IQ15rmpy(_IQ15sqrt(saContext.sum_i_sq), saContext.inv_sqrt_nsamples)); } else { /* Else if there are spurious samples they are most likely noise, so zero all results. */ *SANAL_1ch_VRms = 0; *SANAL_1ch_IRms = 0; } /* This sample window is finished so tidy up ready for the next sample window. */ saContext.prev_sign = saContext.curr_sign;/* Save the just used current sign state, ready for the next iteration. */ saContext.sum_v_sq = 0; /* Clear the summed voltages total. */ saContext.sum_i_sq = 0; /* Clear the summed currents total. */ saContext.nsamples = 0; /* Clear the number of samples. */ } else { /* Else the sample window is ongoing... */ saContext.nsamples++; /* Increment the sample count to show the total number of samples so far (n). */ /* Sum the voltage square with previous squares: ∑V_sq(n) = ∑V_sq(n) + round(V(t)^2). */ saContext.sum_v_sq = saContext.sum_v_sq + _IQ15rsmpy(saContext.vin_norm, saContext.vin_norm); /* Sum the current square with previous squares: ∑I_sq(n) = ∑I_sq(n) + round(I(t)^2). */ saContext.sum_i_sq = saContext.sum_i_sq + _IQ15rsmpy(saContext.iin_norm, saContext.iin_norm); /* Save the just used current sign state, as the previous sign for the next iteration. */ saContext.prev_sign = saContext.curr_sign; } }