I'm porting a program I wrote on a MKR1010 to the Nano ESP32 . This program has a class that requires a timer to operate and by default, the millis() "timer" is used. But if configured, the functions can be passed a different timer to use as a reference (time from a GPS receiver or RTS, etc.). To allow this dual use, I have the class functions written to use a pointer to a timer function which is defined when an object of the class is created.
The Problem
On the MKR1010, this behaved exactly as intended. But when porting to the Nano ESP32, I get this error: a value of type "unsigned long (*)()" cannot be assigned to an entity of type "uint32_t (*)()"
I went and checked the type of the millis() function on both the MKR1010 and Nano ESP32 and each are unsigned long. So with my current understanding, both boards should cause an error.
Why did my code work on the MKR1010 but not on the Nano ESP32?
Code
Highly simplified code but gets the same error. If I compile this with the MKR1010 board selected, there is no error. If I compile as Nano ESP32, I get the conversion error.
static uint32_t getTime()
{
return (millis() + 5); // This would be replaced with a call to whatever timer I happen to be using, millis() is here for simplicity
}
class EXAMPLE_CLASS
{
uint32_t (*refClock)();
public:
EXAMPLE_CLASS(uint32_t (*clock)()) { refClock = clock; }
EXAMPLE_CLASS() { refClock = millis; } //Compilation error: invalid conversion from 'long unsigned int (*)()' to 'uint32_t (*)()' {aka 'unsigned int (*)()'} [-fpermissive]
};
EXAMPLE_CLASS millis_timer;
EXAMPLE_CLASS custom_timer(getTime);
void setup() { }
void loop() { }
uint32_t is an unsigned 32-bit integer type. It is guaranteed to be exactly 32 bits wide, with a minimum range of 0 to 4,294,967,295 (2^32 - 1).
unsigned long is an unsigned integer type whose size can vary depending on the platform. On most modern systems, it is typically 32 bits or 64 bits wide.
Even if it's 32 bits, I guess the compiler is picky... as millis() returns an unsigned long, you should use unsigned long everywhere
I'm aware that unsigned long is not a rigidly defined size. I'm trying to understand why using uint32_t in the sketch uploaded to the MKR1010 (SAMD) board works fine (even though it may be incorrect) but uploading the same thing to the Nano ESP32 does not work.
unsigned long is four bytes on both the Nano ESP32 and the MKR1010
If you have any suggestions about how I should be handling this I'll also take those. I'm generally not a fan of using the "ambiguous" size datatypes because I don't want to design all of my functions to potentially handle different size variables.
Makes sense! Is this just like a generally known thing or is there a good way to understand what the complier settings are.
I found another issue where I had min(var1, 32) where var1 was a uint8_t. On the MKR1010 this worked fine, but on the Nano ESP32 the value 32 was being interpreted as an int. And apparently since min() is a template function both arguments have to be the same type so it failing. Had to manually cast the 32 to a uint8_t to make it work.
There are indeed different type related things biting you
min is usually the arduino macro so will work across types but it can be #undef
You just need to be more cautious and honor types as it’s important in C++
The warnings are your friends
I had a bunch more of those types of things that I had to fix. For whatever reason the MKR1010 settings don't show warnings for that stuff but sure enough all of them were real issues!
But even the warnings that I did get today weren't enough. The code would compile just fine but I had a few places where a function was non-void but didn't return a value and it would just outright crash the code and reset the board.
I found the button in the Arduino IDE to turn on verbose compilation messages but there's a lot of stuff in there that's unrelated to code issues. Do you know a reliable method to get the just the real warnings to show up?
A bug in my code or a bug in the compiler for not flagging it? My code was definitely wrong but it ran with no issues on the MKR1010.
I don't mean that the warnings aren't important. When I turned on verbose output in Arduino IDE there was a whole bunch of other messages that were unrelated to anything I'm doing.
Yes. Not returning anything when you made the promise to the compiler that the function would return something triggers an undefined behavior.. usually it’s caught by the compiler and you get a warning or error but sometimes (rarely) it does not see it.
Oh yeah, definitely was a mistake. I'm just interested in understanding why the bug had no impact on one platform but caused a fatal crash on the other.