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.

CODECOMPOSER: Use of volatile with CLA and CPU interrupts

Part Number: CODECOMPOSER

Hello, I have a compiler question about using volatile with variables shared between the CPU and CLA. I've constructed a simple example which has three files:

cla_shared.c declares two float variables, one in the cla-to-cpu message RAM, the other in the cpu-to-cla message RAM:

// cla_shared.c

// shared variables with cpu
// in cpu2cla message RAM
#pragma SET_DATA_SECTION("SCRATCH_CPU1TOCLA1")
volatile float iir_input_cpu2cla=0;
// in cla2cpu message RAM
#pragma SET_DATA_SECTION("SCRATCH_CLA1TOCPU1")
volatile float iir_output_cla2cpu;

clatasks.cla has the CLA task 1 code. The CLA task takes iir_input_cpu2cla and passes it through an IIR filter, the output of which is iir_output_cla2cpu:

// clatasks.cla

// shared variables with cpu
// in cpu2cla message RAM
extern volatile float iir_input_cpu2cla;
// in cla2cpu message RAM
extern volatile float iir_output_cla2cpu;
// local variables for CLA only
float IIR_SR[6];
float IIR_B[4];
float IIR_A[4];

// cla task 1 is triggered by ePWM interrupt
interrupt void Cla1Task1(void) {
    iir_output_cla2cpu = iir_input_cpu2cla*IIR_B[0] + IIR_SR[5];

    IIR_SR[4] = iir_input_cpu2cla*IIR_B[1] + iir_output_cla2cpu*IIR_A[1] + IIR_SR[3];
    IIR_SR[5] = IIR_SR[4];

    IIR_SR[2] = iir_input_cpu2cla*IIR_B[2] + iir_output_cla2cpu*IIR_A[2] + IIR_SR[1];
    IIR_SR[3] = IIR_SR[2];

    IIR_SR[0] = iir_input_cpu2cla*IIR_B[3] + iir_output_cla2cpu*IIR_A[3];
    IIR_SR[1] = IIR_SR[0];
	
	// trigger the CPU ISR
	CLA_forceSoftwareInterrupt(CLA1SOFT_IN_REGS, 1);
}

cpuisr.c has the cpu ISR code. Every iteration it changes iir_input_cpu2cla (making a sine wave), and then executes some functions based on the values of both iir_input_cpu2cla and iir_output_cla2cpu:

// cpuisr.c

// shared variables with cpu
// in cpu2cla message RAM
extern volatile float iir_input_cpu2cla;
// in cla2cpu message RAM
extern volatile float iir_output_cla2cpu;
// cpu-only variables in GSRAM
float time=0.0;

// CPU ISR is triggered by CLA task 1, software force interrupt
interrupt void CPU_ISR(void) {
	time+=1.0;
	iir_input_cpu2cla=sin(idx*2*3.14159/1000.0);
	if(iir_output_cla2cpu>0.5) {
		// stuff depending on iir_output_cla2cpu
	}
	if(iir_output_cla2cpu<-0.5) {
		// stuff depending on iir_output_cla2cpu
	}
	if(iir_input_cpu2cla>0.5) {
		// stuff depending on iir_input_cpu2cla
	}
	if(iir_input_cpu2cla<-0.5) {
		// stuff depending on iir_input_cpu2cla
	}
	// ack the pie
	PieCtrlRegs.PIEACK.all = PIEACK_GROUP11;
}

The CLA task is triggered periodically (by an ePWM interrupt, for example). At the end of the CLA task, it triggers the CPU ISR via CLA_forceSoftwareInterrupt(). Therefore the CLA task and CPU ISR execute in lock step. Let's assume that the CPU ISR always returns before the next CLA task starts, meaning that they never execute simultaneously.

My question is whether making the shared variables iir_input_cpu2cla and iir_output_cla2cpu volatile is necessary/appropriate. If I know that the task/ISR will never execute while the other is running, then there's no risk of either variable changing in between accesses. But if the variables are qualified as volatile then I worry that performance will be impacted by unnecessary RAM accesses. For example, ClaTask1 only needs one read from iir_input_cpu2cla and one write to iir_output_cla2cpu, but volatile might cause the generated code to read each an extra three times. Similarly CPU_ISR should only need one write to iir_input_cpu2cla and one read of iir_output_cla2cpu, but volatile might cause each to be read two extra times.

But if remove the volatile qualifiers, is there a risk that the they won't be read at all?

Regards,

Mike

  • For a volatile variable, the compiler is required to generate code which assumes that variable may be read or written, by some other means in the system, at any time.  Suppose there is a range of statements where you know that is not possible.  Just before that range of statements, copy the volatile variable into a normal local variable.  In that range statements, use the normal local variable instead.  After that range of statements, copy that normal local variable to the volatile variable.

    Thanks and regards,

    -George

  • Hi George, thanks for the quick response.

    I also had considered copying the volatile variables in the message RAM to non-volatile local variables as a workaround. Sounds like a very safe method, but is there any other way? In my actual code, there are quite a few of the shared variables, and the time for copying all of them at the start and end the ISR/task is pretty significant.

    Regards,

    Mike

  • Maybe this idea makes it practical ... Collect all the shared variables into a structure.  Create two instances of structure.  One is volatile, the other is not.  Copy between them as needed.  Implement the copy with simple structure assignment ...

    non_volatile_instance = volatile_instance;

    Rely on the compiler to optimize that copy.  

    Thanks and regards,

    -George