These chips have a larger upper limit for the DMA transfer than the
nrf52832. For best performance, we should be splitting the transfer in
as large blocks as possible on the given hardware.
- Do not use make([]byte, ...) to allocate, instead call the allocator
directly with a nil (undefined) layout. This makes sure the precise
GC will scan the contents of the allocation, since C could very well
put pointers in there.
- Simplify the map to use the pointer as the key and the size as the
value, instead of storing the slices directly in the map.
Long sleep durations weren't implemented correctly, by simply casting to
a smaller number of bits. What we want is a saturating downcast, which
is what I've used here instead.
This should fix https://github.com/tinygo-org/tinygo/issues/3356.
* Create "pico2-ice" target board
This board has an rp2350b chip on it, as well as a Lattice Semiconductor
iCE40UP5K FPGA. More details of this open hardware board here:
https://pico2-ice.tinyvision.ai/
Tested on a pico2-ice board with:
~/go/bin/tinygo flash -target=pico2-ice src/examples/blinky1/blinky1.go
which blinks the GREEN LED (connected to GPIO0) on this board.
Signed-off-by: Tinkerer <tinkerer@zappem.net>
* More silkscreen labels for pico2-ice board
Reading the schematic and the rev2 board viewer:
https://raw.githubusercontent.com/tinyvision-ai-inc/pico2-ice/refs/heads/main/Board/Rev2/bom/ibom.html
concluded that the RP2350B GPIO pins are not labeled with these
pin numbers in the silkscreen. Instead, the silkscreen refers to
uses of the GPIOs or the ICE numbered pins. RP2340B devoted pins
map to the A1..4 B1..4 pins on the RP PMOD connector. Also
silkscreen "~0".."~6" are labeled as pins N0..N6.
Signed-off-by: Tinkerer <tinkerer@zappem.net>
* Added a smoketest for pico2-ice board and tidied up GPIO defs
Addresses review comments from aykevl.
Signed-off-by: Tinkerer <tinkerer@zappem.net>
Incorrect factors are calculated for baudrates which are a bit
larger than integer multiples of 4194304.
For example for baudrates of 8_400_000 or 58_800_000.
Fixed the same way in newer versions of the RPI SDK.
This function is called when a hard fault occurs. Hard faults happen
when something really bad happens - like writing to unwritable memory or
an unaligned memory access on Cortex-M0. It is not generally possible to
recover from these.
This commit optimizes the code size overhead of hard fault handling:
* It removes the stack overflow checking code.
This may seem like a bad thing, but the only thing this could check
were stack overflows outside goroutines. In practice, this could
only really happen on a stack overflow in the scheduler (unlikely),
or in interrupt code (possible, but interrupts are small so still
unlikely). Most stack overflows happen in regular goroutines, and
weren't caught in the HardFault.
* It makes the panic message similar to a regular panic. This has two
advantages:
* It reduces code size, because the string can be reused between
the HardFault handler and the runtime panic function.
* Using the same pattern automatically makes `-monitor` print the
source address for the hard fault. Not a big benefit as we could
trivially add any other pattern but a nice benefit nonetheless.
Result:
$ tinygo flash -target=microbit -size=short -programmer=openocd -monitor examples/serial
code data bss | flash ram
3036 8 2256 | 3044 2264
[...snip]
Connected to /dev/ttyACM0. Press Ctrl-C to exit.
panic: runtime error at 0x00000344: HardFault with sp=0x200007d0
[tinygo: panic at /home/ayke/src/tinygo/tinygo/src/internal/task/task_stack_cortexm.go:48:4]
(This is with https://github.com/tinygo-org/tinygo/pull/3680 not yet
fixed and some local changes to configure the UART so I can actually see
the panic).
For atsamd21/nrf51 chips this results in a binary size reduction of
around 100 bytes. For other Cortex-M chips it's around 24 bytes but I
hope to change this in the future because a lot of the fault decoding in
runtime_cortexm_hardfault_debug.go should IMHO be done by the TinyGo
monitor instead (I estimate that this would save around 800 bytes on
these chips).
In some cases, e.g nothing connected on the bus, repeated resume-stop sequences can lead to the bus never reaching the stop state, hanging Tx.
This change ensures the resume-stop sequence is submitted once on error. It also moves the error code read to before the sequence to ensure it's valid.
Fixes: #4998
Writing to the UART takes time and that may not be a good idea inside an
interrupt, but it is essential for debugging sometimes (especially since
USB-CDC typically doesn't work inside an interrupt).
This fixes UART support in interrupts for the RP2040 at least. You can
test it with `-serial=uart` and connecting a USB-UART adapter to the
right pins.
Account for the sleep queue base time in the computation of the wakeup
time.
Tested with the following program on pico2.
func main() {
go func() {
for i := range 60 {
const delay = 20 * time.Millisecond
before := time.Now()
time.Sleep(delay)
if d := time.Since(before); true || d < delay {
log.Println(i, "actual", d, "delay", delay)
}
}
}()
time.Sleep(500 * time.Millisecond)
log.Println("******** done sleeping ********")
select {}
}
Without this change, the program would print lines such as:
17 actual 15.494ms delay 20ms
18 actual 15.49ms delay 20ms
19 actual 15.585ms delay 20ms
20 actual 15.493ms delay 20ms
21 actual 15.494ms delay 20ms
22 actual 15.487ms delay 20ms
23 actual 15.498ms delay 20ms
******** done sleeping ********
24 actual 15.548ms delay 20ms
25 actual 20.011ms delay 20ms
26 actual 20.01ms delay 20ms
27 actual 20.011ms delay 20ms
28 actual 20.015ms delay 20ms
Note that while more than one sleeping goroutine is in the timer queue,
the sleep duration is 5ms short.
This gets the path package tests to pass, so we can move ahead with Go
1.25. It should be implemented in the future at some point (that, or
we'll use the upstream testing package instead).
Found this bug while trying to use the upstream testing package instead
of our own. The io/fs package wasn't passing, because the test was run
in a separate goroutine (and therefore a separate thread, with its own
stack) instead of all in the same thread with our own stack
creation/switching implementation.
This makes sure system calls like read don't return EINTR but instead
restart the call on an interrupt. This is by far the more sensible
option, the default POSIX behavior of returning EINTR is extremely
error-prone.
Found this bug while trying to use the upstream testing package instead
of our own.
The previous versions calculated at init() prevented `interp` from running
in many cases, increasing compile times due to the increased need to revert
the partially interpreted results and also increasing binary runtime because
fewer optimizations had happened during interp.
Similar to PWM, I2C can only be used on some pins. To automatically
generate this information per board, we need to add extra comments that
can then be interpreted by doc-gen for the tinygo.org website.
This fixes/improves a few issues with I2C support:
* Validate I2C pins, so only pins that are supported by the hardware
can be used (similar to how it's done with PWM).
* Add address to Tx API (without it, the simulator can't really
simulate I2C).
* Add frequency when configuring. Not currently used, but might be
useful in the future and adding it now avoids possibly breaking
changes.
This is a breaking change, but since the simulator doesn't support I2C
yet that seems fine to me. (It does in my local changes, but those need
to be cleaned up before I can push them).
This should avoid a deadlock when trying to print inside an interrupt,
if the interrupted code is also printing (and therefore has the print
lock taken).