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.

IQ functions cause Illegal ISR when called from ISR

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