nrf: use SPIM peripheral instead of the legacy SPI peripheral
This newer peripheral supports DMA (through EasyDMA) and should generally be faster. Importantly for some operations: interrupts (within 255 byte buffers) will not interfere with the SPI transfer.
Этот коммит содержится в:
родитель
ce539ce583
коммит
cda5fffd98
3 изменённых файлов: 305 добавлений и 185 удалений
|
@ -328,163 +328,3 @@ func (i2c I2C) readByte() (byte, error) {
|
||||||
i2c.Bus.EVENTS_RXDREADY.Set(0)
|
i2c.Bus.EVENTS_RXDREADY.Set(0)
|
||||||
return byte(i2c.Bus.RXD.Get()), nil
|
return byte(i2c.Bus.RXD.Get()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPI on the NRF.
|
|
||||||
type SPI struct {
|
|
||||||
Bus *nrf.SPI_Type
|
|
||||||
}
|
|
||||||
|
|
||||||
// There are 2 SPI interfaces on the NRF5x.
|
|
||||||
var (
|
|
||||||
SPI0 = SPI{Bus: nrf.SPI0}
|
|
||||||
SPI1 = SPI{Bus: nrf.SPI1}
|
|
||||||
)
|
|
||||||
|
|
||||||
// SPIConfig is used to store config info for SPI.
|
|
||||||
type SPIConfig struct {
|
|
||||||
Frequency uint32
|
|
||||||
SCK Pin
|
|
||||||
SDO Pin
|
|
||||||
SDI Pin
|
|
||||||
LSBFirst bool
|
|
||||||
Mode uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure is intended to setup the SPI interface.
|
|
||||||
func (spi SPI) Configure(config SPIConfig) {
|
|
||||||
// Disable bus to configure it
|
|
||||||
spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Disabled)
|
|
||||||
|
|
||||||
// set frequency
|
|
||||||
var freq uint32
|
|
||||||
|
|
||||||
if config.Frequency == 0 {
|
|
||||||
config.Frequency = 4000000 // 4MHz
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case config.Frequency >= 8000000:
|
|
||||||
freq = nrf.SPI_FREQUENCY_FREQUENCY_M8
|
|
||||||
case config.Frequency >= 4000000:
|
|
||||||
freq = nrf.SPI_FREQUENCY_FREQUENCY_M4
|
|
||||||
case config.Frequency >= 2000000:
|
|
||||||
freq = nrf.SPI_FREQUENCY_FREQUENCY_M2
|
|
||||||
case config.Frequency >= 1000000:
|
|
||||||
freq = nrf.SPI_FREQUENCY_FREQUENCY_M1
|
|
||||||
case config.Frequency >= 500000:
|
|
||||||
freq = nrf.SPI_FREQUENCY_FREQUENCY_K500
|
|
||||||
case config.Frequency >= 250000:
|
|
||||||
freq = nrf.SPI_FREQUENCY_FREQUENCY_K250
|
|
||||||
default: // below 250kHz, default to the lowest speed available
|
|
||||||
freq = nrf.SPI_FREQUENCY_FREQUENCY_K125
|
|
||||||
}
|
|
||||||
spi.Bus.FREQUENCY.Set(freq)
|
|
||||||
|
|
||||||
var conf uint32
|
|
||||||
|
|
||||||
// set bit transfer order
|
|
||||||
if config.LSBFirst {
|
|
||||||
conf = (nrf.SPI_CONFIG_ORDER_LsbFirst << nrf.SPI_CONFIG_ORDER_Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// set mode
|
|
||||||
switch config.Mode {
|
|
||||||
case 0:
|
|
||||||
conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
|
|
||||||
conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
|
|
||||||
case 1:
|
|
||||||
conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
|
|
||||||
conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos)
|
|
||||||
case 2:
|
|
||||||
conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos)
|
|
||||||
conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
|
|
||||||
case 3:
|
|
||||||
conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos)
|
|
||||||
conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos)
|
|
||||||
default: // to mode
|
|
||||||
conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
|
|
||||||
conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
|
|
||||||
}
|
|
||||||
spi.Bus.CONFIG.Set(conf)
|
|
||||||
|
|
||||||
// set pins
|
|
||||||
spi.setPins(config.SCK, config.SDO, config.SDI)
|
|
||||||
|
|
||||||
// Re-enable bus now that it is configured.
|
|
||||||
spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Enabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transfer writes/reads a single byte using the SPI interface.
|
|
||||||
func (spi SPI) Transfer(w byte) (byte, error) {
|
|
||||||
spi.Bus.TXD.Set(uint32(w))
|
|
||||||
for spi.Bus.EVENTS_READY.Get() == 0 {
|
|
||||||
}
|
|
||||||
r := spi.Bus.RXD.Get()
|
|
||||||
spi.Bus.EVENTS_READY.Set(0)
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
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.EVENTS_READY.Set(0)
|
|
||||||
_ = spi.Bus.RXD.Get()
|
|
||||||
}
|
|
||||||
for spi.Bus.EVENTS_READY.Get() == 0 {
|
|
||||||
}
|
|
||||||
spi.Bus.EVENTS_READY.Set(0)
|
|
||||||
_ = spi.Bus.RXD.Get()
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
|
@ -29,18 +29,169 @@ func (i2c I2C) setPins(scl, sda Pin) {
|
||||||
i2c.Bus.PSELSDA.Set(uint32(sda))
|
i2c.Bus.PSELSDA.Set(uint32(sda))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPI
|
// SPI on the NRF.
|
||||||
func (spi SPI) setPins(sck, sdo, sdi Pin) {
|
type SPI struct {
|
||||||
if sck == 0 {
|
Bus *nrf.SPI_Type
|
||||||
sck = SPI0_SCK_PIN
|
}
|
||||||
}
|
|
||||||
if sdo == 0 {
|
// There are 2 SPI interfaces on the NRF51.
|
||||||
sdo = SPI0_SDO_PIN
|
var (
|
||||||
}
|
SPI0 = SPI{Bus: nrf.SPI0}
|
||||||
if sdi == 0 {
|
SPI1 = SPI{Bus: nrf.SPI1}
|
||||||
sdi = SPI0_SDI_PIN
|
)
|
||||||
}
|
|
||||||
spi.Bus.PSELSCK.Set(uint32(sck))
|
// SPIConfig is used to store config info for SPI.
|
||||||
spi.Bus.PSELMOSI.Set(uint32(sdo))
|
type SPIConfig struct {
|
||||||
spi.Bus.PSELMISO.Set(uint32(sdi))
|
Frequency uint32
|
||||||
|
SCK Pin
|
||||||
|
SDO Pin
|
||||||
|
SDI Pin
|
||||||
|
LSBFirst bool
|
||||||
|
Mode uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure is intended to setup the SPI interface.
|
||||||
|
func (spi SPI) Configure(config SPIConfig) {
|
||||||
|
// Disable bus to configure it
|
||||||
|
spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Disabled)
|
||||||
|
|
||||||
|
// set frequency
|
||||||
|
var freq uint32
|
||||||
|
|
||||||
|
if config.Frequency == 0 {
|
||||||
|
config.Frequency = 4000000 // 4MHz
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case config.Frequency >= 8000000:
|
||||||
|
freq = nrf.SPI_FREQUENCY_FREQUENCY_M8
|
||||||
|
case config.Frequency >= 4000000:
|
||||||
|
freq = nrf.SPI_FREQUENCY_FREQUENCY_M4
|
||||||
|
case config.Frequency >= 2000000:
|
||||||
|
freq = nrf.SPI_FREQUENCY_FREQUENCY_M2
|
||||||
|
case config.Frequency >= 1000000:
|
||||||
|
freq = nrf.SPI_FREQUENCY_FREQUENCY_M1
|
||||||
|
case config.Frequency >= 500000:
|
||||||
|
freq = nrf.SPI_FREQUENCY_FREQUENCY_K500
|
||||||
|
case config.Frequency >= 250000:
|
||||||
|
freq = nrf.SPI_FREQUENCY_FREQUENCY_K250
|
||||||
|
default: // below 250kHz, default to the lowest speed available
|
||||||
|
freq = nrf.SPI_FREQUENCY_FREQUENCY_K125
|
||||||
|
}
|
||||||
|
spi.Bus.FREQUENCY.Set(freq)
|
||||||
|
|
||||||
|
var conf uint32
|
||||||
|
|
||||||
|
// set bit transfer order
|
||||||
|
if config.LSBFirst {
|
||||||
|
conf = (nrf.SPI_CONFIG_ORDER_LsbFirst << nrf.SPI_CONFIG_ORDER_Pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
// set mode
|
||||||
|
switch config.Mode {
|
||||||
|
case 0:
|
||||||
|
conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
|
||||||
|
conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
|
||||||
|
case 1:
|
||||||
|
conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
|
||||||
|
conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos)
|
||||||
|
case 2:
|
||||||
|
conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos)
|
||||||
|
conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
|
||||||
|
case 3:
|
||||||
|
conf |= (nrf.SPI_CONFIG_CPOL_ActiveLow << nrf.SPI_CONFIG_CPOL_Pos)
|
||||||
|
conf |= (nrf.SPI_CONFIG_CPHA_Trailing << nrf.SPI_CONFIG_CPHA_Pos)
|
||||||
|
default: // to mode
|
||||||
|
conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
|
||||||
|
conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
|
||||||
|
}
|
||||||
|
spi.Bus.CONFIG.Set(conf)
|
||||||
|
|
||||||
|
// set pins
|
||||||
|
if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 {
|
||||||
|
config.SCK = SPI0_SCK_PIN
|
||||||
|
config.SDO = SPI0_SDO_PIN
|
||||||
|
config.SDI = SPI0_SDI_PIN
|
||||||
|
}
|
||||||
|
spi.Bus.PSELSCK.Set(uint32(config.SCK))
|
||||||
|
spi.Bus.PSELMOSI.Set(uint32(config.SDO))
|
||||||
|
spi.Bus.PSELMISO.Set(uint32(config.SDI))
|
||||||
|
|
||||||
|
// Re-enable bus now that it is configured.
|
||||||
|
spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer writes/reads a single byte using the SPI interface.
|
||||||
|
func (spi SPI) Transfer(w byte) (byte, error) {
|
||||||
|
spi.Bus.TXD.Set(uint32(w))
|
||||||
|
for spi.Bus.EVENTS_READY.Get() == 0 {
|
||||||
|
}
|
||||||
|
r := spi.Bus.RXD.Get()
|
||||||
|
spi.Bus.EVENTS_READY.Set(0)
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
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.EVENTS_READY.Set(0)
|
||||||
|
_ = spi.Bus.RXD.Get()
|
||||||
|
}
|
||||||
|
for spi.Bus.EVENTS_READY.Get() == 0 {
|
||||||
|
}
|
||||||
|
spi.Bus.EVENTS_READY.Set(0)
|
||||||
|
_ = spi.Bus.RXD.Get()
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,20 +111,149 @@ func (a ADC) Get() uint16 {
|
||||||
return uint16(value << 4)
|
return uint16(value << 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPI
|
// SPI on the NRF.
|
||||||
func (spi SPI) setPins(sck, sdo, sdi Pin) {
|
type SPI struct {
|
||||||
if sck == 0 {
|
Bus *nrf.SPIM_Type
|
||||||
sck = SPI0_SCK_PIN
|
}
|
||||||
|
|
||||||
|
// There are 3 SPI interfaces on the NRF528xx.
|
||||||
|
var (
|
||||||
|
SPI0 = SPI{Bus: nrf.SPIM0}
|
||||||
|
SPI1 = SPI{Bus: nrf.SPIM1}
|
||||||
|
SPI2 = SPI{Bus: nrf.SPIM2}
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPIConfig is used to store config info for SPI.
|
||||||
|
type SPIConfig struct {
|
||||||
|
Frequency uint32
|
||||||
|
SCK Pin
|
||||||
|
SDO Pin
|
||||||
|
SDI Pin
|
||||||
|
LSBFirst bool
|
||||||
|
Mode uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure is intended to setup the SPI interface.
|
||||||
|
func (spi SPI) Configure(config SPIConfig) {
|
||||||
|
// Disable bus to configure it
|
||||||
|
spi.Bus.ENABLE.Set(nrf.SPIM_ENABLE_ENABLE_Disabled)
|
||||||
|
|
||||||
|
// Pick a default frequency.
|
||||||
|
if config.Frequency == 0 {
|
||||||
|
config.Frequency = 4000000 // 4MHz
|
||||||
}
|
}
|
||||||
if sdo == 0 {
|
|
||||||
sdo = SPI0_SDO_PIN
|
// set frequency
|
||||||
|
var freq uint32
|
||||||
|
switch {
|
||||||
|
case config.Frequency >= 8000000:
|
||||||
|
freq = nrf.SPIM_FREQUENCY_FREQUENCY_M8
|
||||||
|
case config.Frequency >= 4000000:
|
||||||
|
freq = nrf.SPIM_FREQUENCY_FREQUENCY_M4
|
||||||
|
case config.Frequency >= 2000000:
|
||||||
|
freq = nrf.SPIM_FREQUENCY_FREQUENCY_M2
|
||||||
|
case config.Frequency >= 1000000:
|
||||||
|
freq = nrf.SPIM_FREQUENCY_FREQUENCY_M1
|
||||||
|
case config.Frequency >= 500000:
|
||||||
|
freq = nrf.SPIM_FREQUENCY_FREQUENCY_K500
|
||||||
|
case config.Frequency >= 250000:
|
||||||
|
freq = nrf.SPIM_FREQUENCY_FREQUENCY_K250
|
||||||
|
default: // below 250kHz, default to the lowest speed available
|
||||||
|
freq = nrf.SPIM_FREQUENCY_FREQUENCY_K125
|
||||||
}
|
}
|
||||||
if sdi == 0 {
|
spi.Bus.FREQUENCY.Set(freq)
|
||||||
sdi = SPI0_SDI_PIN
|
|
||||||
|
var conf uint32
|
||||||
|
|
||||||
|
// set bit transfer order
|
||||||
|
if config.LSBFirst {
|
||||||
|
conf = (nrf.SPIM_CONFIG_ORDER_LsbFirst << nrf.SPIM_CONFIG_ORDER_Pos)
|
||||||
}
|
}
|
||||||
spi.Bus.PSEL.SCK.Set(uint32(sck))
|
|
||||||
spi.Bus.PSEL.MOSI.Set(uint32(sdo))
|
// set mode
|
||||||
spi.Bus.PSEL.MISO.Set(uint32(sdi))
|
switch config.Mode {
|
||||||
|
case 0:
|
||||||
|
conf &^= (nrf.SPIM_CONFIG_CPOL_ActiveHigh << nrf.SPIM_CONFIG_CPOL_Pos)
|
||||||
|
conf &^= (nrf.SPIM_CONFIG_CPHA_Leading << nrf.SPIM_CONFIG_CPHA_Pos)
|
||||||
|
case 1:
|
||||||
|
conf &^= (nrf.SPIM_CONFIG_CPOL_ActiveHigh << nrf.SPIM_CONFIG_CPOL_Pos)
|
||||||
|
conf |= (nrf.SPIM_CONFIG_CPHA_Trailing << nrf.SPIM_CONFIG_CPHA_Pos)
|
||||||
|
case 2:
|
||||||
|
conf |= (nrf.SPIM_CONFIG_CPOL_ActiveLow << nrf.SPIM_CONFIG_CPOL_Pos)
|
||||||
|
conf &^= (nrf.SPIM_CONFIG_CPHA_Leading << nrf.SPIM_CONFIG_CPHA_Pos)
|
||||||
|
case 3:
|
||||||
|
conf |= (nrf.SPIM_CONFIG_CPOL_ActiveLow << nrf.SPIM_CONFIG_CPOL_Pos)
|
||||||
|
conf |= (nrf.SPIM_CONFIG_CPHA_Trailing << nrf.SPIM_CONFIG_CPHA_Pos)
|
||||||
|
default: // to mode
|
||||||
|
conf &^= (nrf.SPIM_CONFIG_CPOL_ActiveHigh << nrf.SPIM_CONFIG_CPOL_Pos)
|
||||||
|
conf &^= (nrf.SPIM_CONFIG_CPHA_Leading << nrf.SPIM_CONFIG_CPHA_Pos)
|
||||||
|
}
|
||||||
|
spi.Bus.CONFIG.Set(conf)
|
||||||
|
|
||||||
|
// set pins
|
||||||
|
if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 {
|
||||||
|
config.SCK = SPI0_SCK_PIN
|
||||||
|
config.SDO = SPI0_SDO_PIN
|
||||||
|
config.SDI = SPI0_SDI_PIN
|
||||||
|
}
|
||||||
|
spi.Bus.PSEL.SCK.Set(uint32(config.SCK))
|
||||||
|
spi.Bus.PSEL.MOSI.Set(uint32(config.SDO))
|
||||||
|
spi.Bus.PSEL.MISO.Set(uint32(config.SDI))
|
||||||
|
|
||||||
|
// Re-enable bus now that it is configured.
|
||||||
|
spi.Bus.ENABLE.Set(nrf.SPIM_ENABLE_ENABLE_Enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer writes/reads a single byte using the SPI interface.
|
||||||
|
func (spi SPI) Transfer(w byte) (byte, error) {
|
||||||
|
var wbuf, rbuf [1]byte
|
||||||
|
wbuf[0] = w
|
||||||
|
err := spi.Tx(wbuf[:], rbuf[:])
|
||||||
|
return rbuf[0], err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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. Therefore, if the number of bytes don't match it will be
|
||||||
|
// padded until they fit: if len(w) > len(r) the extra bytes received will be
|
||||||
|
// dropped and if len(w) < len(r) extra 0 bytes will be sent.
|
||||||
|
func (spi SPI) Tx(w, r []byte) error {
|
||||||
|
// Unfortunately the hardware (on the nrf52832) only supports up to 255
|
||||||
|
// bytes in the buffers, so if either w or r is longer than that the
|
||||||
|
// transfer needs to be broken up in pieces.
|
||||||
|
// The nrf52840 supports far larger buffers however, which isn't yet
|
||||||
|
// supported.
|
||||||
|
for len(r) != 0 || len(w) != 0 {
|
||||||
|
// Prepare the SPI transfer: set the DMA pointers and lengths.
|
||||||
|
if len(r) != 0 {
|
||||||
|
spi.Bus.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&r[0]))))
|
||||||
|
n := uint32(len(r))
|
||||||
|
if n > 255 {
|
||||||
|
n = 255
|
||||||
|
}
|
||||||
|
spi.Bus.RXD.MAXCNT.Set(n)
|
||||||
|
r = r[n:]
|
||||||
|
}
|
||||||
|
if len(w) != 0 {
|
||||||
|
spi.Bus.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&w[0]))))
|
||||||
|
n := uint32(len(w))
|
||||||
|
if n > 255 {
|
||||||
|
n = 255
|
||||||
|
}
|
||||||
|
spi.Bus.TXD.MAXCNT.Set(n)
|
||||||
|
w = w[n:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the transfer.
|
||||||
|
// Note: this can be improved by not waiting until the transfer is
|
||||||
|
// finished if the transfer is send-only (a common case).
|
||||||
|
spi.Bus.TASKS_START.Set(1)
|
||||||
|
for spi.Bus.EVENTS_END.Get() == 0 {
|
||||||
|
}
|
||||||
|
spi.Bus.EVENTS_END.Set(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitPWM initializes the registers needed for PWM.
|
// InitPWM initializes the registers needed for PWM.
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче