mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 11:07:46 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 65a059a973 | |||
| cb95259adf | |||
| 24d718fa05 |
@@ -683,6 +683,56 @@ func (p Pin) getPinGrouping() (uint8, uint8) {
|
|||||||
return group, pin_in_group
|
return group, pin_in_group
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Static DMA channel allocation.
|
||||||
|
// If there are a lot of DMA using peripherals, we might need to switch to
|
||||||
|
// dynamic allocation instead.
|
||||||
|
const (
|
||||||
|
dmaChannelSERCOM0 = iota
|
||||||
|
dmaChannelSERCOM1
|
||||||
|
dmaChannelSERCOM2
|
||||||
|
dmaChannelSERCOM3
|
||||||
|
dmaChannelSERCOM4
|
||||||
|
dmaChannelSERCOM5
|
||||||
|
dmaChannelSERCOM6
|
||||||
|
dmaChannelSERCOM7
|
||||||
|
dmaNumChannels
|
||||||
|
)
|
||||||
|
|
||||||
|
// DMA descriptor structure. This structure is defined by the hardware, and is
|
||||||
|
// described by "22.9 Register Summary - SRAM" in the datasheet.
|
||||||
|
type dmaDescriptor struct {
|
||||||
|
btctrl uint16
|
||||||
|
btcnt uint16
|
||||||
|
srcaddr unsafe.Pointer
|
||||||
|
dstaddr unsafe.Pointer
|
||||||
|
descaddr unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:align 16
|
||||||
|
var dmaDescriptorSection [dmaNumChannels]dmaDescriptor
|
||||||
|
|
||||||
|
//go:align 16
|
||||||
|
var dmaDescriptorWritebackSection [dmaNumChannels]dmaDescriptor
|
||||||
|
|
||||||
|
// Enable and configure the DMAC peripheral if it hasn't been enabled already.
|
||||||
|
func enableDMAC() {
|
||||||
|
if !sam.DMAC.CTRL.HasBits(sam.DMAC_CTRL_DMAENABLE) {
|
||||||
|
// Init DMAC.
|
||||||
|
// First configure the clocks, then configure the DMA descriptors. Those
|
||||||
|
// descriptors must live in SRAM and must be aligned on a 16-byte
|
||||||
|
// boundary.
|
||||||
|
// Some examples:
|
||||||
|
// http://www.lucadavidian.com/2018/03/08/wifi-controlled-neo-pixels-strips/
|
||||||
|
// https://svn.larosterna.com/oss/trunk/arduino/zerotimer/zerodma.cpp
|
||||||
|
sam.MCLK.AHBMASK.SetBits(sam.MCLK_AHBMASK_DMAC_)
|
||||||
|
sam.DMAC.BASEADDR.Set(uint32(uintptr(unsafe.Pointer(&dmaDescriptorSection))))
|
||||||
|
sam.DMAC.WRBADDR.Set(uint32(uintptr(unsafe.Pointer(&dmaDescriptorWritebackSection))))
|
||||||
|
|
||||||
|
// Enable peripheral with all priorities.
|
||||||
|
sam.DMAC.CTRL.SetBits(sam.DMAC_CTRL_DMAENABLE | sam.DMAC_CTRL_LVLEN0 | sam.DMAC_CTRL_LVLEN1 | sam.DMAC_CTRL_LVLEN2 | sam.DMAC_CTRL_LVLEN3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// InitADC initializes the ADC.
|
// InitADC initializes the ADC.
|
||||||
func InitADC() {
|
func InitADC() {
|
||||||
// ADC Bias Calibration
|
// ADC Bias Calibration
|
||||||
@@ -1652,6 +1702,101 @@ func (spi SPI) txrx(tx, rx []byte) {
|
|||||||
rx[len(rx)-1] = byte(spi.Bus.DATA.Get())
|
rx[len(rx)-1] = byte(spi.Bus.DATA.Get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Channel to be used for SPI transfers.
|
||||||
|
// These channels are currently statically allocated.
|
||||||
|
func (spi SPI) dmaTxChannel() uint8 {
|
||||||
|
return dmaChannelSERCOM0 + spi.SERCOM
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAsync returns whether the SPI supports async operation (usually DMA).
|
||||||
|
//
|
||||||
|
// It returns true on the SAM D5x chips.
|
||||||
|
func (spi SPI) IsAsync() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a transfer in the background.
|
||||||
|
//
|
||||||
|
// After this, another StartTx() or Wait() must be called. The provided byte
|
||||||
|
// slices (tx and rx) may only be accessed again after Wait() was called.
|
||||||
|
func (s SPI) StartTx(tx, rx []byte) error {
|
||||||
|
// Check whether we support doing this transfer using DMA.
|
||||||
|
if len(rx) != 0 {
|
||||||
|
return s.Tx(tx, rx)
|
||||||
|
}
|
||||||
|
if len(tx) == 0 {
|
||||||
|
return nil // nothing to send/receive
|
||||||
|
}
|
||||||
|
if len(tx) != int(uint16(len(tx))) {
|
||||||
|
// The transfer size is a 16-bit field.
|
||||||
|
// TODO: chain multiple transfers in some way when encountering these
|
||||||
|
// large buffer sizes. They're not currently implemented because
|
||||||
|
// transferring 64kB of data is less commonly done.
|
||||||
|
return s.Tx(tx, rx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable DMAC (if not already enabled).
|
||||||
|
enableDMAC()
|
||||||
|
|
||||||
|
// Wait until a possible previous transfer has been completed.
|
||||||
|
s.Wait()
|
||||||
|
|
||||||
|
// Configure the DMA channel, if it hasn't been configured already.
|
||||||
|
dstaddr := unsafe.Pointer(&s.Bus.DATA.Reg)
|
||||||
|
if dmaDescriptorSection[s.dmaTxChannel()].dstaddr != dstaddr {
|
||||||
|
// Configure channel descriptor.
|
||||||
|
dmaDescriptorSection[s.dmaTxChannel()] = dmaDescriptor{
|
||||||
|
btctrl: (1 << 0) | // VALID: Descriptor Valid
|
||||||
|
(0 << 3) | // BLOCKACT=NOACT: Block Action
|
||||||
|
(1 << 10) | // SRCINC: Source Address Increment Enable
|
||||||
|
(0 << 11) | // DSTINC: Destination Address Increment Enable
|
||||||
|
(1 << 12) | // STEPSEL=SRC: Step Selection
|
||||||
|
(0 << 13), // STEPSIZE=X1: Address Increment Step Size
|
||||||
|
dstaddr: dstaddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset channel.
|
||||||
|
sam.DMAC.CHANNEL[s.dmaTxChannel()].CHCTRLA.ClearBits(sam.DMAC_CHANNEL_CHCTRLA_ENABLE)
|
||||||
|
sam.DMAC.CHANNEL[s.dmaTxChannel()].CHCTRLA.SetBits(sam.DMAC_CHANNEL_CHCTRLA_SWRST)
|
||||||
|
|
||||||
|
// Configure channel.
|
||||||
|
sam.DMAC.CHANNEL[s.dmaTxChannel()].CHPRILVL.Set(0)
|
||||||
|
sam.DMAC.CHANNEL[s.dmaTxChannel()].CHCTRLA.Set((sam.DMAC_CHANNEL_CHCTRLA_TRIGACT_BURST << sam.DMAC_CHANNEL_CHCTRLA_TRIGACT_Pos) |
|
||||||
|
(s.triggerSource() << sam.DMAC_CHANNEL_CHCTRLA_TRIGSRC_Pos) |
|
||||||
|
(sam.DMAC_CHANNEL_CHCTRLA_BURSTLEN_SINGLE << sam.DMAC_CHANNEL_CHCTRLA_BURSTLEN_Pos))
|
||||||
|
}
|
||||||
|
|
||||||
|
// For some reason, you have to provide the address just past the end of the
|
||||||
|
// array instead of the address of the array.
|
||||||
|
descriptor := &dmaDescriptorSection[s.dmaTxChannel()]
|
||||||
|
descriptor.srcaddr = unsafe.Pointer(uintptr(unsafe.Pointer(&tx[0])) + uintptr(len(tx)))
|
||||||
|
descriptor.btcnt = uint16(len(tx)) // beat count
|
||||||
|
|
||||||
|
// Start the transfer.
|
||||||
|
sam.DMAC.CHANNEL[s.dmaTxChannel()].CHCTRLA.SetBits(sam.DMAC_CHANNEL_CHCTRLA_ENABLE)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until all active transactions (started by StartTx) have finished. The
|
||||||
|
// buffers provided in StartTx will be available after this method returns.
|
||||||
|
func (spi SPI) Wait() error {
|
||||||
|
// Wait until the previous SPI transfer completed.
|
||||||
|
// This is basically the same thing as in SPI.tx.
|
||||||
|
|
||||||
|
// TODO: maybe block (and sleep) until the transfer has completed?
|
||||||
|
|
||||||
|
for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_TXC) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// read to clear RXC register
|
||||||
|
for spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) {
|
||||||
|
spi.Bus.DATA.Get()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// The QSPI peripheral on ATSAMD51 is only available on the following pins
|
// The QSPI peripheral on ATSAMD51 is only available on the following pins
|
||||||
const (
|
const (
|
||||||
QSPI_SCK = PB10
|
QSPI_SCK = PB10
|
||||||
|
|||||||
@@ -62,6 +62,27 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DMA trigger source
|
||||||
|
func (spi SPI) triggerSource() (tx uint32) {
|
||||||
|
// See TRIGSRC field of CHCTRLA register for description of these constants.
|
||||||
|
switch spi.Bus {
|
||||||
|
case sam.SERCOM0_SPIM:
|
||||||
|
return 0x05
|
||||||
|
case sam.SERCOM1_SPIM:
|
||||||
|
return 0x07
|
||||||
|
case sam.SERCOM2_SPIM:
|
||||||
|
return 0x09
|
||||||
|
case sam.SERCOM3_SPIM:
|
||||||
|
return 0x0A
|
||||||
|
case sam.SERCOM4_SPIM:
|
||||||
|
return 0x0C
|
||||||
|
case sam.SERCOM5_SPIM:
|
||||||
|
return 0x0E
|
||||||
|
default:
|
||||||
|
return 0 // should be unreachable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This chip has three TCC peripherals, which have PWM as one feature.
|
// This chip has three TCC peripherals, which have PWM as one feature.
|
||||||
var (
|
var (
|
||||||
TCC0 = (*TCC)(sam.TCC0)
|
TCC0 = (*TCC)(sam.TCC0)
|
||||||
|
|||||||
@@ -62,6 +62,27 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DMA trigger source
|
||||||
|
func (spi SPI) triggerSource() (tx uint32) {
|
||||||
|
// See TRIGSRC field of CHCTRLA register for description of these constants.
|
||||||
|
switch spi.Bus {
|
||||||
|
case sam.SERCOM0_SPIM:
|
||||||
|
return 0x05
|
||||||
|
case sam.SERCOM1_SPIM:
|
||||||
|
return 0x07
|
||||||
|
case sam.SERCOM2_SPIM:
|
||||||
|
return 0x09
|
||||||
|
case sam.SERCOM3_SPIM:
|
||||||
|
return 0x0B
|
||||||
|
case sam.SERCOM4_SPIM:
|
||||||
|
return 0x0D
|
||||||
|
case sam.SERCOM5_SPIM:
|
||||||
|
return 0x0F
|
||||||
|
default:
|
||||||
|
return 0 // should be unreachable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This chip has five TCC peripherals, which have PWM as one feature.
|
// This chip has five TCC peripherals, which have PWM as one feature.
|
||||||
var (
|
var (
|
||||||
TCC0 = (*TCC)(sam.TCC0)
|
TCC0 = (*TCC)(sam.TCC0)
|
||||||
|
|||||||
@@ -62,6 +62,27 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DMA trigger source
|
||||||
|
func (spi SPI) triggerSource() (tx uint32) {
|
||||||
|
// See TRIGSRC field of CHCTRLA register for description of these constants.
|
||||||
|
switch spi.Bus {
|
||||||
|
case sam.SERCOM0_SPIM:
|
||||||
|
return 0x05
|
||||||
|
case sam.SERCOM1_SPIM:
|
||||||
|
return 0x07
|
||||||
|
case sam.SERCOM2_SPIM:
|
||||||
|
return 0x09
|
||||||
|
case sam.SERCOM3_SPIM:
|
||||||
|
return 0x0A
|
||||||
|
case sam.SERCOM4_SPIM:
|
||||||
|
return 0x0C
|
||||||
|
case sam.SERCOM5_SPIM:
|
||||||
|
return 0x0E
|
||||||
|
default:
|
||||||
|
return 0 // should be unreachable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This chip has five TCC peripherals, which have PWM as one feature.
|
// This chip has five TCC peripherals, which have PWM as one feature.
|
||||||
var (
|
var (
|
||||||
TCC0 = (*TCC)(sam.TCC0)
|
TCC0 = (*TCC)(sam.TCC0)
|
||||||
|
|||||||
@@ -76,6 +76,31 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DMA trigger source
|
||||||
|
func (spi SPI) triggerSource() (tx uint32) {
|
||||||
|
// See TRIGSRC field of CHCTRLA register for description of these constants.
|
||||||
|
switch spi.Bus {
|
||||||
|
case sam.SERCOM0_SPIM:
|
||||||
|
return 0x05
|
||||||
|
case sam.SERCOM1_SPIM:
|
||||||
|
return 0x07
|
||||||
|
case sam.SERCOM2_SPIM:
|
||||||
|
return 0x09
|
||||||
|
case sam.SERCOM3_SPIM:
|
||||||
|
return 0x0A
|
||||||
|
case sam.SERCOM4_SPIM:
|
||||||
|
return 0x0C
|
||||||
|
case sam.SERCOM5_SPIM:
|
||||||
|
return 0x0E
|
||||||
|
case sam.SERCOM6_SPIM:
|
||||||
|
return 0x10
|
||||||
|
case sam.SERCOM7_SPIM:
|
||||||
|
return 0x12
|
||||||
|
default:
|
||||||
|
return 0 // should be unreachable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This chip has five TCC peripherals, which have PWM as one feature.
|
// This chip has five TCC peripherals, which have PWM as one feature.
|
||||||
var (
|
var (
|
||||||
TCC0 = (*TCC)(sam.TCC0)
|
TCC0 = (*TCC)(sam.TCC0)
|
||||||
|
|||||||
@@ -76,6 +76,31 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DMA trigger source
|
||||||
|
func (spi SPI) triggerSource() (tx uint32) {
|
||||||
|
// See TRIGSRC field of CHCTRLA register for description of these constants.
|
||||||
|
switch spi.Bus {
|
||||||
|
case sam.SERCOM0_SPIM:
|
||||||
|
return 0x05
|
||||||
|
case sam.SERCOM1_SPIM:
|
||||||
|
return 0x07
|
||||||
|
case sam.SERCOM2_SPIM:
|
||||||
|
return 0x09
|
||||||
|
case sam.SERCOM3_SPIM:
|
||||||
|
return 0x0A
|
||||||
|
case sam.SERCOM4_SPIM:
|
||||||
|
return 0x0C
|
||||||
|
case sam.SERCOM5_SPIM:
|
||||||
|
return 0x0E
|
||||||
|
case sam.SERCOM6_SPIM:
|
||||||
|
return 0x10
|
||||||
|
case sam.SERCOM7_SPIM:
|
||||||
|
return 0x12
|
||||||
|
default:
|
||||||
|
return 0 // should be unreachable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This chip has five TCC peripherals, which have PWM as one feature.
|
// This chip has five TCC peripherals, which have PWM as one feature.
|
||||||
var (
|
var (
|
||||||
TCC0 = (*TCC)(sam.TCC0)
|
TCC0 = (*TCC)(sam.TCC0)
|
||||||
|
|||||||
@@ -62,6 +62,27 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DMA trigger source
|
||||||
|
func (spi SPI) triggerSource() (tx uint32) {
|
||||||
|
// See TRIGSRC field of CHCTRLA register for description of these constants.
|
||||||
|
switch spi.Bus {
|
||||||
|
case sam.SERCOM0_SPIM:
|
||||||
|
return 0x05
|
||||||
|
case sam.SERCOM1_SPIM:
|
||||||
|
return 0x07
|
||||||
|
case sam.SERCOM2_SPIM:
|
||||||
|
return 0x09
|
||||||
|
case sam.SERCOM3_SPIM:
|
||||||
|
return 0x0A
|
||||||
|
case sam.SERCOM4_SPIM:
|
||||||
|
return 0x0C
|
||||||
|
case sam.SERCOM5_SPIM:
|
||||||
|
return 0x0E
|
||||||
|
default:
|
||||||
|
return 0 // should be unreachable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This chip has five TCC peripherals, which have PWM as one feature.
|
// This chip has five TCC peripherals, which have PWM as one feature.
|
||||||
var (
|
var (
|
||||||
TCC0 = (*TCC)(sam.TCC0)
|
TCC0 = (*TCC)(sam.TCC0)
|
||||||
|
|||||||
@@ -76,6 +76,31 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DMA trigger source
|
||||||
|
func (spi SPI) triggerSource() (tx uint32) {
|
||||||
|
// See TRIGSRC field of CHCTRLA register for description of these constants.
|
||||||
|
switch spi.Bus {
|
||||||
|
case sam.SERCOM0_SPIM:
|
||||||
|
return 0x05
|
||||||
|
case sam.SERCOM1_SPIM:
|
||||||
|
return 0x07
|
||||||
|
case sam.SERCOM2_SPIM:
|
||||||
|
return 0x09
|
||||||
|
case sam.SERCOM3_SPIM:
|
||||||
|
return 0x0A
|
||||||
|
case sam.SERCOM4_SPIM:
|
||||||
|
return 0x0C
|
||||||
|
case sam.SERCOM5_SPIM:
|
||||||
|
return 0x0E
|
||||||
|
case sam.SERCOM6_SPIM:
|
||||||
|
return 0x10
|
||||||
|
case sam.SERCOM7_SPIM:
|
||||||
|
return 0x12
|
||||||
|
default:
|
||||||
|
return 0 // should be unreachable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This chip has five TCC peripherals, which have PWM as one feature.
|
// This chip has five TCC peripherals, which have PWM as one feature.
|
||||||
var (
|
var (
|
||||||
TCC0 = (*TCC)(sam.TCC0)
|
TCC0 = (*TCC)(sam.TCC0)
|
||||||
|
|||||||
@@ -289,7 +289,26 @@ func (spi SPI) isBusy() bool {
|
|||||||
|
|
||||||
// tx writes buffer to SPI ignoring Rx.
|
// tx writes buffer to SPI ignoring Rx.
|
||||||
func (spi SPI) tx(tx []byte) error {
|
func (spi SPI) tx(tx []byte) error {
|
||||||
if len(tx) == 0 {
|
err := spi.StartTx(tx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return spi.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAsync returns whether the SPI supports async operation (usually DMA).
|
||||||
|
//
|
||||||
|
// It returns true on the rp2040.
|
||||||
|
func (spi SPI) IsAsync() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a transfer in the background.
|
||||||
|
//
|
||||||
|
// After this, another StartTx() or Wait() must be called. The provided byte
|
||||||
|
// slices (tx and rx) may only be accessed again after Wait() was called.
|
||||||
|
func (spi SPI) StartTx(tx, rx []byte) error {
|
||||||
|
if len(tx) == 0 && len(rx) == 0 {
|
||||||
// We don't have to do anything.
|
// We don't have to do anything.
|
||||||
// This avoids a panic in &tx[0] when len(tx) == 0.
|
// This avoids a panic in &tx[0] when len(tx) == 0.
|
||||||
return nil
|
return nil
|
||||||
@@ -306,6 +325,15 @@ func (spi SPI) tx(tx []byte) error {
|
|||||||
dreq = 18 // DREQ_SPI1_TX
|
dreq = 18 // DREQ_SPI1_TX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for the previous transmission to complete.
|
||||||
|
for ch.CTRL_TRIG.Get()&rp.DMA_CH0_CTRL_TRIG_BUSY != 0 {
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rx) != 0 {
|
||||||
|
// Fallback. We don't support receiving data using DMA yet.
|
||||||
|
return spi.Tx(tx, rx)
|
||||||
|
}
|
||||||
|
|
||||||
// Configure the DMA peripheral as follows:
|
// Configure the DMA peripheral as follows:
|
||||||
// - set read address, write address, and number of transfer units (bytes)
|
// - set read address, write address, and number of transfer units (bytes)
|
||||||
// - increment read address (in memory), don't increment write address (SSPDR)
|
// - increment read address (in memory), don't increment write address (SSPDR)
|
||||||
@@ -319,6 +347,19 @@ func (spi SPI) tx(tx []byte) error {
|
|||||||
rp.DMA_CH0_CTRL_TRIG_DATA_SIZE_SIZE_BYTE<<rp.DMA_CH0_CTRL_TRIG_DATA_SIZE_Pos |
|
rp.DMA_CH0_CTRL_TRIG_DATA_SIZE_SIZE_BYTE<<rp.DMA_CH0_CTRL_TRIG_DATA_SIZE_Pos |
|
||||||
dreq<<rp.DMA_CH0_CTRL_TRIG_TREQ_SEL_Pos |
|
dreq<<rp.DMA_CH0_CTRL_TRIG_TREQ_SEL_Pos |
|
||||||
rp.DMA_CH0_CTRL_TRIG_EN)
|
rp.DMA_CH0_CTRL_TRIG_EN)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until all active transactions (started by StartTx) have finished. The
|
||||||
|
// buffers provided in StartTx will be available after this method returns.
|
||||||
|
func (spi SPI) Wait() error {
|
||||||
|
// Pick the DMA channel reserved for this SPI peripheral.
|
||||||
|
var ch *dmaChannel
|
||||||
|
if spi.Bus == rp.SPI0 {
|
||||||
|
ch = &dmaChannels[spi0DMAChannel]
|
||||||
|
} else { // SPI1
|
||||||
|
ch = &dmaChannels[spi1DMAChannel]
|
||||||
|
}
|
||||||
|
|
||||||
// Wait until the transfer is complete.
|
// Wait until the transfer is complete.
|
||||||
// TODO: do this more efficiently:
|
// TODO: do this more efficiently:
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
//go:build !baremetal || atmega || esp32 || fe310 || k210 || nrf || (nxp && !mk66f18) || atsamd21 || (stm32 && !stm32f7x2 && !stm32l5x2)
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
// This is a non-async implementation of the async SPI calls.
|
||||||
|
// It is useful for devices that don't support DMA on SPI, or for which it
|
||||||
|
// hasn't been implemented yet.
|
||||||
|
|
||||||
|
// IsAsync returns whether the SPI supports async operation (usually DMA).
|
||||||
|
//
|
||||||
|
// This SPI does not support async operations.
|
||||||
|
func (s SPI) IsAsync() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a transfer in the background.
|
||||||
|
//
|
||||||
|
// Because this SPI implementation doesn't support async operation, it is an
|
||||||
|
// alias for Tx.
|
||||||
|
func (s SPI) StartTx(tx, rx []byte) error {
|
||||||
|
return s.Tx(tx, rx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until all active transactions (started by StartTx) have finished.
|
||||||
|
//
|
||||||
|
// This is a no-op on this SPI implementation.
|
||||||
|
func (s SPI) Wait() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -26,4 +26,7 @@ var _ interface { // 2
|
|||||||
Configure(config SPIConfig) error
|
Configure(config SPIConfig) error
|
||||||
Tx(w, r []byte) error
|
Tx(w, r []byte) error
|
||||||
Transfer(w byte) (byte, error)
|
Transfer(w byte) (byte, error)
|
||||||
|
IsAsync() bool
|
||||||
|
StartTx(tx, rx []byte) error
|
||||||
|
Wait() error
|
||||||
} = (*SPI)(nil)
|
} = (*SPI)(nil)
|
||||||
|
|||||||
Reference in New Issue
Block a user