const (
LED = LED_BUILTIN
LED1 = LED_GREEN
LED2 = LED_ORANGE
LED3 = LED_RED
LED4 = LED_BLUE
LED_BUILTIN = LED_GREEN
LED_GREEN = PD12
LED_ORANGE = PD13
LED_RED = PD14
LED_BLUE = PD15
)
const (
UART_TX_PIN = PA2
UART_RX_PIN = PA3
)
UART pins
const (
SPI1_SCK_PIN = PA5
SPI1_SDI_PIN = PA6
SPI1_SDO_PIN = PA7
SPI0_SCK_PIN = SPI1_SCK_PIN
SPI0_SDI_PIN = SPI1_SDI_PIN
SPI0_SDO_PIN = SPI1_SDO_PIN
)
SPI pins
const (
MEMS_ACCEL_CS = PE3
MEMS_ACCEL_INT1 = PE0
MEMS_ACCEL_INT2 = PE1
)
MEMs accelerometer
const (
I2C0_SCL_PIN = PB6
I2C0_SDA_PIN = PB9
)
const (
TWI_FREQ_100KHZ = 100000
TWI_FREQ_400KHZ = 400000
)
TWI_FREQ is the I2C bus speed. Normally either 100 kHz, or 400 kHz for high-speed bus.
const NoPin = Pin(0xff)
NoPin explicitly indicates “not a pin”. Use this pin if you want to leave one of the pins in a peripheral unconfigured (if supported by the hardware).
const (
DutyCycle2 = 0
DutyCycle16x9 = 1
)
I2C fast mode (Fm) duty cycle
const (
// Mode Flag
PinOutput PinMode = 0
PinInput PinMode = PinInputFloating
PinInputFloating PinMode = 1
PinInputPulldown PinMode = 2
PinInputPullup PinMode = 3
// for UART
PinModeUARTTX PinMode = 4
PinModeUARTRX PinMode = 5
// for I2C
PinModeI2CSCL PinMode = 6
PinModeI2CSDA PinMode = 7
// for SPI
PinModeSPICLK PinMode = 8
PinModeSPISDO PinMode = 9
PinModeSPISDI PinMode = 10
// for analog/ADC
PinInputAnalog PinMode = 11
)
const (
PA0 = portA + 0
PA1 = portA + 1
PA2 = portA + 2
PA3 = portA + 3
PA4 = portA + 4
PA5 = portA + 5
PA6 = portA + 6
PA7 = portA + 7
PA8 = portA + 8
PA9 = portA + 9
PA10 = portA + 10
PA11 = portA + 11
PA12 = portA + 12
PA13 = portA + 13
PA14 = portA + 14
PA15 = portA + 15
PB0 = portB + 0
PB1 = portB + 1
PB2 = portB + 2
PB3 = portB + 3
PB4 = portB + 4
PB5 = portB + 5
PB6 = portB + 6
PB7 = portB + 7
PB8 = portB + 8
PB9 = portB + 9
PB10 = portB + 10
PB11 = portB + 11
PB12 = portB + 12
PB13 = portB + 13
PB14 = portB + 14
PB15 = portB + 15
PC0 = portC + 0
PC1 = portC + 1
PC2 = portC + 2
PC3 = portC + 3
PC4 = portC + 4
PC5 = portC + 5
PC6 = portC + 6
PC7 = portC + 7
PC8 = portC + 8
PC9 = portC + 9
PC10 = portC + 10
PC11 = portC + 11
PC12 = portC + 12
PC13 = portC + 13
PC14 = portC + 14
PC15 = portC + 15
PD0 = portD + 0
PD1 = portD + 1
PD2 = portD + 2
PD3 = portD + 3
PD4 = portD + 4
PD5 = portD + 5
PD6 = portD + 6
PD7 = portD + 7
PD8 = portD + 8
PD9 = portD + 9
PD10 = portD + 10
PD11 = portD + 11
PD12 = portD + 12
PD13 = portD + 13
PD14 = portD + 14
PD15 = portD + 15
PE0 = portE + 0
PE1 = portE + 1
PE2 = portE + 2
PE3 = portE + 3
PE4 = portE + 4
PE5 = portE + 5
PE6 = portE + 6
PE7 = portE + 7
PE8 = portE + 8
PE9 = portE + 9
PE10 = portE + 10
PE11 = portE + 11
PE12 = portE + 12
PE13 = portE + 13
PE14 = portE + 14
PE15 = portE + 15
PH0 = portH + 0
PH1 = portH + 1
)
const (
AF0_SYSTEM = 0
AF1_TIM1_2 = 1
AF2_TIM3_4_5 = 2
AF3_TIM8_9_10_11 = 3
AF4_I2C1_2_3 = 4
AF5_SPI1_SPI2 = 5
AF6_SPI3 = 6
AF7_USART1_2_3 = 7
AF8_USART4_5_6 = 8
AF9_CAN1_CAN2_TIM12_13_14 = 9
AF10_OTG_FS_OTG_HS = 10
AF11_ETH = 11
AF12_FSMC_SDIO_OTG_HS_1 = 12
AF13_DCMI = 13
AF14 = 14
AF15_EVENTOUT = 15
)
Alternative peripheral pin functions
const (
Mode0 = 0
Mode1 = 1
Mode2 = 2
Mode3 = 3
)
SPI phase and polarity configs CPOL and CPHA
var (
UART0 = UART{
Buffer: NewRingBuffer(),
Bus: stm32.USART2,
AltFuncSelector: AF7_USART1_2_3,
}
UART1 = &UART0
)
var (
SPI0 = SPI{
Bus: stm32.SPI1,
AltFuncSelector: AF5_SPI1_SPI2,
}
SPI1 = &SPI0
)
Since the first interface is named SPI1, both SPI0 and SPI1 refer to SPI1. TODO: implement SPI2 and SPI3.
var (
I2C0 = I2C{
Bus: stm32.I2C1,
AltFuncSelector: AF4_I2C1_2_3,
}
)
var (
ErrInvalidInputPin = errors.New("machine: invalid input pin")
ErrInvalidOutputPin = errors.New("machine: invalid output pin")
ErrInvalidClockPin = errors.New("machine: invalid clock pin")
ErrInvalidDataPin = errors.New("machine: invalid data pin")
ErrNoPinChangeChannel = errors.New("machine: no channel available for pin interrupt")
)
var (
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
errSPIInvalidMachineConfig = errors.New("SPI port was not configured properly by the machine")
)
func CPUFrequency() uint32
func NewRingBuffer() *RingBuffer
NewRingBuffer returns a new ring buffer.
type ADC struct {
Pin Pin
}
type ADCConfig struct {
Reference uint32 // analog reference voltage (AREF) in millivolts
Resolution uint32 // number of bits for a single conversion (e.g., 8, 10, 12)
Samples uint32 // number of samples for a single conversion (e.g., 4, 8, 16, 32)
}
ADCConfig holds ADC configuration parameters. If left unspecified, the zero value of each parameter will use the peripheral’s default settings.
type I2C struct {
Bus *stm32.I2C_Type
AltFuncSelector uint8
}
func (i2c I2C) Configure(config I2CConfig) error
Configure is intended to setup the STM32 I2C interface.
func (i2c I2C) ReadRegister(address uint8, register uint8, data []byte) error
ReadRegister transmits the register, restarts the connection as a read operation, and reads the response.
Many I2C-compatible devices are organized in terms of registers. This method is a shortcut to easily read such registers. Also, it only works for devices with 7-bit addresses, which is the vast majority.
func (i2c I2C) Tx(addr uint16, w, r []byte) error
func (i2c I2C) WriteRegister(address uint8, register uint8, data []byte) error
WriteRegister transmits first the register and then the data to the peripheral device.
Many I2C-compatible devices are organized in terms of registers. This method is a shortcut to easily write to such registers. Also, it only works for devices with 7-bit addresses, which is the vast majority.
type I2CConfig struct {
Frequency uint32
SCL Pin
SDA Pin
DutyCycle uint8
}
I2CConfig is used to store config info for I2C.
type PWM struct {
Pin Pin
}
type Pin uint8
Pin is a single pin on a chip, which may be connected to other hardware devices. It can either be used directly as GPIO pin or it can be used in other peripherals like ADC, I2C, etc.
func (p Pin) Configure(config PinConfig)
Configure this pin with the given configuration
func (p Pin) ConfigureAltFunc(config PinConfig, altFunc uint8)
Configure this pin with the given configuration including alternate function mapping if necessary.
func (p Pin) Get() bool
Get returns the current value of a GPIO pin.
func (p Pin) High()
High sets this GPIO pin to high, assuming it has been configured as an output pin. It is hardware dependent (and often undefined) what happens if you set a pin to high that is not configured as an output pin.
func (p Pin) Low()
Low sets this GPIO pin to low, assuming it has been configured as an output pin. It is hardware dependent (and often undefined) what happens if you set a pin to low that is not configured as an output pin.
func (p Pin) Set(high bool)
Set the pin to high or low. Warning: only use this on an output pin!
func (p Pin) SetAltFunc(af uint8)
SetAltFunc maps the given alternative function to the I/O pin
type PinConfig struct {
Mode PinMode
}
type PinMode uint8
type RingBuffer struct {
rxbuffer [bufferSize]volatile.Register8
head volatile.Register8
tail volatile.Register8
}
RingBuffer is ring buffer implementation inspired by post at https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php
func (rb *RingBuffer) Clear()
Clear resets the head and tail pointer to zero.
func (rb *RingBuffer) Get() (byte, bool)
Get returns a byte from the buffer. If the buffer is empty, the method will return a false as the second value.
func (rb *RingBuffer) Put(val byte) bool
Put stores a byte in the buffer. If the buffer is already full, the method will return false.
func (rb *RingBuffer) Used() uint8
Used returns how many bytes in buffer have been used.
type SPI struct {
Bus *stm32.SPI_Type
AltFuncSelector uint8
}
SPI on the STM32Fxxx using MODER / alternate function pins
func (spi SPI) Configure(config SPIConfig)
Configure is intended to setup the STM32 SPI1 interface.
func (spi SPI) Transfer(w byte) (byte, error)
Transfer writes/reads a single byte using the SPI interface.
func (spi SPI) Tx(w, r []byte) error
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)
type SPIConfig struct {
Frequency uint32
SCK Pin
SDO Pin
SDI Pin
LSBFirst bool
Mode uint8
}
SPIConfig is used to store config info for SPI.
type UART struct {
Buffer *RingBuffer
Bus *stm32.USART_Type
Interrupt interrupt.Interrupt
AltFuncSelector uint8
// Registers specific to the chip
rxReg *volatile.Register32
txReg *volatile.Register32
statusReg *volatile.Register32
txEmptyFlag uint32
}
UART representation
func (uart UART) Buffered() int
Buffered returns the number of bytes currently stored in the RX buffer.
func (uart *UART) Configure(config UARTConfig)
Configure the UART.
func (uart UART) Read(data []byte) (n int, err error)
Read from the RX buffer.
func (uart UART) ReadByte() (byte, error)
ReadByte reads a single byte from the RX buffer. If there is no data in the buffer, returns an error.
func (uart UART) Receive(data byte)
Receive handles adding data to the UART’s data buffer. Usually called by the IRQ handler for a machine.
func (uart *UART) SetBaudRate(br uint32)
SetBaudRate sets the communication speed for the UART. Defer to chip-specific routines for calculation
func (uart UART) Write(data []byte) (n int, err error)
Write data to the UART.
func (uart *UART) WriteByte(c byte) error
WriteByte writes a byte of data to the UART.
type UARTConfig struct {
BaudRate uint32
TX Pin
RX Pin
}