Why is the waitcnt getting caught in the 53 second loop?
SRLM
Posts: 5,045
I'm converting the Eddie.spin file to C++, and this loop is problematic for me:
NextCNT := PROCESSRATE + cnt repeat while (rxcheck := Term.rxcheck) < 0 ' Read a byte from the command UART LoopCount++ if KeepAlive and LoopCount > constant(_clkfreq / PROCESSRATE)' Stop motors if no com in one second ifnot PDRunning outa[24..19]~~ waitcnt(constant(_clkfreq / DIVISOR) + cnt) SetPower[LEFT_MOTOR]~ SetPower[RIGHT_MOTOR]~ StillCnt~ Mode := POWER else waitcnt(NextCNT += PROCESSRATE) InputBuffer[InputIndex++] := rxcheckIn Spin, PROCESSRATE is 5000 (CLKFREQ/16000). Spin2cpp generates the following code:
Nextcnt = (Processrate + CNT); Term.Str((int32_t)"Here outer loop!"); while ((Rxcheck = Term.Rxcheck()) < 0) { Term.Str((int32_t)"Here2!"); (Loopcount++); if ((((uint8_t *)&dat[955])[0]) && (Loopcount > 0x3e80)) { if (!(((uint8_t *)&dat[954])[0])) { OUTA = ((OUTA & 0xfe07ffff) | 0x1f80000); } waitcnt((0x186a00 + CNT)); ((int32_t *)&dat[408])[Left_motor] = 0; ((int32_t *)&dat[408])[Right_motor] = 0; ((uint8_t *)&dat[436])[0] = 0; ((uint8_t *)&dat[438])[0] = Power; } else { waitcnt((Nextcnt = (Nextcnt + Processrate))); } } ((uint8_t *)&dat[439])[((*(uint8_t *)&dat[949])++)] = Rxcheck;In the C++ version I have to increase Processrate to about 75000 so that it doesn't hang in the waitcnt. I'm compiling with -mcmm and -Os. Is it really that much slower?
Comments
I see you've inserted some debug prints into the C++ version. Those will obviously take more than 5000 cycles to execute, so again Nextcnt is going to have to be updated after them.
The debug points do slow down the code, but it exhibits the same locking behavior in C++ without them.
__attribute__((fcache)) void somefunction() {}
Functions should be small to use fcache.
In a related point ....
Looking at built-in waitcnt code generation, it looks like CNT is loaded before adding the offset. This is not optimal.
This would be better.
That's not a part of the waitcnt code generation, though, it's the code generation for the expression "CNT + PROCESSRATE" inside waitcnt(CNT+PROCESSRATE). waitcnt itself just takes a single argument, and the code generation for it has no way of knowing how that argument was obtained.
waitcnt2() takes two arguments, and is probably better for most purposes.
Eric
Original statement: waitcnt(period+CNT); The order of the sum does not have any affect.
It's really too bad that we can't just do the right thing though because people historically have tripped over the order in which parameters are placed before waitcnt is executed.
Seems like in this case at least that the builtin waitcnt is not of much value to anyone wanting the smallest possible wait, and should be replaced with an appropriate in-line asm. Fortunately we have the power to do that.
As has recently happened to me. Of course this epiphany most likely didn't help solve the original question though.