Is there any way that, with an AVR arduino (atmega328p, or something in the older ATTiny series'), one can count the clock cycles without using the timer0, timer1 or timer2 peripherals? If one is using all the timers for PWM generation for example, is there any way one can still have some variable present which can be queried from the code and which counts up as the chip runs? Doesn't need to be perfectly accurate, but does need to be workable for much shorter timescales than the fastest which the watchdog timer can give interrupts at.
That is to say, is there any feature in the AVR chips which keeps count of the clock cycles since the device was powered on, such that with some function call, or reading out of a 4 byte or 2 byte variable which the system internally iterates up with each clock cycle, one can read that time since startup. In particular this would continue to time during interrrupt service routines, or during other times when interrupts have been disabled, although it would only need reading out from during normal "loop" code execution. So the not-one-of-the-timer-peripherals "timer" function which you'd be reading would give you the actual time passed since startup (subtract from previously read out times to give intervals ofcourse, and rolling over is easily tolerated thereby) , including time spent in interrupts and such.
One clear use case for this is something where, upon each iteration of the main loop you want to enter a while loop and stay there until say 400us has passed compared to a previous time which you noted down in a variable at an earlier point. If there have been interrupts which have made the main loop slower than normal then the waiting period in the while loop should be cut shorter than normal so as to maintain the 400us timing, if interrupts have occured sufficiently that by the time the while loop starts the program is already "late" for its deadline then it just accepts that and skips waiting (it is NOT expected to anything in future iterations to compensate for the extended wait).
Effectively this is about whether there's a way to get micros() like functionality but using the atmega's own counting of its clock cycles rather than having to use a timer peripheral to do so, it doesn't have to report the result in microseconds though, in clock cycles or some small multiple thereof would be fine.
Unfortunately, no.
Note that using a timer for PWM does not necessarily prevent it from providing tick-information at a higher resolution, using some math between interrupt counts at overflow/top and TCNT values. (This is how micros() works off of timer0 in Arduino, even though it's also used for PWM.)
An ATmega328PB is mostly ATmega328P compatible, and has two extra 16bit timers...
That is not a clear use case at all. The behavior you described is properly accomplished using standard Arduino millis() / micros() based timing techniques. If for example, your loop() code needs to do "something" every 400us, and only 300us have passed since it last did it's "something", there's no reason to wait in a while loop for 100us. Just let the loop() function cycle around and check the elapsed time on every iteration.
I think the OP is looking for something similar to what the Teensy has. On the Teensy there is a 32 bit wide register that automatically increases every clock cycle. This can be read using the macro ARM_DWT_CYCCNT. A read of the register is cheap, only a couple clock cycles . It also does not use any interrupts.
The 8 bit avrs do not have a clock cycle register. I think the closest you could get is by using timer1 without a prescaler.