I’d like to run an interrupt at a specified time interval.
Does the Pokitto have a spare hardware timer that I could hijack to do this?
I’d like to run an interrupt at a specified time interval.
Does the Pokitto have a spare hardware timer that I could hijack to do this?
It has 5 timers: SysTick, CT16B0, CT16B1, CT32B0, CT32B1.
EDIT: Also, there’s SCT0 and SCT1, but I don’t know anything about those yet.
Presumably the 16 and 32 refer to the bit size of the timer?
(In which case I think I can get away with CT16B0 if it can be reset.)
Is there somewhere where these are documented?
Yes, they’re in the UM10732 user manual pdf. Might also want to look at HWSound.cpp.
The main question is: at what interval?
About 16ms.
(I mentioned to you in a PM earlier what my intended use is for them.)
Essentially I want to time it so the screen is drawn at a timed interval,
regardless of what the actual code is doing.
Timer sounds interesting, surely it’s for either gfx or audio?..
Eh, I can’t be bothered with being secretive, may as well come clean.
It’s for the Arduboy2 port.
I’ve figured out the details of how invert
, flipVertical
, flipHorizontal
, allPixelsOn
etc work, and they work independently of when display
is called because they change the behaviour of the actual screen itself.
So essentially I intend to try to emulate the screen’s behaviour by keeping a fake ‘hardware buffer’ and writing it to the Pokitto’s buffer at a timed interval to mimic the screen’s refresh rate.
That way if there are any games that use those functions without calling display
and/or any games that use lots of separate loops instead of just sticking to a single loop and a state machine, then those games will still work as they do on the Arduboy.
(I’ve already got the double buffering mechanism figured out. Two buffers, two pointers.)
For that kind of resolution (16ms) you should not (have to) go into hardware level timer setting
Just use mbed::Ticker https://os.mbed.com/handbook/Ticker
Two buffers? If a game doesn’t clear every frame, when it reads from the buffer it would get stale data, and since they’re packed together, writing a pixel means reading 7 other pixels.
I’m slightly concerned about the “No blocking code in ISR: avoid any call to wait, infinite while loop or blocking calls in general.”.
I haven’t measured my rendering code’s speed but I think it’s between 5 and 10 milliseconds which might be a bit much.
I won’t know until I try though, and this certainly looks a lot easier than all the NVIC_SetVector
, NVIC_EnableIRQ
, Chip_TIMER_Init
etc stuff, thanks for the suggestion.
Technically it’s 4 buffers:
sBuffer
Then I have an activeBuffer
pointer and a passiveBuffer
pointer.
The activeBuffer
points to the buffer that the IRQ uses to paint to the Pokitto’s screen buffer (before calling Display::update
) and the passiveBuffer
points to the buffer that Arduboy2’s sBuffer
is copied to before swapping the pointers (in Arduboy2Core::display
).
That way if the IRQ fires in the middle of sBuffer
being copied to passiveBuffer
then you won’t get any tearing because the data to be pushed to the Pokitto’s screen buffer will be pulled from activeBuffer
.
Also I need at least one hardware buffer to properly implement allPixelsOn
anyway, so this kills two birds with one stone.
allPixelsOn
actually bypasses the hardware buffer so when you disable it the contents of the hardware buffer are written back to the screen.
Interrupts are disabled inside an interrupt, so that’s going to interfere with audio and skew the other timers.
No means of interrupt chaining?
That’s unfortunate. I’d best do some measurements.
If it’s too long I may be able to hack the time down.
To be honest I think 95% of games would be fine even if I didn’t do this.
But if something’s worth doing, it’s worth overdoing.
More like 99.5%. I only remember Evade 2 and @eried’s Back to the Jungle using these effects.
@pharap and @FManga - mbed::ticker is just an mbed extension of systick. Afaik it won’t stop hardware interrupts.
Just try it
In that case if I can’t pull it off then it shouldn’t be too much of an issue.
And remember, it’s only an issue for games that don’t call display
after using those effects, I’d bet Back to the Jungle does.
(I actually contributed some small typo fixes for Back to the Jungle so I remember it relatively well.)
I’m definitely going to try it regardless.
I tested the time.
beforeTime = Pokitto::Core::getTime();
arduboy.display();
afterTime = Pokitto::Core::getTime();
Definitely 10ms.
I could probably cut that down if I really wanted to - I’m using 3 nested loops at the moment, the 3rd of which could easily be unrolled if need be.
I’m not rushing to optimise the code unless it’s really needed though.
Optimising further would begin to sacrifice readability.
The good new is that it works.
The bad news is that it slows down gameplay considerably so it’s unviable.
So for the sake of 3% of games I think I’m going to forgo making it exact.
I think it’s strange how it’s fast enough when it’s called once every 16 ms through sequential code but not when ran through the timer.
But knowing that it would have worked if it weren’t for the slowdown problem is probably good enough for me.
Although…
Know I think about it I do still have one trick up my sleeve…
What if, instead of having a constant timer all the time I:
Arduboy2::display
being calledIt might just work maybe?
This is one of those things where you should not jump into conclusions.
There are n ways of implementing a timer / interrupt and each has its good and bad sides and 5-10x differences in overhead
Are you saying I should now attempt the NVIC_SetVector
, NVIC_EnableIRQ
, Chip_TIMER_Init
etc stuff?
Based on a fairly simple test it looks like it does work.
But the code I’ve got for it is a bit ugly and disorganised at the moment because I’ve tried to make too many changes at once.
I’m going to reorganise my code a bit before attempting to implement these functions properly.
And I think I’ll implement the 95% version first and come back to the timer approach after stress testing.
At least I now know of a way that seems to work.
No. You need to think of all the timing related actions, their order of priority and the necessary resolution. If you implement your own SysTick, you need to disable the SysTick provided by mbed. Then mbed::Timer and mbed::Ticker can no longer be used. Then you’d need to provide an alternative implementation for getTime etc etc etc.
Bottom line is that if you can manage with the mbed HAL (hardware abstraction layer) you should use it. But if you need to go faster (less latency) and you hijack any of the timers, you need to take care of other things that may be dependent on that timer (pwm, audio)