lincomatic / open_evse

Firmware for Open EVSE

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

PlatformIO vs Arduino IDE: same binary firmware?

jbakuwel opened this issue · comments

Hi Glyn,

PlatformIO and Arduino IDE generate different firmware.hex files from openenergymonitor/open_evse. Is that to be expected or am I missing something?

dev@openevse-dev:~/OpenEVSE/eu/open_evse$ ls -al firmware/open_evse/*.hex
-rw-rw-r-- 1 dev dev 88565 Aug 25 22:14 firmware/open_evse/open_evse.ino.standard.hex
-rw-r--r-- 1 dev dev 88016 Aug 25 22:14 firmware/open_evse/open_evse.ino.with_bootloader.standard.hex

dev@openevse-dev:~/OpenEVSE/eu/open_evse$ ls -al .pio/build/openevse/*.hex
-rw-rw-r-- 1 dev dev 87821 Aug 25 22:05 .pio/build/openevse/firmware.hex

Jan

PlatformIO has its own compiler setup, which is hard to control. See the README file for information on which compiler I use and why.

@lincomatic I would be interested to know why you think that, has its own compilers, yes, hard to control, absolutely not. You can use semantic versioning and explicit links on virtually every dependency. You could even fork the platform definitions and have exact control over every aspect of the build environment.

@lincomatic I did read the README a while ago. It seems though that everyone has their own preferences for tool(s) to use, and I trust for good reasons either way :-). In the open source world that is a Great Good (tm). Me thinks anyway. It would be great if we can have both Arduino IDE and Platform IO (assuming they use the same (versions of the) libraries generate the same binary. Or putting it another way: if they yield different results, we'll likely have to spend time in the future figuring out why things don't work or work differently depending on which build environment was used.

My question was mostly for @glynhudson ... I used the openenergymonitor/open_evse repository to compile and got three different results: one binary @glynhudson kindly made for me with one change in a constant and the two binaries I compiled myself (with the same change of course): one with Platform IO, one with Arduino IDE.

I can understand that two build environments produce different results (maybe the linker puts code in a slightly different order) but I would not expect to have three different binaries.

I'm also learning how all this is put together and think everyone here has done a fantastic job producing something very useful. I'd like to contribute one day but have some learning to do first and also would need to understand how the development repo (lincomatic) relates to the two production repos, ie. how changes propagate from one to the other (I assume that's done manually?). I think it makes sense I learn to work with the systems you good folks have put together.

Please address your questions about other repos directly to those repos.

I am the originator and maintainer of the OpenEVSE firmware. My development branch serves as the feeder for the "official" OpenEVSE builds. Any new features or bug fixes are added to my repo. Others decide when it's time to update their own forks w/ my changes, tailored to their needs.

As for why the binaries are different, more important than the linker are the underlying compilers and libraries. Arduino IDE lets you manually select exactly which version you want to use. You can use whatever environment you like for development. Personally, I use Visual Studio+vMicro, because it's a much more powerful development platform than Arduino. But I always make my release builds w/ a well-tested toolchain, currently, the one that I used for UL certification, because the safety code has been thoroughly tested with it. Use of any other version of the toolchain actually nullifies the UL certification.

@lincomatic I would be interested to know why you think that, has its own compilers, yes, hard to control, absolutely not. You can use semantic versioning and explicit links on virtually every dependency. You could even fork the platform definitions and have exact control over every aspect of the build environment.

@jeremypoulter OK, I'm haven't used PIO enough to dig into manual control of the toolchain. As a newbie user, when I tried it last year, I didn't see an easy way to configure it to stick with a specific toolchain. If you have a config file that can force it to use a specific toolchain, I'd love to play w/ that. In particular, if you can get it to use Arduino's v1.6.15 toolchain & libs that I used for UL, that would be terrific.

On more than one occasion, besides the niggling details of compiler errors popping up when upgrading to a new version of toolchain, the optimizer has broken my code. An example is when the watchdog was completely broken, because a newer compiler optimized out my initialization code. I sometimes have to change the code to work around compiler bugs between versions. Timings can also change. The EVSE firmware is for safety. It's risky to switch compilers and libs (which is why I include all of the 3rd party libs in the my code that I've already tested), because the behavior can often change in ways that are very difficult to detect.
Sorry for being a stickler on this topic.. as I've stated elsewhere before, UL actually certifies a device based on an object file, and they require documentation, including the reasons for changing to a different toolchain version, as well as retesting, even if the code doesn't change.

@lincomatic for an example of specifying an explicit version have a look at https://github.com/arendst/Sonoff-Tasmota/blob/development/platformio.ini#L51. Can take a look at exactly matching the Arduino compilers. Is just the same version of GCC sufficient, or does it have to be exactly the same compilers? If the latter that would kind of also imply that the firmware would also need to be built on a particular OS, so I would assume just the same version is good?

@lincomatic for an example of specifying an explicit version have a look at https://github.com/arendst/Sonoff-Tasmota/blob/development/platformio.ini#L51. Can take a look at exactly matching the Arduino compilers. Is just the same version of GCC sufficient, or does it have to be exactly the same compilers? If the latter that would kind of also imply that the firmware would also need to be built on a particular OS, so I would assume just the same version is good?

@jeremypoulter The compilers are all cross-compilers, so it doesn't matter which host OS you use when do do a build, as long as the versions and optimization flags are the same. Also, the core libraries have to be the same. It might be easiest to just take a copy of Arduino, set the IDE to use the target AVR support version, and copy that out of the Arduino config, and then configure PIO to use that.

There's another difference, which probably doesn't matter, but will generate slightly different object code... PIO and Arduino munge the input files slightly differently (since Arduino allows non-standard C usage, leaving out function prototypes, and allowing forward declaration of functions), it rearranges code, and generates its own input files to the g++) I don't know if this can change behavior enough to matter. But I had encountered some compiler errors due to this difference when

@lincomatic take a look at #108 been doing a bit of work to get Platform IO and Arduino IDE producing the same binary. I think what is there is extremely close. Please let me know your thoughts.

Now going back to working out why one of my dev OpenEVSE stopped working...

@lincomatic take a look at #108 been doing a bit of work to get Platform IO and Arduino IDE producing the same binary. I think what is there is extremely close. Please let me know your thoughts.

Now going back to working out why one of my dev OpenEVSE stopped working...

Sorry, I was traveling last week. Will try to take a look this week.

Just another data point on why it's important not to change toolchains w/o extensive testing. I was playing around w/ different AVR toolchains via the Arduino Boards Manager. The latest, 1.8.1 gave me a significant code size savings vs 1.6.15. It's lucky I was playing with RAPI commands. The compiler swap broke a whole slew of $Fx RAPI commands. They were all inexplicably returning $NK even though the code was clearly there to support them.

I finally traced it down to a line of new code that declared and initialized a variable:

case 'L': // jump to bootLoader typedef void (*do_reboot_t)(void); const do_reboot_t do_reboot = (do_reboot_t)((FLASHEND - 511) >> 1);
The declaration/initialization of do_reboot above gets skipped when the case gets skipped. 1.6.15 doesn't like that, and flags it as an error. 1.8.1 silently accepts it, and then breaks all the cases after it!
The fix for 1.8.1 was to surround the code block in curly braces, so it only gets executed when the case is matched. However, there might be some other unknown code that behaves strangely with 1.8.1, so I reverted to 1.6.15.

Did you ever get a chance to look at #108? Because of the reasons you mentioned it really would be good to switch to Platform IO as that makes managing the various components used for building very easy.

I haven't looked into it ... but it feels to me like a compiler flag (enabling/disabling warnings) that was set for 1.6.15 might not have been set for 1.8.1. @jeremypoulter why do you think Platform IO would have made a difference when configured to use the same version (ie. 1.8.1)? Don't get me wrong, I think it's beneficial to have different ways to produce the same binary as that increases the chance of catching issues like this in an early stage.

Getting off topic; but interesting to see the jump to bootloader. Is this on the roadmap to enable flashing from the attached ESP? I've had a play with the 'new' version of optiboot where this works and even a plain tcp to uart bridge would allow avrdude to flash, if not from the web ui.

Platform IO would not have prevented the issues building with 1.8.1. It does however make sure you are using the correct tool chain to build the project with so makes it much easier to get going from fresh. Ie you just clone the repo and build, no messing around figuring out if you have the correct compilers installed, PIO does it all for you.