docs: add page "Go on microcontrollers"
Этот коммит содержится в:
родитель
823ecd5167
коммит
0e65b0da1c
2 изменённых файлов: 133 добавлений и 0 удалений
|
@ -12,4 +12,5 @@ Contents:
|
|||
:maxdepth: 2
|
||||
|
||||
installation
|
||||
microcontrollers
|
||||
internals
|
||||
|
|
132
docs/microcontrollers.rst
Обычный файл
132
docs/microcontrollers.rst
Обычный файл
|
@ -0,0 +1,132 @@
|
|||
.. microcontrollers:
|
||||
|
||||
.. highlight:: go
|
||||
|
||||
|
||||
Go on microcontrollers
|
||||
======================
|
||||
|
||||
TinyGo was designed to run on microcontrollers, but the Go language wasn't.
|
||||
This means there are a few challenges to writing Go code for microcontrollers.
|
||||
|
||||
Microcontrollers have very little RAM and execute code directly from flash.
|
||||
Also, constant globals are generally put in flash whenever possible. The Go
|
||||
language itself heavily relies on garbage collection so care must be taken to
|
||||
avoid dynamic memory allocation.
|
||||
|
||||
|
||||
Heap allocation
|
||||
---------------
|
||||
|
||||
Many operations in Go rely on heap allocation. Some of these heap allocations
|
||||
are optimized away, but not all of them. Also, TinyGo does not yet contain a
|
||||
garbage collector so heap allocation must be avoided whenever possible outside
|
||||
of initialization code.
|
||||
|
||||
These operations currently do heap allocations:
|
||||
|
||||
* Taking the pointer of a local variable. This will result in a heap
|
||||
allocation, unless the compiler can see the resulting pointer never
|
||||
escapes. This causes a heap allocation::
|
||||
|
||||
var global *int
|
||||
|
||||
func foo() {
|
||||
i := 3
|
||||
global = &i
|
||||
}
|
||||
|
||||
This does not cause a heap allocation::
|
||||
|
||||
func foo() {
|
||||
i := 3
|
||||
bar(&i)
|
||||
}
|
||||
|
||||
func bar(i *int) {
|
||||
println(*i)
|
||||
}
|
||||
|
||||
* Converting between ``string`` and ``[]byte``. In general, this causes a
|
||||
heap allocation because one is constant while the other is not: for
|
||||
example, a ``[]byte`` is not allowed to write to the underlying buffer of a
|
||||
``string``. However, there is an optimization that avoids a heap allocation
|
||||
when converting a string to a ``[]byte`` when the compiler can see the
|
||||
slice is never written to. For example, this ``WriteString`` function does
|
||||
not cause a heap allocation::
|
||||
|
||||
func WriteString(s string) {
|
||||
Write([]byte(s))
|
||||
}
|
||||
|
||||
func Write(buf []byte) {
|
||||
for _, c := range buf {
|
||||
WriteByte(c)
|
||||
}
|
||||
}
|
||||
|
||||
* Converting a ``byte`` or ``rune`` into a ``string``. This operation is
|
||||
actually a conversion from a Unicode code point into a single-character
|
||||
string so is similar to the previous point.
|
||||
|
||||
* Concatenating strings, unless one of them is zero length.
|
||||
|
||||
* Creating an interface with a value larger than a pointer. Interfaces in Go
|
||||
are not a zero-cost abstraction and should be used carefully on
|
||||
microcontrollers.
|
||||
|
||||
* Closures where the collection of shared variables between the closure and
|
||||
the main function is larger than a pointer.
|
||||
|
||||
* Creating and modifying maps. Maps have *very* little support at the moment
|
||||
and should not yet be used. They exist mostly for compatibility with some
|
||||
standard library packages.
|
||||
|
||||
* Starting goroutines. There is limited support for goroutines and currently
|
||||
they are not at all efficient. Also, there is no support for channels yet
|
||||
so their usefulness is limited.
|
||||
|
||||
|
||||
The ``volatile`` keyword
|
||||
------------------------
|
||||
|
||||
Go does not have the ``volatile`` keyword like C/C++. This keyword is
|
||||
unnecessary in most desktop use cases but is required for memory mapped I/O on
|
||||
microcontrollers and interrupt handlers. As a workaround, any variable of a
|
||||
type annotated with the ``//go:volatile`` pragma will be marked volatile. For
|
||||
example::
|
||||
|
||||
//go:volatile
|
||||
type volatileBool bool
|
||||
|
||||
var isrFlag volatileBool
|
||||
|
||||
This is a workaround for a limitation in the Go language and should at some
|
||||
point be replaced with something else.
|
||||
|
||||
|
||||
Inline assembly
|
||||
---------------
|
||||
|
||||
The device-specific packages like ``device/avr`` and ``device/arm`` provide
|
||||
``Asm`` functions which you can use to write inline assembly::
|
||||
|
||||
arm.Asm("wfi")
|
||||
|
||||
There is no support yet for inline assembly that takes (register) parameters or
|
||||
returns a value.
|
||||
|
||||
|
||||
Harvard architectures (AVR)
|
||||
---------------------------
|
||||
|
||||
The AVR architecture is a modified Harvard architecture, which means that flash
|
||||
and RAM live in different address spaces. In practice, this means that any
|
||||
given pointer may either point to RAM or flash, but this is not visible from
|
||||
the pointer itself.
|
||||
|
||||
To get TinyGo to work on the Arduino, which uses the AVR architecutre, all
|
||||
global variables (which include string constants!) are marked non-constant and
|
||||
thus are stored in RAM and all pointer dereferences assume that pointers point
|
||||
to RAM. At some point this should be optimized so that obviously constant data
|
||||
is kept in read-only memory but this optimization has not yet been implemented.
|
Загрузка…
Создание таблицы
Сослаться в новой задаче