From 9d6845b7eced385e962e7c2700556c3b20dde12a Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 26 May 2016 11:57:18 -0600 Subject: [PATCH] Add ADC bind method to the EFM32 and LPC17xx ADC drivers --- arch/arm/src/efm32/efm32_adc.c | 51 ++++++++++++++++++++++++++------ arch/arm/src/lpc17xx/lpc17_adc.c | 41 +++++++++++++++++++++++-- drivers/analog/ads1255.c | 9 +++--- 3 files changed, 86 insertions(+), 15 deletions(-) diff --git a/arch/arm/src/efm32/efm32_adc.c b/arch/arm/src/efm32/efm32_adc.c index 102384ff3d..032f92a655 100644 --- a/arch/arm/src/efm32/efm32_adc.c +++ b/arch/arm/src/efm32/efm32_adc.c @@ -2,7 +2,9 @@ * arch/arm/src/efm32/efm32_adc.c * * Copyright (C) 2014 Bouteville Pierre-Noel. All rights reserved. + * Copyright (C) 2016 Gregory Nutt. All rights reserved. * Authors: Bouteville Pierre-Noel + * Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -100,6 +102,7 @@ struct efm32_dev_s { + FAR const struct adc_callback_s *cb; uint8_t irq; /* Interrupt generated by this ADC block */ uint8_t nchannels; /* Number of channels */ uint8_t current; /* Current ADC channel being converted */ @@ -124,6 +127,8 @@ static int adc_interrupt(FAR struct adc_dev_s *dev); /* ADC Driver Methods */ +static int adc_bind(FAR struct adc_dev_s *dev, + FAR const struct adc_callback_s *callback); static void adc_reset(FAR struct adc_dev_s *dev); static int adc_setup(FAR struct adc_dev_s *dev); static void adc_shutdown(FAR struct adc_dev_s *dev); @@ -148,6 +153,7 @@ static void adc_startconv(FAR struct efm32_dev_s *priv, bool enable); static const struct adc_ops_s g_adcops = { + .ao_bind = adc_bind, .ao_reset = adc_reset, .ao_setup = adc_setup, .ao_shutdown = adc_shutdown, @@ -790,7 +796,7 @@ static void adc_startconv(struct efm32_dev_s *priv, bool enable) #endif /**************************************************************************** - * Name: adc_reset + * Name: adc_hw_reset * * Description: * Deinitializes the ADCx peripheral registers to their default @@ -873,6 +879,25 @@ static void adc_enable(FAR struct efm32_dev_s *priv, bool enable) adc_putreg(priv, EFM32_ADC_CR2_OFFSET, regval); } +/**************************************************************************** + * Name: adc_bind + * + * Description: + * Bind the upper-half driver callbacks to the lower-half implementation. This + * must be called early in order to receive ADC event notifications. + * + ****************************************************************************/ + +static int adc_bind(FAR struct adc_dev_s *dev, + FAR const struct adc_callback_s *callback) +{ + FAR struct efm32_dev_s *priv = (FAR struct efm32_dev_s *)dev->ad_priv; + + DEBUGASSERT(priv != NULL); + priv->cb = callback; + return OK; +} + /**************************************************************************** * Name: adc_reset * @@ -1180,14 +1205,21 @@ static int adc_interrupt(FAR struct adc_dev_s *dev) value = adc_getreg(priv, EFM32_ADC_DR_OFFSET); value &= ADC_DR_DATA_MASK; - /* Give the ADC data to the ADC driver. adc_receive accepts 3 parameters: - * - * 1) The first is the ADC device instance for this ADC block. - * 2) The second is the channel number for the data, and - * 3) The third is the converted data for the channel. - */ + /* Verify that the upper-half driver has bound its callback functions */ - adc_receive(dev, priv->chanlist[priv->current], value); + if (priv->cb != NULL) + { + /* Give the ADC data to the ADC driver. The ADC receive method + * accepts 3 parameters: + * + * 1) The first is the ADC device instance for this ADC block. + * 2) The second is the channel number for the data, and + * 3) The third is the converted data for the channel. + */ + + DEBUGASSERT(priv->cb->au_receive != NULL); + priv->cb->au_receive(dev, priv->chanlist[priv->current], value); + } /* Set the channel number of the next channel that will complete conversion */ @@ -1272,7 +1304,8 @@ struct adc_dev_s *efm32_adcinitialize(int intf, const uint8_t *chanlist, int nch /* Configure the selected ADC */ - priv = dev->ad_priv; + priv = dev->ad_priv; + priv->cb = NULL; DEBUGASSERT(nchannels <= ADC_MAX_SAMPLES); priv->nchannels = nchannels; diff --git a/arch/arm/src/lpc17xx/lpc17_adc.c b/arch/arm/src/lpc17xx/lpc17_adc.c index 9d761c6afa..98afd8b1ae 100644 --- a/arch/arm/src/lpc17xx/lpc17_adc.c +++ b/arch/arm/src/lpc17xx/lpc17_adc.c @@ -2,8 +2,9 @@ * arch/arm/src/lpc17xx/lpc17_adc.c * * Copyright (C) 2011 Li Zhuoyi. All rights reserved. + * Copyright (C) 2016 Gregory Nutt. All rights reserved. * Author: Li Zhuoyi - * History: 0.1 2011-08-05 initial version + * Gregory Nutt * * This file is a part of NuttX: * @@ -87,6 +88,7 @@ struct up_dev_s { + FAR const struct adc_callback_s *cb; uint8_t mask; uint32_t sps; int irq; @@ -100,6 +102,8 @@ struct up_dev_s /* ADC methods */ +static int adc_bind(FAR struct adc_dev_s *dev, + FAR const struct adc_callback_s *callback); static void adc_reset(FAR struct adc_dev_s *dev); static int adc_setup(FAR struct adc_dev_s *dev); static void adc_shutdown(FAR struct adc_dev_s *dev); @@ -113,6 +117,7 @@ static int adc_interrupt(int irq, void *context); static const struct adc_ops_s g_adcops = { + .ao_bind = adc_bind, .ao_reset = adc_reset, .ao_setup = adc_setup, .ao_shutdown = adc_shutdown, @@ -137,6 +142,25 @@ static struct adc_dev_s g_adcdev = * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: adc_bind + * + * Description: + * Bind the upper-half driver callbacks to the lower-half implementation. This + * must be called early in order to receive ADC event notifications. + * + ****************************************************************************/ + +static int adc_bind(FAR struct adc_dev_s *dev, + FAR const struct adc_callback_s *callback) +{ + FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->ad_priv; + + DEBUGASSERT(priv != NULL); + priv->cb = callback; + return OK; +} + /**************************************************************************** * Name: adc_reset * @@ -384,7 +408,19 @@ static int adc_interrupt(int irq, void *context) { value = priv->buf[ch] / priv->count[ch]; value <<= 15; - adc_receive(&g_adcdev, ch, value); + + /* Verify that the upper-half driver has bound its callback + * functions. + */ + + if (priv->cb != NULL) + { + /* Perform the data received callback */ + + DEBUGASSERT(priv->cb->au_receive != NULL); + priv->cb->au_receive(&g_adcdev, ch, value); + } + priv->buf[ch] = 0; priv->count[ch] = 0; } @@ -596,6 +632,7 @@ static int adc_interrupt(int irq, void *context) FAR struct adc_dev_s *lpc17_adcinitialize(void) { + g_adcdev.cb = NULL; return &g_adcdev; } diff --git a/drivers/analog/ads1255.c b/drivers/analog/ads1255.c index 3b69e09a0e..8fbe3921ab 100644 --- a/drivers/analog/ads1255.c +++ b/drivers/analog/ads1255.c @@ -140,11 +140,12 @@ static int adc_interrupt(int irq, void *context); static const struct adc_ops_s g_adcops = { - .ao_reset = adc_reset, /* ao_reset */ - .ao_setup = adc_setup, /* ao_setup */ + .ao_bind = adc_bind, /* ao_bind */ + .ao_reset = adc_reset, /* ao_reset */ + .ao_setup = adc_setup, /* ao_setup */ .ao_shutdown = adc_shutdown, /* ao_shutdown */ - .ao_rxint = adc_rxint, /* ao_rxint */ - .ao_ioctl = adc_ioctl /* ao_read */ + .ao_rxint = adc_rxint, /* ao_rxint */ + .ao_ioctl = adc_ioctl /* ao_read */ }; static struct ads1255_dev_s g_adcpriv =