diff options
Diffstat (limited to 'nuttx/arch/arm/src/tiva/tiva_adclow.c')
-rw-r--r-- | nuttx/arch/arm/src/tiva/tiva_adclow.c | 1030 |
1 files changed, 1030 insertions, 0 deletions
diff --git a/nuttx/arch/arm/src/tiva/tiva_adclow.c b/nuttx/arch/arm/src/tiva/tiva_adclow.c new file mode 100644 index 000000000..ede07693b --- /dev/null +++ b/nuttx/arch/arm/src/tiva/tiva_adclow.c @@ -0,0 +1,1030 @@ +/**************************************************************************** + * arch/arm/src/tiva/tiva_adclow.c + * + * Copyright (C) 2015 TRD2 Inc. All rights reserved. + * Author: Calvin Maguranis <calvin.maguranis@trd2inc.com> + * + * References: + * + * TM4C123GH6PM Series Data Sheet + * TI Tivaware driverlib ADC sample code. + * + * The Tivaware sample code has a BSD compatible license that requires this + * copyright notice: + * + * Copyright (c) 2005-2014 Texas Instruments Incorporated. All rights reserved. + * Software License Agreement + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This is part of revision 2.1.0.12573 of the Tiva Peripheral Driver Library. + *****************************************************************************/ + +/* Keep in mind that for every step there should be another entry in the + * CONFIG_ADC_FIFOSIZE value. + * e.g. if there are 12 steps in use; CONFIG_ADC_FIFOSIZE = 12+1 = 13 + * if there are 3 steps in use; CONFIG_ADC_FIFOSIZE = 3+1 = 4 + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/arch.h> +#include <nuttx/wqueue.h> +#include <nuttx/analog/adc.h> + +#include <sys/types.h> + +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <semaphore.h> +#include <errno.h> +#include <debug.h> +#include <assert.h> + +#include <arch/board/board.h> + +#include "up_arch.h" +#include "up_internal.h" +#include "tiva_gpio.h" +#include "tiva_adc.h" +#include "chip/tiva_adc.h" +#include "chip/tiva_pinmap.h" +#include "chip/tiva_syscontrol.h" + +#if defined (CONFIG_TIVA_ADC) && defined (CONFIG_ADC) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifndef CONFIG_TIVA_ADC_CLOCK +# define CONFIG_TIVA_ADC_CLOCK TIVA_ADC_CLOCK_MIN +#endif + +#ifdef CONFIG_TIVA_ADC_VREF +# ifndef CONFIG_ARCH_CHIP_TM4C129 +# error Voltage reference selection only supported in TM4C129 parts +# endif +#endif + +#ifdef CONFIG_TIVA_ADC_ALT_CLK +# warning CONFIG_TIVA_ADC_ALT_CLK unsupported. +#endif + +#ifndef CONFIG_SCHED_WORKQUEUE +# error Work queue support is required (CONFIG_SCHED_WORKQUEUE) +#endif +#ifndef CONFIG_SCHED_HPWORK +# error High priority worker threads is required (CONFIG_SCHED_HPWORK) +#endif + +/* PWM trigger support definitions ******************************************/ + +/* Decodes the PWM generator and module from trigger and converts + * to the TSSEL_PS register + */ + +#define ADC_TRIG_PWM_CFG(t) \ + (1<<(ADC_TSSEL_PS_SHIFT(ADC_TRIG_gen(t)))) + +/* ADC support definitions **************************************************/ + +#define SSE_PROC_TRIG(n) (1 << (n)) +#define SEM_PROCESS_PRIVATE 0 +#define SEM_PROCESS_SHARED 1 + +/* DEBUG ********************************************************************/ + +#ifdef CONFIG_DEBUG_ANALOG +#endif + +/**************************************************************************** + * Public Functions + * **************************************************************************/ + +/* Upper level ADC driver ***************************************************/ + +static void tiva_adc_reset(struct adc_dev_s *dev); +static int tiva_adc_setup(struct adc_dev_s *dev); +static void tiva_adc_shutdown(struct adc_dev_s *dev); +static void tiva_adc_rxint(struct adc_dev_s *dev, bool enable); +static int tiva_adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* ADC lower half device operations */ + +static const struct adc_ops_s g_adcops = +{ + .ao_reset = tiva_adc_reset, + .ao_setup = tiva_adc_setup, + .ao_shutdown = tiva_adc_shutdown, + .ao_rxint = tiva_adc_rxint, + .ao_ioctl = tiva_adc_ioctl, +}; + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct tiva_adc_s +{ + struct adc_dev_s *dev; + bool cfg; /* Configuration state */ + bool ena; /* Operation state */ + uint8_t devno; /* ADC device number */ +}; + +struct tiva_adc_sse_s +{ + sem_t exclsem; /* Mutual exclusion semaphore */ + struct work_s work; /* Supports the interrupt handling "bottom half" */ + bool cfg; /* Configuration state */ + bool ena; /* Sample sequencer operation state */ + uint8_t adc; /* Parent peripheral */ + uint8_t num; /* SSE number */ +}; + +/**************************************************************************** + * Private Function Definitions + ****************************************************************************/ + +static void tiva_adc_interrupt(struct tiva_adc_sse_s *sse); +#ifdef CONFIG_DEBUG_ANALOG +static void tiva_adc_runtimeobj_ptrs(void); +static void tiva_adc_runtimeobj_vals(void); +static void tiva_adc_dump_dev(void); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Run-time ADC objects */ + +#ifdef CONFIG_TIVA_ADC0 +static struct adc_dev_s dev0; +static struct tiva_adc_s adc0; + +static struct tiva_adc_sse_s sse00; +static struct tiva_adc_sse_s sse01; +static struct tiva_adc_sse_s sse02; +static struct tiva_adc_sse_s sse03; +#endif + +#ifdef CONFIG_TIVA_ADC1 +static struct adc_dev_s dev1; +static struct tiva_adc_s adc1; + +static struct tiva_adc_sse_s sse10; +static struct tiva_adc_sse_s sse11; +static struct tiva_adc_sse_s sse12; +static struct tiva_adc_sse_s sse13; +#endif + +/* Offer run-time ADC objects in array form to help reduce the reliance on + * hard-coded, non-generic function calls. + */ + +static struct adc_dev_s *g_devs[] = +{ +#ifdef CONFIG_TIVA_ADC0 + &dev0, +#else + NULL, +#endif +#ifdef CONFIG_TIVA_ADC1 + &dev1 +#else + NULL +#endif +}; + +static struct tiva_adc_s *g_adcs[] = +{ +#ifdef CONFIG_TIVA_ADC0 + &adc0, +#else + NULL, +#endif +#ifdef CONFIG_TIVA_ADC1 + &adc1 +#else + NULL +#endif +}; + +static struct tiva_adc_sse_s *g_sses[] = +{ +#ifdef CONFIG_TIVA_ADC0 + &sse00, &sse01, &sse02, &sse03, +#else + NULL, NULL, NULL, NULL, +#endif +#ifdef CONFIG_TIVA_ADC1 + &sse10, &sse11, &sse12, &sse13 +#else + NULL, NULL, NULL, NULL +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* Interrupt handlers are inevitably hard-coded and specific */ + +#ifdef CONFIG_TIVA_ADC0 +static int tiva_adc0_sse0_interrupt(int irq, void *context) +{ + tiva_adc_interrupt(&sse00); + return OK; +} + +static int tiva_adc0_sse1_interrupt(int irq, void *context) +{ + tiva_adc_interrupt(&sse01); + return OK; +} + +static int tiva_adc0_sse2_interrupt(int irq, void *context) +{ + tiva_adc_interrupt(&sse02); + return OK; +} + +static int tiva_adc0_sse3_interrupt(int irq, void *context) +{ + tiva_adc_interrupt(&sse03); + return OK; +} +#endif + +#ifdef CONFIG_TIVA_ADC1 +static int tiva_adc1_sse0_interrupt(int irq, void *context) +{ + tiva_adc_interrupt(&sse10); + return OK; +} + +static int tiva_adc1_sse1_interrupt(int irq, void *context) +{ + tiva_adc_interrupt(&sse11); + return OK; +} + +static int tiva_adc1_sse2_interrupt(int irq, void *context) +{ + tiva_adc_interrupt(&sse12); + return OK; +} + +static int tiva_adc1_sse3_interrupt(int irq, void *context) +{ + tiva_adc_interrupt(&sse13); + return OK; +} +#endif + +static void tiva_adc_irqinitialize(struct tiva_adc_cfg_s *cfg) +{ + avdbg("initialize irqs for ADC%d...\n", cfg->adc); + +#ifdef CONFIG_TIVA_ADC0 + if (cfg->adc == 0) + { + if (cfg->sse[0] && (cfg->ssecfg[0].trigger > 0)) + { + tiva_adc_irq_attach(0, 0, tiva_adc0_sse0_interrupt); + } + + if (cfg->sse[1] && (cfg->ssecfg[1].trigger > 0)) + { + tiva_adc_irq_attach(0, 1, tiva_adc0_sse1_interrupt); + } + + if (cfg->sse[2] && (cfg->ssecfg[2].trigger > 0)) + { + tiva_adc_irq_attach(0, 2, tiva_adc0_sse2_interrupt); + } + + if (cfg->sse[3] && (cfg->ssecfg[3].trigger > 0)) + { + tiva_adc_irq_attach(0, 3, tiva_adc0_sse3_interrupt); + } + } +#endif +#ifdef CONFIG_TIVA_ADC1 + if (cfg->adc == 1) + { + if (cfg->sse[0] && (cfg->ssecfg[0].trigger > 0)) + { + tiva_adc_irq_attach(1, 0, tiva_adc1_sse0_interrupt); + } + + if (cfg->sse[1] && (cfg->ssecfg[1].trigger > 0)) + { + tiva_adc_irq_attach(1, 1, tiva_adc1_sse1_interrupt); + } + + if (cfg->sse[2] && (cfg->ssecfg[2].trigger > 0)) + { + tiva_adc_irq_attach(1, 2, tiva_adc1_sse2_interrupt); + } + + if (cfg->sse[3] && (cfg->ssecfg[3].trigger > 0)) + { + tiva_adc_irq_attach(1, 3, tiva_adc1_sse3_interrupt); + } + } +#endif +} + +/**************************************************************************** + * Name: tiva_adc_reset + * + * Description: + * Reset the ADC device. Called early to initialize the hardware. This is + * called before tiva_adc_setup() and on error conditions. + * + * Resetting disables interrupts and the enabled SSEs for the ADC. + * + ****************************************************************************/ + +static void tiva_adc_reset(struct adc_dev_s *dev) +{ + avdbg("Resetting...\n"); + + struct tiva_adc_s *priv = (struct tiva_adc_s *)dev->ad_priv; + struct tiva_adc_sse_s *sse; + uint8_t s; + + tiva_adc_rxint(dev, false); + + for (s = 0; s < 4; ++s) + { + sse = g_sses[SSE_IDX(priv->devno, s)]; + + if (sse->ena == true) + { + tiva_adc_sse_enable(priv->devno, s, false); + sse->ena = false; + } + } +} + +/**************************************************************************** + * Name: tiva_adc_setup + * + * Description: + * Configure the ADC. This method is called the first time that the ADC + * device is opened. This will occur when the port is first opened. + * Interrupts are all disabled upon return. + * + ****************************************************************************/ + +static int tiva_adc_setup(struct adc_dev_s *dev) +{ + avdbg("Setup\n"); + + struct tiva_adc_s *priv = (struct tiva_adc_s *)dev->ad_priv; + struct tiva_adc_sse_s *sse; + uint8_t s = 0; + + priv->ena = true; + + for (s = 0; s < 4; ++s) + { + sse = g_sses[SSE_IDX(priv->devno, s)]; + if (sse->cfg == true) + { + tiva_adc_sse_enable(priv->devno, s, true); + sse->ena = true; + } + } + + tiva_adc_rxint(dev, false); + return OK; +} + +/**************************************************************************** + * Name: tiva_adc_shutdown + * + * Description: + * Disable the ADC. This method is called when the ADC device is closed. + * This method reverses the operation the setup method. + * + ****************************************************************************/ + +static void tiva_adc_shutdown(struct adc_dev_s *dev) +{ + struct tiva_adc_s *priv = (struct tiva_adc_s *)dev->ad_priv; + avdbg("Shutdown\n"); + + DEBUGASSERT(priv->ena); + + /* Resetting the ADC peripheral disables interrupts and all SSEs */ + + tiva_adc_reset(dev); + + /* Currently all of the setup operations are undone in reset() */ + +#if 0 + struct tiva_adc_sse_s *sse; + uint8_t s = 0; + + for (s=0; s<4; ++s) + { + } +#endif + + priv->ena = false; +} + +/**************************************************************************** + * Name: tiva_adc_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + * Input Parameters: + * enable - the enable state of interrupts for this device + * + ****************************************************************************/ + +static void tiva_adc_rxint(struct adc_dev_s *dev, bool enable) +{ + avdbg("RXINT=%d\n", enable); + + struct tiva_adc_s *priv = (struct tiva_adc_s *)dev->ad_priv; + struct tiva_adc_sse_s *sse; + uint32_t trigger; + uint8_t s = 0; + + DEBUGASSERT(priv->ena); + + for (s=0; s<4; ++s) + { + trigger = tiva_adc_get_trigger(priv->devno, s); + sse = g_sses[SSE_IDX(priv->devno, s)]; + if ((sse->ena == true) + && (trigger > 0)) + { + tiva_adc_sse_int_enable(priv->devno, s, enable); + } + } +} + +/**************************************************************************** + * Name: tiva_adc_ioctl + * + * Description: + * All ioctl calls will be routed through this method. + * + * Input Parameters: + * cmd - ADC ioctl command + * arg - argument for the ioctl command + * + * Returned Value: + * Non negative value on success; negative value on failure. + * + ****************************************************************************/ + +static int tiva_adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg) +{ + int ret = OK; + + avdbg("cmd=%d arg=%ld\n", cmd, arg); + + switch (cmd) + { + /* Software trigger */ + + case ANIOC_TRIGGER: + { + struct tiva_adc_s *priv = (struct tiva_adc_s *)dev->ad_priv; + uint8_t i = 0; + uint8_t fifo_count = 0; + uint8_t sse = (uint8_t) arg; + int32_t buf[8]; + + /* Get exclusive access to the driver data structure */ + + tiva_adc_lock(priv, sse); + + /* Start conversion and wait for end of conversion */ + + tiva_adc_proc_trig(priv->devno, (uint8_t)SSE_PROC_TRIG(sse)); + while (!tiva_adc_sse_int_status(priv->devno, sse)) + { + usleep(100); + } + + tiva_adc_sse_clear_int(priv->devno, sse); + + /* Pass sampled data to upper ADC driver */ + + fifo_count = tiva_adc_sse_data(priv->devno, sse, buf); + + for (i=0; i<fifo_count; ++i) + { + (void)adc_receive(dev, + tiva_adc_get_ain(priv->devno, sse, i), + buf[i]); + } + + /* Release our lock on the ADC structure */ + + tiva_adc_unlock(priv, sse); + } + break; + + /* PWM triggering */ + +#warning Missing Logic + + /* TODO: Needs to be tested */ + +#ifdef CONFIG_EXPERIMENTAL + case TIVA_ADC_PWM_TRIG_IOCTL: + { + uint8_t sse = (uint8_t)(arg & 0x2); + uint8_t regval = tiva_adc_get_trigger(adc, sse); + + /* Verify input SSE trigger is a PWM trigger */ + + if ((regval & TIVA_ADC_TRIG_PWM0) || + (regval & TIVA_ADC_TRIG_PWM1) || + (regval & TIVA_ADC_TRIG_PWM2) || + (regval & TIVA_ADC_TRIG_PWM3)) + { + tiva_adc_sse_pwm_trig(adc, sse, (uint32_t)(arg&0xFFFFFFFC)); + } + } + break; +#endif + +#warning Missing Logic + + /* Unsupported or invalid command */ + + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: tiva_adc_read + * + * Description: + * This function executes on the worker thread. It is scheduled by + * tiva_adc_interrupt whenever any enabled event occurs. All interrupts + * are disabled when this function runs. tiva_adc_read will + * re-enable interrupts when it completes processing all pending events. + * + * Input Parameters + * arg - The ADC SSE data structure cast to (void *) + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void tiva_adc_read(void *arg) +{ + struct tiva_adc_sse_s *sse = (struct tiva_adc_sse_s *)arg; + struct adc_dev_s *dev = 0; + int irq = tiva_adc_getirq(sse->adc, sse->num); + uint8_t i = 0; + uint8_t fifo_count = 0; + int32_t buf[8]; + + /* Get exclusive access to the driver data structure */ + + tiva_adc_lock(g_adcs[sse->adc], sse->num); + + /* Get sampled data */ + + fifo_count = tiva_adc_sse_data(sse->adc, sse->num, buf); + + /* Determine which adc_dev_s we need */ + + dev = g_devs[sse->adc]; + if (dev == NULL) + { + /* This is a serious error: indicates invalid pointer indirection + * and should cause a full system stop. + */ + alldbg("PANIC!!! Invalid ADC device number given %d\n", sse->adc); + PANIC(); + return; + } + + for (i=0; i<fifo_count; ++i) + { + (void)adc_receive(dev, + tiva_adc_get_ain(sse->adc, sse->num, i), + buf[i]); + avdbg("AIN%d=0x%04x\n", + tiva_adc_get_ain(sse->adc, sse->num, i), buf[i]); + } + + /* Exit, re-enabling ADC interrupts */ + + up_enable_irq(irq); + + /* Release our lock on the ADC structure */ + + tiva_adc_unlock(g_adcs[sse->adc], sse->num); +} + +/**************************************************************************** + * Name: tiva_adc_interrupt + * + * Description: + * This function is called by every interrupt handler and handles the + * actual worker dispatching. + * + ****************************************************************************/ + +static void tiva_adc_interrupt(struct tiva_adc_sse_s *sse) +{ + int ret; + int irq = tiva_adc_getirq(sse->adc, sse->num); + + DEBUGASSERT(sse->ena == true); + + /* disable further interrupts. Interrupts will be re-enabled + * after the worker thread executes. + */ + + up_disable_irq(irq); + + /* Clear interrupt status */ + + tiva_adc_sse_clear_int(sse->adc, sse->num); + + /* Transfer processing to the worker thread. Since interrupts are + * disabled while the work is pending, no special action should be + * required to protected the work queue. + */ + + DEBUGASSERT(sse->work.worker == NULL); + ret = work_queue(HPWORK, &sse->work, tiva_adc_read, sse, 0); + if (ret != 0) + { + adbg("ERROR: Failed to queue work: %d ADC.SSE: %d.%d\n", + ret, sse->adc, sse->num); + } +} + +/**************************************************************************** + * Name: tiva_adc_struct_init + * + * Description: + * Initialize public and private adc structures their member SSE's. + * + ****************************************************************************/ + +static struct tiva_adc_s *tiva_adc_struct_init(struct tiva_adc_cfg_s *cfg) +{ + struct tiva_adc_s *adc = g_adcs[cfg->adc]; + struct tiva_adc_sse_s *sse = 0; + uint8_t s = 0; + + /* Do not re-initialize the run-time structures, there is a chance another + * process is also using this ADC. + */ + + if (adc->cfg == true) + { + goto tiva_adc_struct_init_ok; + } + else + { + if (adc != NULL) + { + adc->ena = false; + adc->devno = cfg->adc; + + for (s=0; s<4; s++) + { + + /* Only configure selected SSEs */ + + if (cfg->sse[s]) + { + sse = g_sses[SSE_IDX(cfg->adc, s)]; + + if (sse != NULL) + { + sse->adc = cfg->adc; + sse->num = s; + sem_init(&sse->exclsem, SEM_PROCESS_PRIVATE, 1); + sse->ena = false; + sse->cfg = true; + } + else + { + goto tiva_adc_struct_init_error; + } + } + } + + /* Initialize the public ADC device data structure */ + + adc->dev = g_devs[cfg->adc]; + if (adc->dev != NULL) + { + adc->dev->ad_ops = &g_adcops; + adc->dev->ad_priv = adc; + } + else + { + goto tiva_adc_struct_init_error; + } + goto tiva_adc_struct_init_ok; + } + else + { + goto tiva_adc_struct_init_error; + } + } + +tiva_adc_struct_init_error: + avdbg("Invalid ADC device number: expected=%d actual=%d\n", + 0, cfg->adc); + avdbg("ADC%d (CONFIG_TIVA_ADC%d) must be enabled in Kconfig first!", + cfg->adc, cfg->adc); + return NULL; + +tiva_adc_struct_init_ok: + adc->cfg = true; + return adc; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tiva_adc_initialize + * + * Description: + * Configuration and bind the ADC to the ADC lower half instance and + * register the ADC driver at 'devpath'. + * + * Input Parameters: + * devpath - The full path to the ADC device. This should be of the + * form /dev/adc0 + * cfg - ADC configuration structure, configures the whole ADC. + * clock - clock speed for all ADC's. This is only set once for the first + * call to tiva_adc_initialize, otherwise the values are ignored. + * sample_rate - maximum sample rate of any ADC. This is only set once + * for the first call to tiva_adc_initialize, otherwise the values are + * ignored. + * + ****************************************************************************/ + +int tiva_adc_initialize(const char *devpath, struct tiva_adc_cfg_s *cfg, + uint32_t clock, uint8_t sample_rate) +{ + struct tiva_adc_s *adc; + int ret = 0; + + avdbg("initializing...\n"); + + /* Initialize the private ADC device data structure */ + + adc = tiva_adc_struct_init(cfg); + if (adc == NULL) + { + adbg("Invalid ADC device number: expected=%d actual=%d\n", + 0, cfg->adc); + return -ENODEV; + } + + /* Turn on peripheral */ + + if (tiva_adc_enable(adc->devno, true) < 0) + { + adbg("ERROR: failure to power ADC peripheral (devno=%d)\n", + cfg->adc); + return ret; + } + + /* Perform actual initialization */ + + tiva_adc_one_time_init(clock, sample_rate); + tiva_adc_configure(cfg); + tiva_adc_irqinitialize(cfg); + + /* Now we are initialized */ + + adc->ena = true; + +#ifdef CONFIG_DEBUG_ANALOG + tiva_adc_runtimeobj_vals(); +#endif + + /* Ensure our lower half is valid */ + + if (adc->dev == NULL) + { + adbg("ERROR: Failed to get interface %s\n", devpath); + return -ENODEV; + } + + avdbg("adc_dev_s=0x%08x\n", adc->dev); + + /* Register the ADC driver */ + + avdbg("Register the ADC driver at %s\n", devpath); + + ret = adc_register(devpath, adc->dev); + if (ret < 0) + { + adbg("ERROR: Failed to register %s to character driver: %d\n", + devpath, ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: tiva_adc_lock + * + * Description: + * Get exclusive access to the ADC interface + * + ****************************************************************************/ + +void tiva_adc_lock(FAR struct tiva_adc_s *priv, int sse) +{ + avdbg("Locking...\n"); + + struct tiva_adc_sse_s *s = g_sses[SSE_IDX(priv->devno, sse)]; + int ret; +#ifdef CONFIG_DEBUG_ANALOG + uint16_t loop_count=0; +#endif + + do + { + ret = sem_wait(&s->exclsem); + + /* This should only fail if the wait was canceled by an signal (and the + * worker thread will receive a lot of signals). + */ + + DEBUGASSERT(ret == OK || errno == EINTR); + +#ifdef CONFIG_DEBUG_ANALOG + if (loop_count % 1000) + { + avdbg("loop=%d\n"); + } + ++loop_count; +#endif + } + while (ret < 0); +} + +/**************************************************************************** + * Name: tiva_adc_unlock + * + * Description: + * Relinquish the lock on the ADC interface + * + ****************************************************************************/ + +void tiva_adc_unlock(FAR struct tiva_adc_s *priv, int sse) +{ + avdbg("Unlocking\n"); + struct tiva_adc_sse_s *s = g_sses[SSE_IDX(priv->devno, sse)]; + sem_post(&s->exclsem); +} + +/* DEBUG ********************************************************************/ + +#ifdef CONFIG_DEBUG_ANALOG + +/**************************************************************************** + * Name: tiva_adc_runtimeobj_ptrs + * + * Description: + * Dumps the address of all run-time objects for verification. + * + ****************************************************************************/ + +static void tiva_adc_runtimeobj_ptrs(void) +{ +# ifdef CONFIG_TIVA_ADC0 + avdbg("ADC0 [struct] [global value] [array value]\n"); + avdbg(" adc_dev_s dev0=0x%08x g_devs[0]=0x%08x\n", &dev0, g_devs[0]); + avdbg(" tiva_adc_s adc0=0x%08x g_adcs[0]=0x%08x\n", &adc0, g_adcs[0]); + avdbg(" tiva_adc_sse_s sse0=0x%08x g_sses[0,0]=0x%08x\n", &sse00, g_sses[SSE_IDX(0,0)]); + avdbg(" tiva_adc_sse_s sse1=0x%08x g_sses[0,1]=0x%08x\n", &sse01, g_sses[SSE_IDX(0,1)]); + avdbg(" tiva_adc_sse_s sse2=0x%08x g_sses[0,2]=0x%08x\n", &sse02, g_sses[SSE_IDX(0,2)]); + avdbg(" tiva_adc_sse_s sse3=0x%08x g_sses[0,3]=0x%08x\n", &sse03, g_sses[SSE_IDX(0,3)]); +# endif +# ifdef CONFIG_TIVA_ADC1 + avdbg("ADC1 [struct] [global value] [array value]\n"); + avdbg(" adc_dev_s dev1=0x%08x g_devs[1]=0x%08x\n", &dev1, g_devs[1]); + avdbg(" tiva_adc_s adc1=0x%08x g_adcs[1]=0x%08x\n", &adc1, g_adcs[1]); + avdbg(" tiva_adc_sse_s sse0=0x%08x g_sses[1,0]=0x%08x\n", &sse10, g_sses[SSE_IDX(1,0)]); + avdbg(" tiva_adc_sse_s sse1=0x%08x g_sses[1,1]=0x%08x\n", &sse11, g_sses[SSE_IDX(1,1)]); + avdbg(" tiva_adc_sse_s sse2=0x%08x g_sses[1,2]=0x%08x\n", &sse12, g_sses[SSE_IDX(1,2)]); + avdbg(" tiva_adc_sse_s sse3=0x%08x g_sses[1,3]=0x%08x\n", &sse13, g_sses[SSE_IDX(1,3)]); +# endif +} + +static void tiva_adc_runtimeobj_vals(void) +{ + struct tiva_adc_sse_s *sse; + uint8_t s; +# ifdef CONFIG_TIVA_ADC0 + avdbg("ADC0 [0x%08x] cfg=%d ena=%d devno=%d\n", + &adc0, adc0.cfg, adc0.ena, adc0.devno); + for (s=0; s<4; ++s) + { + sse = g_sses[SSE_IDX(0, s)]; + avdbg("SSE%d [0x%08x] adc=%d cfg=%d ena=%d num=%d\n", + s, sse, sse->adc, sse->cfg, sse->ena, sse->num); + } +# endif +# ifdef CONFIG_TIVA_ADC1 + avdbg("ADC1 [0x%08x] cfg=%d ena=%d devno=%d\n", + &adc1, adc1.cfg, adc1.ena, adc1.devno); + for (s=0; s<4; ++s) + { + sse = g_sses[SSE_IDX(1, s)]; + avdbg("SSE%d [0x%08x] adc=%d cfg=%d ena=%d num=%d\n", + s, sse, sse->adc, sse->cfg, sse->ena, sse->num); + } +# endif +} + +/**************************************************************************** + * Name: tiva_adc_unlock + * + * Description: + * umps the device level objects for verification. + * + ****************************************************************************/ + +static void tiva_adc_dump_dev(void) +{ +# ifdef CONFIG_TIVA_ADC0 + avdbg("adc_ops_s g_adcops=0x%08x adc0.dev->ad_ops=0x%08x\n", + &g_adcops, adc0.dev->ad_ops); + avdbg("tiva_adc_s adc0=0x%08x adc0.dev->ad_priv=0x%08x\n", + &adc0, adc0.dev->ad_priv); +# endif +# ifdef CONFIG_TIVA_ADC1 + avdbg("adc_ops_s g_adcops=0x%08x adc1.dev->ad_ops=0x%08x\n", + &g_adcops, adc1.dev->ad_ops); + avdbg("tiva_adc_s adc1=0x%08x adc1.dev->ad_priv=0x%08x\n", + &adc1, adc1.dev->ad_priv); +# endif +} +#endif + +#endif /* CONFIG_TIVA_ADC && CONFIG_ADC */ |