Multithreading with Protothreads, Arduino_Threads

no it is no nightmare. All the calculation-code can be kept together in one single function
if you like this "main"- CalcHeading-function calls multiple sub-functions

The difference is that a non-blocking coding style does
quickly jump_in / jump_out of the function proceeding over time

If you use a state-machine the state-machine controls the proceeding through all the calculation steps

in your code right now you use afor-loop and inside a while-loop

for (int i=1;i<=N;i++)
   { 
      while (!IMU.accelAvailable());
      IMU.readAccel(x, y, z);
      averX += x; averY += y;  averZ += z;
   }

the state-machine stays in one state that does check

if  (IMU.accelAvailable()) {
  state = readAccel; // if available move to next state
}
break;

the state "readAccel" does

      IMU.readAccel(x, y, z);
      averX += x; averY += y;  averZ += z;
      state = theFollowingUpState; // proceed to next state / or increment variable **i**
      break;

and so on and so on
this means your code is calling that one and only function calcHeading()
but jumps in does one single step of calculation and then jumps out again
to do other things that run through quickly
and then the function calcHeading() is called again
.
jumps in does one single step of calculation and then jumps out again
to do other things that run through quickly
.
jumps in does one single step of calculation and then jumps out again
to do other things that run through quickly
.
jumps in does one single step of calculation and then jumps out again
to do other things that run through quickly
.
always proceeding through all the calculation-steps
by changing the state-variable to the next state if the next condition to move on becomes true

conditions like
IMU.accelAvailable()
IMU.gyroAvailable()
and at some states you increment a variable like in
for (int i=1;i<=N;i++)
but not as a for-loop but as a repeated call of the CalcHeading-function

In some situations you might find it useful to have a second state-machine that gets called from the first state-machine

The code will be still easy to understand if you give all states names that describe spot-on what the state is doing

and again:
all the calculations are kept together in one single function

void loop() {
  Jump_in do one calculation-step jump_out;
  checkTrigger();
  // end of void loop() jump up to top of void loop()
}

here are some pictures that visualise it

best regards Stefan