Skip to content

Commit 324c502

Browse files
committed
refactor SPI3w; better PIO docs; add more functionality
1 parent 48f084b commit 324c502

File tree

6 files changed

+82
-40
lines changed

6 files changed

+82
-40
lines changed

rp2-pio/pio.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,19 @@ func (pio *PIO) GetIRQ() uint8 {
225225
}
226226

227227
// ClearIRQ clears IRQ flags when 1 is written to bit flag.
228-
func (pio *PIO) ClearIRQ(irqmsk uint8) {
229-
pio.hw.SetIRQ(uint32(irqmsk))
228+
func (pio *PIO) ClearIRQ(irqMask uint8) {
229+
pio.hw.SetIRQ(uint32(irqMask))
230+
}
231+
232+
// SetInputSyncBypassMasked sets the pinMask bits of the INPUT_SYNC_BYPASS register
233+
// with the values in the corresponding bypassMask bits.
234+
//
235+
// There is a 2-flipflop synchronizer on each GPIO input, which protects
236+
// PIO logic from metastabilities. This increases input delay, and for
237+
// fast synchronous IO (e.g. SPI) these synchronizers may need to be bypassed.
238+
// If bit set the corresponding synchronizer is bypassed. If in doubt leave as zeros.
239+
func (pio *PIO) SetInputSyncBypassMasked(bypassMask, pinMask uint32) {
240+
pio.hw.INPUT_SYNC_BYPASS.ReplaceBits(bypassMask, pinMask, 0)
230241
}
231242

232243
// HW returns a pointer to the PIO's hardware registers.

rp2-pio/piolib/spi.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,15 @@ func NewSPI(sm pio.StateMachine, spicfg machine.SPIConfig) (*SPI, error) {
6969

7070
// MOSI, SCK output are low, MISO is input.
7171
outMask := uint32((1 << spicfg.SCK) | (1 << spicfg.SDO))
72+
inMask := uint32(1 << spicfg.SDI)
7273
sm.SetPinsMasked(0, outMask)
73-
sm.SetPindirsMasked(outMask, outMask|(1<<spicfg.SDI))
74+
sm.SetPindirsMasked(outMask, outMask|inMask)
7475

7576
pincfg := machine.PinConfig{Mode: Pio.PinMode()}
7677
spicfg.SCK.Configure(pincfg)
7778
spicfg.SDO.Configure(pincfg)
7879
spicfg.SDI.Configure(pincfg)
79-
Pio.HW().INPUT_SYNC_BYPASS.SetBits(1 << spicfg.SDI)
80+
Pio.SetInputSyncBypassMasked(inMask, inMask)
8081

8182
sm.Init(offset, cfg)
8283
sm.SetEnabled(true)

rp2-pio/piolib/spi3w.go

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
package piolib
44

55
import (
6+
"device/rp"
67
"machine"
8+
"runtime/volatile"
79
"time"
10+
"unsafe"
811

912
pio "github.com/tinygo-org/pio/rp2-pio"
1013
)
@@ -50,21 +53,36 @@ func NewSPI3w(sm pio.StateMachine, dio, clk machine.Pin, baud uint32) (*SPI3w, e
5053
pinCfg := machine.PinConfig{Mode: Pio.PinMode()}
5154
dio.Configure(pinCfg)
5255
clk.Configure(pinCfg)
53-
Pio.HW().INPUT_SYNC_BYPASS.SetBits(1 << dio)
56+
Pio.SetInputSyncBypassMasked(1<<dio, 1<<dio)
57+
58+
dioPad := pinPadCtrl(dio)
59+
// Disable pull up and pull down.
60+
dioPad.ReplaceBits(0, 1, rp.PADS_BANK0_GPIO0_PUE_Pos)
61+
dioPad.ReplaceBits(0, 1, rp.PADS_BANK0_GPIO0_PDE_Pos)
62+
63+
dioPad.ReplaceBits(1, 1, rp.PADS_BANK0_GPIO0_SCHMITT_Pos) // Enable Schmitt trigger.
64+
65+
// 12mA drive strength for both clock and output.
66+
const drive = rp.PADS_BANK0_GPIO0_DRIVE_12mA
67+
const driveMsk = rp.PADS_BANK0_GPIO0_DRIVE_Msk >> rp.PADS_BANK0_GPIO0_DRIVE_Pos
68+
dioPad.ReplaceBits(drive, driveMsk, rp.PADS_BANK0_GPIO0_DRIVE_Pos)
69+
70+
dioPad.ReplaceBits(1, 1, rp.PADS_BANK0_GPIO0_SLEWFAST_Pos) // Enable fast slewrate.
71+
72+
clkPad := pinPadCtrl(clk)
73+
clkPad.ReplaceBits(drive, driveMsk, rp.PADS_BANK0_GPIO0_DRIVE_Pos)
74+
clkPad.ReplaceBits(1, 1, rp.PADS_BANK0_GPIO0_SLEWFAST_Pos) // Enable fast slewrate.
5475

5576
// Initialize state machine.
5677
sm.Init(offset, cfg)
5778
pinMask := uint32(1<<dio | 1<<clk)
5879
sm.SetPindirsMasked(pinMask, pinMask)
5980
sm.SetPinsMasked(0, pinMask)
6081

61-
sm.SetEnabled(true)
62-
6382
spiw := &SPI3w{
64-
sm: sm,
65-
offset: offset,
66-
pinMask: pinMask,
67-
statusEn: true,
83+
sm: sm,
84+
offset: offset,
85+
pinMask: pinMask,
6886
}
6987
return spiw, nil
7088
}
@@ -163,8 +181,8 @@ func (spi *SPI3w) LastStatus() uint32 {
163181
return spi.lastStatus
164182
}
165183

166-
// enableStatus enables the reading of the last status word after a CmdRead/CmdWrite.
167-
func (spi *SPI3w) enableStatus(enabled bool) {
184+
// EnableStatus enables the reading of the last status word after a CmdRead/CmdWrite.
185+
func (spi *SPI3w) EnableStatus(enabled bool) {
168186
spi.statusEn = enabled
169187
}
170188

@@ -250,3 +268,7 @@ func (spi *SPI3w) writeDMA(w []uint32) error {
250268
func (spi *SPI3w) IsDMAEnabled() bool {
251269
return spi.dma.IsValid()
252270
}
271+
272+
func pinPadCtrl(pin machine.Pin) *volatile.Register32 {
273+
return (*volatile.Register32)(unsafe.Pointer(uintptr(unsafe.Pointer(&rp.PADS_BANK0.GPIO0)) + uintptr(4*pin)))
274+
}

rp2-pio/piolib/spi3w.pio

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,23 @@
66
.wrap_target
77

88
; write out x-1 bits
9-
lp:
10-
out pins, 1 side 0
11-
jmp x-- lp side 1
12-
13-
; Switch directions
14-
9+
lp:
10+
out pins, 1 side 0
11+
jmp x-- lp side 1
12+
13+
jmp !y end side 0 ; If y (readbits) is 0 then run to end of program.
14+
15+
; Prepare for read, Switch directions
1516
set pindirs, 0 side 0
1617
nop side 0
17-
18+
1819
; read in y-1 bits
1920
lp2:
2021
in pins, 1 side 1
2122
jmp y-- lp2 side 0
2223

23-
; wait for event and irq host
24-
24+
; wait for event and irq host
25+
end:
2526
wait 1 pin 0 side 0
2627
irq 0 side 0
2728

rp2-pio/piolib/spi3w_pio.go

Lines changed: 6 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rp2-pio/statemachine.go

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,12 @@ func (sm StateMachine) IsEnabled() bool {
9696
return sm.pio.hw.CTRL.HasBits(1 << (rp.PIO0_CTRL_SM_ENABLE_Pos + sm.index))
9797
}
9898

99-
// Restart restarts the state machine
99+
// Restart clears internal StateMachine state which may otherwise be difficult to access, e.g. shift counters.
100100
func (sm StateMachine) Restart() {
101101
sm.pio.hw.CTRL.SetBits(1 << (rp.PIO0_CTRL_SM_RESTART_Pos + sm.index))
102102
}
103103

104-
// Restart a state machine clock divider with a phase of 0
104+
// ClkDivRestart forces clock dividers to restart their count and clear fractional accumulators (phase is zeroed).
105105
func (sm StateMachine) ClkDivRestart() {
106106
sm.pio.hw.CTRL.SetBits(1 << (rp.PIO0_CTRL_CLKDIV_RESTART_Pos + sm.index))
107107
}
@@ -146,16 +146,16 @@ func (sm StateMachine) RxGet() uint32 {
146146

147147
// TxReg gets a pointer to the TX FIFO register for this state machine.
148148
func (sm StateMachine) TxReg() *volatile.Register32 {
149-
start := unsafe.Pointer(&sm.pio.hw.TXF0) // 0x10
149+
start := uintptr(unsafe.Pointer(&sm.pio.hw.TXF0)) // 0x10
150150
offset := uintptr(sm.index) * 4
151-
return (*volatile.Register32)(unsafe.Pointer(uintptr(start) + offset))
151+
return (*volatile.Register32)(unsafe.Pointer(start + offset))
152152
}
153153

154154
// RxReg gets a pointer to the RX FIFO register for this state machine.
155155
func (sm StateMachine) RxReg() *volatile.Register32 {
156-
start := unsafe.Pointer(&sm.pio.hw.RXF0) // 0x20
156+
start := uintptr(unsafe.Pointer(&sm.pio.hw.RXF0)) // 0x20
157157
offset := uintptr(sm.index) * 4
158-
return (*volatile.Register32)(unsafe.Pointer(uintptr(start) + offset))
158+
return (*volatile.Register32)(unsafe.Pointer(start + offset))
159159
}
160160

161161
// RxFIFOLevel returns the number of elements currently in a state machine's RX FIFO.
@@ -238,6 +238,9 @@ func (sm StateMachine) SetPinsMasked(valueMask, pinMask uint32) {
238238
sm.setPinExec(SrcDestPins, valueMask, pinMask)
239239
}
240240

241+
// SetPindirsMasked sets the pin directions (input/output) on multiple pins for
242+
// the PIO instance. This method repeatedly reconfigures the state machines pins.
243+
// Use this method as convenience to set initial pin states BEFORE running state machine.
241244
func (sm StateMachine) SetPindirsMasked(dirMask, pinMask uint32) {
242245
sm.setPinExec(SrcDestPinDirs, dirMask, pinMask)
243246
}
@@ -337,10 +340,10 @@ func (sm StateMachine) Jmp(toAddr uint8, cond JmpCond) {
337340
}
338341

339342
const (
340-
_REG_ALIAS_RW_BITS = 0x0 << 12
341-
_REG_ALIAS_XOR_BITS = 0x1 << 12
342-
_REG_ALIAS_SET_BITS = 0x2 << 12
343-
_REG_ALIAS_CLR_BITS = 0x3 << 12
343+
// regAliasRW = 0x0 << 12
344+
regAliasXOR = 0x1 << 12
345+
regAliasSET = 0x2 << 12
346+
regAliasCLR = 0x3 << 12
344347
)
345348

346349
// Gets the 'XOR' alias for a register
@@ -354,10 +357,13 @@ const (
354357
// - Addr + 0x1000 : atomic XOR on write
355358
// - Addr + 0x2000 : atomic bitmask set on write
356359
// - Addr + 0x3000 : atomic bitmask clear on write
357-
func xorRegister(reg *volatile.Register32) *volatile.Register32 {
358-
return (*volatile.Register32)(unsafe.Pointer(uintptr(unsafe.Pointer(reg)) | _REG_ALIAS_XOR_BITS))
360+
//
361+
//go:inline
362+
func aliasReg(alias uintptr, reg *volatile.Register32) *volatile.Register32 {
363+
alias = uintptr(unsafe.Pointer(reg)) | alias
364+
return (*volatile.Register32)(unsafe.Pointer(alias))
359365
}
360366

361367
func xorBits(reg *volatile.Register32, bits uint32) {
362-
xorRegister(reg).Set(bits)
368+
aliasReg(regAliasXOR, reg).Set(bits)
363369
}

0 commit comments

Comments
 (0)