Do it all at once in preparation for Go 1.18 support.
To make this commit, I've simply modified the `fmt-check` Makefile
target to rewrite files instead of listing the differences. So this is a
fully mechanical change, it should not have introduced any errors.
There is no need to put these in the board files as the I2S is the same
on all Microchip SAM D21 chips. This simplifies the code and avoids some
special *_baremetal.go files.
This change does not change the resulting binaries.
Instead of defining them separately for each board, define them once in
the chip definition and later simply use &sercomUART1 etc. to refer to
them. This is simpler and less error-prone.
I found two bugs while working on this:
- The P1AM-100 board mixed SERCOM 5 and SERCOM 3. It looks like SERCOM
5 was intended, based on the used pins.
- The Adafruit Matrix Portal appears to have configured the wrong
interrupt.
Unfortunately, I can't test these fixes. However, they make it clear
that such a change is important to avoid bugs.
I tested this commit on the PyBadge and the Circuit Playground Express.
Previously, the machine.UART0 object had two meanings:
- it was the first UART on the chip
- it was the default output for println
These two meanings conflict, and resulted in workarounds like:
- Defining UART0 to refer to the USB-CDC interface (atsamd21,
atsamd51, nrf52840), even though that clearly isn't an UART.
- Defining NRF_UART0 to avoid a conflict with UART0 (which was
redefined as a USB-CDC interface).
- Defining aliases like UART0 = UART1, which refer to the same
hardware peripheral (stm32).
This commit changes this to use a new machine.Serial object for the
default serial port. It might refer to the first or second UART
depending on the board, or even to the USB-CDC interface. Also, UART0
now really refers to the first UART on the chip, no longer to a USB-CDC
interface.
The changes in the runtime package are all just search+replace. The
changes in the machine package are a mixture of search+replace and
manual modifications.
This commit does not affect binary size, in fact it doesn't affect the
resulting binary at all.
This means that machine.UART0, machine.UART1, etc are of type
*machine.UART, not machine.UART. This makes them easier to pass around
and avoids surprises when they are passed around by value while they
should be passed around by reference.
There is a small code size impact in some cases, but it is relatively
minor.
Make the USBCDC use a pointer receiver everywhere. This makes it easier
to pass around the object in the future.
This commit sometimes changes code size, but not significantly (a few
bytes) and usually in a positive way.
My eventual goal is the following:
- Declare `machine.USB` (or similar, name TBD) as a pointer receiver
for the USB-CDC interface.
- Let `machine.UART0` always point to an UART, never actually to a
USBCDC object.
- Define `machine.Serial`, which is either a real UART or an USB-CDC,
depending on the board.
This way, if you want a real UART you can use machine.UARTx and if you
just want to print to the default serial port, you can use
machine.Serial.
This change does have an effect on code size and memory consumption.
There is often a small reduction (-8 bytes) in RAM consumption and an
increase in flash consumption.
It is always implemented exactly the same way (as an uint8) so there is
no reason to implement it in each target separately.
This also makes it easier to add some documentation to it.
This commit refactors PWM support in the machine package to be more
flexible. The new API can be used to produce tones at a specific
frequency and control servos in a portable way, by abstracting over
counter widths and prescalers.
This makes it possible to assign I2C objects (machine.I2C0,
machine.I2C1, etc.) without needing to take a pointer.
This is important especially in the future when I2C may be driven using
DMA and the machine.I2C type needs to store some state.
Calling errors.New in an error path causes a heap allocation at an
already unfortunate moment. It is more efficient to create these error
values in globals and return these constant globals. If these errors are
not used (because the related code was optimized out), the globals will
also be optimized out.
Somehow moving to LLVM memory intrinsics for calls like memcpy made the
machine.sendUSBPacket get inlined. This is a problem because it is
called in many different functions and it is just big enough to cause a
significant file size increase.
Adding //go:noinline solves this problem and gets the examples/blinky1
program below the file size it was before this change (tested:
itsybitsy-m0, itsybitsy-m4, circuitplay-bluefruit).
This commit lets the compiler know about interrupts and allows
optimizations to be performed based on that: interrupts are eliminated
when they appear to be unused in a program. This is done with a new
pseudo-call (runtime/interrupt.New) that is treated specially by the
compiler.
These all-caps constants aren't in the Go style, so rename it to
CPUFrequency (which is more aligned with Go style). Additionally, make
it a function so that it is possible to add support for changing the
frequency in the future.
Tested by running `make smoketest`. None of the outputs did change.
Instead of configuring machine.I2C0, machine.I2C1, etc. statically,
allow the pins to be set using machine.I2CConfig. This will also
automatically configure the correct pin mode for each pin instead of
having to specify that manually.