diff --git a/Makefile b/Makefile index 3295b9cd..64d7708f 100644 --- a/Makefile +++ b/Makefile @@ -298,8 +298,11 @@ smoketest: $(TINYGO) build -size short -o test.hex -target=wioterminal examples/blinky1 @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=pygamer examples/blinky1 + @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=xiao examples/blinky1 @$(MD5SUM) test.hex + $(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/dac + @$(MD5SUM) test.hex ifneq ($(AVR), 0) $(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial @$(MD5SUM) test.hex diff --git a/src/examples/dac/dac.go b/src/examples/dac/dac.go new file mode 100644 index 00000000..f1c80c74 --- /dev/null +++ b/src/examples/dac/dac.go @@ -0,0 +1,40 @@ +// Simplistic example using the DAC on the Circuit Playground Express. +// +// To actually use the DAC for producing complex waveforms or samples requires a DMA +// timer-based playback mechanism which is beyond the scope of this example. +package main + +import ( + "machine" + "time" +) + +func main() { + enable := machine.PA30 + enable.Configure(machine.PinConfig{Mode: machine.PinOutput}) + enable.Set(true) + + speaker := machine.A0 + speaker.Configure(machine.PinConfig{Mode: machine.PinOutput}) + + machine.DAC0.Configure(machine.DACConfig{}) + + data := []uint16{32768, 8192, 2048, 512, 0} + + for { + for _, val := range data { + play(val) + time.Sleep(500 * time.Millisecond) + } + } +} + +func play(val uint16) { + for i := 0; i < 100; i++ { + machine.DAC0.Set(val) + time.Sleep(2 * time.Millisecond) + + machine.DAC0.Set(0) + time.Sleep(2 * time.Millisecond) + } +} diff --git a/src/machine/machine_atsamd21.go b/src/machine/machine_atsamd21.go index 027e007e..36967a09 100644 --- a/src/machine/machine_atsamd21.go +++ b/src/machine/machine_atsamd21.go @@ -2209,3 +2209,53 @@ func ResetProcessor() { arm.SystemReset() } + +// DAC on the SAMD21. +type DAC struct { +} + +var ( + DAC0 = DAC{} +) + +// DACConfig placeholder for future expansion. +type DACConfig struct { +} + +// Configure the DAC. +// output pin must already be configured. +func (dac DAC) Configure(config DACConfig) { + // Turn on clock for DAC + sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_DAC_) + + // Use Generic Clock Generator 0 as source for DAC. + sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_DAC << sam.GCLK_CLKCTRL_ID_Pos) | + (sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) | + sam.GCLK_CLKCTRL_CLKEN) + waitForSync() + + // reset DAC + sam.DAC.CTRLA.Set(sam.DAC_CTRLA_SWRST) + syncDAC() + + // wait for reset complete + for sam.DAC.CTRLA.HasBits(sam.DAC_CTRLA_SWRST) { + } + + // enable + sam.DAC.CTRLB.Set(sam.DAC_CTRLB_EOEN | sam.DAC_CTRLB_REFSEL_AVCC) + sam.DAC.CTRLA.Set(sam.DAC_CTRLA_ENABLE) +} + +// Set writes a single 16-bit value to the DAC. +// Since the ATSAMD21 only has a 10-bit DAC, the passed-in value will be scaled down. +func (dac DAC) Set(value uint16) error { + sam.DAC.DATA.Set(value >> 6) + syncDAC() + return nil +} + +func syncDAC() { + for sam.DAC.STATUS.HasBits(sam.DAC_STATUS_SYNCBUSY) { + } +}