diff --git a/host/bcm283x/dma.go b/host/bcm283x/dma.go index 3841f1806..8af1a1090 100644 --- a/host/bcm283x/dma.go +++ b/host/bcm283x/dma.go @@ -417,7 +417,7 @@ type controlBlock struct { // // dreq can be dmaFire, dmaPwm, dmaPcmTx, etc. waits is additional wait state // between clocks. -func (c *controlBlock) initBlock(srcAddr, dstAddr, l uint32, srcIO, dstIO bool, dreq dmaTransferInfo, waits int) error { +func (c *controlBlock) initBlock(srcAddr, dstAddr, l uint32, srcIO, dstIO, srcInc, dstInc bool, dreq dmaTransferInfo, waits int) error { if srcIO && dstIO { return errors.New("only one of src and dst can be I/O") } @@ -444,27 +444,32 @@ func (c *controlBlock) initBlock(srcAddr, dstAddr, l uint32, srcIO, dstIO bool, if srcAddr == 0 { t |= dmaSrcIgnore c.srcAddr = 0 - } else if srcIO { - // Memory mapped register - c.srcAddr = physToBus(srcAddr) - // BUG: EXPERIMENTING. - //t |= dmaSrcInc - //c.srcAddr = physToUncachedPhys(srcAddr) } else { - // Normal memory - t |= dmaSrcInc - c.srcAddr = physToUncachedPhys(srcAddr) + if srcIO { + // Memory mapped register + c.srcAddr = physToBus(srcAddr) + } else { + // Normal memory + c.srcAddr = physToUncachedPhys(srcAddr) + } + if srcInc { + t |= dmaSrcInc + } } if dstAddr == 0 { t |= dmaDstIgnore c.dstAddr = 0 - } else if dstIO { - // Memory mapped register - c.dstAddr = physToBus(dstAddr) } else { - // Normal memory - t |= dmaDstInc - c.dstAddr = physToUncachedPhys(dstAddr) + if dstIO { + // Memory mapped register + c.dstAddr = physToBus(dstAddr) + } else { + // Normal memory + c.dstAddr = physToUncachedPhys(dstAddr) + } + if dstInc { + t |= dmaDstInc + } } if dreq != dmaFire { // dmaSrcDReq | @@ -508,15 +513,12 @@ func (d *dmaChannel) isAvailable() bool { // // It doesn't clear the local controlBlock cached values. func (d *dmaChannel) reset() { - // Make sure nothing is happening. d.cs = dmaReset // Clear bits if needed. - d.cs = dmaEnd | dmaInterrupt - // Clear values and error bits. + // TODO(simokawa): Test if it works as expected. + d.cs = dmaInterrupt d.cbAddr = 0 d.nextCB = 0 - d.debug = dmaReadError | dmaFIFOError | dmaReadLastNotSetError - d.cs = 0 } // startIO initializes the DMA channel to start a transmission. @@ -642,6 +644,53 @@ func runIO(pCB pmem.Mem, liteOk bool) error { return ch.wait() } +func allocateCB(size int) ([]controlBlock, *videocore.Mem, error) { + buf, err := videocore.Alloc((size + 0xFFF) &^ 0xFFF) + if err != nil { + return nil, nil, err + } + var cb []controlBlock + if err := buf.AsPOD(&cb); err != nil { + buf.Close() + return nil, nil, err + } + return cb, buf, nil +} + +func startPWMbyDMA(p *Pin, rng, data uint32) (*dmaChannel, *videocore.Mem, error) { + cb, buf, err := allocateCB(4096) + if err != nil { + return nil, nil, err + } + u := buf.Uint32() + cbBytes := uint32(32) + offsetBytes := cbBytes * 2 + u[offsetBytes/4] = uint32(1) << uint(p.number&31) + physBuf := uint32(buf.PhysAddr()) + physBit := physBuf + offsetBytes + dest := [2]uint32{ + gpioBaseAddr + 0x28 + 4*uint32(p.number/32), // clear + gpioBaseAddr + 0x1C + 4*uint32(p.number/32), // set + } + waits := 0 + // High + cb[0].initBlock(physBit, dest[1], data*4, false, true, false, false, dmaPWM, waits) + cb[0].nextCB = physBuf + cbBytes + // Low + cb[1].initBlock(physBit, dest[0], (rng-data)*4, false, true, false, false, dmaPWM, waits) + cb[1].nextCB = physBuf // Loop back to cb[0] + + // OK with lite channels. + _, ch := pickChannel() + if ch == nil { + buf.Close() + return nil, nil, errors.New("bcm283x-dma: no channel available") + } + ch.startIO(physBuf) + + return ch, buf, nil +} + // physToUncachedPhys returns the uncached physical memory address backing a // physical memory address. // @@ -696,16 +745,16 @@ func smokeTest() error { // process startup, which may cause undesirable glitches. // Initializes the PWM clock right away to 1MHz. - _, waits, err := setPWMClockSource(1000000) + _, waits, err := setPWMClockSource(1000000, 10) if err != nil { return err } - if err := cb.initBlock(uint32(pSrc), uint32(pDst)+holeSize, size-2*holeSize, false, false, dmaPWM, waits); err != nil { + if err := cb.initBlock(uint32(pSrc), uint32(pDst)+holeSize, size-2*holeSize, false, false, true, true, dmaPWM, waits); err != nil { return err } } else { // Use maximum performance. - if err := cb.initBlock(uint32(pSrc), uint32(pDst)+holeSize, size-2*holeSize, false, false, dmaFire, 0); err != nil { + if err := cb.initBlock(uint32(pSrc), uint32(pDst)+holeSize, size-2*holeSize, false, false, true, true, dmaFire, 0); err != nil { return err } } @@ -763,6 +812,17 @@ func (d *driverDMA) Close() error { return nil } +func resetDMA(ch int) error { + if ch < len(dmaMemory.channels) { + dmaMemory.channels[ch].reset() + } else if ch == 15 { + dmaChannel15.reset() + } else { + return fmt.Errorf("Invalid dma channel %d.", ch) + } + return nil +} + func init() { if isArm { periph.MustRegister(&driverDMA{}) diff --git a/host/bcm283x/dma_test.go b/host/bcm283x/dma_test.go index 2e93b901c..d9da6fc30 100644 --- a/host/bcm283x/dma_test.go +++ b/host/bcm283x/dma_test.go @@ -51,45 +51,45 @@ func TestDmaStride_String(t *testing.T) { func TestControlBlock(t *testing.T) { c := controlBlock{} - if c.initBlock(0, 0, 0, true, true, dmaFire, 0) == nil { + if c.initBlock(0, 0, 0, true, true, false, false, dmaFire, 0) == nil { t.Fatal("can't set both") } - if c.initBlock(0, 0, 0, false, false, dmaFire, 0) == nil { + if c.initBlock(0, 0, 0, false, false, true, true, dmaFire, 0) == nil { t.Fatal("need at least one addr") } - if c.initBlock(0, 1, 0, true, false, dmaFire, 0) == nil { + if c.initBlock(0, 1, 0, true, false, false, true, dmaFire, 0) == nil { t.Fatal("srcIO requires srcAddr") } - if c.initBlock(1, 0, 0, false, true, dmaFire, 0) == nil { + if c.initBlock(1, 0, 0, false, true, true, false, dmaFire, 0) == nil { t.Fatal("dstIO requires dstAddr") } - if c.initBlock(1, 1, 0, false, false, dmaSrcIgnore, 0) == nil { + if c.initBlock(1, 1, 0, false, false, true, true, dmaSrcIgnore, 0) == nil { t.Fatal("must not specify anything other than clock source") } - if c.initBlock(1, 1, 0, false, false, dmaFire, 100) == nil { + if c.initBlock(1, 1, 0, false, false, true, true, dmaFire, 100) == nil { t.Fatal("dstIO requires dstAddr") } - if c.initBlock(1, 1, 0, false, false, dmaFire, 1) == nil { + if c.initBlock(1, 1, 0, false, false, true, true, dmaFire, 1) == nil { t.Fatal("dmaFire can't use waits") } - if err := c.initBlock(1, 0, 0, false, false, dmaFire, 0); err != nil { + if err := c.initBlock(1, 0, 0, false, false, true, true, dmaFire, 0); err != nil { t.Fatal(err) } - if err := c.initBlock(0, 1, 0, false, false, dmaFire, 0); err != nil { + if err := c.initBlock(0, 1, 0, false, false, true, true, dmaFire, 0); err != nil { t.Fatal(err) } - if err := c.initBlock(1, 0, 0, true, false, dmaFire, 0); err != nil { + if err := c.initBlock(1, 0, 0, true, false, false, true, dmaFire, 0); err != nil { t.Fatal(err) } - if err := c.initBlock(0, 1, 0, false, true, dmaPCMTX, 0); err != nil { + if err := c.initBlock(0, 1, 0, false, true, true, false, dmaPCMTX, 0); err != nil { t.Fatal(err) } } func TestControlBlockGo_String(t *testing.T) { c := controlBlock{} - if err := c.initBlock(0, 1, 0, false, true, dmaPCMTX, 0); err != nil { + if err := c.initBlock(0, 1, 0, false, true, false, false, dmaPCMTX, 0); err != nil { t.Fatal(err) } 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) { d := dmaChannel{} d.reset() d.startIO(0) - 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}" + 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}" if s := d.GoString(); s != expected { t.Fatalf("%q", s) } diff --git a/host/bcm283x/pwm.go b/host/bcm283x/pwm.go index 301a82298..521317ca8 100644 --- a/host/bcm283x/pwm.go +++ b/host/bcm283x/pwm.go @@ -220,7 +220,7 @@ func (p *pwmMap) reset() { // It may select an higher frequency than the one requested. // // Other potentially good clock sources are PCM, SPI and UART. -func setPWMClockSource(hz uint64) (uint64, int, error) { +func setPWMClockSource(hz uint64, div uint32) (uint64, int, error) { if pwmMemory == nil { return 0, 0, errors.New("subsystem PWM not initialized") } @@ -229,22 +229,19 @@ func setPWMClockSource(hz uint64) (uint64, int, error) { } actual, divs, err := clockMemory.pwm.set(hz, dmaWaitcyclesMax+1) if err == nil { - pwmMemory.ctl = 0 - Nanospin(10 * time.Microsecond) - pwmMemory.status = pwmStatusMask - Nanospin(10 * time.Microsecond) // It acts as a clock multiplier, since this amount of data is sent per // clock tick. - pwmMemory.rng1 = 10 // 32? + pwmMemory.rng1 = uint32(divs) * div Nanospin(10 * time.Microsecond) // Periph data (?) // Use low priority. pwmMemory.dmaCfg = pwmDMAEnable | pwmDMACfg(15<