pru: Add support for ADC input
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
b85755c0ff
commit
c9b6662138
|
@ -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):
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
if MACH_PRU
|
||||
|
||||
config PRU_SELECT
|
||||
bool
|
||||
default y
|
||||
select HAVE_GPIO_ADC
|
||||
|
||||
config BOARD_DIRECTORY
|
||||
string
|
||||
default "pru"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -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)
|
||||
;
|
||||
|
|
Loading…
Reference in New Issue