aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/machine/machine_nrf51.go
blob: ae6ff61a843524dddae6bb689b435354de8a3e5a (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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
//go:build nrf51

package machine

import (
	"device/nrf"
)

const eraseBlockSizeValue = 1024

func eraseBlockSize() int64 {
	return eraseBlockSizeValue
}

// Get peripheral and pin number for this GPIO pin.
func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) {
	return nrf.GPIO, uint32(p)
}

func (uart *UART) setPins(tx, rx Pin) {
	nrf.UART0.PSELTXD.Set(uint32(tx))
	nrf.UART0.PSELRXD.Set(uint32(rx))
}

func (i2c *I2C) setPins(scl, sda Pin) {
	i2c.Bus.PSELSCL.Set(uint32(scl))
	i2c.Bus.PSELSDA.Set(uint32(sda))
}

// SPI on the NRF.
type SPI struct {
	Bus *nrf.SPI_Type
}

// There are 2 SPI interfaces on the NRF51.
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) error {
	// 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)

	return nil
}

// 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
}

// InitADC initializes the registers needed for ADC.
func InitADC() {
	return // no specific setup on nrf51 machine.
}

// Configure configures an ADC pin to be able to read analog data.
func (a ADC) Configure(ADCConfig) {
	return // no pin specific setup on nrf51 machine.
}

// Get returns the current value of a ADC pin in the range 0..0xffff.
func (a ADC) Get() uint16 {
	var value uint32

	adcPin := a.getADCPin()

	// Enable ADC.
	nrf.ADC.SetENABLE(nrf.ADC_ENABLE_ENABLE_Enabled)

	// Set pin to read.
	nrf.ADC.SetCONFIG_PSEL(adcPin)

	// config ADC
	nrf.ADC.SetCONFIG_RES(nrf.ADC_CONFIG_RES_10bit)
	nrf.ADC.SetCONFIG_INPSEL(nrf.ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling)
	nrf.ADC.SetCONFIG_REFSEL(nrf.ADC_CONFIG_REFSEL_SupplyOneThirdPrescaling)

	// Start tasks.
	nrf.ADC.TASKS_START.Set(1)

	// Wait until the sample task is done.
	for nrf.ADC.EVENTS_END.Get() == 0 {
	}
	nrf.ADC.EVENTS_END.Set(0x00)

	value = nrf.ADC.GetRESULT()

	// Stop the ADC
	nrf.ADC.TASKS_STOP.Set(1)

	// Disable ADC.
	nrf.ADC.SetENABLE(nrf.ADC_ENABLE_ENABLE_Disabled)

	if value < 0 {
		value = 0
	}

	// Return 16-bit result from 10-bit value.
	return uint16(value << 6)
}

func (a ADC) getADCPin() uint32 {
	switch a.Pin {
	case 1:
		return nrf.ADC_CONFIG_PSEL_AnalogInput2

	case 2:
		return nrf.ADC_CONFIG_PSEL_AnalogInput3

	case 3:
		return nrf.ADC_CONFIG_PSEL_AnalogInput4

	case 4:
		return nrf.ADC_CONFIG_PSEL_AnalogInput5

	case 5:
		return nrf.ADC_CONFIG_PSEL_AnalogInput6

	case 6:
		return nrf.ADC_CONFIG_PSEL_AnalogInput7

	case 26:
		return nrf.ADC_CONFIG_PSEL_AnalogInput0

	case 27:
		return nrf.ADC_CONFIG_PSEL_AnalogInput1

	default:
		return 0
	}
}