Skip to content

Commit d4fd245

Browse files
committed
tidy up deadlines
1 parent 1ffe1d0 commit d4fd245

File tree

4 files changed

+101
-32
lines changed

4 files changed

+101
-32
lines changed

rp2-pio/config.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ func (cfg *StateMachineConfig) SetSidesetParams(bitCount uint8, optional bool, p
110110

111111
// SetSidesetPins sets the lowest-numbered pin that will be affected by a side-set
112112
// operation.
113+
//
114+
// Remember to also set the pindir of the pin(s).
113115
func (cfg *StateMachineConfig) SetSidesetPins(firstPin machine.Pin) {
114116
checkPinBaseAndCount(firstPin, 1)
115117
cfg.PinCtrl = (cfg.PinCtrl & ^uint32(rp.PIO0_SM0_PINCTRL_SIDESET_BASE_Msk)) |
@@ -123,6 +125,8 @@ func (cfg *StateMachineConfig) SetSidesetPins(firstPin machine.Pin) {
123125
// OUT PINDIRS or MOV PINS instruction. The data written to this pin will always be
124126
// the least-significant bit of the OUT or MOV data.
125127
// - Count defines the number of pins that will be affected by an OUT PINS, 0..32 inclusive.
128+
//
129+
// Remember to also set the pindir of the pin(s).
126130
func (cfg *StateMachineConfig) SetOutPins(base machine.Pin, count uint8) {
127131
checkPinBaseAndCount(base, count)
128132
cfg.PinCtrl = (cfg.PinCtrl & ^uint32(rp.PIO0_SM0_PINCTRL_OUT_BASE_Msk|rp.PIO0_SM0_PINCTRL_OUT_COUNT_Msk)) |
@@ -137,6 +141,8 @@ func (cfg *StateMachineConfig) SetOutPins(base machine.Pin, count uint8) {
137141
// The mapping of SET and OUT onto pins is configured independently. They may be mapped to distinct locations, for example
138142
// if one pin is to be used as a clock signal, and another for data. They may also be overlapping ranges of pins: a UART
139143
// transmitter might use SET to assert start and stop bits, and OUT instructions to shift out FIFO data to the same pins.
144+
//
145+
// Remember to also set the pindir of the pin(s).
140146
func (cfg *StateMachineConfig) SetSetPins(base machine.Pin, count uint8) {
141147
checkPinBaseAndCount(base, count)
142148
cfg.PinCtrl = (cfg.PinCtrl & ^uint32(rp.PIO0_SM0_PINCTRL_SET_BASE_Msk|rp.PIO0_SM0_PINCTRL_SET_COUNT_Msk)) |
@@ -145,6 +151,8 @@ func (cfg *StateMachineConfig) SetSetPins(base machine.Pin, count uint8) {
145151
}
146152

147153
// SetInPins in a state machine configuration. Can overlap with OUT, SET and SIDESET pins.
154+
//
155+
// Remember to also set the pindir of the pin(s).
148156
func (cfg *StateMachineConfig) SetInPins(base machine.Pin) {
149157
checkPinBaseAndCount(base, 1)
150158
cfg.PinCtrl = (cfg.PinCtrl & ^uint32(rp.PIO0_SM0_PINCTRL_IN_BASE_Msk)) | (uint32(base) << rp.PIO0_SM0_PINCTRL_IN_BASE_Pos)

rp2-pio/piolib/all_generate.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package piolib
22

33
import (
44
"errors"
5+
"math"
56
"runtime"
7+
"time"
68
)
79

8-
const timeoutRetries = 1023
10+
const timeoutRetries = math.MaxUint16 * 8
911

1012
var (
1113
errTimeout = errors.New("piolib:timeout")
@@ -23,3 +25,40 @@ var (
2325
func gosched() {
2426
runtime.Gosched()
2527
}
28+
29+
type deadliner struct {
30+
// timeout is a bitshift value for the timeout.
31+
timeout uint8
32+
}
33+
34+
type deadline struct {
35+
t time.Time
36+
}
37+
38+
func (dl deadline) expired() bool {
39+
if dl.t.IsZero() {
40+
return false
41+
}
42+
return time.Since(dl.t) > 0
43+
}
44+
45+
func (ch deadliner) newDeadline() deadline {
46+
var t time.Time
47+
if ch.timeout != 0 {
48+
t = time.Now().Add(time.Duration(1 << ch.timeout))
49+
}
50+
return deadline{t: t}
51+
}
52+
53+
func (ch *deadliner) setTimeout(timeout time.Duration) {
54+
if timeout <= 0 {
55+
return // No timeout.
56+
}
57+
for i := uint8(0); i < 64; i++ {
58+
calc := time.Duration(1 << i)
59+
if calc > timeout {
60+
ch.timeout = i
61+
return
62+
}
63+
}
64+
}

rp2-pio/piolib/dma.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func (arb *dmaArbiter) Channel(channel uint8) dmaChannel {
4343
type dmaChannel struct {
4444
hw *dmaChannelHW
4545
arb *dmaArbiter
46+
dl deadliner
4647
idx uint8
4748
}
4849

@@ -163,7 +164,7 @@ const (
163164
)
164165

165166
// Push32 writes each element of src slice into the memory location at dst.
166-
func (ch dmaChannel) Push32(dst *uint32, src []uint32, dreq uint32) {
167+
func (ch dmaChannel) Push32(dst *uint32, src []uint32, dreq uint32) error {
167168
hw := ch.HW()
168169
srcPtr := uint32(uintptr(unsafe.Pointer(&src[0])))
169170
dstPtr := uint32(uintptr(unsafe.Pointer(dst)))
@@ -182,18 +183,18 @@ func (ch dmaChannel) Push32(dst *uint32, src []uint32, dreq uint32) {
182183

183184
hw.CTRL_TRIG.Set(cc.CTRL)
184185

185-
retries := timeoutRetries
186-
for ch.busy() && retries > 0 {
186+
deadline := ch.dl.newDeadline()
187+
for ch.busy() {
188+
if deadline.expired() {
189+
return errTimeout
190+
}
187191
gosched()
188-
retries--
189-
}
190-
if retries == 0 {
191-
println("DMA push32 timeout")
192192
}
193+
return nil
193194
}
194195

195196
// Pull32 reads the memory location at src into dst slice, incrementing dst pointer but not src.
196-
func (ch dmaChannel) Pull32(dst []uint32, src *uint32, dreq uint32) {
197+
func (ch dmaChannel) Pull32(dst []uint32, src *uint32, dreq uint32) error {
197198
hw := ch.HW()
198199
srcPtr := uint32(uintptr(unsafe.Pointer(src)))
199200
dstPtr := uint32(uintptr(unsafe.Pointer(&dst[0])))
@@ -212,14 +213,14 @@ func (ch dmaChannel) Pull32(dst []uint32, src *uint32, dreq uint32) {
212213

213214
hw.CTRL_TRIG.Set(cc.CTRL)
214215

215-
retries := timeoutRetries
216-
for ch.busy() && retries > 0 {
216+
deadline := ch.dl.newDeadline()
217+
for ch.busy() {
218+
if deadline.expired() {
219+
return errTimeout
220+
}
217221
gosched()
218-
retries--
219-
}
220-
if retries == 0 {
221-
println("DMA push32 timeout")
222222
}
223+
return nil
223224
}
224225

225226
// abort aborts the current transfer sequence on the channel and blocks until

rp2-pio/piolib/spi3w.go

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package piolib
44

55
import (
66
"machine"
7+
"time"
78

89
pio "github.com/tinygo-org/pio/rp2-pio"
910
)
@@ -17,6 +18,7 @@ type SPI3w struct {
1718

1819
enableStatus bool
1920
lastStatus uint32
21+
pinMask uint32
2022
}
2123

2224
func NewSPI3w(sm pio.StateMachine, dio, clk machine.Pin, baud uint32) (*SPI3w, error) {
@@ -53,14 +55,15 @@ func NewSPI3w(sm pio.StateMachine, dio, clk machine.Pin, baud uint32) (*SPI3w, e
5355
// Initialize state machine.
5456
sm.Init(offset, cfg)
5557
pinMask := uint32(1<<dio | 1<<clk)
56-
sm.SetPindirsMasked(0, pinMask)
58+
sm.SetPindirsMasked(pinMask, pinMask)
5759
sm.SetPinsMasked(0, pinMask)
5860

5961
sm.SetEnabled(true)
6062

6163
spiw := &SPI3w{
62-
sm: sm,
63-
offset: offset,
64+
sm: sm,
65+
offset: offset,
66+
pinMask: pinMask,
6467
}
6568
return spiw, nil
6669
}
@@ -103,40 +106,46 @@ func (spi *SPI3w) read(r []uint32) error {
103106
return spi.readDMA(r)
104107
}
105108
i := 0
106-
retries := timeoutRetries
107-
for i < len(r) && retries > 0 {
109+
deadline := spi.newDeadline()
110+
for i < len(r) {
108111
if spi.sm.IsRxFIFOEmpty() {
112+
if deadline.expired() {
113+
return errTimeout
114+
}
109115
gosched()
110-
retries--
111116
continue
112117
}
113118
r[i] = spi.sm.RxGet()
114119
spi.sm.TxPut(r[i])
115120
i++
116121
}
117-
if retries <= 0 {
118-
return errTimeout
119-
}
122+
120123
return nil
121124
}
122125

123126
func (spi *SPI3w) write(w []uint32) error {
124127
if spi.IsDMAEnabled() {
125128
return spi.writeDMA(w)
126129
}
130+
127131
i := 0
128-
retries := timeoutRetries
129-
for i < len(w) && retries > 0 {
132+
deadline := spi.newDeadline()
133+
for i < len(w) {
130134
if spi.sm.IsTxFIFOFull() {
135+
if deadline.expired() {
136+
return errTimeout
137+
}
131138
gosched()
132-
retries--
133139
continue
134140
}
135141
spi.sm.TxPut(w[i])
136142
i++
137143
}
138-
if retries <= 0 {
139-
return errTimeout
144+
for !spi.sm.IsTxFIFOEmpty() {
145+
if deadline.expired() {
146+
return errTimeout
147+
}
148+
gosched()
140149
}
141150
return nil
142151
}
@@ -151,6 +160,15 @@ func (spi *SPI3w) EnableStatus(enabled bool) {
151160
spi.enableStatus = enabled
152161
}
153162

163+
// SetTimeout sets the read/write timeout. Use 0 as argument to disable timeouts.
164+
func (spi *SPI3w) SetTimeout(timeout time.Duration) {
165+
spi.dma.dl.setTimeout(timeout)
166+
}
167+
168+
func (spi *SPI3w) newDeadline() deadline {
169+
return spi.dma.dl.newDeadline()
170+
}
171+
154172
func (spi *SPI3w) getStatus() error {
155173
var buf [1]uint32
156174
err := spi.read(buf[:1])
@@ -161,12 +179,14 @@ func (spi *SPI3w) getStatus() error {
161179
return nil
162180
}
163181

182+
func (spi *SPI3w) forcePinsLow() { spi.sm.SetPinsMasked(0, spi.pinMask) }
183+
164184
func (spi *SPI3w) prepTx(readbits, writebits uint32) {
165185
spi.sm.SetEnabled(false)
166186

167-
spi.sm.ClearFIFOs()
168-
spi.sm.SetX(readbits)
169-
spi.sm.SetY(writebits)
187+
// spi.sm.ClearFIFOs()
188+
spi.sm.SetX(writebits)
189+
spi.sm.SetY(readbits)
170190
spi.sm.Exec(pio.EncodeSet(pio.SrcDestPinDirs, 1)) // Set Pindir out.
171191
spi.sm.Jmp(spi.offset+spi3wWrapTarget, pio.JmpAlways)
172192

@@ -188,6 +208,7 @@ func (spi *SPI3w) EnableDMA(enabled bool) error {
188208
if !ok {
189209
return errDMAUnavail
190210
}
211+
channel.dl = spi.dma.dl // Copy deadline.
191212
spi.dma = channel
192213
return nil
193214
}

0 commit comments

Comments
 (0)