Progress on STM32 ADC driver
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4173 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
44298ea306
commit
d601f00c92
@ -2,7 +2,8 @@
|
||||
* arch/arm/src/stm32/stm32_adc.c
|
||||
*
|
||||
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
||||
* Author: Li Zhuoyi <gnutt@nuttx.org>
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
* Diego Sanchez <dsanchez@nx-engineering.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -32,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
@ -80,22 +81,57 @@
|
||||
|
||||
#if defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2) || defined(CONFIG_STM32_ADC3)
|
||||
|
||||
/* ADC interrupts */
|
||||
|
||||
#ifdef CONFIG_STM32_STM32F10XX
|
||||
# define ADC_SR_ALLINTS (ADC_SR_AWD | ADC_SR_EOC | ADC_SR_JEOC)
|
||||
#else
|
||||
# define ADC_SR_ALLINTS (ADC_SR_AWD | ADC_SR_EOC | ADC_SR_JEOC | ADC_SR_OVR)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_STM32_STM32F10XX
|
||||
# define ADC_CR1_ALLINTS (ADC_CR1_AWDIE | ADC_CR1_EOCIE | ADC_CR1_JEOCIE)
|
||||
#else
|
||||
# define ADC_CR1_ALLINTS (ADC_CR1_AWDIE | ADC_CR1_EOCIE | ADC_CR1_JEOCIE | ADC_CR1_OVRIE)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This structure describes the state of one ADC block */
|
||||
|
||||
struct stm32_dev_s
|
||||
{
|
||||
int irq;
|
||||
# warning "Missing logic"
|
||||
int irq; /* Interrupt generated by this ADC block */
|
||||
xcpt_t isr; /* Interrupt handler for this ADC block */
|
||||
uint32_t base; /* Base address of registers unique to this ADC block */
|
||||
|
||||
int32_t buf[8];
|
||||
uint8_t count[8];
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* ADC Register access */
|
||||
|
||||
static uint32_t adc_getreg(struct stm32_dev_s *priv, int offset);
|
||||
static void adc_putreg(struct stm32_dev_s *priv, int offset, uint32_t value);
|
||||
|
||||
/* ADC Interrupt Handler */
|
||||
|
||||
static int adc_interrupt(int irq, void *context);
|
||||
static void adc_interrupt(FAR struct stm32_dev_s *priv);
|
||||
#if defined(CONFIG_STM32_STM32F10XX) && (defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2))
|
||||
static int adc12_interrupt(int irq, void *context)
|
||||
#endif
|
||||
#ifdef CONFIG_STM32_STM32F10XX && defined (CONFIG_STM32_ADC3)
|
||||
static int adc3_interrupt(int irq, void *context)
|
||||
#endif
|
||||
#ifdef CONFIG_STM32_STM32F40XX
|
||||
static int adc123_interrupt(int irq, void *context)
|
||||
#endif
|
||||
|
||||
/* ADC Driver Methods */
|
||||
|
||||
@ -104,7 +140,6 @@ static int adc_setup(FAR struct adc_dev_s *dev);
|
||||
static void adc_shutdown(FAR struct adc_dev_s *dev);
|
||||
static void adc_rxint(FAR struct adc_dev_s *dev, bool enable);
|
||||
static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg);
|
||||
static int adc_interrupt(int irq, void *context);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
@ -123,17 +158,19 @@ static const struct adc_ops_s g_adcops =
|
||||
static struct stm32_dev_s g_adcpriv1 =
|
||||
{
|
||||
#ifdef CONFIG_STM32_STM32F10XX
|
||||
.irq = STM32_IRQ_ADC12;
|
||||
.irq = STM32_IRQ_ADC12,
|
||||
.isr = adc12_interrupt,
|
||||
#else
|
||||
.irq = STM32_IRQ_ADC;
|
||||
.irq = STM32_IRQ_ADC,
|
||||
.isr = adc123_interrupt,
|
||||
#endif
|
||||
# warning "Missing logic"
|
||||
.base = STM32_ADC1_BASE,
|
||||
};
|
||||
|
||||
static struct adc_dev_s g_adcdev1 =
|
||||
{
|
||||
.ad_ops = &g_adcops,
|
||||
.ad_priv= &g_adcpriv1
|
||||
.ad_priv= &g_adcpriv1,
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -141,17 +178,19 @@ static struct adc_dev_s g_adcdev1 =
|
||||
static struct stm32_dev_s g_adcpriv2 =
|
||||
{
|
||||
#ifdef CONFIG_STM32_STM32F10XX
|
||||
.irq = STM32_IRQ_ADC12;
|
||||
.irq = STM32_IRQ_ADC12,
|
||||
.isr = adc12_interrupt,
|
||||
#else
|
||||
.irq = STM32_IRQ_ADC;
|
||||
.irq = STM32_IRQ_ADC,
|
||||
.isr = adc123_interrupt,
|
||||
#endif
|
||||
# warning "Missing logic"
|
||||
.base = STM32_ADC2_BASE,
|
||||
};
|
||||
|
||||
static struct adc_dev_s g_adcdev2 =
|
||||
{
|
||||
.ad_ops = &g_adcops
|
||||
.ad_priv= &g_adcpriv2
|
||||
.ad_ops = &g_adcops,
|
||||
.ad_priv= &g_adcpriv2,
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -160,17 +199,19 @@ static struct adc_dev_s g_adcdev2 =
|
||||
static struct stm32_dev_s g_adcpriv3 =
|
||||
{
|
||||
#ifdef CONFIG_STM32_STM32F10XX
|
||||
.irq = STM32_IRQ_ADC3;
|
||||
.irq = STM32_IRQ_ADC3,
|
||||
.isr = adc3_interrupt,
|
||||
#else
|
||||
.irq = STM32_IRQ_ADC;
|
||||
.irq = STM32_IRQ_ADC,
|
||||
.isr = adc123_interrupt,
|
||||
#endif
|
||||
# warning "Missing logic"
|
||||
.base = STM32_ADC3_BASE,
|
||||
};
|
||||
|
||||
static struct adc_dev_s g_adcdev3 =
|
||||
{
|
||||
.ad_ops = &g_adcops,
|
||||
.ad_priv= &g_adcpriv3
|
||||
.ad_priv= &g_adcpriv3,
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -180,28 +221,41 @@ static struct adc_dev_s g_adcdev3 =
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: adc_interrupt
|
||||
* Name: adc_getreg
|
||||
*
|
||||
* Description:
|
||||
* ADC interrupt handler.
|
||||
* Read the value of an ADC register.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - A reference to the ADC block status
|
||||
* offset - The offset to the register to read
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int adc_interrupt(int irq, void *context)
|
||||
static uint32_t adc_getreg(struct stm32_dev_s *priv, int offset)
|
||||
{
|
||||
FAR struct stm32_dev_s *priv;
|
||||
uint32_t regval;
|
||||
return getreg32(priv->base + offset);
|
||||
}
|
||||
|
||||
/* Determine which ADC caused the interrupt */
|
||||
# warning "Missing logic"
|
||||
/****************************************************************************
|
||||
* Name: adc_getreg
|
||||
*
|
||||
* Description:
|
||||
* Read the value of an ADC register.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - A reference to the ADC block status
|
||||
* offset - The offset to the register to read
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Handle the ADC interrupt */
|
||||
# warning "Missing logic"
|
||||
return OK;
|
||||
static void adc_putreg(struct stm32_dev_s *priv, int offset, uint32_t value)
|
||||
{
|
||||
putreg32(value, priv->base + offst);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -225,7 +279,52 @@ static void adc_reset(FAR struct adc_dev_s *dev)
|
||||
|
||||
flags = irqsave();
|
||||
|
||||
# warning "Missing logic"
|
||||
/* Initialize the ADC data structures */
|
||||
|
||||
/* ADC1 CR Configuration */
|
||||
|
||||
regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET);
|
||||
regval &= ~ADC_CR1_DUALMOD_MASK;
|
||||
regval &= ~ADC_CR1_SCAN; /* Clear DUALMODE and SCAN bits */
|
||||
adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval);
|
||||
|
||||
/* Initialize the ADC_Mode (ADC_Mode_Independent) */
|
||||
|
||||
regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET);
|
||||
regval |= ADC_CR1_IND;
|
||||
|
||||
/* Initialize the ADC_CR1_SCAN member DISABLE */
|
||||
|
||||
regval &= ~ADC_CR1_SCAN;
|
||||
adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval);
|
||||
|
||||
/* ADC1 CR2 Configuration */
|
||||
/* Clear CONT, ALIGN and EXTTRIG bits */
|
||||
|
||||
regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET);
|
||||
regval &= ~ADC_CR2_CONT;
|
||||
regval &= ~ADC_CR2_ALIGN;
|
||||
regval &= ~ADC_CR2_EXTSEL_MASK;
|
||||
adc_putreg(priv, STM32_ADC_CR2_OFFSET, regval);
|
||||
|
||||
/* Set CONT, ALIGN and EXTTRIG bits */
|
||||
/* Initialize the ALIGN: Data alignment Right */
|
||||
|
||||
regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET);
|
||||
regval &= ~ADC_CR2_ALIGN;
|
||||
|
||||
/* Initialize the External event select "Timer CC1 event" */
|
||||
regval &= ~ADC_CR2_EXTSEL_MASK;
|
||||
|
||||
/* Initialize the ADC_ContinuousConvMode "Single conversion mode" */
|
||||
regval &= ~ADC_CR2_CONT;
|
||||
adc_putreg(priv, STM32_ADC_CR2_OFFSET, regval);
|
||||
|
||||
/* ADC1 SQR1 Configuration */
|
||||
|
||||
regval = adc_getreg(priv, STM32_ADC_SQR1_OFFSET);
|
||||
regval &= ~ADC_SQR1_L_MASK; /* L = 0000: 1 conversion */
|
||||
adc_putreg(priv, STM32_ADC_SQR_OFFSET1, regval);
|
||||
|
||||
irqrestore(flags);
|
||||
}
|
||||
@ -249,15 +348,19 @@ static int adc_setup(FAR struct adc_dev_s *dev)
|
||||
{
|
||||
FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv;
|
||||
int ret;
|
||||
|
||||
uint32_t regval = 0;
|
||||
int i;
|
||||
/* Attach the ADC interrupt */
|
||||
|
||||
ret = irq_attach(priv->irq, adc_interrupt);
|
||||
ret = irq_attach(priv->irq, priv->isr);
|
||||
if (ret == OK)
|
||||
{
|
||||
/* Initialize the ADC data structures */
|
||||
#warning "Missing logic"
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
priv->buf[i]=0;
|
||||
priv->count[i]=0;
|
||||
}
|
||||
|
||||
/* Enable the ADC interrupt */
|
||||
|
||||
up_enable_irq(priv->irq);
|
||||
@ -288,7 +391,6 @@ static void adc_shutdown(FAR struct adc_dev_s *dev)
|
||||
irq_detach(priv->irq);
|
||||
|
||||
/* Disable and reset the ADC module */
|
||||
#warning "Missing logic"
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -306,15 +408,22 @@ static void adc_shutdown(FAR struct adc_dev_s *dev)
|
||||
static void adc_rxint(FAR struct adc_dev_s *dev, bool enable)
|
||||
{
|
||||
FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv;
|
||||
uint32_t regval;
|
||||
|
||||
uint32_t adc_getreg(priv, STM32_ADC_CR1_OFFSET);
|
||||
if (enable)
|
||||
{
|
||||
#warning "Missing logic"
|
||||
/* Enable the end-of-conversion ADC interrupt */
|
||||
|
||||
regval |= ADC_CR1_EOCIE;
|
||||
}
|
||||
else
|
||||
{
|
||||
#warning "Missing logic"
|
||||
/* Enable all ADC interrupts */
|
||||
|
||||
regval &= ~ADC_CR1_ALLINTS;
|
||||
}
|
||||
adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -334,6 +443,178 @@ static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg)
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: adc_interrupt
|
||||
*
|
||||
* Description:
|
||||
* Common ADC interrupt handler.
|
||||
*
|
||||
* Input Parameters:
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void adc_interrupt(FAR struct stm32_dev_s *priv)
|
||||
{
|
||||
uint32_t regval;
|
||||
unsigned char ch; /* channel */
|
||||
int32_t value;
|
||||
|
||||
regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET);
|
||||
regval &= ADC_CR1_AWDCH_MASK;
|
||||
ch = regval;
|
||||
|
||||
/* Handle the ADC interrupt */
|
||||
|
||||
# warning "still missing logic, value computation"
|
||||
adc_receive(priv, ch, value);
|
||||
priv->buf[ch] = 0;
|
||||
priv->count[ch] = 0;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: adc12_interrupt
|
||||
*
|
||||
* Description:
|
||||
* ADC12 interrupt handler for the STM32 F1 family.
|
||||
*
|
||||
* Input Parameters:
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_STM32_STM32F10XX) && (defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2))
|
||||
static int adc12_interrupt(int irq, void *context)
|
||||
{
|
||||
uint32_regval;
|
||||
uint32_t pending;
|
||||
|
||||
/* Check for pending ADC1 interrupts */
|
||||
|
||||
#ifdef CONFIG_STM32_ADC1
|
||||
regval = getreg32(priv, STM32_ADC1_SR);
|
||||
pending = regval & ADC_SR_ALLINTS;
|
||||
if (pending != 0)
|
||||
{
|
||||
adc_interrupt(&g_adcpriv1);
|
||||
regval &= ~pending;
|
||||
putreg32(regval, STM32_ADC1_SR);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check for pending ADC2 interrupts */
|
||||
|
||||
#ifdef CONFIG_STM32_ADC2
|
||||
regval = getreg32(priv, STM32_ADC2_SR);
|
||||
pending = regval & ADC_SR_ALLINTS;
|
||||
if (pending != 0)
|
||||
{
|
||||
adc_interrupt(&g_adcpriv2);
|
||||
regval &= ~pending;
|
||||
putreg32(regval, STM32_ADC2_SR);
|
||||
}
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: adc3_interrupt
|
||||
*
|
||||
* Description:
|
||||
* ADC1/2 interrupt handler for the STM32 F1 family.
|
||||
*
|
||||
* Input Parameters:
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_STM32_STM32F10XX && defined (CONFIG_STM32_ADC3)
|
||||
static int adc3_interrupt(int irq, void *context)
|
||||
{
|
||||
uint32_t regval;
|
||||
uint32_t pending;
|
||||
|
||||
/* Check for pending ADC3 interrupts */
|
||||
|
||||
regval = getreg32(priv, STM32_ADC3_SR);
|
||||
pending = regval & ADC_SR_ALLINTS;
|
||||
if (pending != 0)
|
||||
{
|
||||
adc_interrupt(&g_adcpriv3);
|
||||
regval &= ~pending;
|
||||
putreg32(regval, STM32_ADC3_SR);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: adc123_interrupt
|
||||
*
|
||||
* Description:
|
||||
* ADC1/2/3 interrupt handler for the STM32 F4 family.
|
||||
*
|
||||
* Input Parameters:
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_STM32_STM32F40XX
|
||||
static int adc123_interrupt(int irq, void *context)
|
||||
{
|
||||
uint32_t regval;
|
||||
uint32_t pending;
|
||||
|
||||
/* Check for pending ADC1 interrupts */
|
||||
|
||||
#ifdef CONFIG_STM32_ADC1
|
||||
regval = getreg32(priv, STM32_ADC1_SR);
|
||||
pending = regval & ADC_SR_ALLINTS;
|
||||
if (pending != 0)
|
||||
{
|
||||
adc_interrupt(&g_adcpriv1);
|
||||
regval &= ~pending;
|
||||
putreg32(regval, STM32_ADC1_SR);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check for pending ADC2 interrupts */
|
||||
|
||||
#ifdef CONFIG_STM32_ADC2
|
||||
regval = getreg32(priv, STM32_ADC2_SR);
|
||||
pending = regval & ADC_SR_ALLINTS;
|
||||
if (pending != 0)
|
||||
{
|
||||
adc_interrupt(&g_adcpriv2);
|
||||
regval &= ~pending;
|
||||
putreg32(regval, STM32_ADC2_SR);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check for pending ADC3 interrupts */
|
||||
|
||||
#ifdef CONFIG_STM32_ADC3
|
||||
regval = getreg32(priv, STM32_ADC3_SR);
|
||||
pending = regval & ADC_SR_ALLINTS;
|
||||
if (pending != 0)
|
||||
{
|
||||
adc_interrupt(&g_adcpriv2);
|
||||
regval &= ~pending;
|
||||
putreg32(regval, STM32_ADC3_SR);
|
||||
}
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -351,6 +632,9 @@ static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg)
|
||||
|
||||
struct adc_dev_s *up_adcinitialize(int intf)
|
||||
{
|
||||
# warning "Question: How do you plan to handle the ADC channels? Can we do"
|
||||
# " 16 or 18 individual channels? or one group?"
|
||||
|
||||
#ifdef CONFIG_STM32_ADC1
|
||||
if (intf == 1)
|
||||
{
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Copyright (C) 2011 Li Zhuoyi. All rights reserved.
|
||||
* Author: Li Zhuoyi <lzyy.cn@gmail.com>
|
||||
* History: 0.1 2011-08-04 initial version
|
||||
* 0.2 remove ao_read
|
||||
* 0.2 remove ao_read
|
||||
*
|
||||
* Derived from include/nuttx/can.h
|
||||
* Copyright (C) 2008, 2009 Gregory Nutt. All rights reserved.
|
||||
@ -138,13 +138,13 @@ struct adc_ops_s
|
||||
|
||||
struct adc_dev_s
|
||||
{
|
||||
uint8_t ad_ocount; /* The number of times the device has been opened */
|
||||
uint8_t ad_nrxwaiters; /* Number of threads waiting to enqueue a message */
|
||||
sem_t ad_closesem; /* Locks out new opens while close is in progress */
|
||||
sem_t ad_recvsem; /* Used to wakeup user waiting for space in ad_recv.buffer */
|
||||
struct adc_fifo_s ad_recv; /* Describes receive FIFO */
|
||||
uint8_t ad_ocount; /* The number of times the device has been opened */
|
||||
uint8_t ad_nrxwaiters; /* Number of threads waiting to enqueue a message */
|
||||
sem_t ad_closesem; /* Locks out new opens while close is in progress */
|
||||
sem_t ad_recvsem; /* Used to wakeup user waiting for space in ad_recv.buffer */
|
||||
struct adc_fifo_s ad_recv; /* Describes receive FIFO */
|
||||
const struct adc_ops_s *ad_ops; /* Arch-specific operations */
|
||||
void *ad_priv; /* Used by the arch-specific logic */
|
||||
void *ad_priv; /* Used by the arch-specific logic */
|
||||
};
|
||||
|
||||
/************************************************************************************
|
||||
|
Loading…
Reference in New Issue
Block a user