TinyGo is Go language that runs on a microcontroller..  It works well in an ARM M0 part.  Go is a general purpose language.  It's more modern than C, but not object oriented like Python.  See https://tinygo.org/ for more info and installation instructions.

In microcontroller systems like Arduino IDE, every LED blinky tutorial starts with config, set a pin, delay, clear a pin, delay, loop.  That's great until you want to do more that blink 1 LED.  The sleep delay takes up 100% of the attention of the micro and you can't do anything else inside a sleep function.  There's only one thread. 

Intermediate examples show how to use millis() and conditional tests.  This allows one thread to flip LEDs on and off at scheduled times.  This works, but it gets complicated in some applications.

What if you could just tell the compiler to do several things at once?  Wouldn't that be better?  Well Go can do that.  Goroutines tell the compiler to make a new thread and run some function in the background.  Normally this would require an OS or RTOS.  This basic concurrency is built into Go and TinyGo.

This code will blink 2 LEDs at some arbitrary durations.  The delay times were chosen to be odd fractions of seconds.  The target board is a Seeeduino Xiao.  The LEDs are connected to D5 and D6.  The 2 LEDs will blink independently forever.

package main
/* TinyGo
 * Use lazy concurrency for independent blinking LEDs
 * Target is Seeeduino XIAO
 * Bob U. 2021/08/01
 */

import (
    "machine"
    "time"
)

// declare and init LED pins outside of main()
var led1 = machine.D6    // white LED
var led2 = machine.D5    // orange LED

func main() {
// config pins
    led1.Configure(machine.PinConfig{Mode: machine.PinOutput})
    led2.Configure(machine.PinConfig{Mode: machine.PinOutput})

// run slow_blink as concurrent goroutine
    go slow_blink()

// fast_blink runs in main() forever
    for {
        led1.Low()
        time.Sleep(time.Millisecond * 199)

        led1.High()
        time.Sleep(time.Millisecond * 67)
    }
}

func slow_blink() {
    // blink without end
    for {
        led2.Low()
        time.Sleep(time.Millisecond * 987)
        
        led2.High()
        time.Sleep(time.Millisecond * 1234)
    }
}

 The import section loads libraries for timing and machine I/O

The LED variables have to be declared outside of main().  This is a global assignment.  If not, the function won't able to use the variable names.  The slow_blink function doesn't inherit anything from main().

main function initializes the pins for output.  Then it calls the slow_blink function as a goroutine.  This tells the compiler that slow_blink should run as a separate process.  Next the fast blink section blinks the white LED forever.  This uses sleep functions that use up the whole thread.  It's an infinite loop.

The slow_blink function is nothing special.  This also uses sleep functions that use up the whole thread.  There is no return from this function.  It's an infinite loop.

This would never work in C, C++ or Python.  It does work in Go, because goroutines make a new execution thread.  This works well in the limited hardware of a ARM M0 processor.  I made a video of the blinking LEDs, but Hackaday won't host videos.  The video wasn't that interesting.  You get the idea.  White LED blinks fast, orange LED blinks slow.  Timing is great and this was simple to write.

This only works because there's no data shared between the functions.  Each function stands on its own.  The slow_blink() function doesn't even know main() exists.  If there were messages or data to be exchanged, then locks or channels would be required.  Even so, it's very useful in the microcontroller and hardware world.  The controller can walk and chew gum at the same time.  No scheduling required.

Here's the command line to run the compiler.  The default...

Read more »