From c9b66621381fda9d3af02253ca30c0119b62d7b2 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Thu, 11 May 2017 14:53:00 -0400 Subject: [PATCH] pru: Add support for ADC input Signed-off-by: Kevin O'Connor --- klippy/pins.py | 10 ++++++- src/pru/Kconfig | 5 ++++ src/pru/gpio.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++ src/pru/gpio.h | 8 ++++++ src/pru/internal.h | 33 ++++++++++++++++++++++- src/pru/main.c | 2 -- src/pru/pru0.c | 45 ++++++++++++++++++++++++++++++- 7 files changed, 165 insertions(+), 5 deletions(-) diff --git a/klippy/pins.py b/klippy/pins.py index 034f33c1..c4d5d2a2 100644 --- a/klippy/pins.py +++ b/klippy/pins.py @@ -21,12 +21,17 @@ def named_pins(fmt, port_count, bit_count=32): for port in range(port_count) for portbit in range(bit_count) } +def beaglebone_pins(): + gpios = named_pins("gpio%d_%d", 4) + gpios.update({"AIN%d" % i: i+4*32 for i in range(8)}) + return gpios + MCU_PINS = { "atmega168": port_pins(4), "atmega644p": port_pins(4), "at90usb1286": port_pins(5), "atmega1280": port_pins(12), "atmega2560": port_pins(12), "sam3x8e": port_pins(4, 32), - "pru": named_pins("gpio%d_%d", 4), + "pru": beaglebone_pins(), } @@ -126,6 +131,9 @@ beagleboneblack_mappings = { 'P9_27': 'gpio3_19', 'P9_28': 'gpio3_17', 'P9_29': 'gpio3_15', 'P9_30': 'gpio3_16', 'P9_31': 'gpio3_14', 'P9_41': 'gpio0_20', 'P9_42': 'gpio3_20', 'P9_43': 'gpio0_7', 'P9_44': 'gpio3_18', + + 'P9_33': 'AIN4', 'P9_35': 'AIN6', 'P9_36': 'AIN5', 'P9_37': 'AIN2', + 'P9_38': 'AIN3', 'P9_39': 'AIN0', 'P9_40': 'AIN1', } def update_map_beaglebone(pins, mcu): 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 // memset #include // write_r31 #include // CT_CFG +#include // CT_IEP #include // CT_INTC #include // pru_rpmsg_send #include // VIRTIO_ID_RPMSG @@ -76,6 +77,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) ;