machine/samd21: implement SPI interface for currently supported SAMD21 boards
Signed-off-by: Ron Evans <ron@hybridgroup.com>
Этот коммит содержится в:
родитель
ea3d232c84
коммит
665c3bdaa6
4 изменённых файлов: 154 добавлений и 15 удалений
|
@ -53,13 +53,13 @@ const (
|
|||
PROXIMITY = A10
|
||||
)
|
||||
|
||||
// USBCDC pins
|
||||
// USBCDC pins (logical UART0)
|
||||
const (
|
||||
USBCDC_DM_PIN = PA24
|
||||
USBCDC_DP_PIN = PA25
|
||||
)
|
||||
|
||||
// UART0 pins
|
||||
// UART0 pins (logical UART1)
|
||||
const (
|
||||
UART_TX_PIN = PB08 // PORTB
|
||||
UART_RX_PIN = PB09 // PORTB
|
||||
|
@ -67,8 +67,11 @@ const (
|
|||
|
||||
// I2C pins
|
||||
const (
|
||||
SDA_PIN = PA00 // SDA: SERCOM3/PAD[0]
|
||||
SCL_PIN = PA01 // SCL: SERCOM3/PAD[1]
|
||||
SDA_PIN = PB02 // I2C0 external
|
||||
SCL_PIN = PB03 // I2C0 external
|
||||
|
||||
SDA1_PIN = PA00 // I2C1 internal
|
||||
SCL1_PIN = PA01 // I2C1 internal
|
||||
)
|
||||
|
||||
// I2C on the Circuit Playground Express.
|
||||
|
@ -76,3 +79,15 @@ var (
|
|||
I2C0 = I2C{Bus: sam.SERCOM5_I2CM} // external 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}
|
||||
)
|
||||
|
|
|
@ -58,3 +58,15 @@ const (
|
|||
var (
|
||||
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}
|
||||
)
|
||||
|
|
|
@ -163,6 +163,19 @@ func (p GPIO) Configure(config GPIOConfig) {
|
|||
// enable port config
|
||||
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:
|
||||
if p.Pin&1 > 0 {
|
||||
// odd pin, so save the even pins
|
||||
|
@ -257,9 +270,6 @@ var (
|
|||
|
||||
// The first hardware serial port on the SAMD21. Uses the SERCOM0 interface.
|
||||
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 (
|
||||
|
@ -272,6 +282,11 @@ const (
|
|||
sercomTXPad0 = 0 // Only for UART
|
||||
sercomTXPad2 = 1 // Only for UART
|
||||
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.
|
||||
|
@ -408,13 +423,6 @@ func handleUART1() {
|
|||
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.
|
||||
type I2C struct {
|
||||
Bus *sam.SERCOM_I2CM_Type
|
||||
|
@ -644,6 +652,110 @@ func (i2c I2C) readByte() byte {
|
|||
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
|
||||
const period = 0xFFFF
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build nrf stm32f103xx
|
||||
// +build nrf stm32f103xx atsamd21g18a
|
||||
|
||||
package machine
|
||||
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче