[Solved] Is there a spare timer on the Pokitto that I can hijack?

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.

  • SysTick is used for time keeping.
  • CT32B0 is used for sound
  • AFAIK, the other 3 are free

EDIT: Also, there’s SCT0 and SCT1, but I don’t know anything about those yet.

1 Like

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.

1 Like

The main question is: at what interval?

1 Like

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.

1 Like

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.)

3 Likes

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

1 Like

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. :thinking:

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:

  • Arduboy2’s sBuffer
  • Pokitto’s screen buffer
  • Fake OLED buffer 1
  • Fake OLED buffer 2

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.

1 Like

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.

1 Like

More like 99.5%. I only remember Evade 2 and @eried’s Back to the Jungle using these effects.

1 Like

@pharap and @FManga - mbed::ticker is just an mbed extension of systick. Afaik it won’t stop hardware interrupts.

Just try it

2 Likes

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.

1 Like

@jonne & @FManga

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:

  • enable a temporary timer when any ‘screen changing’ function is activated
  • somehow delay it if multiple ‘screen changing’ functions are called in quick succession
  • disable it either upon firing or upon Arduboy2::display being called

It 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.


Thank you @jonne and @FManga for your suggestions.

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)