aboutsummaryrefslogtreecommitdiffstats
path: root/src/pru/gpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pru/gpio.c')
-rw-r--r--src/pru/gpio.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/src/pru/gpio.c b/src/pru/gpio.c
index 7fdbb0d6..d0d0268b 100644
--- a/src/pru/gpio.c
+++ b/src/pru/gpio.c
@@ -4,9 +4,11 @@
//
// 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_out_setup
+#include "internal.h" // ADC
#include "sched.h" // sched_shutdown
@@ -140,3 +142,68 @@ gpio_in_read(struct gpio_in g)
{
return !!(*g.reg & g.bit);
}
+
+
+/****************************************************************
+ * Analog to Digital Converter (ADC) pins
+ ****************************************************************/
+
+DECL_CONSTANT(ADC_MAX, 4095);
+
+struct gpio_adc
+gpio_adc_setup(uint8_t pin)
+{
+ uint8_t chan = pin - ARRAY_SIZE(digital_regs) * 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;
+}