From a6d2ff5d4d9ed8da5035461c0fd3c6e49cd8b485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Fri, 16 Jan 2026 09:48:38 +0000 Subject: [PATCH] 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. Co-authored-by: Ona --- src/machine/machine_attiny85.go | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/machine/machine_attiny85.go b/src/machine/machine_attiny85.go index 99b1b501b..41e3bbac4 100644 --- a/src/machine/machine_attiny85.go +++ b/src/machine/machine_attiny85.go @@ -405,6 +405,9 @@ type SPI struct { // USICR value configured for the selected SPI mode usicrValue uint8 + + // LSB-first mode (requires software bit reversal) + lsbFirst bool } // SPI0 is the USI-based SPI interface on the ATTiny85 @@ -500,15 +503,30 @@ func (s *SPI) Configure(config SPIConfig) error { s.delayCycles = 0 } - // Note: LSBFirst is not directly supported by USI hardware - // It would need to be implemented in software if required + // Store LSBFirst setting for use in Transfer + s.lsbFirst = config.LSBFirst return nil } +// reverseByte reverses the bit order of a byte (MSB <-> LSB) +// Used for LSB-first SPI mode since USI hardware only supports MSB-first +func reverseByte(b byte) byte { + b = (b&0xF0)>>4 | (b&0x0F)<<4 + b = (b&0xCC)>>2 | (b&0x33)<<2 + b = (b&0xAA)>>1 | (b&0x55)<<1 + return b +} + // Transfer performs a single byte SPI transfer (send and receive simultaneously) // This implements the USI-based SPI transfer using the "clock strobing" technique func (s *SPI) Transfer(b byte) (byte, error) { + // For LSB-first mode, reverse the bits before sending + // USI hardware only supports MSB-first, so we do it in software + if s.lsbFirst { + b = reverseByte(b) + } + // Load the byte to transmit into the USI Data Register s.usidr.Set(b) @@ -542,6 +560,13 @@ func (s *SPI) Transfer(b byte) (byte, error) { } } - // After 8 bits are transferred, return the received byte - return s.usidr.Get(), nil + // Get the received byte + result := s.usidr.Get() + + // For LSB-first mode, reverse the received bits + if s.lsbFirst { + result = reverseByte(result) + } + + return result, nil }