aboutsummaryrefslogtreecommitdiffstats
path: root/src/pru
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2017-05-11 14:53:00 -0400
committerKevin O'Connor <kevin@koconnor.net>2017-05-17 19:46:12 -0400
commitc9b66621381fda9d3af02253ca30c0119b62d7b2 (patch)
tree1333398554d21c932fd394d2abe8d4ab5d4d8218 /src/pru
parentb85755c0ff4cb31aeafc9fd0abd63094508d731b (diff)
downloadkutter-c9b66621381fda9d3af02253ca30c0119b62d7b2.tar.gz
kutter-c9b66621381fda9d3af02253ca30c0119b62d7b2.tar.xz
kutter-c9b66621381fda9d3af02253ca30c0119b62d7b2.zip
pru: Add support for ADC input
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src/pru')
-rw-r--r--src/pru/Kconfig5
-rw-r--r--src/pru/gpio.c67
-rw-r--r--src/pru/gpio.h8
-rw-r--r--src/pru/internal.h33
-rw-r--r--src/pru/main.c2
-rw-r--r--src/pru/pru0.c45
6 files changed, 156 insertions, 4 deletions
diff --git a/src/pru/Kconfig b/src/pru/Kconfig
index 483c0447..5b177272 100644
--- a/src/pru/Kconfig
+++ b/src/pru/Kconfig
@@ -2,6 +2,11 @@
if MACH_PRU
+config PRU_SELECT
+ bool
+ default y
+ select HAVE_GPIO_ADC
+
config BOARD_DIRECTORY
string
default "pru"
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;
+}
diff --git a/src/pru/gpio.h b/src/pru/gpio.h
index 65c52724..fc5e16b9 100644
--- a/src/pru/gpio.h
+++ b/src/pru/gpio.h
@@ -19,4 +19,12 @@ struct gpio_in {
struct gpio_in gpio_in_setup(uint8_t pin, int8_t pull_up);
uint8_t gpio_in_read(struct gpio_in g);
+struct gpio_adc {
+ uint8_t chan;
+};
+struct gpio_adc gpio_adc_setup(uint8_t pin);
+uint32_t gpio_adc_sample(struct gpio_adc g);
+uint16_t gpio_adc_read(struct gpio_adc g);
+void gpio_adc_cancel_sample(struct gpio_adc g);
+
#endif // gpio.h
diff --git a/src/pru/internal.h b/src/pru/internal.h
index 8556eed7..109dd3a2 100644
--- a/src/pru/internal.h
+++ b/src/pru/internal.h
@@ -34,6 +34,37 @@ struct shared_mem {
#define SIGNAL_PRU0_WAITING 0xefefefef
#define SIGNAL_PRU1_READY 0xabababab
-static struct shared_mem *SHARED_MEM = (void*)0x10000;
+#define SHARED_MEM ((struct shared_mem *)0x10000)
+
+// Hardware ADC registers
+struct beaglebone_adc {
+ uint32_t pad_00[10];
+ uint32_t irqstatus;
+ uint32_t irqenable_set;
+ uint32_t irqenable_clr;
+ uint32_t irqwakeup;
+ uint32_t dmaenable_set;
+ uint32_t dmaenable_clr;
+ uint32_t ctrl;
+ uint32_t adcstat;
+ uint32_t adcrange;
+ uint32_t adc_clkdiv;
+ uint32_t adc_misc;
+ uint32_t stepenable;
+ uint32_t idleconfig;
+ uint32_t ts_charge_stepconfig;
+ uint32_t ts_charge_delay;
+ struct {
+ uint32_t config;
+ uint32_t delay;
+ } step[16];
+ uint32_t fifo0count;
+ uint32_t pad_e8[6];
+ uint32_t fifo0data;
+ uint32_t pad_104[63];
+ uint32_t fifo1data;
+};
+
+#define ADC ((struct beaglebone_adc *)0x44e0d000)
#endif // internal.h
diff --git a/src/pru/main.c b/src/pru/main.c
index fcf66b39..df69a01e 100644
--- a/src/pru/main.c
+++ b/src/pru/main.c
@@ -90,8 +90,6 @@ static void
timer_init(void)
{
CT_IEP.TMR_CNT = 0;
- CT_IEP.TMR_CMP_CFG = 0x01 << 1;
- CT_IEP.TMR_GLB_CFG = 0x11;
timer_shutdown();
}
diff --git a/src/pru/pru0.c b/src/pru/pru0.c
index e4bd1c46..1455c820 100644
--- a/src/pru/pru0.c
+++ b/src/pru/pru0.c
@@ -8,6 +8,7 @@
#include <string.h> // memset
#include <pru/io.h> // write_r31
#include <pru_cfg.h> // CT_CFG
+#include <pru_iep.h> // CT_IEP
#include <pru_intc.h> // CT_INTC
#include <pru_rpmsg.h> // pru_rpmsg_send
#include <pru_virtio_ids.h> // VIRTIO_ID_RPMSG
@@ -77,6 +78,44 @@ process_io(struct pru_rpmsg_transport *transport)
/****************************************************************
+ * Peripheral reset
+ ****************************************************************/
+
+static void
+timer_reset(void)
+{
+ CT_IEP.TMR_CMP_CFG = 0x01 << 1;
+ CT_IEP.TMR_GLB_CFG = 0x11;
+}
+
+static void
+adc_reset(void)
+{
+ // Disable ADC
+ ADC->ctrl = (1<<2);
+ barrier();
+ // Clear registers
+ ADC->irqstatus = 0xffffffff;
+ ADC->irqenable_clr = 0xffffffff;
+ ADC->dmaenable_clr = 0xffffffff;
+ ADC->adc_clkdiv = 0;
+ ADC->stepenable = 0;
+ ADC->idleconfig = 0;
+ int i;
+ for (i=0; i<8; i++) {
+ ADC->step[i].config = i<<19;
+ ADC->step[i].delay = 0;
+ }
+ // Enable ADC
+ barrier();
+ writel(&ADC->ctrl, 0x07);
+ // Drain fifo
+ while (readl(&ADC->fifo0count))
+ readl(&ADC->fifo0data);
+}
+
+
+/****************************************************************
* Resource table
****************************************************************/
@@ -218,8 +257,12 @@ main(void)
, CHAN_DESC, CHAN_PORT) != PRU_RPMSG_SUCCESS)
;
- // Wait for PRU1 to be ready
+ // Reset peripherals
memset(SHARED_MEM, 0, sizeof(*SHARED_MEM));
+ timer_reset();
+ adc_reset();
+
+ // Wait for PRU1 to be ready
writel(&SHARED_MEM->signal, SIGNAL_PRU0_WAITING);
while (readl(&SHARED_MEM->signal) != SIGNAL_PRU1_READY)
;