aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/machine/machine_nrf52.go
diff options
context:
space:
mode:
authorRon Evans <[email protected]>2018-10-02 16:23:55 +0200
committerAyke van Laethem <[email protected]>2018-10-04 13:56:44 +0200
commit8f7b7e6ee34869d9dc8cc41db7cd2bd1e8be50e2 (patch)
tree125e475e5f5892ce9f71d6c070c60220a6cf00d0 /src/machine/machine_nrf52.go
parent3e98fbcdc8d862f9725d5b5fa6331620c2a0ff76 (diff)
downloadtinygo-8f7b7e6ee34869d9dc8cc41db7cd2bd1e8be50e2.tar.gz
tinygo-8f7b7e6ee34869d9dc8cc41db7cd2bd1e8be50e2.zip
nrf52: implement ADC and PWM interfaces
Signed-off-by: Ron Evans <[email protected]>
Diffstat (limited to 'src/machine/machine_nrf52.go')
-rw-r--r--src/machine/machine_nrf52.go154
1 files changed, 154 insertions, 0 deletions
diff --git a/src/machine/machine_nrf52.go b/src/machine/machine_nrf52.go
new file mode 100644
index 000000000..f62c10f1d
--- /dev/null
+++ b/src/machine/machine_nrf52.go
@@ -0,0 +1,154 @@
+// +build nrf52
+
+package machine
+
+import (
+ "device/nrf"
+ "unsafe"
+)
+
+// InitADC initializes the registers needed for ADC.
+func InitADC() {
+ return // no specific setup on nrf52 machine.
+}
+
+// Configure configures an ADC pin to be able to read analog data.
+func (a ADC) Configure() {
+ return // no pin specific setup on nrf52 machine.
+}
+
+// Get returns the current value of a ADC pin in the range 0..0xffff.
+func (a ADC) Get() uint16 {
+ var pwmPin uint32
+ var value int16
+
+ switch a.Pin {
+ case 2:
+ pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput0
+
+ case 3:
+ pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput1
+
+ case 4:
+ pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput2
+
+ case 5:
+ pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput3
+
+ case 28:
+ pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput4
+
+ case 29:
+ pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput5
+
+ case 30:
+ pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput6
+
+ case 31:
+ pwmPin = nrf.SAADC_CH_PSELP_PSELP_AnalogInput7
+
+ default:
+ return 0
+ }
+
+ nrf.SAADC.RESOLUTION = nrf.SAADC_RESOLUTION_VAL_12bit
+
+ // Enable ADC.
+ nrf.SAADC.ENABLE = (nrf.SAADC_ENABLE_ENABLE_Enabled << nrf.SAADC_ENABLE_ENABLE_Pos)
+ for i := 0; i < 8; i++ {
+ nrf.SAADC.CH[i].PSELN = nrf.SAADC_CH_PSELP_PSELP_NC
+ nrf.SAADC.CH[i].PSELP = nrf.SAADC_CH_PSELP_PSELP_NC
+ }
+
+ // Configure ADC.
+ nrf.SAADC.CH[0].CONFIG = ((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESP_Pos) & nrf.SAADC_CH_CONFIG_RESP_Msk) |
+ ((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESN_Pos) & nrf.SAADC_CH_CONFIG_RESN_Msk) |
+ ((nrf.SAADC_CH_CONFIG_GAIN_Gain1_5 << nrf.SAADC_CH_CONFIG_GAIN_Pos) & nrf.SAADC_CH_CONFIG_GAIN_Msk) |
+ ((nrf.SAADC_CH_CONFIG_REFSEL_Internal << nrf.SAADC_CH_CONFIG_REFSEL_Pos) & nrf.SAADC_CH_CONFIG_REFSEL_Msk) |
+ ((nrf.SAADC_CH_CONFIG_TACQ_3us << nrf.SAADC_CH_CONFIG_TACQ_Pos) & nrf.SAADC_CH_CONFIG_TACQ_Msk) |
+ ((nrf.SAADC_CH_CONFIG_MODE_SE << nrf.SAADC_CH_CONFIG_MODE_Pos) & nrf.SAADC_CH_CONFIG_MODE_Msk)
+
+ // Set pin to read.
+ nrf.SAADC.CH[0].PSELN = nrf.RegValue(pwmPin)
+ nrf.SAADC.CH[0].PSELP = nrf.RegValue(pwmPin)
+
+ // Destination for sample result.
+ nrf.SAADC.RESULT.PTR = nrf.RegValue(uintptr(unsafe.Pointer(&value)))
+ nrf.SAADC.RESULT.MAXCNT = 1 // One sample
+
+ // Start tasks.
+ nrf.SAADC.TASKS_START = 1
+ for nrf.SAADC.EVENTS_STARTED == 0 {
+ }
+ nrf.SAADC.EVENTS_STARTED = 0x00
+
+ // Start the sample task.
+ nrf.SAADC.TASKS_SAMPLE = 1
+
+ // Wait until the sample task is done.
+ for nrf.SAADC.EVENTS_END == 0 {
+ }
+ nrf.SAADC.EVENTS_END = 0x00
+
+ // Stop the ADC
+ nrf.SAADC.TASKS_STOP = 1
+ for nrf.SAADC.EVENTS_STOPPED == 0 {
+ }
+ nrf.SAADC.EVENTS_STOPPED = 0
+
+ // Disable the ADC.
+ nrf.SAADC.ENABLE = (nrf.SAADC_ENABLE_ENABLE_Disabled << nrf.SAADC_ENABLE_ENABLE_Pos)
+
+ if value < 0 {
+ value = 0
+ }
+
+ // Return 16-bit result from 12-bit value.
+ return uint16(value << 4)
+}
+
+// PWM
+var (
+ pwmChannelPins = [3]uint32{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
+ pwms = [3]*nrf.PWM_Type{nrf.PWM0, nrf.PWM1, nrf.PWM2}
+ pwmChannelSequence [3]uint16
+)
+
+// InitPWM initializes the registers needed for PWM.
+func InitPWM() {
+ return
+}
+
+// Configure configures a PWM pin for output.
+func (pwm PWM) Configure() {
+}
+
+// Set turns on the duty cycle for a PWM pin using the provided value.
+func (pwm PWM) Set(value uint16) {
+ for i := 0; i < 3; i++ {
+ if pwmChannelPins[i] == 0xFFFFFFFF || pwmChannelPins[i] == uint32(pwm.Pin) {
+ pwmChannelPins[i] = uint32(pwm.Pin)
+ pwmChannelSequence[i] = (value >> 2) | 0x8000 // set bit 15 to invert polarity
+
+ p := pwms[i]
+
+ p.PSEL.OUT[0] = nrf.RegValue(pwm.Pin)
+ p.PSEL.OUT[1] = nrf.RegValue(pwm.Pin)
+ p.PSEL.OUT[2] = nrf.RegValue(pwm.Pin)
+ p.PSEL.OUT[3] = nrf.RegValue(pwm.Pin)
+ p.ENABLE = (nrf.PWM_ENABLE_ENABLE_Enabled << nrf.PWM_ENABLE_ENABLE_Pos)
+ p.PRESCALER = nrf.PWM_PRESCALER_PRESCALER_DIV_2
+ p.MODE = nrf.PWM_MODE_UPDOWN_Up
+ p.COUNTERTOP = 16384 // frequency
+ p.LOOP = 0
+ p.DECODER = (nrf.PWM_DECODER_LOAD_Common << nrf.PWM_DECODER_LOAD_Pos) | (nrf.PWM_DECODER_MODE_RefreshCount << nrf.PWM_DECODER_MODE_Pos)
+ p.SEQ[0].PTR = nrf.RegValue(uintptr(unsafe.Pointer(&pwmChannelSequence[i])))
+ p.SEQ[0].CNT = 1
+ p.SEQ[0].REFRESH = 1
+ p.SEQ[0].ENDDELAY = 0
+ p.TASKS_SEQSTART[0] = 1
+
+ break
+ }
+ }
+}