Skip to content

Commit 14a2504

Browse files
jespinoona-agent
andcommitted
machine/attiny85: fix USI SPI data corruption
Remove USICLK from Transfer() loop - setting both USICLK and USITC simultaneously caused double-shifting of data. USICLK is a strobe bit that shifts data when written, while USITC toggles the clock pin. With both set, data was shifted twice per iteration. Fix: Configure USICR once in Configure() with mode bits, then only toggle USITC in Transfer() using SetBits() to preserve configuration. Also removed incorrect pin validation that would fail for PB0 (value 0). Co-authored-by: Ona <no-reply@ona.com>
1 parent 6220e55 commit 14a2504

File tree

1 file changed

+20
-17
lines changed

1 file changed

+20
-17
lines changed

src/machine/machine_attiny85.go

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,10 @@ var SPI0 = &SPI{
6161

6262
// Configure sets up the USI for SPI communication
6363
func (s *SPI) Configure(config SPIConfig) error {
64-
// Validate configuration
64+
// Validate configuration - check that USI registers are set
6565
if s.usicr == (*volatile.Register8)(unsafe.Pointer(uintptr(0))) ||
6666
s.usisr == (*volatile.Register8)(unsafe.Pointer(uintptr(0))) ||
67-
s.usidr == (*volatile.Register8)(unsafe.Pointer(uintptr(0))) ||
68-
s.sck == 0 || s.sdi == 0 || s.sdo == 0 || s.cs == 0 {
67+
s.usidr == (*volatile.Register8)(unsafe.Pointer(uintptr(0))) {
6968
return errSPIInvalidMachineConfig
7069
}
7170

@@ -84,17 +83,23 @@ func (s *SPI) Configure(config SPIConfig) error {
8483
s.cs.High()
8584
s.cs.Configure(PinConfig{Mode: PinOutput})
8685

87-
// Reset USI registers
86+
// Reset USI data register
8887
s.usidr.Set(0)
8988
s.usisr.Set(0)
9089

90+
// Configure USI for SPI mode:
91+
// - USIWM0: Three-wire mode (SPI)
92+
// - USICS1: External clock source (software controlled via USITC)
93+
// - USICLK: Clock strobe - enables counter increment on USITC toggle
94+
//
9195
// Note: ATTiny85 USI doesn't have configurable frequency dividers like dedicated SPI hardware
9296
// The SPI clock speed is determined by how fast the software toggles the clock
9397
// For now, we'll ignore the Frequency parameter as it runs at maximum software speed
94-
98+
//
9599
// Note: LSBFirst and Mode configurations are not directly supported by USI
96100
// These would need to be implemented in software if required
97101
// For now, we use the standard MSB-first, Mode 0 (CPOL=0, CPHA=0)
102+
s.usicr.Set(avr.USICR_USIWM0 | avr.USICR_USICS1 | avr.USICR_USICLK)
98103

99104
return nil
100105
}
@@ -110,20 +115,18 @@ func (s *SPI) Transfer(b byte) (byte, error) {
110115
s.usisr.Set(avr.USISR_USIOIF)
111116

112117
// Clock the data out/in
113-
// We need 16 clock edges (8 bits × 2 edges per bit)
118+
// We need 16 clock toggles (8 bits × 2 edges per bit)
114119
// The USI counter counts each clock edge, so it overflows at 16
120+
//
121+
// IMPORTANT: Only toggle USITC here, not USICLK!
122+
// - USITC toggles the clock pin
123+
// - With USICS1 set (software clock strobe mode), the data shifts on clock edges
124+
// - USICLK is a separate strobe that would cause extra shifts if set here
125+
//
126+
// The USICR register was configured in Configure() with USIWM0 | USICS1.
127+
// We use OR-assign to preserve that configuration and only set USITC.
115128
for !s.usisr.HasBits(avr.USISR_USIOIF) {
116-
// Toggle the clock pin and strobe the clock
117-
// This single write causes the USI hardware to:
118-
// 1. Toggle the SCK pin (via USITC bit)
119-
// 2. Shift one bit out on DO and read one bit in on DI (via USICLK bit)
120-
// 3. Increment the 4-bit counter
121-
//
122-
// USIWM0 = 1: Three-wire mode (SPI mode)
123-
// USICS1 = 1: Software clock strobe (we control the clock)
124-
// USICLK = 1: Clock strobe (shift the data)
125-
// USITC = 1: Toggle the clock pin
126-
s.usicr.Set(avr.USICR_USIWM0 | avr.USICR_USICS1 | avr.USICR_USICLK | avr.USICR_USITC)
129+
s.usicr.SetBits(avr.USICR_USITC)
127130
}
128131

129132
// After 8 bits are transferred, return the received byte

0 commit comments

Comments
 (0)