From d2856bd6bda228403065d3596b90f8c29c5544bc Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Mon, 16 Sep 2019 14:15:05 +0200 Subject: [PATCH] nrf: improve SPI write-only speed, by making use of double buffering The SPI peripheral in the nrf chips support double buffering, which makes it possible to keep sending continuously. This change introduces double buffering on the nrf chips, which should improve SPI performance. Tested on the pca10040 (nrf52832). --- src/machine/machine_nrf.go | 73 ++++++++++++++++++++++++++++++++++++++ src/machine/spi.go | 2 +- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/machine/machine_nrf.go b/src/machine/machine_nrf.go index f6641999..e8859c41 100644 --- a/src/machine/machine_nrf.go +++ b/src/machine/machine_nrf.go @@ -5,6 +5,12 @@ package machine import ( "device/arm" "device/nrf" + "errors" +) + +var ( + ErrTxSlicesRequired = errors.New("SPI Tx requires a write or read slice, or both") + ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size") ) type PinMode uint8 @@ -322,3 +328,70 @@ func (spi SPI) Transfer(w byte) (byte, error) { // TODO: handle SPI errors return byte(r), nil } + +// Tx handles read/write operation for SPI interface. Since SPI is a syncronous write/read +// interface, there must always be the same number of bytes written as bytes read. +// The Tx method knows about this, and offers a few different ways of calling it. +// +// This form sends the bytes in tx buffer, putting the resulting bytes read into the rx buffer. +// Note that the tx and rx buffers must be the same size: +// +// spi.Tx(tx, rx) +// +// This form sends the tx buffer, ignoring the result. Useful for sending "commands" that return zeros +// until all the bytes in the command packet have been received: +// +// spi.Tx(tx, nil) +// +// This form sends zeros, putting the result into the rx buffer. Good for reading a "result packet": +// +// spi.Tx(nil, rx) +// +func (spi SPI) Tx(w, r []byte) error { + if w == nil && r == nil { + return ErrTxSlicesRequired + } + + var err error + + switch { + case len(w) == 0: + // read only, so write zero and read a result. + for i := range r { + r[i], err = spi.Transfer(0) + if err != nil { + return err + } + } + case len(r) == 0: + // write only + spi.Bus.TXD.Set(uint32(w[0])) + w = w[1:] + for _, b := range w { + spi.Bus.TXD.Set(uint32(b)) + for spi.Bus.EVENTS_READY.Get() == 0 { + } + _ = spi.Bus.RXD.Get() + spi.Bus.EVENTS_READY.Set(0) + } + for spi.Bus.EVENTS_READY.Get() == 0 { + } + _ = spi.Bus.RXD.Get() + spi.Bus.EVENTS_READY.Set(0) + + default: + // write/read + if len(w) != len(r) { + return ErrTxInvalidSliceSize + } + + for i, b := range w { + r[i], err = spi.Transfer(b) + if err != nil { + return err + } + } + } + + return nil +} diff --git a/src/machine/spi.go b/src/machine/spi.go index b913f200..340b4486 100644 --- a/src/machine/spi.go +++ b/src/machine/spi.go @@ -1,4 +1,4 @@ -// +build nrf sam stm32,!stm32f407 +// +build sam stm32,!stm32f407 package machine