學 Go 玩創客,TinyGo 初體驗(1):安裝環境並在 Arduino Uno/Nano 執行第一支程式

Image for post
Image for post
Photo by Fab Lentz on Unsplash

TinyGo 是什麼,它又能做什麼呢?

Image for post
Image for post

一條迷你狗走天下

「我的初衷是:如果 Python 也能在開發板上跑,那 Go 當然就能在更低階的開發板上執行了。」

— — Ayke van Laëthem(TinyGo 的創建者)

想了解 TinyGo 的威力,不妨先來看上面這支影片。在這支影片裡,身為 TinyGo 共同開發者之一的 Ron Evans 先拿標準 Go 1.12 版編譯了個「Hello World」範例,然後用 TinyGo 0.9.0 版再編譯一次。前者得到的大小是 1100 KB,而後者僅有 11.6 KB。

完全相同的程式碼,怎麼會有如此懸殊的產出?

根據 Ron Evans 的說法,訣竅就在於寫一個新的編譯器,這個編譯器不會針對任何作業系統產生 runtime(畢竟微控制器沒有作業系統)。如此一來,剩下的「骨架」就非常小了。TinyGo 改用一個以 LLVM 撰寫的編譯器來編譯原始檔,藉此產生出一個小非常多的二進位檔案。於是,讓 Go 語言在開發板以及 WebAssembly (WASM) 的環境運作就變得可行。

也就是說,不若 MicroPython 是精簡版的 Python,TinyGo 基本上其實就是把 Golang 套用在一個新編譯器而已。當然,由於原始 Go 的套件有些跟 runtime 息息相關,所以它們是無法被 TinyGo 編譯的(不然就得等 TinyGo 寫出自己的版本)。此外,既然是設計給開發板,TinyGo 不僅有針對開發板設計的 machine package,此套件的內容還會因應開發板的種類而變化(使用者在編譯時必須指定要編譯的「target」)。

TinyGo 最有趣的特點,或許是其設計還受 MicroPython(應該說 CircuitPython,乃紐約的 Adafruit 公司修改自 MicroPython、替自家 SAMD21/51 系列開發板設計的版本)影響,所以許多硬體控制的功能就頗有 MicroPython 的風格。因此從語言上,TinyGo 似乎可說融合了 C 語言(Go 和 C,Java 很類似)和 MicroPython 的各自優點。

Image for post
Image for post
Photo by Riccardo Annandale on Unsplash

但就筆者而言,這還不是 TinyGo 最令人訝異之處。TinyGo 之所以值得注意,是因為它已經(試圖)支援種類眾多的開發板:

  1. 8 位元 AVR 處理器:ATmega328P、ATmega2560、ATtiny85
  2. 32 位元 ARM Cortex M0+ 家族:SAMD21、nRF51
  3. 32 位元 ARM Cortex M3:STM32F1
  4. 32 位元 ARM Cortex M4:SAMD51、nRF52、STM32F4

由於台灣鄰近中國之故,我們長年最容易接觸的就是廉價的 AVR 開發板,以及 ESP 家族。SAMD21/51 和 nRF52 近年似乎已是國外的推行主流,但因這邊得進口,在台灣很少人會用。顯而易見,TinyGo 主要的設計對象仍是 32 位元微處理器。

在 TinyGo 的支援列表中,甚至包括兩款智慧型手表,以及 2001 年的 Game Boy Advance,甚至是 Nintendo Switch。更多硬體已經加入陣營:來自對岸的 Seeeduino XIAO(使用 SAMD21,僅售 5 美元)和 Wio Terminal(SAMD51),極受歡迎的 ESP8266/ESP32 也在 0.15.0 版加入初步支援。誰知道呢?TinyGo 統一開發板的威力,也許將會比我們想像的更強大哩。

TinyGo 尚未成熟(但值得關注)

不過,我也得說,在寫這篇文的時候,TinyGo 離實用化其實還有一段距離。

儘管目前 TinyGo 名義上和 Arduino 有合作、並也成為 Google 官方贊助的專案,實際參與開發的人數仍只有不到 10 人。TinyGo 仍在經歷可觀的變動及改良,而且要做的不只是 TinyGo 本身,開發團隊也得發展諸如 TinyGo drivers(寫給各種感測器模組的 Go 驅動程式)以及 TinyFont(適用於各種螢幕的字型庫)之類的周邊功能。

Image for post
Image for post
Photo by Ian Schneider on Unsplash

目前最大的問題或許是,有太多類型迥異的開發板加入,開發者自己也不見得拿得到手,以致許多板子都有一部分功能尚未實作(比如欠缺類比輸入、PWM 輸出或 SPI 等)。TinyGo 能使用的標準 Go package 還在補充中,此外部分 TinyGo drivers 也有待改進 — — 例如,本文開頭連結的文章所提到的 Arduino Nano 33 IoT,雖然有其 ESP32 網路模組用的驅動程式,但功能仍很有限。

最後,TinyGo 必須借助外部燒錄工具才能將程式寫進某些開發板上,對一些板子來說有點麻煩。如果將來能像 Arduino IDE 一樣整合在一塊,那就更好了。

而當前支援 Go 語言的編輯器也不多,我目前是用 VSCode 加 Go 外掛來編輯原始檔,存檔後再用底下的終端機以指令手動上傳(出現錯誤就再改),另外開一個 Tera Term 來讀 UART 輸出結果。

所以,TinyGo 想在大多數開發板上達到 MicroPython 現有的實用化程度,或許還得等一陣子。不過,我們可以先來體驗看看如何撰寫並上載 Go 到台灣比較常見的幾種開發板 — — 包括我們最熟悉的 Arduino Uno 與 Arduino Nano。在後續的文章中,筆者還會介紹 BBC micro:bit 以及其他幾種板子的燒錄方法。

以下稱的 Nano 若無特別註明,指的就是較舊的 ATmega328 版 Nano 3.0。

透過開發板的互動性實作,其實或許更能刺激使用者學習 Go 語言的興趣。畢竟單純在電腦上學 Go,豈不是太無趣了?

環境安裝與設定

在 Windows 安裝 Go/TinyGo

1、下載和安裝 Go(比如 go1.15.x.windows-amd64.msi),安裝至 C:\。安裝程式應該會自動將 Go 的路徑加入你的系統 Path 變數。

2、下載 TinyGo(比如 tinygo0.16.0.windows-amd64.zip)和解壓縮到 C:\。

到控制台→系統→進階系統設定→環境變數(N)…然後在使用者或系統的 Path 變數加入路徑:

C:\tinygo\bin

3、現在打開命令提示字元,輸入

tinygo version

如果你看到以下結果,就代表路徑都正常:

tinygo version 0.16.0 windows/amd64 (using go version go1.15.5 and LLVM version 10.0.1)
Image for post
Image for post
Photo by Mariya Pampova on Unsplash

在 Linux 安裝 Go/TinyGo

1、先確保系統在最新狀態:

sudo apt-get updatesudo apt-get dist-upgrade -y

2、下載和安裝 Go:(可能不是最新版本)

sudo apt-get install golang-go 

若你用的是 Ubuntu,能安裝的 Go 版本可能太舊,這時你可用以下指令來取得新版的 Go,再執行一次上面的安裝指令即可:

sudo add-apt-repository ppa:longsleep/golang-backports
sudo apt update

3、下載和解壓縮 TinyGo:

使用 Ubuntu/Debian 系統:

sudo wget https://github.com/tinygo-org/tinygo/releases/download/v0.16.0/tinygo_0.16.0_amd64.debsudo dpkg -i tinygo_0.16.0_amd64.deb

若是樹莓派則得用以下指令:

sudo wget https://github.com/tinygo-org/tinygo/releases/download/v0.16.0/tinygo_0.16.0_arm.debsudo dpkg -i tinygo_0.16.0_arm.deb

實際網址及最新版本編號請參考 TinyGo 的 release 清單

4、加入 TinyGo 路徑:

確保回到 home 目錄,先打開 bashrc 文件

nano ~/.bashrc

然後在最後一行加入

export GOPATH=$HOME/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
export PATH=$PATH:/usr/local/tinygo/bin

按 Ctrl+X 然後 Y 來存檔。

重開終端機來讓路徑生效,或者你可在終端機複製貼上這行執行一次,讓它現場生效。

5、最後在終端機輸入:

tinygo version

看到以下結果便代表路徑設置成功:(下面是我的樹莓派的結果,我自己用手動方式安裝最新的 Go)

tinygo version 0.16.0 linux/arm (using go version go1.15.5 and LLVM version 10.0.1)

更新 Go 與 TinyGo

將來當 Go 或 TinyGo 有更新時,照上面的方式安裝新版即可(在 Windows 要先刪掉舊的 tinygo 資料夾)。已經加入的路徑不用再重加一次。

設定 VSCode

筆者目前是在 Windows 上用 Visual Studio Code 來編輯 TinyGo 程式,不過由於我不是業界開發人士,所以並不熟 VSCode。但使用 VSCode 有很多好處,包括能依語法標示顏色、存檔時還會自動排版/import 套件等等,相當方便。

如果有更好的做法,歡迎提供給我。在這裡簡單說一下我目前的做法。

在 VSCode 安裝 Go 的 extension 後,從 Files → Perferences → Settings 然後點 Edit in settings.json。在此設定檔內加入:

"go.goroot": "C:\\Go,C:\\tinygo,","go.gopath": "C:\\Users\\你的使用者名稱\\go",

接著存檔,這樣 TinyGo 以及其他套件(包括之後會用到的驅動程式)應該就能抓到了。當然這並不是必要的,只是讓錯誤訊息不會那麼多而已,畢竟我們不會直接用 VSCode 來編譯 TinyGo 程式。

編輯器仍會顯示找不到 machine 套件,這是正常的,因為該套件在編譯時才會根據不同板子來產生對應的版本。

從 0.15.0 版發布後,他們在 VSCode 也有新增一個 plugin(tinygo),不過詳細用法我還不夠清楚。

安裝 AVR 上傳工具(for Arduino Uno/Nano)

為了能把編譯好的程式寫入 Arduino Uno 或 Nano,我們必須安裝額外的工具。這些其實在 Arduino IDE 內也有提供。

在 Windows 下,我個人的做法是下載這個人家打包好的 AVR-GCC 並將之解壓到 C:\。你同樣得將以下路徑加入 Path 系統變數(注意版本編號):

C:\avr-gcc-10.1.0-x64-windows\bin

Linux 比較簡單一點,只要執行下面這三行指令即可:

sudo apt-get install gcc-avrsudo apt-get install avr-libcsudo apt-get install avrdude

編譯和上載 blinky 範例程式

Image for post
Image for post
Photo by Pavan Trikutam on Unsplash

在 Windows 檢查連接埠號碼

將你的 Arduino Uno 或 Nano 接上電腦。若在 Windows,到控制台→裝置管理員,看看你的板子是在連接埠的幾號 COM。以筆者的例子來說是 COM5。

Image for post
Image for post

通常同一個板子的 COM 號碼會固定。不過,也有的時候會改變。所以每次使用前最好還是確認一下。

另一個檢查 COM 號碼的快速方式是在 Windows 的命令提示字元視窗輸入 mode:

C:\Users\使用者> mode裝置 COM1 的狀態:
------------
傳輸速率: 1200
同位檢查: None
資料位元: 7
停止位元: 1
逾時: OFF
XON/XOFF: OFF
CTS 交握: OFF
DSR 交握: OFF
DSR 敏感度: OFF
DTR 電路: ON
RTS 電路: ON
裝置 COM5 的狀態: <--- 這個就是 Arduino Uno
-------------
傳輸速率: 0
同位檢查: None
資料位元: 0
停止位元: 1
逾時: OFF
XON/XOFF: OFF
CTS 交握: OFF
DSR 交握: OFF
DSR 敏感度: OFF
DTR 電路: OFF
RTS 電路: ON

在 Linux 檢查連接埠名稱

在 Linux 系統,連接埠通常會是 /dev/ttyACM0,也有可能是 /dev/ttyUSB0。如果真的不確定,在終端機用以下指令來查詢:

dmesg | grep tty

上傳 TinyGo 範例程式

打開命令提示字元(從 VSCode 的 Terminal 也可),輸入以下這行指令:

tinygo flash -target arduino -port COM5 examples/blinky1

「tinygo flash」 會執行編譯並上傳的兩步驟動作。參數 target 是開發板類型,「arduino」指的是 Arduino Uno;如果是 Nano 就改成 arduino-nano。port 是連接埠,examples/blinky1 是 TinyGo 提供的範例程式。

參數也可使用 =:

tinygo flash -target=arduino -port=COM15 examples/blinky1

若前面路徑都有設定正確的話,執行並稍待片刻,應該就能看到以下訊息:

avrdude: AVR device initialized and ready to accept instructionsReading | ################################################## | 100% 0.01savrdude: Device signature = 0x1e950f (probably m328p)
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "C:\Users\Admin\AppData\Local\Temp\tinygo454908831\main.hex"
avrdude: writing flash (558 bytes):
Writing | ################################################## | 100% 0.15savrdude: 558 bytes of flash written
avrdude: verifying flash memory against C:\Users\Admin\AppData\Local\Temp\tinygo454908831\main.hex:
avrdude: load data flash data from input file C:\Users\Admin\AppData\Local\Temp\tinygo454908831\main.hex:
avrdude: input file C:\Users\Admin\AppData\Local\Temp\tinygo454908831\main.hex contains 558 bytes
avrdude: reading on-chip flash data:
Reading | ################################################## | 100% 0.13savrdude: verifying ...
avrdude: 558 bytes of flash verified
avrdude: safemode: Fuses OK (E:00, H:00, L:00)avrdude done. Thank you.
Image for post
Image for post

板子上的內建 LED 燈會開始閃爍。可以看到編譯的檔案大小為 558 bytes,而功能類似的程式在 Arduino 1.8.13 編譯出來則為 924 bytes。

上載自己的程式

最簡單的方式是在 C:\Users\使用者名稱\go\src(Windows)或 /home/使用者名稱/go/src/(Linux)的位置創一個目錄 main,並在底下放一個文字檔 main.go 當作你的通用測試程式。以後只要在這個檔案修改程式,直接上傳測試就很方便了。

在這個 main.go 內貼上下面的程式碼:

package main

import (
"machine"
"time"
)

func main() {
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
for {
led.High()
time.Sleep(time.Millisecond * 500)
led.Low()
time.Sleep(time.Millisecond * 500)
}
}

這其實就是前面的 blinky1 範例程式,這也是 TinyGo 的最基本範例。你可以試試看修改 time.Sleep 這行後面的數字,好改變內建 LED 燈的閃動速度。

要上載這支程式,使用以下的指令即可:(這裡我們改以 Arduino Nano 為例)

tinygo flash -target arduino-nano -port COM10 main
Image for post
Image for post

在本系列的下一篇中,我們將會以經典的 Arduino 創客主題來展示 Go 語言的一些基本特性,甚至擴及到一些其他的開發板(如 Arduino Nano 33 IoT 和 BBC micro:bit)。

當然,Arduino Uno/Nano 在運行 TinyGo 上仍有一些限制:

  1. 尚未實作 SPI 功能。
  2. PWM 只能調 duty cycle,還無法調頻率。
  3. 由於記憶體不夠,許多 TinyGo 驅動程式跑不動。(之後會講如何下載並使用這些驅動程式。)
  4. 由於記憶體不夠,Go 的 concurrency(可以平行跑兩個以上的程序)功能預設是關閉的。

不過許多腳位基本控制是可行的,而這就足夠拿來做不少應用了。

Image for post
Image for post
Photo by Kevin Schmid on Unsplash

Written by

Former translator and currently a tech-book editor based in Taiwan. https://krantasblog.blogspot.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store