Skip to content
This repository was archived by the owner on Sep 20, 2023. It is now read-only.

Commit 89f628e

Browse files
committed
Implement DMA based PWM, not enabled yet.
1 parent ba06c14 commit 89f628e

File tree

4 files changed

+105
-48
lines changed

4 files changed

+105
-48
lines changed

host/bcm283x/dma.go

Lines changed: 85 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ type controlBlock struct {
417417
//
418418
// dreq can be dmaFire, dmaPwm, dmaPcmTx, etc. waits is additional wait state
419419
// between clocks.
420-
func (c *controlBlock) initBlock(srcAddr, dstAddr, l uint32, srcIO, dstIO bool, dreq dmaTransferInfo, waits int) error {
420+
func (c *controlBlock) initBlock(srcAddr, dstAddr, l uint32, srcIO, dstIO, srcInc, dstInc bool, dreq dmaTransferInfo, waits int) error {
421421
if srcIO && dstIO {
422422
return errors.New("only one of src and dst can be I/O")
423423
}
@@ -444,27 +444,32 @@ func (c *controlBlock) initBlock(srcAddr, dstAddr, l uint32, srcIO, dstIO bool,
444444
if srcAddr == 0 {
445445
t |= dmaSrcIgnore
446446
c.srcAddr = 0
447-
} else if srcIO {
448-
// Memory mapped register
449-
c.srcAddr = physToBus(srcAddr)
450-
// BUG: EXPERIMENTING.
451-
//t |= dmaSrcInc
452-
//c.srcAddr = physToUncachedPhys(srcAddr)
453447
} else {
454-
// Normal memory
455-
t |= dmaSrcInc
456-
c.srcAddr = physToUncachedPhys(srcAddr)
448+
if srcIO {
449+
// Memory mapped register
450+
c.srcAddr = physToBus(srcAddr)
451+
} else {
452+
// Normal memory
453+
c.srcAddr = physToUncachedPhys(srcAddr)
454+
}
455+
if srcInc {
456+
t |= dmaSrcInc
457+
}
457458
}
458459
if dstAddr == 0 {
459460
t |= dmaDstIgnore
460461
c.dstAddr = 0
461-
} else if dstIO {
462-
// Memory mapped register
463-
c.dstAddr = physToBus(dstAddr)
464462
} else {
465-
// Normal memory
466-
t |= dmaDstInc
467-
c.dstAddr = physToUncachedPhys(dstAddr)
463+
if dstIO {
464+
// Memory mapped register
465+
c.dstAddr = physToBus(dstAddr)
466+
} else {
467+
// Normal memory
468+
c.dstAddr = physToUncachedPhys(dstAddr)
469+
}
470+
if dstInc {
471+
t |= dmaDstInc
472+
}
468473
}
469474
if dreq != dmaFire {
470475
// dmaSrcDReq |
@@ -508,15 +513,11 @@ func (d *dmaChannel) isAvailable() bool {
508513
//
509514
// It doesn't clear the local controlBlock cached values.
510515
func (d *dmaChannel) reset() {
511-
// Make sure nothing is happening.
512516
d.cs = dmaReset
513517
// Clear bits if needed.
514-
d.cs = dmaEnd | dmaInterrupt
515-
// Clear values and error bits.
518+
// TODO(simokawa): Test if it works as expected.
519+
d.cs = dmaInterrupt
516520
d.cbAddr = 0
517-
d.nextCB = 0
518-
d.debug = dmaReadError | dmaFIFOError | dmaReadLastNotSetError
519-
d.cs = 0
520521
}
521522

522523
// startIO initializes the DMA channel to start a transmission.
@@ -642,6 +643,54 @@ func runIO(pCB pmem.Mem, liteOk bool) error {
642643
return ch.wait()
643644
}
644645

646+
func allocateCB(size int) ([]controlBlock, *videocore.Mem, error) {
647+
buf, err := videocore.Alloc((size + 0xFFF) &^ 0xFFF)
648+
if err != nil {
649+
return nil, nil, err
650+
}
651+
// TODO(simokawa): call buf.Close()
652+
var cb []controlBlock
653+
if err := buf.AsPOD(&cb); err != nil {
654+
buf.Close()
655+
return nil, nil, err
656+
}
657+
return cb, buf, nil
658+
}
659+
660+
func startPWMbyDMA(p *Pin, rng, data uint32) (*dmaChannel, *videocore.Mem, error) {
661+
cb, buf, err := allocateCB(4096)
662+
if err != nil {
663+
return nil, nil, err
664+
}
665+
u := buf.Uint32()
666+
cb_bytes := uint32(32)
667+
offset_bytes := cb_bytes * 2
668+
u[offset_bytes/4] = uint32(1) << uint(p.number&31)
669+
physBuf := uint32(buf.PhysAddr())
670+
physBit := physBuf + offset_bytes
671+
dest := [2]uint32{
672+
gpioBaseAddr + 0x28 + 4*uint32(p.number/32), // clear
673+
gpioBaseAddr + 0x1C + 4*uint32(p.number/32), // set
674+
}
675+
waits := 0
676+
// High
677+
cb[0].initBlock(physBit, dest[1], data*4, false, true, false, false, dmaPWM, waits)
678+
cb[0].nextCB = physBuf + cb_bytes
679+
// Low
680+
cb[1].initBlock(physBit, dest[0], (rng-data)*4, false, true, false, false, dmaPWM, waits)
681+
cb[1].nextCB = physBuf // Loop back to cb[0]
682+
683+
// OK with lite channels.
684+
_, ch := pickChannel()
685+
if ch == nil {
686+
buf.Close()
687+
return nil, nil, errors.New("bcm283x-dma: no channel available")
688+
}
689+
ch.startIO(physBuf)
690+
691+
return ch, buf, nil
692+
}
693+
645694
// physToUncachedPhys returns the uncached physical memory address backing a
646695
// physical memory address.
647696
//
@@ -696,16 +745,16 @@ func smokeTest() error {
696745
// process startup, which may cause undesirable glitches.
697746

698747
// Initializes the PWM clock right away to 1MHz.
699-
_, waits, err := setPWMClockSource(1000000)
748+
_, waits, err := setPWMClockSource(1000000, 10)
700749
if err != nil {
701750
return err
702751
}
703-
if err := cb.initBlock(uint32(pSrc), uint32(pDst)+holeSize, size-2*holeSize, false, false, dmaPWM, waits); err != nil {
752+
if err := cb.initBlock(uint32(pSrc), uint32(pDst)+holeSize, size-2*holeSize, false, false, true, true, dmaPWM, waits); err != nil {
704753
return err
705754
}
706755
} else {
707756
// Use maximum performance.
708-
if err := cb.initBlock(uint32(pSrc), uint32(pDst)+holeSize, size-2*holeSize, false, false, dmaFire, 0); err != nil {
757+
if err := cb.initBlock(uint32(pSrc), uint32(pDst)+holeSize, size-2*holeSize, false, false, true, true, dmaFire, 0); err != nil {
709758
return err
710759
}
711760
}
@@ -763,6 +812,17 @@ func (d *driverDMA) Close() error {
763812
return nil
764813
}
765814

815+
func resetDMA(ch int) error {
816+
if ch < len(dmaMemory.channels) {
817+
dmaMemory.channels[ch].reset()
818+
} else if ch == 15 {
819+
dmaChannel15.reset()
820+
} else {
821+
return fmt.Errorf("Invalid dma channel %d.", ch)
822+
}
823+
return nil
824+
}
825+
766826
func init() {
767827
if isArm {
768828
periph.MustRegister(&driverDMA{})

host/bcm283x/dma_test.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,45 +51,45 @@ func TestDmaStride_String(t *testing.T) {
5151

5252
func TestControlBlock(t *testing.T) {
5353
c := controlBlock{}
54-
if c.initBlock(0, 0, 0, true, true, dmaFire, 0) == nil {
54+
if c.initBlock(0, 0, 0, true, true, false, false, dmaFire, 0) == nil {
5555
t.Fatal("can't set both")
5656
}
57-
if c.initBlock(0, 0, 0, false, false, dmaFire, 0) == nil {
57+
if c.initBlock(0, 0, 0, false, false, true, true, dmaFire, 0) == nil {
5858
t.Fatal("need at least one addr")
5959
}
60-
if c.initBlock(0, 1, 0, true, false, dmaFire, 0) == nil {
60+
if c.initBlock(0, 1, 0, true, false, false, true, dmaFire, 0) == nil {
6161
t.Fatal("srcIO requires srcAddr")
6262
}
63-
if c.initBlock(1, 0, 0, false, true, dmaFire, 0) == nil {
63+
if c.initBlock(1, 0, 0, false, true, true, false, dmaFire, 0) == nil {
6464
t.Fatal("dstIO requires dstAddr")
6565
}
66-
if c.initBlock(1, 1, 0, false, false, dmaSrcIgnore, 0) == nil {
66+
if c.initBlock(1, 1, 0, false, false, true, true, dmaSrcIgnore, 0) == nil {
6767
t.Fatal("must not specify anything other than clock source")
6868
}
69-
if c.initBlock(1, 1, 0, false, false, dmaFire, 100) == nil {
69+
if c.initBlock(1, 1, 0, false, false, true, true, dmaFire, 100) == nil {
7070
t.Fatal("dstIO requires dstAddr")
7171
}
72-
if c.initBlock(1, 1, 0, false, false, dmaFire, 1) == nil {
72+
if c.initBlock(1, 1, 0, false, false, true, true, dmaFire, 1) == nil {
7373
t.Fatal("dmaFire can't use waits")
7474
}
7575

76-
if err := c.initBlock(1, 0, 0, false, false, dmaFire, 0); err != nil {
76+
if err := c.initBlock(1, 0, 0, false, false, true, true, dmaFire, 0); err != nil {
7777
t.Fatal(err)
7878
}
79-
if err := c.initBlock(0, 1, 0, false, false, dmaFire, 0); err != nil {
79+
if err := c.initBlock(0, 1, 0, false, false, true, true, dmaFire, 0); err != nil {
8080
t.Fatal(err)
8181
}
82-
if err := c.initBlock(1, 0, 0, true, false, dmaFire, 0); err != nil {
82+
if err := c.initBlock(1, 0, 0, true, false, false, true, dmaFire, 0); err != nil {
8383
t.Fatal(err)
8484
}
85-
if err := c.initBlock(0, 1, 0, false, true, dmaPCMTX, 0); err != nil {
85+
if err := c.initBlock(0, 1, 0, false, true, true, false, dmaPCMTX, 0); err != nil {
8686
t.Fatal(err)
8787
}
8888
}
8989

9090
func TestControlBlockGo_String(t *testing.T) {
9191
c := controlBlock{}
92-
if err := c.initBlock(0, 1, 0, false, true, dmaPCMTX, 0); err != nil {
92+
if err := c.initBlock(0, 1, 0, false, true, false, false, dmaPCMTX, 0); err != nil {
9393
t.Fatal(err)
9494
}
9595
expected := "{\n transferInfo: NoWideBursts|SrcIgnore|DstDReq|WaitResp|PCMTX,\n srcAddr: 0x0,\n dstAddr: 0x7e000001,\n txLen: 0,\n stride: 0x0,\n nextCB: 0x0,\n}"
@@ -125,7 +125,7 @@ func TestDmaChannel_GoString(t *testing.T) {
125125
d := dmaChannel{}
126126
d.reset()
127127
d.startIO(0)
128-
expected := "{\n cs: WaitForOutstandingWrites|Active|pp8|p8,\n cbAddr: 0x0,\n transferInfo: Fire,\n srcAddr: 0x0,\n dstAddr: 0x0,\n txLen: 0,\n stride: 0x0,\n nextCB: 0x0,\n debug: ReadError|FIFOError|ReadLastNotSetError,\n reserved: {...},\n}"
128+
expected := "{\n cs: WaitForOutstandingWrites|Active|pp8|p8,\n cbAddr: 0x0,\n transferInfo: Fire,\n srcAddr: 0x0,\n dstAddr: 0x0,\n txLen: 0,\n stride: 0x0,\n nextCB: 0x0,\n debug: 0,\n reserved: {...},\n}"
129129
if s := d.GoString(); s != expected {
130130
t.Fatalf("%q", s)
131131
}

host/bcm283x/pwm.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ func (p *pwmMap) reset() {
220220
// It may select an higher frequency than the one requested.
221221
//
222222
// Other potentially good clock sources are PCM, SPI and UART.
223-
func setPWMClockSource(hz uint64) (uint64, int, error) {
223+
func setPWMClockSource(hz uint64, div uint32) (uint64, int, error) {
224224
if pwmMemory == nil {
225225
return 0, 0, errors.New("subsystem PWM not initialized")
226226
}
@@ -229,22 +229,19 @@ func setPWMClockSource(hz uint64) (uint64, int, error) {
229229
}
230230
actual, divs, err := clockMemory.pwm.set(hz, dmaWaitcyclesMax+1)
231231
if err == nil {
232-
pwmMemory.ctl = 0
233-
Nanospin(10 * time.Microsecond)
234-
pwmMemory.status = pwmStatusMask
235-
Nanospin(10 * time.Microsecond)
236232
// It acts as a clock multiplier, since this amount of data is sent per
237233
// clock tick.
238-
pwmMemory.rng1 = 10 // 32?
234+
pwmMemory.rng1 = uint32(divs) * div
239235
Nanospin(10 * time.Microsecond)
240236
// Periph data (?)
241237

242238
// Use low priority.
243239
pwmMemory.dmaCfg = pwmDMAEnable | pwmDMACfg(15<<pwmPanicShift|15)
244240
Nanospin(10 * time.Microsecond)
245-
pwmMemory.ctl = pwmClearFIFO
241+
pwmMemory.ctl |= pwmClearFIFO
246242
Nanospin(10 * time.Microsecond)
247-
pwmMemory.ctl = pwm1UseFIFO | pwm1Enable
243+
old := pwmMemory.ctl
244+
pwmMemory.ctl = (old & ^pwmControl(0xff)) | pwm1UseFIFO | pwm1Enable
248245
}
249246
// Convert divisor into wait cycles.
250247
return actual, divs - 1, err

host/bcm283x/pwm_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import "testing"
99
func TestPWMMap(t *testing.T) {
1010
p := pwmMap{}
1111
p.reset()
12-
if _, _, err := setPWMClockSource(10); err == nil {
12+
if _, _, err := setPWMClockSource(10, 10); err == nil {
1313
t.Fatal("pwmMemory is nil")
1414
}
1515
defer func() {
1616
pwmMemory = nil
1717
}()
1818
pwmMemory = &p
19-
if _, _, err := setPWMClockSource(10); err == nil {
19+
if _, _, err := setPWMClockSource(10, 10); err == nil {
2020
t.Fatal("clockMemory is nil")
2121
}
2222
}

0 commit comments

Comments
 (0)