* machine/attiny85: add USI-based SPI support
Implement SPI communication for ATTiny85 using the USI (Universal Serial
Interface) hardware in three-wire mode. The ATTiny85 lacks dedicated SPI
hardware but can emulate SPI using the USI module with software clock
strobing.
Implementation details:
- Configure USI in three-wire mode for SPI operation
- Use clock strobing technique to shift data in/out
- Pin mapping: PB2 (SCK), PB1 (MOSI/DO), PB0 (MISO/DI)
- Support both Transfer() and Tx() methods
The implementation uses the USI control register (USICR) to toggle the
clock pin, which triggers automatic bit shifting in hardware. This is
more efficient than pure software bit-banging.
Current limitations:
- Frequency configuration not yet implemented (runs at max software speed)
- Only SPI Mode 0 (CPOL=0, CPHA=0) supported
- Only MSB-first bit order supported
* machine/attiny85: add SPI frequency configuration support
Add software-based frequency control for USI SPI. The ATtiny85 USI lacks
hardware prescalers, so frequency is controlled via delay loops between
clock toggles.
- Calculate delay cycles based on requested frequency and CPU clock
- Fast path (no delay) when frequency is 0 or max speed requested
- Delay loop uses nop instructions for timing control
* machine/attiny85: add SPI mode configuration support
Add support for all 4 SPI modes (Mode 0-3) using USI hardware:
- Mode 0 (CPOL=0, CPHA=0): Clock idle low, sample on rising edge
- Mode 1 (CPOL=0, CPHA=1): Clock idle low, sample on falling edge
- Mode 2 (CPOL=1, CPHA=0): Clock idle high, sample on falling edge
- Mode 3 (CPOL=1, CPHA=1): Clock idle high, sample on rising edge
CPOL is controlled by setting the clock pin idle state.
CPHA is controlled via the USICS0 bit in USICR.
* machine/attiny85: add LSB-first bit order support
Add software-based LSB-first support for USI SPI. The USI hardware only
supports MSB-first, so bit reversal is done in software before sending
and after receiving.
Uses an efficient parallel bit swap algorithm (3 operations) to reverse
the byte.
* GNUmakefile: add mcp3008 SPI example to digispark smoketest
Test the USI-based SPI implementation for ATtiny85/digispark.
* machine/attiny85: minimize SPI RAM footprint
Reduce SPI struct from ~14 bytes to 1 byte to fit in ATtiny85's limited
512 bytes of RAM.
Changes:
- Remove register pointers (use avr.USIDR/USISR/USICR directly)
- Remove pin fields (USI pins are fixed: PB0/PB1/PB2)
- Remove CS pin management (user must handle CS)
- Remove frequency control (runs at max speed)
- Remove LSBFirst support
The SPI struct now only stores the USICR configuration byte.
* Revert "machine/attiny85: minimize SPI RAM footprint"
This reverts commit 387ccad494.
* machine/attiny85: reduce SPI RAM usage by 10 bytes
Remove unnecessary fields from SPI struct while keeping all functionality:
- Remove register pointers (use avr.USIDR/USISR/USICR directly)
- Remove pin fields (USI pins are fixed: PB0/PB1/PB2)
- Remove CS pin (user must manage it, standard practice)
Kept functional fields:
- delayCycles for frequency control
- usicrValue for SPI mode support
- lsbFirst for bit order support
SPI struct reduced from 14 bytes to 4 bytes.
---------
* machine/attiny85: add PWM support for Timer0 and Timer1
Add complete PWM implementation for ATtiny85, supporting both Timer0
and Timer1 with their respective output channels:
- Timer0: 8-bit timer for pins PB0 (OC0A) and PB1 (OC0B)
- Timer1: 8-bit high-speed timer for pins PB1 (OC1A) and PB4 (OC1B)
Timer1 provides more flexible period control with configurable top value
(OCR1C) and extended prescaler options (1-16384), making it well-suited
for LED PWM control and other applications requiring variable frequencies.
Implements full PWM interface including Configure, SetPeriod, Channel,
Set, SetInverting, Top, Counter, and Period methods.
* machine/digispark: document PWM support on pins
Add documentation to the Digispark board file indicating which pins
support PWM output:
- P0 (PB0): Timer0 channel A
- P1 (PB1): Timer0 channel B or Timer1 channel A
- P4 (PB4): Timer1 channel B
Includes package comment explaining Timer0 vs Timer1 capabilities,
with Timer1 recommended for more flexible frequency control.
* machine/attiny85: optimize PWM prescaler lookups
Replace verbose switch statements with more efficient implementations:
- SetPeriod: Use bit shift (top >>= prescaler-1) instead of 15-case
switch for dividing uint64 by power-of-2 prescaler values
- Period: Replace switch statements with compact uint16 lookup tables
for both Timer0 and Timer1, casting to uint64 only when needed
This addresses review feedback about inefficient switch-based lookups.
On AVR, this approach is significantly smaller:
- Bit shifts for uint64 division: ~34 bytes vs ~140 bytes
- uint16 tables: 22 bytes code + 32/16 bytes data vs ~140 bytes
- Total savings: ~190 bytes (68% reduction)
* examples/pwm: add digispark support and smoketest
Add digispark.go configuration for PWM example using Timer1 with pins P1 (LED) and P4. Also add digispark PWM example to GNUmakefile smoketests.
---------
* - Fix SPI initialization by disabling interface before configuration.
- Ensure proper 8-bit configuration for STM32G0 SPI data register access.
- Add default pin initialization for SPI.
* Add Window Watchdog (WWDG) and ADC support for STM32G0
* Comment cleanup
* Refactored STM32G0 ADC sampling time configuration to use `switch` for improved readability
* Add STM32G0B1 target support
Introduce support for STM32G0B1 microcontrollers, including target-specific JSON files, linker scripts, and runtime initialization. This update adds hardware support for GPIO, UART, SPI, I2C, timers, and additional board-specific configurations like Nucleo-G0B1RE.
* Update STM32G0 clock initialization to 64MHz and adjust related configurations
Reconfigure STM32G0 to use a 64MHz system clock via PLL with HSI16 as the source. Update flash latency, prescaler settings, and I2C timing values to reflect the new frequency.
* Cleanup
* Cleanup
* Add STM32G0-specific UART implementation
Introduce a new UART implementation for the STM32G0 series with chip-specific setup and configuration methods. Update the generic STM32 UART code to exclude STM32G0.
* Refactor STM32G0 runtime and machine code to utilize chip-specific register access functions
Simplify and standardize register operations with dedicated setter methods in the STM32G0 runtime and machine code and cleanup redundant syntax.
* Remove redundant commented-out APBENR1 register operations in STM32G0 machine code
* Introduce FDCAN support for STM32G0B1 series
Add FDCAN peripheral implementation targeting STM32G0B1, including support for standard, extended identifiers, and bit rate configuration. Update board files to include FDCAN pins, instances, and clock configuration for Nucleo-G0B1RE and Amken Trio boards.
Remove the sendUSBPacket maxLen param because this greatly confused the compiler.
It also fixes a bug where the length provided to the hardware may not match the length of the packet.
sendUSBPacket now panics if the sent packet is too big.
I also fixed some of the string descriptor logic where we could create a packet without fully populating it.
RP2* systems might require some more work since they are implemented very differently?
I don't have any of those to test with yet, so maybe someone can deal with them in a seperate PR?
The data to write is specififed in words, not in bytes.
This fix is needed for correctness. Without it, a
`machine.Flash.WriteAt` call can result in **data loss** since it will
overwrite more data than it should.
Enabling USB consumes a lot of power. So it's better to keep it disabled
by default when the serial port is set to something other than "usb"
(USB-CDC).
On my nice!nano clone, it reduces current consumption from 1mA to
0.13mA (and most of the rest is probably consumed by a connected SCD41
sensor).
This change might break some expectations, when a board uses USB but not
USB-CDC (I think this is rare, but I didn't check specifically).
VDDH is typically connected to USB (~5V) or directly to a battery.
Measuring the voltage on VDDH is a way to measure the current battery
voltage, which in turn can be useful to determine how much power is left
in the battery.
I've special cased the nrf52840 in a somewhat unusual way, maybe there
is a better way, feel free to comment!
Flash operations must go through the SoftDevice if it is enabled,
otherwise they will crash the chip. (And even then the SoftDevice
doesn't guarantee they'll succeed, depending on advertisement frequency
etc). But this patch makes sure to call the appropriate APIs so that
flash is usable while using Bluetooth.
Ideally we'd use something like
https://github.com/tinygo-org/tinygo/pull/5016 but that's a bit more
involved. As a quick improvement, call gosched() instead.
Example where I use this: a custom WS2812 driver that uses SPI to
transfer the data. It's useful to be able to switch back to the main
goroutine during the transfer to render the next LED update.
Writing the pointer of a buffer to memory-mapped I/O will normally cause
it to escape, which forces the compiler to heap-allocate the buffer. But
we do know how long the value stays alive, so we can tell the compiler
to keep it alive exactly until it is not needed anymore - and tell it to
not treat the pointer-to-uintptr cast as escaping.
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.
* 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.
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.
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).