aboutsummaryrefslogtreecommitdiffstats
path: root/src/pru/adc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pru/adc.c')
-rw-r--r--src/pru/adc.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/src/pru/adc.c b/src/pru/adc.c
new file mode 100644
index 00000000..64d4fcb4
--- /dev/null
+++ b/src/pru/adc.c
@@ -0,0 +1,77 @@
+// Analog to digital conversion (ADC) code on PRU
+//
+// Copyright (C) 2017 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "board/io.h" // readl
+#include "command.h" // shutdown
+#include "compiler.h" // ARRAY_SIZE
+#include "gpio.h" // gpio_adc_setup
+#include "internal.h" // ADC
+#include "sched.h" // sched_shutdown
+
+
+/****************************************************************
+ * Analog to Digital Converter (ADC) pins
+ ****************************************************************/
+
+DECL_CONSTANT(ADC_MAX, 4095);
+
+struct gpio_adc
+gpio_adc_setup(uint8_t pin)
+{
+ uint8_t chan = pin - 4 * 32;
+ if (chan >= 8)
+ shutdown("Not an adc channel");
+ if (!readl(&ADC->ctrl))
+ shutdown("ADC module not enabled");
+ return (struct gpio_adc){ .chan = chan };
+}
+
+enum { ADC_DUMMY=0xff };
+static uint8_t last_analog_read = ADC_DUMMY;
+static uint16_t last_analog_sample;
+
+// Try to sample a value. Returns zero if sample ready, otherwise
+// returns the number of clock ticks the caller should wait before
+// retrying this function.
+uint32_t
+gpio_adc_sample(struct gpio_adc g)
+{
+ uint8_t last = last_analog_read;
+ if (last == ADC_DUMMY) {
+ // Start sample
+ last_analog_read = g.chan;
+ writel(&ADC->stepenable, 1 << (g.chan + 1));
+ goto need_delay;
+ }
+ if (last == g.chan) {
+ // Check if sample ready
+ while (readl(&ADC->fifo0count)) {
+ uint32_t sample = readl(&ADC->fifo0data);
+ if (sample >> 16 == g.chan) {
+ last_analog_read = ADC_DUMMY;
+ last_analog_sample = sample;
+ return 0;
+ }
+ }
+ }
+need_delay:
+ return 160;
+}
+
+// Read a value; use only after gpio_adc_sample() returns zero
+uint16_t
+gpio_adc_read(struct gpio_adc g)
+{
+ return last_analog_sample;
+}
+
+// Cancel a sample that may have been started with gpio_adc_sample()
+void
+gpio_adc_cancel_sample(struct gpio_adc g)
+{
+ if (last_analog_read == g.chan)
+ last_analog_read = ADC_DUMMY;
+}