Browse Source

machine/samd21: implement SPI interface for currently supported SAMD21 boards

Signed-off-by: Ron Evans <ron@hybridgroup.com>
pull/147/head
Ron Evans 6 years ago
committed by Ayke
parent
commit
665c3bdaa6
  1. 23
      src/machine/board_circuitplay_express.go
  2. 12
      src/machine/board_itsybitsy-m0.go
  3. 132
      src/machine/machine_atsamd21.go
  4. 2
      src/machine/spi.go

23
src/machine/board_circuitplay_express.go

@ -53,13 +53,13 @@ const (
PROXIMITY = A10 PROXIMITY = A10
) )
// USBCDC pins // USBCDC pins (logical UART0)
const ( const (
USBCDC_DM_PIN = PA24 USBCDC_DM_PIN = PA24
USBCDC_DP_PIN = PA25 USBCDC_DP_PIN = PA25
) )
// UART0 pins // UART0 pins (logical UART1)
const ( const (
UART_TX_PIN = PB08 // PORTB UART_TX_PIN = PB08 // PORTB
UART_RX_PIN = PB09 // PORTB UART_RX_PIN = PB09 // PORTB
@ -67,8 +67,11 @@ const (
// I2C pins // I2C pins
const ( const (
SDA_PIN = PA00 // SDA: SERCOM3/PAD[0] SDA_PIN = PB02 // I2C0 external
SCL_PIN = PA01 // SCL: SERCOM3/PAD[1] SCL_PIN = PB03 // I2C0 external
SDA1_PIN = PA00 // I2C1 internal
SCL1_PIN = PA01 // I2C1 internal
) )
// I2C on the Circuit Playground Express. // I2C on the Circuit Playground Express.
@ -76,3 +79,15 @@ var (
I2C0 = I2C{Bus: sam.SERCOM5_I2CM} // external device I2C0 = I2C{Bus: sam.SERCOM5_I2CM} // external device
I2C1 = I2C{Bus: sam.SERCOM1_I2CM} // internal device I2C1 = I2C{Bus: sam.SERCOM1_I2CM} // internal device
) )
// SPI pins (internal flash)
const (
SPI0_SCK_PIN = PA21 // SCK: SERCOM3/PAD[3]
SPI0_MOSI_PIN = PA20 // MOSI: SERCOM3/PAD[2]
SPI0_MISO_PIN = PA16 // MISO: SERCOM3/PAD[0]
)
// SPI on the Circuit Playground Express.
var (
SPI0 = SPI{Bus: sam.SERCOM3_SPI}
)

12
src/machine/board_itsybitsy-m0.go

@ -58,3 +58,15 @@ const (
var ( var (
I2C0 = I2C{Bus: sam.SERCOM3_I2CM} I2C0 = I2C{Bus: sam.SERCOM3_I2CM}
) )
// SPI pins
const (
SPI0_SCK_PIN = PB11 // SCK: SERCOM4/PAD[3]
SPI0_MOSI_PIN = PB10 // MOSI: SERCOM4/PAD[2]
SPI0_MISO_PIN = PA12 // MISO: SERCOM4/PAD[0]
)
// SPI on the ItsyBitsy M0.
var (
SPI0 = SPI{Bus: sam.SERCOM4_SPI}
)

132
src/machine/machine_atsamd21.go

@ -163,6 +163,19 @@ func (p GPIO) Configure(config GPIOConfig) {
// enable port config // enable port config
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR | sam.PORT_PINCFG0_INEN) p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR | sam.PORT_PINCFG0_INEN)
case GPIO_SERCOM_ALT:
if p.Pin&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
p.setPMux(val | (GPIO_SERCOM_ALT << sam.PORT_PMUX0_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
p.setPMux(val | (GPIO_SERCOM_ALT << sam.PORT_PMUX0_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR)
case GPIO_COM: case GPIO_COM:
if p.Pin&1 > 0 { if p.Pin&1 > 0 {
// odd pin, so save the even pins // odd pin, so save the even pins
@ -257,9 +270,6 @@ var (
// The first hardware serial port on the SAMD21. Uses the SERCOM0 interface. // The first hardware serial port on the SAMD21. Uses the SERCOM0 interface.
UART1 = UART{Bus: sam.SERCOM0_USART, Buffer: NewRingBuffer()} UART1 = UART{Bus: sam.SERCOM0_USART, Buffer: NewRingBuffer()}
// The second hardware serial port on the SAMD21. Uses the SERCOM1 interface.
UART2 = UART{Bus: sam.SERCOM1_USART, Buffer: NewRingBuffer()}
) )
const ( const (
@ -272,6 +282,11 @@ const (
sercomTXPad0 = 0 // Only for UART sercomTXPad0 = 0 // Only for UART
sercomTXPad2 = 1 // Only for UART sercomTXPad2 = 1 // Only for UART
sercomTXPad023 = 2 // Only for UART with TX on PAD0, RTS on PAD2 and CTS on PAD3 sercomTXPad023 = 2 // Only for UART with TX on PAD0, RTS on PAD2 and CTS on PAD3
spiTXPad0SCK1 = 0
spiTXPad2SCK3 = 1
spiTXPad3SCK1 = 2
spiTXPad0SCK3 = 3
) )
// Configure the UART. // Configure the UART.
@ -408,13 +423,6 @@ func handleUART1() {
UART1.Bus.INTFLAG |= sam.SERCOM_USART_INTFLAG_RXC UART1.Bus.INTFLAG |= sam.SERCOM_USART_INTFLAG_RXC
} }
//go:export SERCOM1_IRQHandler
func handleUART2() {
// should reset IRQ
UART2.Receive(byte((UART2.Bus.DATA & 0xFF)))
UART2.Bus.INTFLAG |= sam.SERCOM_USART_INTFLAG_RXC
}
// I2C on the SAMD21. // I2C on the SAMD21.
type I2C struct { type I2C struct {
Bus *sam.SERCOM_I2CM_Type Bus *sam.SERCOM_I2CM_Type
@ -644,6 +652,110 @@ func (i2c I2C) readByte() byte {
return byte(i2c.Bus.DATA) return byte(i2c.Bus.DATA)
} }
// SPI
type SPI struct {
Bus *sam.SERCOM_SPI_Type
}
// SPIConfig is used to store config info for SPI.
type SPIConfig struct {
Frequency uint32
SCK uint8
MOSI uint8
MISO uint8
LSBFirst bool
Mode uint8
}
// Configure is intended to setup the SPI interface.
func (spi SPI) Configure(config SPIConfig) {
config.SCK = SPI0_SCK_PIN
config.MOSI = SPI0_MOSI_PIN
config.MISO = SPI0_MISO_PIN
doPad := spiTXPad2SCK3
diPad := sercomRXPad0
// set default frequency
if config.Frequency == 0 {
config.Frequency = 4000000
}
// Disable SPI port.
spi.Bus.CTRLA &^= sam.SERCOM_SPI_CTRLA_ENABLE
for (spi.Bus.SYNCBUSY & sam.SERCOM_SPI_SYNCBUSY_ENABLE) > 0 {
}
// enable pins
GPIO{config.SCK}.Configure(GPIOConfig{Mode: GPIO_SERCOM_ALT})
GPIO{config.MOSI}.Configure(GPIOConfig{Mode: GPIO_SERCOM_ALT})
GPIO{config.MISO}.Configure(GPIOConfig{Mode: GPIO_SERCOM_ALT})
// reset SERCOM
spi.Bus.CTRLA |= sam.SERCOM_SPI_CTRLA_SWRST
for (spi.Bus.CTRLA&sam.SERCOM_SPI_CTRLA_SWRST) > 0 ||
(spi.Bus.SYNCBUSY&sam.SERCOM_SPI_SYNCBUSY_SWRST) > 0 {
}
// set bit transfer order
dataOrder := 0
if config.LSBFirst {
dataOrder = 1
}
// Set SPI master
spi.Bus.CTRLA = (sam.SERCOM_SPI_CTRLA_MODE_SPI_MASTER << sam.SERCOM_SPI_CTRLA_MODE_Pos) |
sam.RegValue(doPad<<sam.SERCOM_SPI_CTRLA_DOPO_Pos) |
sam.RegValue(diPad<<sam.SERCOM_SPI_CTRLA_DIPO_Pos) |
sam.RegValue(dataOrder<<sam.SERCOM_SPI_CTRLA_DORD_Pos)
spi.Bus.CTRLB |= (0 << sam.SERCOM_SPI_CTRLB_CHSIZE_Pos) | // 8bit char size
sam.SERCOM_SPI_CTRLB_RXEN // receive enable
for (spi.Bus.SYNCBUSY & sam.SERCOM_SPI_SYNCBUSY_CTRLB) > 0 {
}
// set mode
switch config.Mode {
case 0:
spi.Bus.CTRLA &^= sam.SERCOM_SPI_CTRLA_CPHA
spi.Bus.CTRLA &^= sam.SERCOM_SPI_CTRLA_CPOL
case 1:
spi.Bus.CTRLA |= sam.SERCOM_SPI_CTRLA_CPHA
spi.Bus.CTRLA &^= sam.SERCOM_SPI_CTRLA_CPOL
case 2:
spi.Bus.CTRLA &^= sam.SERCOM_SPI_CTRLA_CPHA
spi.Bus.CTRLA |= sam.SERCOM_SPI_CTRLA_CPOL
case 3:
spi.Bus.CTRLA |= sam.SERCOM_SPI_CTRLA_CPHA | sam.SERCOM_SPI_CTRLA_CPOL
default: // to mode 0
spi.Bus.CTRLA &^= sam.SERCOM_SPI_CTRLA_CPHA
spi.Bus.CTRLA &^= sam.SERCOM_SPI_CTRLA_CPOL
}
// Set synch speed for SPI
baudRate := (CPU_FREQUENCY / (2 * config.Frequency)) - 1
spi.Bus.BAUD = sam.RegValue8(baudRate)
// Enable SPI port.
spi.Bus.CTRLA |= sam.SERCOM_SPI_CTRLA_ENABLE
for (spi.Bus.SYNCBUSY & sam.SERCOM_SPI_SYNCBUSY_ENABLE) > 0 {
}
}
// Transfer writes/reads a single byte using the SPI interface.
func (spi SPI) Transfer(w byte) (byte, error) {
// write data
spi.Bus.DATA = sam.RegValue(w)
// wait for receive
for (spi.Bus.INTFLAG & sam.SERCOM_SPI_INTFLAG_RXC) == 0 {
}
// return data
return byte(spi.Bus.DATA), nil
}
// PWM // PWM
const period = 0xFFFF const period = 0xFFFF

2
src/machine/spi.go

@ -1,4 +1,4 @@
// +build nrf stm32f103xx // +build nrf stm32f103xx atsamd21g18a
package machine package machine

Loading…
Cancel
Save