Skip to content

Commit d2856bd

Browse files
aykevldeadprogram
authored andcommitted
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).
1 parent 869d2c4 commit d2856bd

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

src/machine/machine_nrf.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ package machine
55
import (
66
"device/arm"
77
"device/nrf"
8+
"errors"
9+
)
10+
11+
var (
12+
ErrTxSlicesRequired = errors.New("SPI Tx requires a write or read slice, or both")
13+
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
814
)
915

1016
type PinMode uint8
@@ -322,3 +328,70 @@ func (spi SPI) Transfer(w byte) (byte, error) {
322328
// TODO: handle SPI errors
323329
return byte(r), nil
324330
}
331+
332+
// Tx handles read/write operation for SPI interface. Since SPI is a syncronous write/read
333+
// interface, there must always be the same number of bytes written as bytes read.
334+
// The Tx method knows about this, and offers a few different ways of calling it.
335+
//
336+
// This form sends the bytes in tx buffer, putting the resulting bytes read into the rx buffer.
337+
// Note that the tx and rx buffers must be the same size:
338+
//
339+
// spi.Tx(tx, rx)
340+
//
341+
// This form sends the tx buffer, ignoring the result. Useful for sending "commands" that return zeros
342+
// until all the bytes in the command packet have been received:
343+
//
344+
// spi.Tx(tx, nil)
345+
//
346+
// This form sends zeros, putting the result into the rx buffer. Good for reading a "result packet":
347+
//
348+
// spi.Tx(nil, rx)
349+
//
350+
func (spi SPI) Tx(w, r []byte) error {
351+
if w == nil && r == nil {
352+
return ErrTxSlicesRequired
353+
}
354+
355+
var err error
356+
357+
switch {
358+
case len(w) == 0:
359+
// read only, so write zero and read a result.
360+
for i := range r {
361+
r[i], err = spi.Transfer(0)
362+
if err != nil {
363+
return err
364+
}
365+
}
366+
case len(r) == 0:
367+
// write only
368+
spi.Bus.TXD.Set(uint32(w[0]))
369+
w = w[1:]
370+
for _, b := range w {
371+
spi.Bus.TXD.Set(uint32(b))
372+
for spi.Bus.EVENTS_READY.Get() == 0 {
373+
}
374+
_ = spi.Bus.RXD.Get()
375+
spi.Bus.EVENTS_READY.Set(0)
376+
}
377+
for spi.Bus.EVENTS_READY.Get() == 0 {
378+
}
379+
_ = spi.Bus.RXD.Get()
380+
spi.Bus.EVENTS_READY.Set(0)
381+
382+
default:
383+
// write/read
384+
if len(w) != len(r) {
385+
return ErrTxInvalidSliceSize
386+
}
387+
388+
for i, b := range w {
389+
r[i], err = spi.Transfer(b)
390+
if err != nil {
391+
return err
392+
}
393+
}
394+
}
395+
396+
return nil
397+
}

src/machine/spi.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// +build nrf sam stm32,!stm32f407
1+
// +build sam stm32,!stm32f407
22

33
package machine
44

0 commit comments

Comments
 (0)