aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/machine/machine_stm32_moder_gpio.go
blob: b8585c28c76ffb4d5846c85363d732ea5e135a56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//go:build stm32 && !stm32f103

package machine

import (
	"device/stm32"
)

// GPIO for the stm32 families except the stm32f1xx which uses a simpler but
//  less flexible mechanism. Extend the go:build directive above to exclude other
//  models in the stm32f1xx series as necessary

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

	// for PWM
	PinModePWMOutput PinMode = 12
)

// Define several bitfields that have different names across chip families but
// essentially have the same meaning.
const (
	// MODER bitfields.
	gpioModeInput     = 0
	gpioModeOutput    = 1
	gpioModeAlternate = 2
	gpioModeAnalog    = 3
	gpioModeMask      = 0x3

	// PUPDR bitfields.
	gpioPullFloating = 0
	gpioPullUp       = 1
	gpioPullDown     = 2
	gpioPullMask     = 0x3

	// OSPEED bitfields.
	gpioOutputSpeedVeryHigh = 3
	gpioOutputSpeedHigh     = 2
	gpioOutputSpeedMedium   = 1
	gpioOutputSpeedLow      = 0
	gpioOutputSpeedMask     = 0x3
)

// Configure this pin with the given configuration
func (p Pin) Configure(config PinConfig) {
	// Use the default system alternate function; this
	//  will only be used if you try to call this with
	//  one of the peripheral modes instead of vanilla GPIO.
	p.ConfigureAltFunc(config, 0)
}

// Configure this pin with the given configuration including alternate
//
//	function mapping if necessary.
func (p Pin) ConfigureAltFunc(config PinConfig, altFunc uint8) {
	// Configure the GPIO pin.
	p.enableClock()
	port := p.getPort()
	pos := (uint8(p) % 16) * 2 // assume each field is two bits in size (with mask 0x3)

	switch config.Mode {

	// GPIO
	case PinInputFloating:
		port.MODER.ReplaceBits(gpioModeInput, gpioModeMask, pos)
		port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos)
	case PinInputPulldown:
		port.MODER.ReplaceBits(gpioModeInput, gpioModeMask, pos)
		port.PUPDR.ReplaceBits(gpioPullDown, gpioPullMask, pos)
	case PinInputPullup:
		port.MODER.ReplaceBits(gpioModeInput, gpioModeMask, pos)
		port.PUPDR.ReplaceBits(gpioPullUp, gpioPullMask, pos)
	case PinOutput:
		port.MODER.ReplaceBits(gpioModeOutput, gpioModeMask, pos)
		port.OSPEEDR.ReplaceBits(gpioOutputSpeedHigh, gpioOutputSpeedMask, pos)

	// UART
	case PinModeUARTTX:
		port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos)
		port.OSPEEDR.ReplaceBits(gpioOutputSpeedHigh, gpioOutputSpeedMask, pos)
		port.PUPDR.ReplaceBits(gpioPullUp, gpioPullMask, pos)
		p.SetAltFunc(altFunc)
	case PinModeUARTRX:
		port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos)
		port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos)
		p.SetAltFunc(altFunc)

	// I2C
	case PinModeI2CSCL:
		port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos)
		port.OTYPER.ReplaceBits(stm32.GPIO_OTYPER_OT0_OpenDrain, stm32.GPIO_OTYPER_OT0_Msk, pos/2)
		port.OSPEEDR.ReplaceBits(gpioOutputSpeedLow, gpioOutputSpeedMask, pos)
		port.PUPDR.ReplaceBits(gpioPullUp, gpioPullMask, pos)
		p.SetAltFunc(altFunc)
	case PinModeI2CSDA:
		port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos)
		port.OTYPER.ReplaceBits(stm32.GPIO_OTYPER_OT0_OpenDrain, stm32.GPIO_OTYPER_OT0_Msk, pos/2)
		port.OSPEEDR.ReplaceBits(gpioOutputSpeedLow, gpioOutputSpeedMask, pos)
		port.PUPDR.ReplaceBits(gpioPullUp, gpioPullMask, pos)
		p.SetAltFunc(altFunc)

	// SPI
	case PinModeSPICLK:
		port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos)
		port.OSPEEDR.ReplaceBits(gpioOutputSpeedHigh, gpioOutputSpeedMask, pos)
		port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos)
		p.SetAltFunc(altFunc)
	case PinModeSPISDO:
		port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos)
		port.OSPEEDR.ReplaceBits(gpioOutputSpeedLow, gpioOutputSpeedMask, pos)
		port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos)
		p.SetAltFunc(altFunc)
	case PinModeSPISDI:
		port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos)
		port.OSPEEDR.ReplaceBits(gpioOutputSpeedLow, gpioOutputSpeedMask, pos)
		port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos)
		p.SetAltFunc(altFunc)

	// PWM
	case PinModePWMOutput:
		port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos)
		port.OSPEEDR.ReplaceBits(gpioOutputSpeedHigh, gpioOutputSpeedMask, pos)
		port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos)
		p.SetAltFunc(altFunc)

	// ADC
	case PinInputAnalog:
		port.MODER.ReplaceBits(gpioModeAnalog, gpioModeMask, pos)
		port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos)
	}
}

// SetAltFunc maps the given alternative function to the I/O pin
func (p Pin) SetAltFunc(af uint8) {
	port := p.getPort()
	pin := uint8(p) % 16
	pos := (pin % 8) * 4
	if pin < 8 {
		port.AFRL.ReplaceBits(uint32(af), 0xf, pos)
	} else {
		port.AFRH.ReplaceBits(uint32(af), 0xf, pos)
	}
}