aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/machine
diff options
context:
space:
mode:
authordeadprogram <[email protected]>2024-12-08 10:37:30 +0100
committerRon Evans <[email protected]>2024-12-18 15:23:00 +0100
commit5701bf81f30d06daa4bc093f716f496c16147e10 (patch)
treeadeee6085ded92d0226cac3601fcc1d546ee495f /src/machine
parent6110f0bc1b5cb807fa2ac01b12b5aeffcf3308c6 (diff)
downloadtinygo-5701bf81f30d06daa4bc093f716f496c16147e10.tar.gz
tinygo-5701bf81f30d06daa4bc093f716f496c16147e10.zip
feature: modify i2s interface/implementation to better match specification
Signed-off-by: deadprogram <[email protected]>
Diffstat (limited to 'src/machine')
-rw-r--r--src/machine/board_arduino_mkr1000.go5
-rw-r--r--src/machine/board_arduino_mkrwifi1010.go3
-rw-r--r--src/machine/board_arduino_nano33.go3
-rw-r--r--src/machine/board_arduino_zero.go3
-rw-r--r--src/machine/board_circuitplay_express.go3
-rw-r--r--src/machine/board_feather-m0-express.go3
-rw-r--r--src/machine/board_feather-m0.go3
-rw-r--r--src/machine/board_gemma-m0.go3
-rw-r--r--src/machine/board_grandcentral-m4.go3
-rw-r--r--src/machine/board_itsybitsy-m0.go3
-rw-r--r--src/machine/board_p1am-100.go3
-rw-r--r--src/machine/board_qtpy.go3
-rw-r--r--src/machine/board_trinket.go3
-rw-r--r--src/machine/board_wioterminal.go8
-rw-r--r--src/machine/board_xiao.go3
-rw-r--r--src/machine/i2s.go34
-rw-r--r--src/machine/machine_atsamd21.go153
17 files changed, 171 insertions, 68 deletions
diff --git a/src/machine/board_arduino_mkr1000.go b/src/machine/board_arduino_mkr1000.go
index 2c9ae603f..f5130120e 100644
--- a/src/machine/board_arduino_mkr1000.go
+++ b/src/machine/board_arduino_mkr1000.go
@@ -74,8 +74,9 @@ const (
// I2S pins
const (
I2S_SCK_PIN Pin = PA10
- I2S_SD_PIN Pin = PA07
- I2S_WS_PIN = NoPin // TODO: figure out what this is on Arduino Nano 33.
+ I2S_SDO_PIN Pin = PA07
+ I2S_SDI_PIN = NoPin
+ I2S_WS_PIN = NoPin // TODO: figure out what this is on Arduino MKR1000
)
// USB CDC identifiers
diff --git a/src/machine/board_arduino_mkrwifi1010.go b/src/machine/board_arduino_mkrwifi1010.go
index 18330f37f..c68da9b62 100644
--- a/src/machine/board_arduino_mkrwifi1010.go
+++ b/src/machine/board_arduino_mkrwifi1010.go
@@ -74,7 +74,8 @@ const (
// I2S pins
const (
I2S_SCK_PIN Pin = PA10
- I2S_SD_PIN Pin = PA07
+ I2S_SDO_PIN Pin = PA07
+ I2S_SDI_PIN = NoPin
I2S_WS_PIN = NoPin // TODO: figure out what this is on Arduino MKR WiFi 1010.
)
diff --git a/src/machine/board_arduino_nano33.go b/src/machine/board_arduino_nano33.go
index 17f255443..9232d3819 100644
--- a/src/machine/board_arduino_nano33.go
+++ b/src/machine/board_arduino_nano33.go
@@ -118,7 +118,8 @@ const (
// I2S pins
const (
I2S_SCK_PIN Pin = PA10
- I2S_SD_PIN Pin = PA08
+ I2S_SDO_PIN Pin = PA08
+ I2S_SDI_PIN = NoPin
I2S_WS_PIN = NoPin // TODO: figure out what this is on Arduino Nano 33.
)
diff --git a/src/machine/board_arduino_zero.go b/src/machine/board_arduino_zero.go
index f09fb47c5..758fcb16e 100644
--- a/src/machine/board_arduino_zero.go
+++ b/src/machine/board_arduino_zero.go
@@ -69,7 +69,8 @@ const (
// I2S pins - might not be exposed
const (
I2S_SCK_PIN Pin = PA10
- I2S_SD_PIN Pin = PA07
+ I2S_SDO_PIN Pin = PA07
+ I2S_SDI_PIN = NoPin
I2S_WS_PIN Pin = PA11
)
diff --git a/src/machine/board_circuitplay_express.go b/src/machine/board_circuitplay_express.go
index 1601fcab3..ce1f29c75 100644
--- a/src/machine/board_circuitplay_express.go
+++ b/src/machine/board_circuitplay_express.go
@@ -102,7 +102,8 @@ var SPI0 = sercomSPIM3
// I2S pins
const (
I2S_SCK_PIN = PA10
- I2S_SD_PIN = PA08
+ I2S_SDO_PIN = PA08
+ I2S_SDI_PIN = NoPin
I2S_WS_PIN = NoPin // no WS, instead uses SCK to sync
)
diff --git a/src/machine/board_feather-m0-express.go b/src/machine/board_feather-m0-express.go
index a0f7c2305..226369ffc 100644
--- a/src/machine/board_feather-m0-express.go
+++ b/src/machine/board_feather-m0-express.go
@@ -81,7 +81,8 @@ var SPI0 = sercomSPIM4
// I2S pins
const (
I2S_SCK_PIN = PA10
- I2S_SD_PIN = PA07
+ I2S_SDO_PIN = PA07
+ I2S_SDI_PIN = NoPin
I2S_WS_PIN = NoPin // TODO: figure out what this is on Feather M0 Express.
)
diff --git a/src/machine/board_feather-m0.go b/src/machine/board_feather-m0.go
index 5cd339340..f38d8ec88 100644
--- a/src/machine/board_feather-m0.go
+++ b/src/machine/board_feather-m0.go
@@ -76,7 +76,8 @@ var SPI0 = sercomSPIM4
// I2S pins
const (
I2S_SCK_PIN = PA10
- I2S_SD_PIN = PA08
+ I2S_SDO_PIN = PA08
+ I2S_SDI_PIN = NoPin
I2S_WS_PIN = NoPin // TODO: figure out what this is on Feather M0.
)
diff --git a/src/machine/board_gemma-m0.go b/src/machine/board_gemma-m0.go
index 3702c74c3..af1caaad6 100644
--- a/src/machine/board_gemma-m0.go
+++ b/src/machine/board_gemma-m0.go
@@ -76,7 +76,8 @@ var (
// I2S (not connected, needed for atsamd21).
const (
I2S_SCK_PIN = NoPin
- I2S_SD_PIN = NoPin
+ I2S_SDO_PIN = NoPin
+ I2S_SDI_PIN = NoPin
I2S_WS_PIN = NoPin
)
diff --git a/src/machine/board_grandcentral-m4.go b/src/machine/board_grandcentral-m4.go
index 46fb95697..61ef6a89b 100644
--- a/src/machine/board_grandcentral-m4.go
+++ b/src/machine/board_grandcentral-m4.go
@@ -224,7 +224,8 @@ const (
I2S_SCK_PIN = I2S0_SCK_PIN // default pins
I2S_WS_PIN = I2S0_FS_PIN //
- I2S_SD_PIN = I2S0_SDO_PIN //
+ I2S_SDO_PIN = I2S0_SDO_PIN
+ I2S_SDI_PIN = NoPin
)
// SD card pins
diff --git a/src/machine/board_itsybitsy-m0.go b/src/machine/board_itsybitsy-m0.go
index 67ebdee90..0cc6cad31 100644
--- a/src/machine/board_itsybitsy-m0.go
+++ b/src/machine/board_itsybitsy-m0.go
@@ -89,7 +89,8 @@ var SPI1 = sercomSPIM5
// I2S pins
const (
I2S_SCK_PIN = PA10
- I2S_SD_PIN = PA08
+ I2S_SDO_PIN = PA08
+ I2S_SDI_PIN = NoPin
I2S_WS_PIN = NoPin // TODO: figure out what this is on ItsyBitsy M0.
)
diff --git a/src/machine/board_p1am-100.go b/src/machine/board_p1am-100.go
index d6fbdcb36..f2a7d13f9 100644
--- a/src/machine/board_p1am-100.go
+++ b/src/machine/board_p1am-100.go
@@ -123,7 +123,8 @@ var (
// I2S pins
const (
I2S_SCK_PIN Pin = D2
- I2S_SD_PIN Pin = A6
+ I2S_SDO_PIN Pin = A6
+ I2S_SDI_PIN = NoPin
I2S_WS_PIN = D3
)
diff --git a/src/machine/board_qtpy.go b/src/machine/board_qtpy.go
index 49bb9c97b..e8a93e38d 100644
--- a/src/machine/board_qtpy.go
+++ b/src/machine/board_qtpy.go
@@ -81,7 +81,8 @@ var (
// I2S pins
const (
I2S_SCK_PIN = PA10
- I2S_SD_PIN = PA08
+ I2S_SDO_PIN = PA08
+ I2S_SDI_PIN = NoPin // TODO: figure out what this is on QT Py M0.
I2S_WS_PIN = NoPin // TODO: figure out what this is on QT Py M0.
)
diff --git a/src/machine/board_trinket.go b/src/machine/board_trinket.go
index 2ce419a4a..089eadbf0 100644
--- a/src/machine/board_trinket.go
+++ b/src/machine/board_trinket.go
@@ -67,7 +67,8 @@ var (
// I2S pins
const (
I2S_SCK_PIN = PA10
- I2S_SD_PIN = PA08
+ I2S_SDO_PIN = PA08
+ I2S_SDI_PIN = NoPin // TODO: figure out what this is on Trinket M0.
I2S_WS_PIN = NoPin // TODO: figure out what this is on Trinket M0.
)
diff --git a/src/machine/board_wioterminal.go b/src/machine/board_wioterminal.go
index 99a04d6ec..6997120b9 100644
--- a/src/machine/board_wioterminal.go
+++ b/src/machine/board_wioterminal.go
@@ -376,6 +376,14 @@ var (
I2C1 = sercomI2CM3
)
+// I2S pins
+const (
+ I2S_SCK_PIN = BCM18
+ I2S_SDO_PIN = BCM21
+ I2S_SDI_PIN = BCM20
+ I2S_WS_PIN = BCM19
+)
+
// SPI pins
const (
SPI0_SCK_PIN = SCK // SCK: SERCOM5/PAD[1]
diff --git a/src/machine/board_xiao.go b/src/machine/board_xiao.go
index f0ecf068e..5bbb34d68 100644
--- a/src/machine/board_xiao.go
+++ b/src/machine/board_xiao.go
@@ -82,7 +82,8 @@ var SPI0 = sercomSPIM0
// I2S pins
const (
I2S_SCK_PIN = PA10
- I2S_SD_PIN = PA08
+ I2S_SDO_PIN = PA08
+ I2S_SDI_PIN = NoPin // TODO: figure out what this is on Xiao
I2S_WS_PIN = NoPin // TODO: figure out what this is on Xiao
)
diff --git a/src/machine/i2s.go b/src/machine/i2s.go
index 8f5e30953..13dc80f61 100644
--- a/src/machine/i2s.go
+++ b/src/machine/i2s.go
@@ -1,4 +1,4 @@
-//go:build sam
+//go:build sam && atsamd21
// This is the definition for I2S bus functions.
// Actual implementations if available for any given hardware
@@ -9,6 +9,22 @@
package machine
+import "errors"
+
+// If you are getting a compile error on this line please check to see you've
+// correctly implemented the methods on the I2S type. They must match
+// the interface method signatures type to type perfectly.
+// If not implementing the I2S type please remove your target from the build tags
+// at the top of this file.
+var _ interface {
+ SetSampleFrequency(freq uint32) error
+ ReadMono(b []uint16) (int, error)
+ ReadStereo(b []uint32) (int, error)
+ WriteMono(b []uint16) (int, error)
+ WriteStereo(b []uint32) (int, error)
+ Enable(enabled bool)
+} = (*I2S)(nil)
+
type I2SMode uint8
type I2SStandard uint8
type I2SClockSource uint8
@@ -18,6 +34,7 @@ const (
I2SModeSource I2SMode = iota
I2SModeReceiver
I2SModePDM
+ I2SModeSourceReceiver
)
const (
@@ -39,11 +56,20 @@ const (
I2SDataFormat32bit = 32
)
+var (
+ ErrInvalidSampleFrequency = errors.New("i2s: invalid sample frequency")
+)
+
// All fields are optional and may not be required or used on a particular platform.
type I2SConfig struct {
- SCK Pin
- WS Pin
- SD Pin
+ // clock
+ SCK Pin
+ // word select
+ WS Pin
+ // data out
+ SDO Pin
+ // data in
+ SDI Pin
Mode I2SMode
Standard I2SStandard
ClockSource I2SClockSource
diff --git a/src/machine/machine_atsamd21.go b/src/machine/machine_atsamd21.go
index fe67f45a3..3d0abc0fa 100644
--- a/src/machine/machine_atsamd21.go
+++ b/src/machine/machine_atsamd21.go
@@ -926,23 +926,26 @@ func (i2c *I2C) readByte() byte {
// I2S
type I2S struct {
- Bus *sam.I2S_Type
+ Bus *sam.I2S_Type
+ Frequency uint32
+ DataFormat I2SDataFormat
}
var I2S0 = I2S{Bus: sam.I2S}
// Configure is used to configure the I2S interface. You must call this
// before you can use the I2S bus.
-func (i2s I2S) Configure(config I2SConfig) {
+func (i2s *I2S) Configure(config I2SConfig) error {
// handle defaults
if config.SCK == 0 {
config.SCK = I2S_SCK_PIN
config.WS = I2S_WS_PIN
- config.SD = I2S_SD_PIN
+ config.SDO = I2S_SDO_PIN
+ config.SDI = I2S_SDI_PIN
}
if config.AudioFrequency == 0 {
- config.AudioFrequency = 48000
+ config.AudioFrequency = 44100
}
if config.DataFormat == I2SDataFormatDefault {
@@ -952,39 +955,17 @@ func (i2s I2S) Configure(config I2SConfig) {
config.DataFormat = I2SDataFormat32bit
}
}
+ i2s.DataFormat = config.DataFormat
// Turn on clock for I2S
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_I2S_)
- // setting clock rate for sample.
- division_factor := CPUFrequency() / (config.AudioFrequency * uint32(config.DataFormat))
-
- // Switch Generic Clock Generator 3 to DFLL48M.
- sam.GCLK.GENDIV.Set((sam.GCLK_CLKCTRL_GEN_GCLK3 << sam.GCLK_GENDIV_ID_Pos) |
- (division_factor << sam.GCLK_GENDIV_DIV_Pos))
- waitForSync()
-
- sam.GCLK.GENCTRL.Set((sam.GCLK_CLKCTRL_GEN_GCLK3 << sam.GCLK_GENCTRL_ID_Pos) |
- (sam.GCLK_GENCTRL_SRC_DFLL48M << sam.GCLK_GENCTRL_SRC_Pos) |
- sam.GCLK_GENCTRL_IDC |
- sam.GCLK_GENCTRL_GENEN)
- waitForSync()
-
- // Use Generic Clock Generator 3 as source for I2S.
- sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_I2S_0 << sam.GCLK_CLKCTRL_ID_Pos) |
- (sam.GCLK_CLKCTRL_GEN_GCLK3 << sam.GCLK_CLKCTRL_GEN_Pos) |
- sam.GCLK_CLKCTRL_CLKEN)
- waitForSync()
-
- // reset the device
- i2s.Bus.CTRLA.SetBits(sam.I2S_CTRLA_SWRST)
- for i2s.Bus.SYNCBUSY.HasBits(sam.I2S_SYNCBUSY_SWRST) {
+ if err := i2s.SetSampleFrequency(config.AudioFrequency); err != nil {
+ return err
}
// disable device before continuing
- for i2s.Bus.SYNCBUSY.HasBits(sam.I2S_SYNCBUSY_ENABLE) {
- }
- i2s.Bus.CTRLA.ClearBits(sam.I2S_CTRLA_ENABLE)
+ i2s.Enable(false)
// setup clock
if config.ClockSource == I2SClockSourceInternal {
@@ -1067,19 +1048,25 @@ func (i2s I2S) Configure(config I2SConfig) {
}
// set serializer mode.
- if config.Mode == I2SModePDM {
+ switch config.Mode {
+ case I2SModePDM:
i2s.Bus.SERCTRL1.SetBits(sam.I2S_SERCTRL_SERMODE_PDM2)
- } else {
+ case I2SModeSource:
+ i2s.Bus.SERCTRL1.SetBits(sam.I2S_SERCTRL_SERMODE_TX)
+ case I2SModeReceiver:
i2s.Bus.SERCTRL1.SetBits(sam.I2S_SERCTRL_SERMODE_RX)
}
- // configure data pin
- config.SD.Configure(PinConfig{Mode: PinCom})
+ // configure data pins
+ if config.SDO != NoPin {
+ config.SDO.Configure(PinConfig{Mode: PinCom})
+ }
+ if config.SDI != NoPin {
+ config.SDI.Configure(PinConfig{Mode: PinCom})
+ }
// re-enable
- i2s.Bus.CTRLA.SetBits(sam.I2S_CTRLA_ENABLE)
- for i2s.Bus.SYNCBUSY.HasBits(sam.I2S_SYNCBUSY_ENABLE) {
- }
+ i2s.Enable(true)
// enable i2s clock
i2s.Bus.CTRLA.SetBits(sam.I2S_CTRLA_CKEN0)
@@ -1090,11 +1077,23 @@ func (i2s I2S) Configure(config I2SConfig) {
i2s.Bus.CTRLA.SetBits(sam.I2S_CTRLA_SEREN1)
for i2s.Bus.SYNCBUSY.HasBits(sam.I2S_SYNCBUSY_SEREN1) {
}
+
+ return nil
}
-// Read data from the I2S bus into the provided slice.
+// Read mono data from the I2S bus into the provided slice.
// The I2S bus must already have been configured correctly.
-func (i2s I2S) Read(p []uint32) (n int, err error) {
+func (i2s *I2S) ReadMono(p []uint16) (n int, err error) {
+ return i2sRead(i2s, p)
+}
+
+// Read stereo data from the I2S bus into the provided slice.
+// The I2S bus must already have been configured correctly.
+func (i2s *I2S) ReadStereo(p []uint32) (n int, err error) {
+ return i2sRead(i2s, p)
+}
+
+func i2sRead[T uint16 | uint32](i2s *I2S, p []T) (int, error) {
i := 0
for i = 0; i < len(p); i++ {
// Wait until ready
@@ -1105,7 +1104,7 @@ func (i2s I2S) Read(p []uint32) (n int, err error) {
}
// read data
- p[i] = i2s.Bus.DATA1.Get()
+ p[i] = T(i2s.Bus.DATA1.Get())
// indicate read complete
i2s.Bus.INTFLAG.Set(sam.I2S_INTFLAG_RXRDY1)
@@ -1114,9 +1113,19 @@ func (i2s I2S) Read(p []uint32) (n int, err error) {
return i, nil
}
-// Write data to the I2S bus from the provided slice.
+// Write mono data to the I2S bus from the provided slice.
// The I2S bus must already have been configured correctly.
-func (i2s I2S) Write(p []uint32) (n int, err error) {
+func (i2s *I2S) WriteMono(p []uint16) (n int, err error) {
+ return i2sWrite(i2s, p)
+}
+
+// Write stereo data to the I2S bus from the provided slice.
+// The I2S bus must already have been configured correctly.
+func (i2s *I2S) WriteStereo(p []uint32) (n int, err error) {
+ return i2sWrite(i2s, p)
+}
+
+func i2sWrite[T uint16 | uint32](i2s *I2S, p []T) (int, error) {
i := 0
for i = 0; i < len(p); i++ {
// Wait until ready
@@ -1127,7 +1136,7 @@ func (i2s I2S) Write(p []uint32) (n int, err error) {
}
// write data
- i2s.Bus.DATA1.Set(p[i])
+ i2s.Bus.DATA1.Set(uint32(p[i]))
// indicate write complete
i2s.Bus.INTFLAG.Set(sam.I2S_INTFLAG_TXRDY1)
@@ -1136,18 +1145,64 @@ func (i2s I2S) Write(p []uint32) (n int, err error) {
return i, nil
}
-// Close the I2S bus.
-func (i2s I2S) Close() error {
- // Sync wait
- for i2s.Bus.SYNCBUSY.HasBits(sam.I2S_SYNCBUSY_ENABLE) {
+// SetSampleFrequency is used to set the sample frequency for the I2S bus.
+func (i2s *I2S) SetSampleFrequency(freq uint32) error {
+ if freq == 0 {
+ return ErrInvalidSampleFrequency
}
- // disable I2S
- i2s.Bus.CTRLA.ClearBits(sam.I2S_CTRLA_ENABLE)
+ if i2s.Frequency == freq {
+ return nil
+ }
+
+ i2s.Frequency = freq
+
+ // setting clock rate for sample.
+ division_factor := CPUFrequency() / (i2s.Frequency * uint32(i2s.DataFormat))
+
+ // Switch Generic Clock Generator 3 to DFLL48M.
+ sam.GCLK.GENDIV.Set((sam.GCLK_CLKCTRL_GEN_GCLK3 << sam.GCLK_GENDIV_ID_Pos) |
+ (division_factor << sam.GCLK_GENDIV_DIV_Pos))
+ waitForSync()
+
+ sam.GCLK.GENCTRL.Set((sam.GCLK_CLKCTRL_GEN_GCLK3 << sam.GCLK_GENCTRL_ID_Pos) |
+ (sam.GCLK_GENCTRL_SRC_DFLL48M << sam.GCLK_GENCTRL_SRC_Pos) |
+ sam.GCLK_GENCTRL_IDC |
+ sam.GCLK_GENCTRL_GENEN)
+ waitForSync()
+
+ // Use Generic Clock Generator 3 as source for I2S.
+ sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_I2S_0 << sam.GCLK_CLKCTRL_ID_Pos) |
+ (sam.GCLK_CLKCTRL_GEN_GCLK3 << sam.GCLK_CLKCTRL_GEN_Pos) |
+ sam.GCLK_CLKCTRL_CLKEN)
+ waitForSync()
+
+ // reset the device
+ i2s.Bus.CTRLA.SetBits(sam.I2S_CTRLA_SWRST)
+ for i2s.Bus.SYNCBUSY.HasBits(sam.I2S_SYNCBUSY_SWRST) {
+ }
return nil
}
+// Enabled is used to enable or disable the I2S bus.
+func (i2s *I2S) Enable(enabled bool) {
+ if enabled {
+ i2s.Bus.CTRLA.SetBits(sam.I2S_CTRLA_ENABLE)
+ for i2s.Bus.SYNCBUSY.HasBits(sam.I2S_SYNCBUSY_ENABLE) {
+ }
+
+ return
+ }
+
+ // disable
+ for i2s.Bus.SYNCBUSY.HasBits(sam.I2S_SYNCBUSY_ENABLE) {
+ }
+ i2s.Bus.CTRLA.ClearBits(sam.I2S_CTRLA_ENABLE)
+
+ return
+}
+
func waitForSync() {
for sam.GCLK.STATUS.HasBits(sam.GCLK_STATUS_SYNCBUSY) {
}