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