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

Commit 74f4bb3

Browse files
committed
Implement DMA based PWM, which is enabled for all GPIO pins expcept PWM0 pins.
1 parent ba06c14 commit 74f4bb3

File tree

5 files changed

+181
-130
lines changed

5 files changed

+181
-130
lines changed

host/bcm283x/dma.go

Lines changed: 69 additions & 13 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
}
@@ -452,9 +452,11 @@ func (c *controlBlock) initBlock(srcAddr, dstAddr, l uint32, srcIO, dstIO bool,
452452
//c.srcAddr = physToUncachedPhys(srcAddr)
453453
} else {
454454
// Normal memory
455-
t |= dmaSrcInc
456455
c.srcAddr = physToUncachedPhys(srcAddr)
457456
}
457+
if srcInc {
458+
t |= dmaSrcInc
459+
}
458460
if dstAddr == 0 {
459461
t |= dmaDstIgnore
460462
c.dstAddr = 0
@@ -463,9 +465,11 @@ func (c *controlBlock) initBlock(srcAddr, dstAddr, l uint32, srcIO, dstIO bool,
463465
c.dstAddr = physToBus(dstAddr)
464466
} else {
465467
// Normal memory
466-
t |= dmaDstInc
467468
c.dstAddr = physToUncachedPhys(dstAddr)
468469
}
470+
if dstInc {
471+
t |= dmaDstInc
472+
}
469473
if dreq != dmaFire {
470474
// dmaSrcDReq |
471475
t |= dmaDstDReq | dreq | dmaTransferInfo(waits<<dmaWaitCyclesShift)
@@ -508,15 +512,8 @@ func (d *dmaChannel) isAvailable() bool {
508512
//
509513
// It doesn't clear the local controlBlock cached values.
510514
func (d *dmaChannel) reset() {
511-
// Make sure nothing is happening.
512515
d.cs = dmaReset
513-
// Clear bits if needed.
514-
d.cs = dmaEnd | dmaInterrupt
515-
// Clear values and error bits.
516516
d.cbAddr = 0
517-
d.nextCB = 0
518-
d.debug = dmaReadError | dmaFIFOError | dmaReadLastNotSetError
519-
d.cs = 0
520517
}
521518

522519
// startIO initializes the DMA channel to start a transmission.
@@ -642,6 +639,54 @@ func runIO(pCB pmem.Mem, liteOk bool) error {
642639
return ch.wait()
643640
}
644641

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

698743
// Initializes the PWM clock right away to 1MHz.
699-
_, waits, err := setPWMClockSource(1000000)
744+
_, waits, err := setPWMClockSource(1000000, 10)
700745
if err != nil {
701746
return err
702747
}
703-
if err := cb.initBlock(uint32(pSrc), uint32(pDst)+holeSize, size-2*holeSize, false, false, dmaPWM, waits); err != nil {
748+
if err := cb.initBlock(uint32(pSrc), uint32(pDst)+holeSize, size-2*holeSize, false, false, true, true, dmaPWM, waits); err != nil {
704749
return err
705750
}
706751
} else {
707752
// Use maximum performance.
708-
if err := cb.initBlock(uint32(pSrc), uint32(pDst)+holeSize, size-2*holeSize, false, false, dmaFire, 0); err != nil {
753+
if err := cb.initBlock(uint32(pSrc), uint32(pDst)+holeSize, size-2*holeSize, false, false, true, true, dmaFire, 0); err != nil {
709754
return err
710755
}
711756
}
@@ -763,6 +808,17 @@ func (d *driverDMA) Close() error {
763808
return nil
764809
}
765810

811+
func ResetDMA(ch int) error {
812+
if ch < len(dmaMemory.channels) {
813+
dmaMemory.channels[ch].reset()
814+
} else if ch == 15 {
815+
dmaChannel15.reset()
816+
} else {
817+
return fmt.Errorf("Invalid dma channel %d.", ch)
818+
}
819+
return nil
820+
}
821+
766822
func init() {
767823
if isArm {
768824
periph.MustRegister(&driverDMA{})

host/bcm283x/dma_test.go

Lines changed: 12 additions & 12 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, true, 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}"

0 commit comments

Comments
 (0)