@@ -61,11 +61,10 @@ var SPI0 = &SPI{
6161
6262// Configure sets up the USI for SPI communication
6363func (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