SAMA5 ADC/Touchscreen: A little more logic

This commit is contained in:
Gregory Nutt
2013-10-01 14:40:34 -06:00
parent 183421fe07
commit afa475e948
5 changed files with 311 additions and 147 deletions
+8 -4
View File
@@ -432,12 +432,16 @@
# define ADC_TSMR_TSMODE_5WIRE (3 << ADC_TSMR_TSMODE_SHIFT) /* 5-wire Touchscreen */
#define ADC_TSMR_TSAV_SHIFT (4) /* Bit 4-5: Touchscreen Average */
#define ADC_TSMR_TSAV_MASK (3 << ADC_TSMR_TSAV_SHIFT)
# define ADC_TSMR_TSAV_ NFILTER (0 << ADC_TSMR_TSAV_SHIFT) /* No Filtering */
# define ADC_TSMR_TSAV_ 2CONV (1 << ADC_TSMR_TSAV_SHIFT) /* Average 2 ADC conversions */
# define ADC_TSMR_TSAV_ 4CONV (2 << ADC_TSMR_TSAV_SHIFT) /* Average 4 ADC conversions */
# define ADC_TSMR_TSAV_ 8CONV (3 << ADC_TSMR_TSAV_SHIFT) /* Averages 8 ADC conversions */
# define ADC_TSMR_TSAV_NFILTER (0 << ADC_TSMR_TSAV_SHIFT) /* No Filtering */
# define ADC_TSMR_TSAV_2CONV (1 << ADC_TSMR_TSAV_SHIFT) /* Average 2 ADC conversions */
# define ADC_TSMR_TSAV_4CONV (2 << ADC_TSMR_TSAV_SHIFT) /* Average 4 ADC conversions */
# define ADC_TSMR_TSAV_8CONV (3 << ADC_TSMR_TSAV_SHIFT) /* Averages 8 ADC conversions */
#define ADC_TSMR_TSFREQ_SHIFT (8) /* Bit 8-11: Touchscreen Frequency */
#define ADC_TSMR_TSFREQ_MASK (15 << ADC_TSMR_TSFREQ_SHIFT)
# define ADC_TSMR_TSFREQ_DIV1 (0 << ADC_TSMR_TSFREQ_SHIFT) /* TS freq = trigger freq */
# define ADC_TSMR_TSFREQ_DIV2 (1 << ADC_TSMR_TSFREQ_SHIFT) /* TS freq = trigger freq / 2 */
# define ADC_TSMR_TSFREQ_DIV4 (2 << ADC_TSMR_TSFREQ_SHIFT) /* TS freq = trigger freq / 4 */
# define ADC_TSMR_TSFREQ_DIV8 (3 << ADC_TSMR_TSFREQ_SHIFT) /* TS freq = trigger freq / 8 */
# define ADC_TSMR_TSFREQ(n) ((uint32_t)(n) << ADC_TSMR_TSFREQ_SHIFT)
#define ADC_TSMR_TSSCTIM_SHIFT (16) /* Bit 16-19: Touchscreen Switches Closure Time */
#define ADC_TSMR_TSSCTIM_MASK (15 << ADC_TSMR_TSSCTIM_SHIFT)
+132 -15
View File
@@ -50,6 +50,7 @@
#include <arch/board/board.h>
#include <nuttx/arch.h>
#include <nuttx/wqueue.h>
#include <nuttx/analog/adc.h>
#include "up_internal.h"
@@ -147,11 +148,13 @@ struct sam_adc_s
{
#ifdef SAMA5_ADC_HAVE_CHANNELS
struct adc_dev_s dev; /* The external via of the ADC device */
uint32_t pending; /* Pending EOC events */
#ifdef CONFIG_SAMA5_ADC_DMA
DMA_HANDLE dma; /* Handle for DMA channel */
#endif
struct work_s work; /* Supports the interrupt handling "bottom half" */
#endif
sem_t exclsem; /* Supports exclusive access to the ADC interface */
/* Debug stuff */
@@ -184,7 +187,8 @@ static int sam_adc_dmasetup(struct sam_adc_s *priv, FAR uint8_t *buffer,
/* ADC interrupt handling */
#ifdef SAMA5_ADC_HAVE_CHANNELS
static void sam_adc_endconversion(struct sam_adc_s *priv, uint32_t pending);
static void sam_tsd_bottomhalf(void *arg);
static int sam_tsd_schedule(struct sam_tsd_s *priv, uint32_t pending);
#endif
static int sam_adc_interrupt(int irq, void *context);
@@ -321,7 +325,7 @@ static void sam_adc_dmacallback(DMA_HANDLE handle, void *arg, int result)
* invalidating the data cache.
*
* Input Parameters:
* dev - An instance of the SDIO device interface
* priv - An instance of the ADC device interface
* buffer - The memory to DMA from
* buflen - The size of the DMA transfer in bytes
*
@@ -331,10 +335,9 @@ static void sam_adc_dmacallback(DMA_HANDLE handle, void *arg, int result)
****************************************************************************/
#ifdef CONFIG_SAMA5_ADC_DMA
static int sam_adc_dmasetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
static int sam_adc_dmasetup(FAR struct sam_adc_s *priv, FAR uint8_t *buffer,
size_t buflen)
{
struct sam_dev_s *priv = (struct sam_dev_s *)dev;
uint32_t paddr;
uint32_t maddr;
@@ -370,18 +373,40 @@ static int sam_adc_dmasetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
* ADC interrupt handling
****************************************************************************/
/****************************************************************************
* Name: sam_adc_endconversion
* Name: sam_tsd_bottomhalf
*
* Description:
* End of conversion interrupt handler
* This function executes on the worker thread. It is scheduled by
* sam_tsd_interrupt whenever any enabled end-of-conversion event occurs.
* All EOC interrupts are disabled when this function runs. sam_tsd_bottomhalf
* will re-enable EOC interrupts when it completes processing all pending
* EOC events.
*
* Input Parameters
* arg - The ADC private data structure cast to (void *)
*
* Returned Value:
* None
*
****************************************************************************/
static void sam_adc_endconversion(struct sam_adc_s *priv, uint32_t pending)
static void sam_tsd_bottomhalf(void *arg)
{
struct sam_tsd_s *priv = (struct sam_tsd_s *)arg;
uint32_t regval;
uint32_t pending;
int chan;
ASSERT(priv != NULL);
/* Get the set of unmasked, pending ADC interrupts */
pending = priv->pending;
/* Get exclusive access to the driver data structure */
sam_adc_lock(priv->adc);
/* Check for the end of conversion event on each channel */
for (chan = 0; chan < SAM_ADC_NCHANNELS && pending != 0; chan++)
@@ -396,8 +421,54 @@ static void sam_adc_endconversion(struct sam_adc_s *priv, uint32_t pending)
pending &= ~bit;
}
}
/* Exit, re-enabling ADC interrupts */
ignored:
/* Re-enable ADC interrupts. */
sam_adc_putreg32(priv->adc, SAM_ADC_IER, SAMA5_CHAN_ENABLE);
/* Release our lock on the ADC structure */
sem_adc_unlock(priv->adc);
}
/****************************************************************************
* Name: sam_tsd_schedule
****************************************************************************/
static int sam_tsd_schedule(struct sam_tsd_s *priv, uint32_t pending)
{
int ret;
/* Disable further touchscreen interrupts. Touchscreen interrupts will be
* re-enabled after the worker thread executes.
*/
sam_adc_putreg32(priv->adc, SAM_ADC_IDR, ADC_INT_EOCALL);
/* Save the set of pending interrupts for the bottom half (in case any
* were cleared by reading the ISR.
*/
priv->pending = pending.
/* Transfer processing to the worker thread. Since touchscreen ADC interrupts are
* disabled while the work is pending, no special action should be required
* to protected the work queue.
*/
DEBUGASSERT(priv->work.worker == NULL);
ret = work_queue(HPWORK, &priv->work, sam_tsd_bottomhalf, priv, 0);
if (ret != 0)
{
illdbg("Failed to queue work: %d\n", ret);
}
return OK;
}
#endif /* SAMA5_ADC_HAVE_CHANNELS */
/****************************************************************************
@@ -439,9 +510,16 @@ static int sam_adc_interrupt(int irq, void *context)
if ((pending & ADC_INT_EOCALL) != 0)
{
/* Let the touchscreen handle its interrupts */
/* Schedule sampling to occur by the interrupt bottom half on the
* worker thread.
*/
ret = sam_tsd_schedule(priv, pending);
if (ret < 0)
{
idbg("ERROR: sam_tsd_schedule failed: %d\n", ret);
}
sam_adc_endconversion(pending);
pending &= ~ADC_INT_EOCALL;
}
#endif
@@ -649,6 +727,10 @@ struct adc_dev_s *sam_adc_initialize(void)
sam_configpio(PIO_ADC_TRG);
#endif
/* Initialize the ADC device data structure */
sem_init(&priv->exclsem, 0, 1);
#ifdef CONFIG_SAMA5_ADC_DMA
/* Allocate a DMA channel */
@@ -669,6 +751,44 @@ struct adc_dev_s *sam_adc_initialize(void)
return &g_adcdev;
}
/****************************************************************************
* Name: sam_adc_lock
*
* Description:
* Get exclusive access to the ADC interface
*
****************************************************************************/
void sam_adc_lock(FAR struct sam_adc_s *priv)
{
int ret;
do
{
ret = sem_wait(&priv->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);
}
while (ret < 0);
}
/****************************************************************************
* Name: sam_adc_unlock
*
* Description:
* Relinquish the lock on the ADC interface
*
****************************************************************************/
void sam_adc_unlock(FAR struct sam_adc_s *priv)
{
sem_post(&priv->exclsem)
}
/****************************************************************************
* Name: sam_adc_getreg
*
@@ -678,9 +798,8 @@ struct adc_dev_s *sam_adc_initialize(void)
****************************************************************************/
#ifdef CONFIG_SAMA5_ADC_REGDEBUG
static uint32_t sam_adc_getreg(ADC_HANDLE handle, uintptr_t address)
static uint32_t sam_adc_getreg(struct sam_adc_s *priv, uintptr_t address)
{
struct sam_adc_s *priv = (struct sam_adc_s *)handle;
uint32_t regval = getreg32(address);
if (sam_adc_checkreg(priv, false, regval, address))
@@ -701,10 +820,8 @@ static uint32_t sam_adc_getreg(ADC_HANDLE handle, uintptr_t address)
****************************************************************************/
#ifdef CONFIG_SAMA5_ADC_REGDEBUG
void sam_adc_putreg(ADC_HANDLE handle, uintptr_t address, uint32_t regval)
void sam_adc_putreg(struct sam_adc_s *priv, uintptr_t address, uint32_t regval)
{
struct sam_adc_s *priv = (struct sam_adc_s *)handle;
if (sam_adc_checkreg(priv, true, regval, address))
{
lldbg("%08x<-%08x\n", address, regval);
+31 -6
View File
@@ -50,6 +50,10 @@
****************************************************************************/
/* Configuration ************************************************************/
#ifndef CONFIG_SCHED_WORKQUEUE
# error Work queue support is required (CONFIG_SCHED_WORKQUEUE)
#endif
#ifndef CONFIG_DEBUG
# undef CONFIG_SAMA5_ADC_REGDEBUG
#endif
@@ -116,22 +120,43 @@ extern "C"
*
****************************************************************************/
FAR struct adc_dev_s *sam_adcinitialize(void);
struct sam_adc_s;
FAR struct sam_adc_s *sam_adcinitialize(void);
/****************************************************************************
* Interfaces exported from the ADC to the touchscreen driver
****************************************************************************/
/****************************************************************************
* Name: sam_adc_lock
*
* Description:
* Get exclusive access to the ADC interface
*
****************************************************************************/
void sam_adc_lock(FAR struct sam_adc_s *priv);
/****************************************************************************
* Name: sam_adc_unlock
*
* Description:
* Relinquish the lock on the ADC interface
*
****************************************************************************/
void sam_adc_unlock(FAR struct sam_adc_s *priv);
/****************************************************************************
* Name: sam_adc_getreg
*
* Description:
* Read any 32-bit register using an absolute address.
* Read any 32-bit register using an absolute address.
*
****************************************************************************/
#ifdef CONFIG_SAMA5_ADC_REGDEBUG
uint32_t sam_adc_getreg(FAR struct adc_dev_s *, uintptr_t address)
uint32_t sam_adc_getreg(FAR struct sam_adc_s *priv, uintptr_t address);
#else
# define sam_adc_getreg(handle,addr) getreg32(addr)
#endif
@@ -140,13 +165,13 @@ uint32_t sam_adc_getreg(FAR struct adc_dev_s *, uintptr_t address)
* Name: sam_adc_putreg
*
* Description:
* Write to any 32-bit register using an absolute address.
* Write to any 32-bit register using an absolute address.
*
****************************************************************************/
#ifdef CONFIG_SAMA5_ADC_REGDEBUG
void sam_adc_putreg(FAR struct adc_dev_s *dev, uintptr_t address,
uint32_t regval)
void sam_adc_putreg(FAR struct sam_adc_s *priv, uintptr_t address,
uint32_t regval);
#else
# define sam_adc_putreg(handle,addr,val) putreg32(val,addr)
#endif
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -88,7 +88,8 @@ extern "C"
*
****************************************************************************/
int sam_tsd_register(FAR struct adc_dev_s *dev, int minor);
struct sam_adc_s;
int sam_tsd_register(FAR struct sam_adc_s *adc, int minor);
/****************************************************************************
* Interfaces exported from the touchscreen to the ADC driver