Go — a modern programming language with roots at Google — is one of the new generation languages that would like to unseat C (and C++) for what we think of as traditional programming. It is only for PCs, though, right? Not so fast! TinyGo provides a compiler that — in their words — is for small places. How small? They can target code for the Arduino Uno or the BBC micro:bit. It can also produce code for x86 or ARM Linux (both 32- and 64-bit) as well as WebAssembly. They claim that a recent project to add ESP8266 and EPS32 support to LLVM will eventually enable TinyGo to target those platforms, too.
As you would expect, there are some subtle differences between TinyGo and the full-blown version. The compiler handles the entire program at once which is slower but offers more for optimization. Certain optimizations for interface methods are not used in TinyGo, and global variable handling changes to accommodate moving data from flash to RAM efficiently. TinyGo passes parameters in registers.
Other changes are more profound. For example, there’s no garbage collection yet, so you are urged to not perform heap allocations after initialization. There are also a few other major features not supported. Concurrency in the form of goroutines and channels, cgo, reflection, and three index slices won’t work. Maps are available, but only with certain key types. Because of the missing pieces, many of the packages in the standard library won’t build.
Of course, the other modern language in the same position is Rust and if you were wondering why Go instead of Rust, there’s an FAQ for that. Do you need Go on the Arduino? Maybe not. However, if you are a Go programmer, maybe this opens up some possibilities for you.
We remember a hacker jukebox that used Go. We also remember someone using it on the ill-fated Intel Edison.
25 thoughts on “TinyGo Brings Go To Arduino”
And this was last week’s news. Next! Incidentally Al, Parallax called, they want you back.
A.K.A. Spyware Inc.
> A.K.A. Spyware Inc.
… because an ATMEGA328 with no built-in networking hardware is such a big spyware threat…
Might be about acceptance of the “Go” language… If a developer invested time to learn Go he will try to use it more often instead of another language he has to learn from scratch again.
– Seeding stage: create acceptance for exploitable (=security and price) solutions (complex programming languages where its easy to hide vulnerabilities deep in the foundation, vulnerable repositories with poor security screening due to high change dynamics, cloud computing where physical security of the machine is in the hands of others thus taking physical security away from individuals, make vulnerable solutions cheap and well supported like for cloud computing or software as a service, …)
– Growing stage: Increase the user base (create good press, feed social media with “success stories”, present how much money is to make by following this “new, hipp, agile” path of doing things…) This stage easily takes 5 to 15 years.
– Harvest stage: Once most developers abandon or forget the “old” solutions and are at stage where the “old” ways seem to demanding (cost, time, not possible to maintain anymore) increase the prices, sell the data even if it was intended to be kept private, create new rules where breaching these new rules comes with a penalty (cost, social de-ranking).
Go is in many ways simpler and safer than the alternatives. If someone insists on writing C they are more likely to write code with security issues hidden in fundamental pieces…
tinfoil hat alert!
PLEASE explain to me how this could happen with an *open source* PROGRAMMING LANGUAGE.
I don’t know a single developer who knows exactly one programming language. It doesn’t make sense for an employable developer today to know only one language… Lock-in is virtually impossible if not actually impossible.
Oh wait you listed stages: you are clearly more smarter than everywon else
If the source code is available it can be checked for any kind of spyware such as browsers like Chromium which is built from Chrome’s source but without the garbage that comes with stock Chrome.
Unseat C… Small places… I’m thinking of the Microchip XC compiler that can compile for the PIC10F206 with 512 flash words and 24 bytes of RAM, or even the 10F200 with 256 words of flash and 16 bytes of RAM.
I know XC is a rubbish compiler, and the PIC is a rubbish architecture. But to compile a high level language into that is a nice trick.
You haven’t really seen the worst of PIC until you are forced to work with CCS compiler.
Hehe yes I found a bug in their compiler back in the 90’s that stopped the project I was working on until they fixed it. I had to tell them exactly what was behind the bug (incorrect setting of a register) and how to fix it. You’d have thought they’d have given me a freebie (like a discount or whatever) for that, but no…
We don’t have to look that far. TinyGo is targeting AVR, so there’s this gem: https://hackaday.com/2014/03/20/usb-on-the-attiny10/ And a couple of years ago I read an article on using GCC with ATtinys with no RAM at all, thanks to binding variables to registers (https://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_regbind). Unfortunately I cannot find it now.
One of the maintainers of TinyGo here. First of all, thanks for including us here, Hackaday. We appreciate it!
A couple of corrections, TinyGo does in fact support garbage collection, and we have a couple of different algorithms you can choose from. It is worth pointing this out, although it is also true that it is not a good practice to do heap allocations on devices with such limited memory.
Another important point, TinyGo does in fact support both goroutines and channels, which are required for concurrency. The support is currently based on LLVM co-routines so it runs pretty efficiently. That said, we are in the process of adding a more powerful scheduler to allow for even more concurrency especially on 32-bit ARM processors.
We are actively working on the next release of TinyGo which will be adding a lot more compatibility with the various parts of the Go stdlib and also other packages written in Go.
Lastly, a bit of trivia. I am that someone who was running Go on the Intel Edison. Now with TinyGo around, we have the option to run Go on even smaller devices.
Thanks for the clarifications. A lot of that info was off the web site so either it has been recently updated or it is out of date. What’s odd is I looked at the lang-support page on Archive.org and it does say you have some support for goroutines (at least one at a time) and GC for ARM only. However, I know I saw some page that said otherwise, so if I can find it, that might help you update it.
Ah here’s the gc one: https://tinygo.org/compiler-internals/heap-allocation/
Not sure where I picked up on the goroutines other than it sounds like they are not fully supported and maybe I overread that. “At the time of writing (2019-07-05), support for goroutines and channels has not been fully realized but simple programs usually work.”
Glad to see your work on this is moving and thanks again for the clarifications.
A lot of FUD there in your Rust vs. Go FAQ section:
Rust does not support concurrency? Where did you get that idea? Of course there’s concurrency — it’s even dubbed fearless because unlike other languages you don’t have to worry tripping over threads and shared state. Regarding MCUs and concurrency, I’d highly recommend checking out the RTFM framework, it’s a hard-realtime, fully deterministic, statically checked multitasking framework; totally overkill in most simple use cases but unbeatable.
Re #[no_std]: Rust hast two standard libraries “core” and “std”, all of the functionality working without heap is part of “core” and “std” extends that to data structures requiring the existence of a heap, like fully dynamic vecs, hashmaps and some I/O stuff. The grand plan is here is to move everything into “core” and “alloc” (which is a new library taking over all heap handling and collection types) and have “std” simply be a facade which re-exports stuff from “core” and “alloc”. Also allocators are now pluggable and the do exist for microcontrollers as well so it is actually possible to use “std” there, too however I would not recommend it because you’re giving up everything determinism and safety that way which is what makes MCUs and Rust all that useful… Sticking to no_std has very drawbacks at the moment and they’ll even decrease in the future. Library (in Rust lingo crate) writers are actually encouraged to make their code “no_std” compatible if possible which provides a lot of advantages including the ability to easily use them on MCUs and with WebAssembly.
I find TinyGo interesting but more as an alternative to embedded JS or Python approaches.
LLVM has at least the advantage over GCC that it has built-in support for many target architechtures, not like GCC where you need to built your own toolchain, which is barely packaged in linux distros.
“/clang –target=arm-arm-none-eabi -march=armv8.2-a -mfpu=none -c /tmp/test.c -o /tmp/test.o”
Yeah, a big package trying to support lots of architectures and OS peculiarities I’ll never need.
Using crosstools-ng to build a toolchain tailored to your target is easy.
“easy” being hoping that your target architecture is supported under the host platform and sufficiently tested.
Yes, this is one of the reasons to choose LLVM. Download one binary and be able to target all the targets. If we had used LLVM, we would need to provide a separate download for AVR, for ARM, for x86, RISC-V, … having one download avoids all this trouble. In fact, one of the things I like about Go is its easy cross compilation, which is something I’d like to keep in TinyGo.
Also, as a compiler developer LLVM has a nice library-based architecture that makes building new compilers a whole lot simpler. This is why most new compiled languages choose to use LLVM, such as Rust and Swift. I’m not aware of a compiler (outside of built-in compilers) that uses GCC as a library.
In the future, we will eventually fully support CGo for cross compilation using musl for example.
Oops, I meant “if we had used GCC…”.
Uhm, actually GCC supports far more architectures than LLVM, just not concurrently. I find it tricky to call a winner here.
A clarification: TinyGo has already added partial or full support for most of the limitations listed here. For example, there is garbage collection for most targets, there is partial CGo support, concurrency/channels has partial support (simple stuff works) and is right now being improved, reflection has enough support to be able to use the fmt package so the big pieces are there, and three index slices have been implemented and will be part of the next release.
A somewhat out of date list can be seen here:
Oops, I see that Ron Evans has already pointed out most of these things. Feel free to delete these two comments.
This project is awesome!
I wonder if there’s anyway to directly access registers on a microcontrollers via TinyGo / golang. It doesn’t have to be super fast or efficient.
You mean to directly access registers of peripherals? Yes, this is fully supported. The API itself is automatically generated by a Python script from SVD (ARM/RISC-V) or ATDF (AVR) files – very similar to how they do it for Rust:
An important difference is that TinyGo does not (yet?) enforce restrictions on readable/writable memory. This would probably be a good thing, however usually invalid reads and writes do nothing or return garbage – I haven’t yet seen it do anything unsafe.
Oh and this interface should be just as fast as in C (untested but I don’t see a reason why it wouldn’t).
Please be kind and respectful to help make the comments section excellent. (Comment Policy)