-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparallel8.go
126 lines (107 loc) · 2.71 KB
/
parallel8.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//go:build rp2040
package piolib
import (
"errors"
"machine"
"unsafe"
pio "github.com/tinygo-org/pio/rp2-pio"
)
// Parallel8Tx is a 8-wire, only send Parallel implementation.
type Parallel8Tx struct {
sm pio.StateMachine
offset uint8
dma dmaChannel
}
// unused for now.
const noDMA uint32 = 0xffff_ffff
func NewParallel8Tx(sm pio.StateMachine, wr, dStart machine.Pin, baud uint32) (*Parallel8Tx, error) {
sm.TryClaim() // SM should be claimed beforehand, we just guarantee it's claimed.
const nPins = 8
if dStart+nPins > 31 {
return nil, errors.New("invalid D0..D7 pin range")
}
baud *= 6 // ??? why 6?
whole, frac, err := pio.ClkDivFromFrequency(baud, machine.CPUFrequency())
if err != nil {
return nil, err
}
Pio := sm.PIO()
offset, err := Pio.AddProgram(parallel8Instructions, parallel8Origin)
if err != nil {
return nil, err
}
// Configure pins.
pinCfg := machine.PinConfig{Mode: Pio.PinMode()}
for i := dStart; i < dStart+nPins; i++ {
i.Configure(pinCfg)
}
wr.Configure(pinCfg)
sm.SetPindirsConsecutive(wr, 1, true)
sm.SetPindirsConsecutive(dStart, nPins, true)
cfg := parallel8ProgramDefaultConfig(offset)
cfg.SetOutPins(dStart, nPins)
cfg.SetSidesetPins(wr)
cfg.SetFIFOJoin(pio.FifoJoinTx)
cfg.SetOutShift(true, true, nPins)
cfg.SetClkDivIntFrac(whole, frac)
sm.Init(offset, cfg)
sm.SetEnabled(true)
return &Parallel8Tx{sm: sm, offset: offset}, nil
}
func (pl *Parallel8Tx) Write(data []uint8) error {
if pl.IsDMAEnabled() {
return pl.dmaWrite(data)
}
retries := int8(127)
for _, char := range data {
if !pl.sm.IsTxFIFOFull() {
pl.sm.TxPut(uint32(char))
} else if retries > 0 {
gosched()
retries--
} else {
return errTimeout
}
}
return nil
}
func (pl *Parallel8Tx) IsDMAEnabled() bool {
return pl.dma.IsValid()
}
func (pl *Parallel8Tx) EnableDMA(enabled bool) error {
if !pl.sm.IsValid() {
return errors.New("PIO Statemachine needs initializing") //Not initialized
}
dmaAlreadyEnabled := pl.IsDMAEnabled()
if !enabled || dmaAlreadyEnabled {
if !enabled && dmaAlreadyEnabled {
pl.dma.Unclaim()
pl.dma = dmaChannel{} // Invalidate DMA channel.
}
return nil
}
channel, ok := _DMA.ClaimChannel()
if !ok {
return errDMAUnavail
}
channel.dl = pl.dma.dl // Copy deadline.
pl.dma = channel
cc := pl.dma.CurrentConfig()
cc.setBSwap(false)
cc.setTransferDataSize(dmaTxSize8)
pl.dma.Init(cc)
return nil
}
func (pl *Parallel8Tx) dmaWrite(data []byte) error {
dreq := dmaPIO_TxDREQ(pl.sm)
err := pl.dma.Push8((*byte)(unsafe.Pointer(&pl.sm.TxReg().Reg)), data, dreq)
if err != nil {
return err
}
// DMA is done after this point but we still have to wait for
// the FIFO to be empty
for !pl.sm.IsTxFIFOEmpty() {
gosched()
}
return nil
}