From b7b23ace3f8502049909a8426ccf52d694a9543b Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 26 May 2023 17:28:04 +0200 Subject: [PATCH] samd21: fix issue with WS2812 driver The regular port access is around 4 cycles, instead of the usual 2 cycles for a store instruction on Cortex-M0+. The IOBUS however is faster, I didn't measure exactly but I guess it's 2 cycles as expected. This fixes a bug in the WS2812 driver that only happens on samd21 chips: https://github.com/tinygo-org/drivers/issues/540 --- src/machine/machine_atsamd21g18.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/machine/machine_atsamd21g18.go b/src/machine/machine_atsamd21g18.go index 383f51d9..9b78ad33 100644 --- a/src/machine/machine_atsamd21g18.go +++ b/src/machine/machine_atsamd21g18.go @@ -46,10 +46,14 @@ func init() { // Return the register and mask to enable a given GPIO pin. This can be used to // implement bit-banged drivers. func (p Pin) PortMaskSet() (*uint32, uint32) { + // Note: using PORT_IOBUS for faster pin accesses. + // The regular PORT registers appear to take around 4 clock cycles to store, + // which is longer than the ws2812 driver expects. The IOBUS is is fast + // enough to avoid this issue. if p < 32 { - return &sam.PORT.OUTSET0.Reg, 1 << uint8(p) + return &sam.PORT_IOBUS.OUTSET0.Reg, 1 << uint8(p) } else { - return &sam.PORT.OUTSET1.Reg, 1 << uint8(p-32) + return &sam.PORT_IOBUS.OUTSET1.Reg, 1 << uint8(p-32) } } @@ -57,9 +61,9 @@ func (p Pin) PortMaskSet() (*uint32, uint32) { // implement bit-banged drivers. func (p Pin) PortMaskClear() (*uint32, uint32) { if p < 32 { - return &sam.PORT.OUTCLR0.Reg, 1 << uint8(p) + return &sam.PORT_IOBUS.OUTCLR0.Reg, 1 << uint8(p) } else { - return &sam.PORT.OUTCLR1.Reg, 1 << uint8(p-32) + return &sam.PORT_IOBUS.OUTCLR1.Reg, 1 << uint8(p-32) } }