Sunday, 21 February 2016

Arduino sucks

Anyone who knows me, knows of my distaste for Arduino.
It's not (just) snobbery. Arduino is a great introduction to electronics for a lot of people. My biggest problem with it, is that all too often, that's where it ends.

I've been doing some consultancy work, and using Arduino.
The decision to use the Arduino platform was made because, apparently, people who know how to use Arduino are more plentiful than people who know how to use PICs or other, more obscure microcontroller parts. This is certainly true. And - being more plentiful - the inference is, cheaper to hire. This may also be true.

But plentiful access to developers is a double-edged sword. Just like everyone who ever used Microsoft Word became a web developer in the late 90s, the problem with plentiful developers is that it naturally introduces a wide range of skill levels. And while there will be some people who really know their stuff and producing good quality, well-designed, solid robust code, there will be an awful lot of charlatans doing more harm than good by publishing poor-quality code. And to anyone who isn't an expert, all developers start to look the same....

Arduino is a community supported project. Unfortunately, a lot of people not only using, but supporting, Arduino are..... well, there's no nice way to say it.... not very good.

There are a lot of libraries out there which are really badly written. Even from sources which have now become synonymous with Arduino and a source of "good code".

The early wav-shield code from Adafruit was very clever - it enabled people to play wav files in their embedded projects with nothing more than an mcu, an sd card holder and a speaker.

But the code was also pretty terrible.
Almost the entire sound playing routine was written inside the interrupt routine. There were so very few cycles remaining between interrupts that anything that tried to use the wav-shield code ended up being very flaky indeed - mcu resets, lost variable values and processor lock-ups were not uncommon.

I don't know if the code has been updated since, but when we looked at it before embarking on writing our own wav-player (entirely from scratch) a few years ago, the wav-shield Arduino library was horrible. The trouble is, hardly anyone who used it actually bothered to read the source code. They just copied-and-pasted what they'd been given and got on with the more interesting elements of their project. That's fine. If you're trying to get a job done, get on with finishing the job, not messing about understanding the inner workings of how it all works.

And that's also the problem with having lots of "Arduino developers" available when choosing Arduino as a platform. There are loads of developers who have used Arduino, but the number who actually know what they are doing is a tiny fraction of this. So when your project hits a problem, and you're left with a developer who only knows the copy-and-paste approach to embedded development, you've got a problem!

Arduino isn't really a "stable" platform for developing anything but the simplest of projects. And the level of support offered by the community isn't as great as the number of users of the platform would suggest (let's not get into how flaky the actual AVR mcu hardware is - that's a whole other discussion - this is just about developers and people who actually code for the things).

  • Sometimes it's just badly-written libraries.
  • Sometimes it's libraries written by people who've never read a datasheet, who don't even understand that a microcontroller is made up of registers and how to manipulate them correctly.
  • Sometimes it's libraries written by people with little electronics understanding, so they try to "code out" inaccuracies created by not understanding the things connected to the microcontroller pins.
  • Sometimes it's libraries that are incompatible with each other (libraries that take over the timer1 module for example, can't be used with other libraries that also want to use timer1). Sometimes fixing this would be as simple as moving one library onto another timer. But that might affect something else using another library - since not all libraries make it clear which mcu peripherals they use and which they need exclusive access to.

Despite this, after spending a day or more trying to understand why something isn't working properly, even when the problem comes down to timer conflicts or something along those lines, it's not even shonky code that makes Arduino so horrible to work with.

If the problem is a badly written library, well, it's all open source so there's nothing stopping you from rolling up your sleeves and finding and/or fixing whatever it is that's stopping the code from working (although by this time, it'd probably be quicker and easier to have developed the entire code yourself from first principles!)

What really makes Arduino stink is that the language tries to shoehorn C++ style 16-bit development into an 8-bit, flat, procedural architecture. Just one tiny example is the overuse (and abuse) of ints (16-bit, 2-byte integers) that litter example Arduino code found all over the internet.

But it gets even worse than this. Because sometimes, it's actually necessary to use the "wrong" datatype, to get code to work consistently. When you're using "correct" datatypes, and performing simple, core tasks, and the results are inconsistent, then there's an inherent problem with the language.

Long-time users of Arduino just laugh this kind of thing off or simply shrug and say "it's designed for artists, not programmers". But that's just denying the problem; if you're using the language correctly, but it's not working properly (or - worse still, as we recently found, works inconsistently, introducing intermittent errors) then it's not really fit for purpose!

Here's just the latest example of Arduino "weirdness" we encountered recently.
It involves writing a two-byte (16-bit) value to eeprom, and recalling it back. Casting different datatypes while assuming the language will automatically convert others is a classic way of introducing errors that are almost impossible to find, let alone debug and resolve.

So, partly for code-portability reasons, and partly to avoid data-type errors creeping into code when it's moved from one platform/language to another, on any 8-bit platform, we always write values as 8-bit values. That means that a two-byte/16-bit value is written to eeprom (and called back) as two single byte values.

The first byte value is the value we wish to store, divided by 256.
The second byte value is the remainder of the value to store.

When recalling the value, we get the first byte value from eeprom and multiply by 256. Then get the second byte value from eeprom and add it to the first. This technique works whatever language you're working with and for any platform.

Except Arduino.

Arduino screws things up.
More worryingly, it sometimes screws things up.

Here we create two byte data types.
A byte data type is an 8-bit, single byte value.

We pull back the first value from eeprom, multiply by 256, pull back the second and add it. In this example, our values were 0x6B and 0xA3. In real money, that's (107*256) + 163 = 27,555. Google agrees; put 0x6BA3 to decimal into the search bar and Google tells you it's 27555

Arduino says the value is 27299.

Even - as shown in the screenshot above - when casting data values into ints the problem doesn't go away. We even tried - although not shown above - taking each value from eeprom and performing a binary AND operation with the value 0xFF to force each eeprom value into the range 0-255. Arduino still pulled out the second value as a 32-bit value and treated it as -163, not the positive integer 163.

Frustratingly - the problem doesn't always manifest itself. So sometimes - depending on exactly which values you use/store in eeprom - the correct total value is arrived at. And it's not always the second of two bytes that is handled by the compiled code as  32-bit value; sometimes it is treated like an 8-bit value, sometimes the first byte is messed up, sometimes both, sometimes neither.

This isn't even about poor coding.
There's nothing wrong with manually splitting a two-byte/16-bit value into single bytes and storing them in eeprom. What really stinks is that the Arduino language/compiler makes such a mess of perfectly legitimate code.

What amazes us more than anything is how these "quirks" are generally accepted by the Arduino community. No less than five different long-term Arduino users told us, having had this problem demonstrated to them, to simply use an external eeprom; not to fix the problem, but to avoid using the parts of the Arduino architecture that are problematic.

And that's why Arduino sucks.
The actual platform is flaky.
A lot of the libraries and published code are flaky.
And problems are not fixed - they're just avoided.

I'm sure plenty of the nerds at nerd club will disagree. I've probably upset a lot of people with this rant. But, among the respected developers I deal with, a lot of them also agree that Arduino is the Duplo of microcontrollers suited only for rapid, hobby prototyping, and not really suitable for "commercial" or "industrial" uses.

I think I'll take the Arduino approach. I can't be bothered to fix the underlying problems with Arduino (of which this is just one of many). So I'll work around them. By simply avoiding them - by avoiding Arduino entirely (wherever possible!)

No comments:

Post a Comment