Display Framerate?

Hey, I was wondering if there was a way to access a variable or something that would return the framerate Arduboy is running at. Like for example, for an fps display in the corner of the screen. Thanks.

I am not sure the Arduboy library exposes the current frame rate.

Typically it is controlled by the programmer - you set it during setup() using the setFrameRate() function. If you are not doing this, then the default is 60 FPS.

The easiest way to do what you want is to store the framerate into a variable and use it to both set the frame rate at he beginning of the game and to print the FPS on screen. You can change the variable and call setFrameRate() at any time if you want your game to speed up. Obviously, there is an upper limit where you code cannot complete fast enough and the FPS is actually lower than you think.

If you are trying to determine whether your code is completing in time, look at nextFrameDEV() which will give you a visual indication of slow code via the LEDs.

https://mlxxxp.github.io/documents/Arduino/libraries/Arduboy2/Doxygen/html/classArduboy2Base.html#a45c6a2b014749458b68f4866b274e033

2 Likes

Thanks, I will look into nextFrameDEV. :smile:

In addition to nextFrameDEV(), you can look at cpuLoad().

2 Likes

You can actually uncap the framerate by simply not using if(!arduboy.nextFrame()) return;,
because nextFrame contains all the framerate limitation logic.
But if you uncapped the framerate then you’d have to be careful about how your program is written.
Particularly any kind of time-dependent logic like physics simulation or responding to player input.

I can’t think of any reason to actually do this vs something like setFrameRate(150) or whatever our theoretical max is… Like you said easy to screw it up. :slight_smile: And you get the power saving stuff for free when using the frame rate stuff built-in.

I’m actually thinking that I should uncap the framerate, but as you said, pretty much every single thing that uses the framerate for timing would be screwed. If I was to theoretically uncap the framerate and make my games work like that, is there any way of still getting accurate timings for things like pausing for dialog boxes?

Why are you thinking that? On this hardware there isn’t really a reason to go over 60 FPS (that I know of).

If I was to theoretically uncap the framerate and make my games work like that, is there any way of still getting accurate timings for things like pausing for dialog boxes?

Count everything manually in millis(). Even things like getting input become complex with no frame rate pacing. Only polling for buttons each frame means you don’t have to worry about debouncing input, etc.

Thanks, I’ll look into it.

What are you hoping to achieve by uncapping the frame rate?

If I make a program that i want to run at maximum capacity, i would want to let it, not limit it.

1 Like

Even if your battery runs down in 1 hour or your screen melts? :stuck_out_tongue:

60 FPS is the gold standard for this kind of platform. Gameboy was 60 FPS. You’re just burning battery and making life harder on yourself by uncapping it… Also you only have so many pixels, so often limits the effective frame rate in any case unless your sprites are moving CRAZY fast.

It should be noted that not many games run at 60FPS on the Nintendo Switch, and the select few that do are either Nintendo’s first-party titles or low-resolution games that the developers can choose performance over graphics. The Nintendo Switch has quite some trouble running games at 60FPS at 720p, and unfortunately Fortnite will not be one of them. Read more

Seems even the switch can’t hit 60 FPS for some titles…


So if unless you just LIKE PAIN you should start by getting your game working at 60FPS and then see if you even have any CPU left over. :slight_smile: If not the whole discussion is irrelevant.

Technically whatever technique you use it won’t be millisecond-accurate anyway, whether the framerate is capped or uncapped.

Arduino’s millis() function will typically return an accurate number of milliseconds since the program started, so you can use it to make timers for doing roughly accurate timing.

Be aware that the timer will eventually overflow and reset to zero.
It would take ~50 days, so unless you’re making a virtual pet and putting the Arduboy into sleep mode it won’t be an issue, but it’s good to be aware anyway.

Why ~50 days?

millis is actually unsigned long millis(void), and an unsigned long on an AVR chip (like the Arduboy’s) is 32 bits, so it will overflow when 4294967296 milliseconds have elapsed.
That’s ~4294967.3 seconds, or ~71582.79 minutes, or ~1193.1 hours, or ~49.72 days.

There’s also unsigned long micros(void), which is more precise.
It’s probably more precise than you need and it will overflow much quicker (specifically in just over one hour), but I’ll mention it anyway.

I remember I actually wrote a millis-based timer once (probably because someone was asking something similar), but I can’t remember where I put it.

It’s not particularly difficult though. (Unless you need to take overflow into account.)
Something rudimentary like this should work:

class Timer
{
public:
	using TimePoint = decltype(millis());
	using Duration = decltype(Time(0) - Time(0));
	
private:
	TimePoint startTime;
	TimePoint currentTime;
	
public:
	Duration getElapsedTime() const
	{
		return (this->currentTime - this->startTime);
	}
	
	bool hasElapsed(Duration duration) const
	{
		return (this->getElapsedTime() >= duration);
	}

	void reset()
	{
		this->startTime = millis();
		this->currentTime = this->startTime;
	}
	
	void update()
	{
		this->currentTime = millis();
	}
};

There’s a relevant article here.

I’ve modified the code in it to demonstrate that Timer class I just threw together:

// Milliseconds of on-time
constexpr unsigned long onTime = 250;

// Milliseconds of off-time
constexpr unsigned long offTime = 750;

// LED pin index
constexpr int ledPin = 13;

// Current LED state
int ledState = LOW;

Timer timer;

void setup()
{
	// Set the digital pin as an output
	pinMode(ledPin, OUTPUT);

	// Reset the timer
	timer.reset();
}

void loop()
{
	// Update the timer
	timer.update();

	switch(ledState)
	{
		case HIGH:
			if(timer.hasElapsed(onTime))
			{
				// Reset the timer
				timer.reset();

				// Set the state low
				ledState = LOW;

				// Update the LED
				digitalWrite(ledPin, ledState);
			}
			break;
		case LOW:
			if(timer.hasElapsed(offTime))
			{
				// Reset the timer
				timer.reset();

				// Set the state high
				ledState = HIGH;

				// Update the LED
				digitalWrite(ledPin, ledState);
			}
			break;
	}
}

Bear in mind that the time being tested here is the time at the start of the loop,
so the duration being measured is the duration between the start of one loop to the start of the next.

Dealing with time can get tricky because varying amounts of time pass between each line of code, so where (or when?) you take a time reading becomes part of the code’s logic and can have an impact on the code’s behaviour.

Good point. I think I will probably only need to use nextFrameDev() anyway. And cpuLoad() will definitely be useful for displaying the data. Thanks for all the useful responses!

Remember nextFrameDEV() is really only intended to be used when developing and you want the feedback via the LED. Once you have completed your coding and testing, flip back to the ‘proper’ function nextFrame().

1 Like

I will. :wink: