1// +build nrf52840
2
3package machine
4
5import (
6	"device/nrf"
7	"unsafe"
8)
9
10func CPUFrequency() uint32 {
11	return 64000000
12}
13
14// Hardware pins
15const (
16	P0_00 Pin = 0
17	P0_01 Pin = 1
18	P0_02 Pin = 2
19	P0_03 Pin = 3
20	P0_04 Pin = 4
21	P0_05 Pin = 5
22	P0_06 Pin = 6
23	P0_07 Pin = 7
24	P0_08 Pin = 8
25	P0_09 Pin = 9
26	P0_10 Pin = 10
27	P0_11 Pin = 11
28	P0_12 Pin = 12
29	P0_13 Pin = 13
30	P0_14 Pin = 14
31	P0_15 Pin = 15
32	P0_16 Pin = 16
33	P0_17 Pin = 17
34	P0_18 Pin = 18
35	P0_19 Pin = 19
36	P0_20 Pin = 20
37	P0_21 Pin = 21
38	P0_22 Pin = 22
39	P0_23 Pin = 23
40	P0_24 Pin = 24
41	P0_25 Pin = 25
42	P0_26 Pin = 26
43	P0_27 Pin = 27
44	P0_28 Pin = 28
45	P0_29 Pin = 29
46	P0_30 Pin = 30
47	P0_31 Pin = 31
48	P1_00 Pin = 32
49	P1_01 Pin = 33
50	P1_02 Pin = 34
51	P1_03 Pin = 35
52	P1_04 Pin = 36
53	P1_05 Pin = 37
54	P1_06 Pin = 38
55	P1_07 Pin = 39
56	P1_08 Pin = 40
57	P1_09 Pin = 41
58	P1_10 Pin = 42
59	P1_11 Pin = 43
60	P1_12 Pin = 44
61	P1_13 Pin = 45
62	P1_14 Pin = 46
63	P1_15 Pin = 47
64)
65
66// Get peripheral and pin number for this GPIO pin.
67func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) {
68	if p >= 32 {
69		return nrf.P1, uint32(p - 32)
70	} else {
71		return nrf.P0, uint32(p)
72	}
73}
74
75func (uart UART) setPins(tx, rx Pin) {
76	nrf.UART0.PSEL.TXD.Set(uint32(tx))
77	nrf.UART0.PSEL.RXD.Set(uint32(rx))
78}
79
80func (i2c I2C) setPins(scl, sda Pin) {
81	i2c.Bus.PSEL.SCL.Set(uint32(scl))
82	i2c.Bus.PSEL.SDA.Set(uint32(sda))
83}
84
85// SPI
86func (spi SPI) setPins(sck, sdo, sdi Pin) {
87	if sck == 0 {
88		sck = SPI0_SCK_PIN
89	}
90	if sdo == 0 {
91		sdo = SPI0_SDO_PIN
92	}
93	if sdi == 0 {
94		sdi = SPI0_SDI_PIN
95	}
96	spi.Bus.PSEL.SCK.Set(uint32(sck))
97	spi.Bus.PSEL.MOSI.Set(uint32(sdo))
98	spi.Bus.PSEL.MISO.Set(uint32(sdi))
99}
100
101// InitADC initializes the registers needed for ADC.
102func InitADC() {
103	return // no specific setup on nrf52840 machine.
104}
105
106// Configure configures an ADC pin to be able to read analog data.
107func (a ADC) Configure() error {
108	return nil // no pin specific setup on nrf52840 machine.
109}
110
111// Get returns the current value of a ADC pin in the range 0..0xffff.
112func (a ADC) Get() uint16 {
113	var pwmPin uint32
114	var value int16
115
116	switch a.Pin {
117	case 2:
118		pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput0
119
120	case 3:
121		pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput1
122
123	case 4:
124		pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput2
125
126	case 5:
127		pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput3
128
129	case 28:
130		pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput4
131
132	case 29:
133		pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput5
134
135	case 30:
136		pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput6
137
138	case 31:
139		pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput7
140
141	default:
142		return 0
143	}
144
145	nrf.SAADC.RESOLUTION.Set(nrf.SAADC_RESOLUTION_VAL_12bit)
146
147	// Enable ADC.
148	nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Enabled << nrf.SAADC_ENABLE_ENABLE_Pos)
149	for i := 0; i < 8; i++ {
150		nrf.SAADC.CH[i].PSELN.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
151		nrf.SAADC.CH[i].PSELP.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
152	}
153
154	// Configure ADC.
155	nrf.SAADC.CH[0].CONFIG.Set(((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESP_Pos) & nrf.SAADC_CH_CONFIG_RESP_Msk) |
156		((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESN_Pos) & nrf.SAADC_CH_CONFIG_RESN_Msk) |
157		((nrf.SAADC_CH_CONFIG_GAIN_Gain1_5 << nrf.SAADC_CH_CONFIG_GAIN_Pos) & nrf.SAADC_CH_CONFIG_GAIN_Msk) |
158		((nrf.SAADC_CH_CONFIG_REFSEL_Internal << nrf.SAADC_CH_CONFIG_REFSEL_Pos) & nrf.SAADC_CH_CONFIG_REFSEL_Msk) |
159		((nrf.SAADC_CH_CONFIG_TACQ_3us << nrf.SAADC_CH_CONFIG_TACQ_Pos) & nrf.SAADC_CH_CONFIG_TACQ_Msk) |
160		((nrf.SAADC_CH_CONFIG_MODE_SE << nrf.SAADC_CH_CONFIG_MODE_Pos) & nrf.SAADC_CH_CONFIG_MODE_Msk))
161
162	// Set pin to read.
163	nrf.SAADC.CH[0].PSELN.Set(pwmPin)
164	nrf.SAADC.CH[0].PSELP.Set(pwmPin)
165
166	// Destination for sample result.
167	nrf.SAADC.RESULT.PTR.Set(uint32(uintptr(unsafe.Pointer(&value))))
168	nrf.SAADC.RESULT.MAXCNT.Set(1) // One sample
169
170	// Start tasks.
171	nrf.SAADC.TASKS_START.Set(1)
172	for nrf.SAADC.EVENTS_STARTED.Get() == 0 {
173	}
174	nrf.SAADC.EVENTS_STARTED.Set(0x00)
175
176	// Start the sample task.
177	nrf.SAADC.TASKS_SAMPLE.Set(1)
178
179	// Wait until the sample task is done.
180	for nrf.SAADC.EVENTS_END.Get() == 0 {
181	}
182	nrf.SAADC.EVENTS_END.Set(0x00)
183
184	// Stop the ADC
185	nrf.SAADC.TASKS_STOP.Set(1)
186	for nrf.SAADC.EVENTS_STOPPED.Get() == 0 {
187	}
188	nrf.SAADC.EVENTS_STOPPED.Set(0)
189
190	// Disable the ADC.
191	nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Disabled << nrf.SAADC_ENABLE_ENABLE_Pos)
192
193	if value < 0 {
194		value = 0
195	}
196
197	// Return 16-bit result from 12-bit value.
198	return uint16(value << 4)
199}
200
201// PWM
202var (
203	pwmChannelPins     = [4]uint32{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
204	pwms               = [4]*nrf.PWM_Type{nrf.PWM0, nrf.PWM1, nrf.PWM2, nrf.PWM3}
205	pwmChannelSequence [4]uint16
206)
207
208// InitPWM initializes the registers needed for PWM.
209func InitPWM() {
210	return
211}
212
213// Configure configures a PWM pin for output.
214func (pwm PWM) Configure() {
215}
216
217// Set turns on the duty cycle for a PWM pin using the provided value.
218func (pwm PWM) Set(value uint16) {
219	for i := 0; i < 4; i++ {
220		if pwmChannelPins[i] == 0xFFFFFFFF || pwmChannelPins[i] == uint32(pwm.Pin) {
221			pwmChannelPins[i] = uint32(pwm.Pin)
222			pwmChannelSequence[i] = (value >> 2) | 0x8000 // set bit 15 to invert polarity
223
224			p := pwms[i]
225
226			p.PSEL.OUT[0].Set(uint32(pwm.Pin))
227			p.PSEL.OUT[1].Set(uint32(pwm.Pin))
228			p.PSEL.OUT[2].Set(uint32(pwm.Pin))
229			p.PSEL.OUT[3].Set(uint32(pwm.Pin))
230			p.ENABLE.Set(nrf.PWM_ENABLE_ENABLE_Enabled << nrf.PWM_ENABLE_ENABLE_Pos)
231			p.PRESCALER.Set(nrf.PWM_PRESCALER_PRESCALER_DIV_2)
232			p.MODE.Set(nrf.PWM_MODE_UPDOWN_Up)
233			p.COUNTERTOP.Set(16384) // frequency
234			p.LOOP.Set(0)
235			p.DECODER.Set((nrf.PWM_DECODER_LOAD_Common << nrf.PWM_DECODER_LOAD_Pos) | (nrf.PWM_DECODER_MODE_RefreshCount << nrf.PWM_DECODER_MODE_Pos))
236			p.SEQ[0].PTR.Set(uint32(uintptr(unsafe.Pointer(&pwmChannelSequence[i]))))
237			p.SEQ[0].CNT.Set(1)
238			p.SEQ[0].REFRESH.Set(1)
239			p.SEQ[0].ENDDELAY.Set(0)
240			p.TASKS_SEQSTART[0].Set(1)
241
242			break
243		}
244	}
245}
246