volatile uint32_t global_prev = 0; volatile uint32_t global_now = 0; volatile uint32_t global_ok = 0; void setup() { Serial.begin(115200); while(!Serial); Serial.println("Start"); HardwareTimer timer(TIM2); if (true) { // This testcase tries to trigger a problem in stm32duino // getMicroseconds(), where: // - A systick overflow happens between HAL_GetTicks() and the // reading of the systick VALUE, and // - Another ISR that uses micros() and thus clears COUNTFLAG // triggers between the overflow and checking COUNTFLAG. // // This picks a timer overflow value that is big enough to leave CPU // time for other things, small enough to occur often enough so it // will also occur at the right time hopefull, and a prime number to // hopefully it will occur at different moments in the loop each // time (rather than the same, maybe wrong moment). Though loop, // timer interrupt and systick interrupt all need specific relative // timings, so even if this is shares no divisors with the loop and // systick timings, the loop and systick might still be divisible // and settle into a rhythm that never triggers the problem... timer.setOverflow(449 /* prime */); timer.attachInterrupt([]() { micros();}); timer.resume(); uint32_t prev = 0; uint32_t ok = 0; while(true) { uint32_t now = micros(); if ((int32_t)(now - prev) < 0) { Serial.print("OK: "); Serial.println(ok); ok = 0; Serial.print("BACKWARDS: "); Serial.print(prev); Serial.print(" -> "); Serial.println(now); } else { ++ok; } prev = now; } } else { // This testcase tries to trigger a problem in stm32duno // getMicroseconds() where: // - A systick overflow happens between HAL_GetTicks() and the // reading of the systick VALUE // when called with the systick ISR disabled (PRIMASK set, or from a // high-priority ISR), which is not handled properly. Serial.print("SysTick LOAD (should be 83999): "); Serial.println(SysTick->LOAD); // This value is a little less than the systick period (tested with // 84Mhz), so there is one ISR per systick overflow and because this // value is prime (absolute, so also relative to the systick // period), it tries every timing relative to the systick eventually // (84000 different ones, one each ms, so after 84s it has done an // exhaustive search, but because the value is not 84000-1, but a // little less, and the window for this problem is not 1 but a // little more, it will find some problematic timings earlier. timer.setOverflow(83911); timer.setInterruptPriority(0, 0); timer.attachInterrupt([]() { global_prev = micros(); global_now = micros(); ++global_ok; }); timer.resume(); uint32_t ok = 0; while(true) { __disable_irq(); auto now = global_now, prev = global_prev, ok = global_ok; __enable_irq(); // Check that the micros captured by the ISR does not run backward if ((int32_t)(now - prev) < 0) { // Only print once for each error case global_now = global_prev; global_ok = 0; Serial.print("OK: "); Serial.println(ok - 1); Serial.print("BACKWARDS: "); Serial.print(prev); Serial.print(" -> "); Serial.println(now); } } } } void loop() {}