diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2017-05-11 14:53:00 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2017-05-17 19:46:12 -0400 |
commit | c9b66621381fda9d3af02253ca30c0119b62d7b2 (patch) | |
tree | 1333398554d21c932fd394d2abe8d4ab5d4d8218 /src/pru | |
parent | b85755c0ff4cb31aeafc9fd0abd63094508d731b (diff) | |
download | kutter-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/Kconfig | 5 | ||||
-rw-r--r-- | src/pru/gpio.c | 67 | ||||
-rw-r--r-- | src/pru/gpio.h | 8 | ||||
-rw-r--r-- | src/pru/internal.h | 33 | ||||
-rw-r--r-- | src/pru/main.c | 2 | ||||
-rw-r--r-- | src/pru/pru0.c | 45 |
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) ; |