You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/05/22 15:10:12 UTC
[incubator-nuttx] branch master updated: arm/tlsr82: optimize the adc driver.
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 200109fd28 arm/tlsr82: optimize the adc driver.
200109fd28 is described below
commit 200109fd2869cfbbe558f9b7f8571e5c32ee8db4
Author: wangbowen6 <wa...@xiaomi.com>
AuthorDate: Wed May 18 22:53:27 2022 +0800
arm/tlsr82: optimize the adc driver.
1. Add vbat mode for chip internal voltage sample;
2. Add adc channel config;
3. Using DFIFO2 to get the sample value, follow telink sdk.
4. Add calibration function and config;
Signed-off-by: wangbowen6 <wa...@xiaomi.com>
---
arch/arm/src/tlsr82/Kconfig | 44 ++
arch/arm/src/tlsr82/hardware/tlsr82_adc.h | 40 ++
arch/arm/src/tlsr82/hardware/tlsr82_dfifo.h | 83 +++
arch/arm/src/tlsr82/tlsr82_adc.c | 622 +++++++++++++++------
arch/arm/src/tlsr82/tlsr82_adc.h | 16 +
arch/arm/src/tlsr82/tlsr82_timer.h | 14 +
.../tlsr82/tlsr8278adk80d/src/tlsr8278_bringup.c | 39 +-
7 files changed, 681 insertions(+), 177 deletions(-)
diff --git a/arch/arm/src/tlsr82/Kconfig b/arch/arm/src/tlsr82/Kconfig
index fb740c18f2..1adae2580f 100644
--- a/arch/arm/src/tlsr82/Kconfig
+++ b/arch/arm/src/tlsr82/Kconfig
@@ -314,6 +314,50 @@ menuconfig TLSR82_ADC
bool "ADC Configuration"
default n
+if TLSR82_ADC
+
+config TLSR82_ADC_CALI
+ bool "TLSR82 Adc calibration enable"
+ default n
+ ---help---
+ When enable the adc calibration, adc driver will read the calibration
+ parameters stored in the falsh during initialization and use these
+ parameters to calibrate the sample value.
+
+config TLSR82_ADC_CALI_PARA_ADDR
+ hex
+ default 0x3fff8 if TLSR82_ADC_CALI
+ ---help---
+ This is the adc calibration parameters address, this address must be
+ equal to the address defined in production tools.
+
+config TLSR82_ADC_CHAN0
+ bool "TLSR82 Adc channel 0 enable"
+ default n
+
+config TLSR82_ADC_CHAN1
+ bool "TLSR82 Adc channel 1 enable"
+ default n
+
+config TLSR82_ADC_CHAN2
+ bool "TLSR82 Adc channel 2 enable"
+ default n
+
+config TLSR82_ADC_VBAT
+ bool "TLSR82 Adc channel Vbat enable"
+ default n
+
+config TLSR82_ADC_FILT_NUM
+ int "TLSR82 Adc filter average number"
+ default 4
+ ---help---
+ This number determines the average number during sampling, driver will
+ remove max and min sample values and calculate the average of the
+ remaining values as the last sample value.
+ Note: This number must be multiple of 4.
+
+endif
+
menuconfig TLSR82_LPCOMP
bool "LPCOMP Configuration"
default n
diff --git a/arch/arm/src/tlsr82/hardware/tlsr82_adc.h b/arch/arm/src/tlsr82/hardware/tlsr82_adc.h
index c384916fda..950e3c1ad9 100644
--- a/arch/arm/src/tlsr82/hardware/tlsr82_adc.h
+++ b/arch/arm/src/tlsr82/hardware/tlsr82_adc.h
@@ -62,6 +62,46 @@
#define ADC_VREF_1P2V (0x2 << ADC_VREF_SHIFT)
#define ADC_VREF_RSVD2 (0x3 << ADC_VREF_SHIFT)
+/* ADC analog input positive and negative channel definition */
+
+#define ADC_CHAN_POS_SHIFT 4
+#define ADC_CHAN_POS_MASK (0xf << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_NOINPUT (0 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B0 (1 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B1 (2 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B2 (3 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B3 (4 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B4 (5 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B5 (6 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B6 (7 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_B7 (8 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_C4 (9 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_C5 (10 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_PGA0 (11 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_PGA1 (12 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_TEMSENSOR (13 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_TEMSENSOR_EE (14 << ADC_CHAN_POS_SHIFT)
+#define ADC_CHAN_POS_VBAT (15 << ADC_CHAN_POS_SHIFT)
+
+#define ADC_CHAN_NEG_SHIFT 0
+#define ADC_CHAN_NEG_MASK (0xf << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_NOINPUT (0 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B0 (1 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B1 (2 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B2 (3 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B3 (4 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B4 (5 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B5 (6 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B6 (7 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_B7 (8 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_C4 (9 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_C5 (10 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_PGA0 (11 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_PGA1 (12 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_TEMSENSOR (13 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_TEMSENSOR_EE (14 << ADC_CHAN_NEG_SHIFT)
+#define ADC_CHAN_NEG_GND (15 << ADC_CHAN_NEG_SHIFT)
+
/* ADC Mode, Resolution definition */
#define ADC_MODE_RES_SHIFT 0
diff --git a/arch/arm/src/tlsr82/hardware/tlsr82_dfifo.h b/arch/arm/src/tlsr82/hardware/tlsr82_dfifo.h
new file mode 100644
index 0000000000..df78568c3b
--- /dev/null
+++ b/arch/arm/src/tlsr82/hardware/tlsr82_dfifo.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+ * arch/arm/src/tlsr82/hardware/tlsr82_dfifo.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_TLSR82_HARDWARE_TLSR82_DFIFO_H
+#define __ARCH_ARM_SRC_TLSR82_HARDWARE_TLSR82_DFIFO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <arch/tlsr82/chip.h>
+
+#include "hardware/tlsr82_register.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* DFIFO = DMA FIFO */
+
+/* DFIFO0 ~ DFIFO2 address and size register definition */
+
+#define DFIFO0_ADDR_REG REG_ADDR16(0xb00)
+#define DFIFO0_SIZE_REG REG_ADDR8(0xb02)
+#define DFIFO0_ADDRHI_REG REG_ADDR8(0xb03)
+
+#define DFIFO1_ADDR_REG REG_ADDR16(0xb04)
+#define DFIFO1_SIZE_REG REG_ADDR8(0xb06)
+#define DFIFO1_ADDRHI_REG REG_ADDR8(0xb07)
+
+#define DFIFO2_ADDR_REG REG_ADDR16(0xb08)
+#define DFIFO2_SIZE_REG REG_ADDR8(0xb0a)
+#define DFIFO2_ADDRHI_REG REG_ADDR8(0xb0b)
+
+#define DFIFO_ADC_ADDR_REG DFIFO2_ADDR_REG
+#define DFIFO_ADC_SIZE_REG DFIFO2_SIZE_REG
+#define DFIFO_ADC_ADDRHI_REG DFIFO0_ADDRHI_REG
+
+/* DFIFO mode register definition */
+
+#define DFIFO_MODE_REG REG_ADDR8(0xb10)
+
+/* DFIFO read and write buffer register definition */
+
+#define DFIFO0_RPTR_REG REG_ADDR16(0xb14)
+#define DFIFO0_WPTR_REG REG_ADDR16(0xb16)
+
+#define DFIFO1_RPTR_REG REG_ADDR16(0xb18)
+#define DFIFO1_WPTR_REG REG_ADDR16(0xb1a)
+
+#define DFIFO2_RPTR_REG REG_ADDR16(0xb1c)
+#define DFIFO2_WPTR_REG REG_ADDR16(0xb1e)
+
+/* DFIFO mode bit definition */
+
+#define DFIFO_MODE_DFIFO0_IN BIT(0)
+#define DFIFO_MODE_DFIFO1_IN BIT(1)
+#define DFIFO_MODE_DFIFO2_IN BIT(2)
+#define DFIFO_MODE_DFIFO0_OUT BIT(3)
+#define DFIFO_MODE_DFIFO0_L_INT BIT(4)
+#define DFIFO_MODE_DFIFO0_H_INT BIT(5)
+#define DFIFO_MODE_DFIFO1_H_INT BIT(6)
+#define DFIFO_MODE_DFIFO2_H_INT BIT(7)
+
+#endif /* __ARCH_ARM_SRC_TLSR82_HARDWARE_TLSR82_DFIFO_H */
diff --git a/arch/arm/src/tlsr82/tlsr82_adc.c b/arch/arm/src/tlsr82/tlsr82_adc.c
index 9a43a21a1f..229e97fdf6 100644
--- a/arch/arm/src/tlsr82/tlsr82_adc.c
+++ b/arch/arm/src/tlsr82/tlsr82_adc.c
@@ -37,6 +37,9 @@
#include "tlsr82_adc.h"
#include "tlsr82_gpio.h"
#include "tlsr82_analog.h"
+#include "tlsr82_flash.h"
+#include "tlsr82_timer.h"
+#include "hardware/tlsr82_dfifo.h"
/****************************************************************************
* Pre-processor Definitions
@@ -52,6 +55,23 @@
# define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
+/* Default reference voltage 1175 mV */
+
+#define ADC_DEFAULT_VREF 1175
+
+#define ADC_FILT_NUM CONFIG_TLSR82_ADC_FILT_NUM
+
+#if (ADC_FILT_NUM & 0x3) != 0
+# error "The filter number must be multiple of 4 !"
+#endif
+
+/* ADC Channel type definition */
+
+#define ADC_CHAN_TYPE_NONE 0
+#define ADC_CHAN_TYPE_BASE 1
+#define ADC_CHAN_TYPE_VBAT 2
+#define ADC_CHAN_TYPE_TEMP 3
+
/****************************************************************************
* Private Types
****************************************************************************/
@@ -60,22 +80,26 @@
struct adc_info_s
{
- uint32_t vref; /* The reference voltage (mV) */
- bool calied; /* Calibration finished or not */
- bool registered; /* Have registered a adc device */
- bool configed; /* Adc has been configured or not */
- const bool cali; /* Calibration enable/disable, default enable */
+ uint32_t base_vref; /* The reference voltage (mV) or gain for base/gpio mode */
+ int base_off; /* The offset for base/gpio mode two-point calibration */
+ uint32_t vbat_vref; /* The reference voltage (mV) for vbat mode */
+ bool base_two; /* Base/Gpio mode two-point calibration or not */
+ bool registered; /* Have registered a adc device */
+ bool configed; /* Adc has been configured or not */
+ uint8_t channel; /* Adc current channel */
+ uint8_t channeltype; /* Adc current channel type */
};
/* ADC Private Data */
struct adc_chan_s
{
- uint32_t ref; /* Reference count */
- struct adc_info_s *info; /* Adc information */
- const uint8_t channel; /* Channel number */
- const uint32_t pinset; /* GPIO pin number */
- const struct adc_callback_s *cb; /* Upper driver callback */
+ uint32_t ref; /* Reference count */
+ struct adc_info_s *info; /* Adc information */
+ const uint8_t channeltype; /* Channel number */
+ const uint8_t channel; /* Channel number */
+ const uint32_t pinset; /* GPIO pin number */
+ const struct adc_callback_s *cb; /* Upper driver callback */
};
/****************************************************************************
@@ -85,8 +109,7 @@ struct adc_chan_s
static void tlsr82_adc_reset(void);
static void tlsr82_adc_power_ctrl(bool enable);
static void tlsr82_adc_clk_ctrl(bool enable);
-static void tlsr82_adc_set_sampleclk(uint32_t clk);
-static void tlsr82_adc_config(uint32_t cfg);
+static void tlsr82_adc_config(struct adc_chan_s *priv);
static void tlsr82_adc_pin_config(uint32_t pinset);
static void tlsr82_adc_chan_config(uint32_t pinset);
@@ -104,14 +127,18 @@ static void adc_read_work(struct adc_dev_s *dev);
* Private Data
****************************************************************************/
-/* ADC information */
+/* ADC module information */
-static struct adc_info_s g_adc_chan0_info =
+static struct adc_info_s g_adc_module0_info =
{
- .vref = 1175, /* Default reference voltage is 1175mV (1.2V) */
- .registered = false,
- .configed = false,
- .cali = true, /* Default calibration switch is enable */
+ .base_vref = ADC_DEFAULT_VREF,
+ .base_off = 0,
+ .vbat_vref = ADC_DEFAULT_VREF,
+ .base_two = false,
+ .registered = false,
+ .configed = false,
+ .channel = ADC_CHAN_NONE,
+ .channeltype = ADC_CHAN_TYPE_NONE,
};
/* ADC interface operations */
@@ -126,21 +153,151 @@ static const struct adc_ops_s g_adcops =
.ao_ioctl = adc_ioctl,
};
+/* ADC normal channel, for gpio sample */
+
+#ifdef CONFIG_TLSR82_ADC_CHAN0
static struct adc_chan_s g_adc_chan0 =
{
- .info = &g_adc_chan0_info,
- .channel = 0,
- .pinset = GPIO_PIN_PB2,
+ .info = &g_adc_module0_info,
+ .channeltype = ADC_CHAN_TYPE_BASE,
+ .channel = ADC_CHAN_0,
+ .pinset = GPIO_PIN_PB2,
};
static struct adc_dev_s g_adc_chan0_dev =
{
- .ad_ops = &g_adcops,
- .ad_priv = &g_adc_chan0,
+ .ad_ops = &g_adcops,
+ .ad_priv = &g_adc_chan0,
+};
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_CHAN1
+static struct adc_chan_s g_adc_chan1 =
+{
+ .info = &g_adc_module0_info,
+ .channeltype = ADC_CHAN_TYPE_BASE,
+ .channel = ADC_CHAN_1,
+ .pinset = GPIO_PIN_PB3,
+};
+
+static struct adc_dev_s g_adc_chan1_dev =
+{
+ .ad_ops = &g_adcops,
+ .ad_priv = &g_adc_chan1,
+};
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_CHAN2
+static struct adc_chan_s g_adc_chan2 =
+{
+ .info = &g_adc_module0_info,
+ .channeltype = ADC_CHAN_TYPE_BASE,
+ .channel = ADC_CHAN_2,
+ .pinset = GPIO_PIN_PB5,
+};
+
+static struct adc_dev_s g_adc_chan2_dev =
+{
+ .ad_ops = &g_adcops,
+ .ad_priv = &g_adc_chan2,
};
+#endif
+
+/* ADC Bat channel, for chip battery sample */
+
+#ifdef CONFIG_TLSR82_ADC_VBAT
+static struct adc_chan_s g_adc_chanbat =
+{
+ .info = &g_adc_module0_info,
+ .channeltype = ADC_CHAN_TYPE_VBAT,
+ .channel = ADC_CHAN_VBAT,
+ .pinset = GPIO_INVLD_CFG,
+};
+
+static struct adc_dev_s g_adc_chanbat_dev =
+{
+ .ad_ops = &g_adcops,
+ .ad_priv = &g_adc_chanbat,
+};
+#endif
static sem_t g_sem_excl = SEM_INITIALIZER(1);
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: tlsr82_adc_dfifo_enable
+ *
+ * Description:
+ * Enable the adc dfifo/dfifo2, the dfifo2 will copy the adc sample data
+ * to the address in DFIFO_ADC_ADDR_REG.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static inline void tlsr82_adc_dfifo_enable(void)
+{
+ DFIFO_MODE_REG |= DFIFO_MODE_DFIFO2_IN;
+}
+
+/****************************************************************************
+ * Name: tlsr82_adc_dfifo_disable
+ *
+ * Description:
+ * Disable the adc dfifo/dfifo2
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static inline void tlsr82_adc_dfifo_disable(void)
+{
+ DFIFO_MODE_REG &= ~DFIFO_MODE_DFIFO2_IN;
+}
+
+/****************************************************************************
+ * Name: tlsr82_adc_dfifo_config
+ *
+ * Description:
+ * Config the data buffer, so DFIFO2 can copy sample value to buffer
+ *
+ * Input Parameters:
+ * buffer - the buffer to store the adc sample data
+ * size - the buffer size, this size must be multiple of 4
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static inline void tlsr82_adc_dfifo_config(uint8_t *buffer, size_t size)
+{
+ /* Config the data buffer, so DFIFO2 can copy sample value to buffer
+ * DFIFO buffer address : only need low 16 bit, beacause the high 16 bit
+ * must be 0x0084
+ * DFIFO buffer size : DFIFO_ADC_SIZE_REG = n ==> 4 * (n + 1) size
+ * DFIFO_ADC_SIZE_REG = size / 4 - 1
+ */
+
+ DFIFO_ADC_ADDR_REG = (uint16_t)((uint32_t)buffer & 0xffff);
+ DFIFO_ADC_SIZE_REG = (size >> 2) - 1;
+
+ /* Clear the dfifo write pointer */
+
+ DFIFO2_WPTR_REG = 0;
+}
+
/****************************************************************************
* Private Functions
****************************************************************************/
@@ -224,19 +381,66 @@ static void tlsr82_adc_clk_ctrl(bool enable)
* Name: tlsr82_adc_config
*
* Description:
- * Config the adc, after this, the adc can start sample.
+ * Config the adc to different mode, after this, the adc can start sample
+ * the voltage in the gpio pin (Base mode) or the chip volatge (Vbat
+ * channel mode).
+ * Five configuration conditions:
+ * 1. Same channel, do not need do not need re-configuration;
+ * 2. adc module has not been configured, must configure it;
+ * 3. adc module has been configured, but current channel and configured
+ * channel are both vbat channel, do not need re-configuration;
+ * 4. adc module has been configured, but current channel and configured
+ * channel are both base channel, only configure the channel;
+ * 5. others, need re-configuration.
*
* Input Parameters:
- * cfg - adc pinset
+ * priv - adc channel handler
*
* Returned Value:
* None
*
****************************************************************************/
-static void tlsr82_adc_config(uint32_t cfg)
+static void tlsr82_adc_config(struct adc_chan_s *priv)
{
- /* Follow the datasheet and sdk adc_vbat_init() to config the adc */
+ uint8_t channel = priv->info->channel;
+ uint8_t channeltype = priv->info->channeltype;
+
+ ainfo("Current channel=%u, channeltype=%u\n", channel, channeltype);
+ ainfo("Input channel=%u, channeltype=%u\n",
+ priv->channel, priv->channeltype);
+
+ DEBUGASSERT(priv != NULL && priv->channel != ADC_CHAN_NONE);
+
+ /* If current channel type is same as the priv channel type, do not
+ * need re-configure all the register.
+ */
+
+ if (channeltype == priv->channeltype)
+ {
+ if (channeltype == ADC_CHAN_TYPE_BASE && channel != priv->channel)
+ {
+ /* The channel type is base and the input channel (GPIO pin) is
+ * different, only need re-configure the adc input channel.
+ */
+
+ tlsr82_adc_chan_config(priv->pinset);
+ priv->info->channel = priv->channel;
+ }
+
+ return;
+ }
+
+ ainfo("Start config\n");
+
+ /* Follow the sdk code adc_base_init() and adc_vbat_channel_init()
+ * to config the adc, VBAT_CHAN mode is samiler to BASE mode, the
+ * differences are:
+ * 1. adc divider : VBAT_CHAN mode, 1/3
+ * BASE mode, 1
+ * 2. pre-scale : VBAT_CHAN mode, 1
+ * BASE mode, 1/8
+ */
/* Enable misc chanel and set totaol length for sampling state be 2 */
@@ -253,14 +457,34 @@ static void tlsr82_adc_config(uint32_t cfg)
tlsr82_analog_write(ADC_SAMP1_REG, 240 & 0xff);
tlsr82_analog_write(ADC_SAMP3_REG, ((240 >> 8) << 6) | (10 & 0xff));
- /* Divider select OFF */
+ /* Divider select 1/3 or OFF */
- tlsr82_analog_modify(ADC_DIVIDER_REG, ADC_DIVIDER_SEL_MASK,
- ADC_DIVIDER_SEL_OFF);
+#ifdef CONFIG_TLSR82_ADC_VBAT
+ if (priv->channeltype == ADC_CHAN_TYPE_VBAT)
+ {
+ tlsr82_analog_modify(ADC_DIVIDER_REG, ADC_DIVIDER_SEL_MASK,
+ ADC_DIVIDER_SEL_1F3);
+ }
+ else
+#endif
+ {
+ tlsr82_analog_modify(ADC_DIVIDER_REG, ADC_DIVIDER_SEL_MASK,
+ ADC_DIVIDER_SEL_OFF);
+ }
/* Set the adc differential channel */
- tlsr82_adc_chan_config(cfg);
+#ifdef CONFIG_TLSR82_ADC_VBAT
+ if (priv->channeltype == ADC_CHAN_TYPE_VBAT)
+ {
+ tlsr82_analog_write(ADC_CHAN_REG, ADC_CHAN_POS_VBAT |
+ ADC_CHAN_NEG_GND);
+ }
+ else
+#endif
+ {
+ tlsr82_adc_chan_config(priv->pinset);
+ }
/* Enable the Different input mode */
@@ -286,8 +510,23 @@ static void tlsr82_adc_config(uint32_t cfg)
* When pre-scaling is 1/8, the ADC_DIVIDER_REG_0xf9 <4> must be 1
*/
- tlsr82_analog_modify(ADC_SCALE_REG, ADC_SCALE_MASK, ADC_SCALE_1F8);
- tlsr82_analog_modify(ADC_DIVIDER_REG, 0, (0x1 << 4));
+#ifdef CONFIG_TLSR82_ADC_VBAT
+ if (priv->channeltype == ADC_CHAN_TYPE_VBAT)
+ {
+ tlsr82_analog_modify(ADC_SCALE_REG, ADC_SCALE_MASK, ADC_SCALE_1);
+ tlsr82_analog_modify(ADC_DIVIDER_REG, BIT_RNG(4, 5), 0);
+ }
+ else
+#endif
+ {
+ tlsr82_analog_modify(ADC_SCALE_REG, ADC_SCALE_MASK, ADC_SCALE_1F8);
+ tlsr82_analog_modify(ADC_DIVIDER_REG, BIT(4), BIT(4));
+ }
+
+ /* Set current channel and current type */
+
+ priv->info->channel = priv->channel;
+ priv->info->channeltype = priv->channeltype;
}
/****************************************************************************
@@ -311,17 +550,13 @@ static void tlsr82_adc_pin_config(uint32_t pinset)
GPIO_SET_AS_GPIO(GPIO_GET(GROUP, cfg), GPIO_GET(PIN, cfg));
- /* Vbat mode pin config, disable input, enable output, output set high */
+ /* Base mode pin config, diable input, disable output, output set low */
tlsr82_gpio_input_ctrl(cfg, false);
- tlsr82_gpio_output_ctrl(cfg, true);
+ tlsr82_gpio_output_ctrl(cfg, false);
- tlsr82_gpiowrite(cfg, true);
-
- /* Base mode pin config, diable input, disable output, output set low */
-
- /* nothing */
+ tlsr82_gpiowrite(cfg, false);
}
/****************************************************************************
@@ -364,53 +599,16 @@ static void tlsr82_adc_chan_config(uint32_t pinset)
return;
}
+ /* Config gpio */
+
+ tlsr82_adc_pin_config(pinset);
+
/* Config the positive and negative input, here, the negative input
* is always configured to GND (0x0f).
*/
- tlsr82_analog_write(ADC_CHAN_REG, (pinadc << 4) | 0x0f);
-}
-
-/****************************************************************************
- * Name: read_efuse
- *
- * Description:
- * Read Efuse data.
- *
- * Input Parameters:
- * addr - register address
- * b_off - bit offset
- * b_size - bit size
- *
- * Returned Value:
- * Efuse data.
- *
- ****************************************************************************/
-
-static uint32_t read_efuse(uint32_t addr, uint32_t b_off, uint32_t b_size)
-{
- uint32_t data;
- uint32_t regval;
- uint32_t shift = 32 - b_size;
- uint32_t mask = UINT32_MAX >> shift;
- uint32_t res = b_off % 32;
- uint32_t regaddr = addr + (b_off / 32 * 4);
-
- regval = getreg32(regaddr);
- data = regval >> res;
- if (res <= shift)
- {
- data &= mask;
- }
- else
- {
- shift = 32 - res;
-
- regval = getreg32(regaddr + 4);
- data |= (regval & (mask >> shift)) << shift;
- }
-
- return data;
+ tlsr82_analog_write(ADC_CHAN_REG, (pinadc << ADC_CHAN_POS_SHIFT) |
+ ADC_CHAN_NEG_GND);
}
/****************************************************************************
@@ -490,49 +688,79 @@ static void adc_dump(const char *msg)
static uint16_t adc_read(void)
{
- volatile uint8_t adc_misc_data_l;
- volatile uint8_t adc_misc_data_h;
- volatile uint16_t adc_misc_data;
-
- /* Stop the adc sample */
+ volatile uint16_t data_buf[ADC_FILT_NUM];
+ uint16_t tmp;
+ uint16_t max = 0;
+ uint16_t min = UINT16_MAX;
+ uint32_t sum = 0;
+ uint32_t currtime;
+ int i;
- tlsr82_analog_modify(ADC_CTRL1_REG, ADC_CTRL1_SAMP_MASK,
- ADC_CTRL1_SAMP_OFF);
+ /* Clear the data buffer and config */
- /* Get adc sample value */
+ memset((void *)data_buf, 0, ADC_FILT_NUM);
- adc_misc_data_l = tlsr82_analog_read(ADC_DATAL_REG);
- adc_misc_data_h = tlsr82_analog_read(ADC_DATAH_REG);
+ tlsr82_adc_dfifo_config((uint8_t *)data_buf, ADC_FILT_NUM);
- /* Restart the adc sample */
+ /* Enable DFIFO 2 */
- tlsr82_analog_modify(ADC_CTRL1_REG, ADC_CTRL1_SAMP_MASK,
- ADC_CTRL1_SAMP_ON);
+ tlsr82_adc_dfifo_enable();
- /* Combine the adc sample value and process */
+ /* Wait at least 2 sample cycle, frequency = 96k, T = 10.4us */
- adc_misc_data = (adc_misc_data_h << 8 | adc_misc_data_l);
+ currtime = tlsr82_time();
+ while (!tlsr82_time_exceed(currtime, 25));
- if (adc_misc_data & BIT(13))
+ for (i = 0; i < ADC_FILT_NUM; i++)
{
+ while (data_buf[i] == 0 && !tlsr82_time_exceed(currtime, 25));
+ currtime = tlsr82_time();
+
/* Bit13 is the sign bit, bit13 = 1 indicates the data
- * is negative.
+ * is negative but we only get the low 13bit data.
*/
- adc_misc_data = 0;
- }
- else
- {
- /* Only get the low 13bit data */
+ tmp = data_buf[i];
+ if (tmp & BIT(13))
+ {
+ tmp = 0;
+ }
+ else
+ {
+ tmp &= 0x1fff;
+ }
+
+ sum += tmp;
+
+ if (tmp > max)
+ {
+ max = tmp;
+ }
- adc_misc_data &= 0x1fff;
+ if (tmp < min)
+ {
+ min = tmp;
+ }
+
+ ainfo("data_buf[%d]=%u\n", i, tmp);
}
- return adc_misc_data;
+ /* Disable DFIFO 2 */
+
+ tlsr82_adc_dfifo_disable();
+
+ ainfo("sum=%lu, max=%u, min=%u, filt_num=%d\n",
+ sum, max, min, ADC_FILT_NUM);
+
+ /* Remove max, min value and get the average value */
+
+ tmp = (sum - min - max) / (ADC_FILT_NUM - 2);
+
+ return tmp;
}
/****************************************************************************
- * Name: adc_calibrate
+ * Name: tlsr82_adc_calibrate
*
* Description:
* ADC calibration.
@@ -545,85 +773,80 @@ static uint16_t adc_read(void)
*
****************************************************************************/
-#if 0
-
-static void adc_calibrate(void)
+#ifdef CONFIG_TLSR82_ADC_CALI
+static void tlsr82_adc_calibrate(struct adc_chan_s *priv)
{
- uint16_t cali_val;
- uint16_t adc;
- uint16_t adc_max = 0;
- uint16_t adc_min = UINT16_MAX;
- uint32_t adc_sum = 0;
- uint32_t regval;
+ uint8_t cali_data[7];
- regval = read_efuse(ADC_CAL_BASE_REG, ADC_CAL_VER_OFF, ADC_CAL_VER_LEN);
- if (regval == 1)
- {
- ainfo("Calibrate based on efuse data\n");
-
- regval = read_efuse(ADC_CAL_BASE_REG, ADC_CAL_DATA_OFF,
- ADC_CAL_DATA_LEN);
- cali_val = regval + ADC_CAL_DATA_COMP;
- }
- else
- {
- ainfo("Calibrate based on GND voltage\n");
+ uint32_t base_vref;
+ uint32_t vbat_vref;
- /* Enable Vdef */
+ memset((void *)cali_data, 0, sizeof(cali_data));
+ tlsr82_flash_read_data(CONFIG_TLSR82_ADC_CALI_PARA_ADDR, cali_data,
+ sizeof(cali_data));
- rom_i2c_writereg_mask(I2C_ADC, I2C_ADC_HOSTID,
- I2C_ADC1_DEF, I2C_ADC1_DEF_MSB,
- I2C_ADC1_DEF_LSB, 1);
+ ainfo("Calibration data: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ cali_data[0], cali_data[1], cali_data[2], cali_data[3],
+ cali_data[4], cali_data[5], cali_data[6]);
- /* Start sampling */
+ /* Calibration parameters format follow the telink sdk code */
- adc_samplecfg(ADC_CAL_CHANNEL);
+ /* Base/gpio mode calibration parameters read */
- /* Enable internal connect GND (for calibration). */
+ if (cali_data[4] <= 0x7f && cali_data[5] != 0xff &&
+ cali_data[6] != 0xff)
+ {
+ /* Two-point calibration exist, the base_vref as the gain to use
+ * Method of calculating two-point gpio calibration Flash_gain
+ * and Flash_offset:
+ * gain = (data[6] << 8) + data[5] + 1000 mv
+ * offset = data[4] - 20 mv
+ */
- rom_i2c_writereg_mask(I2C_ADC, I2C_ADC_HOSTID,
- I2C_ADC1_ENCAL_GND, I2C_ADC1_ENCAL_GND_MSB,
- I2C_ADC1_ENCAL_GND_LSB, 1);
+ priv->info->base_vref = (cali_data[6] << 8) + cali_data[5] + 1000;
+ priv->info->base_off = (int)cali_data[4] - 20;
+ priv->info->base_two = true;
+ }
+ else
+ {
+ /* One-point calibration exist
+ * Method of calculating calibration Flash_gpio_vref value:
+ * vref = 1175 + data[0] - 255 + data[1] mV
+ * = 920 + data[0] + data[1] mV
+ */
- for (int i = 1; i < ADC_CAL_CNT_MAX ; i++)
+ base_vref = 920 + cali_data[0] + cali_data[1];
+ if (base_vref >= 1047 && base_vref <= 1302)
{
- adc_set_calibration(0);
- adc = adc_read();
-
- adc_sum += adc;
- adc_max = MAX(adc, adc_max);
- adc_min = MIN(adc, adc_min);
+ priv->info->base_vref = base_vref;
}
- cali_val = (adc_sum - adc_max - adc_min) / (ADC_CAL_CNT_MAX - 2);
-
- /* Disable internal connect GND (for calibration). */
-
- rom_i2c_writereg_mask(I2C_ADC, I2C_ADC_HOSTID,
- I2C_ADC1_ENCAL_GND,
- I2C_ADC1_ENCAL_GND_MSB,
- I2C_ADC1_ENCAL_GND_LSB, 0);
+ priv->info->base_two = false;
}
- ainfo("calibration value: %" PRIu16 "\n", cali_val);
-
- /* Set final calibration parameters */
+ /* Vbat mode calibration parameters read */
- adc_set_calibration(cali_val);
-
- /* Set calibration digital parameters */
-
- regval = read_efuse(ADC_CAL_BASE_REG, ADC_CAL_VOL_OFF, ADC_CAL_VOL_LEN);
- if (regval & BIT(ADC_CAL_VOL_LEN - 1))
+ if (cali_data[2] != 0xff || cali_data[3] != 0xff)
{
- g_cal_digit = 2000 - (regval & ~(BIT(ADC_CAL_VOL_LEN - 1)));
- }
- else
- {
- g_cal_digit = 2000 + regval;
+ /* One-point calibration exist
+ * Method of calculating calibration Flash_vbat_vref value:
+ * vref = 1175 + data[2] - 255 + data[3] mV
+ * = 920 + data[2] + data[3] mV
+ */
+
+ vbat_vref = 920 + cali_data[2] + cali_data[3];
+ if (vbat_vref >= 1047 && vbat_vref <= 1302)
+ {
+ priv->info->vbat_vref = vbat_vref;
+ }
}
-}
+ ainfo("Calibration paramters:\n");
+ ainfo(" base two-point: gain=%d, offset=%d\n",
+ priv->info->base_vref, priv->info->base_off);
+ ainfo(" base one-point: vref=%lu\n", priv->info->base_vref);
+ ainfo(" vbat one-point: vref=%lu\n", priv->info->vbat_vref);
+}
#endif
/****************************************************************************
@@ -654,7 +877,9 @@ static void adc_read_work(struct adc_dev_s *dev)
return;
}
- tlsr82_adc_chan_config(priv->pinset);
+ /* Config the adc */
+
+ tlsr82_adc_config(priv);
/* Dump adc register for debug */
@@ -667,9 +892,27 @@ static void adc_read_work(struct adc_dev_s *dev)
* negative input be gnd, so the actual adc resolution is 13bit.
*/
- adc = (value * priv->info->vref * 8) >> 13;
+#ifdef CONFIG_TLSR82_ADC_VBAT
+ if (priv->channeltype == ADC_CHAN_TYPE_VBAT)
+ {
+ /* Vbat channel mode, divider = 1/3, scale = 1 ==> factor = 3 */
+
+ adc = (value * priv->info->vbat_vref * 3) >> 13;
+ }
+ else
+#endif
+ {
+ /* Base/gpio mode, divider = 1, scale = 1/8 ==> factor = 8 */
+
+ adc = (value * priv->info->base_vref * 8) >> 13;
+
+ if (priv->info->base_two)
+ {
+ adc += priv->info->base_off;
+ }
+ }
- /* Calibration */
+ /* Put adc value to the adc buffer */
priv->cb->au_receive(dev, priv->channel, adc);
@@ -793,11 +1036,18 @@ static int adc_setup(struct adc_dev_s *dev)
tlsr82_adc_clk_ctrl(true);
- /* Config ADC hardware (Calibration and gpio) */
+ /* Read the calibration parameters */
- ainfo("pin: 0x%" PRIx32 "\n", priv->pinset);
+#ifdef CONFIG_TLSR82_ADC_CALI
+ tlsr82_adc_calibrate(priv);
+#endif
+
+ /* Config ADC hardware */
- tlsr82_adc_config(priv->pinset);
+ ainfo("pin: 0x%" PRIx32 ", channel: %" PRIu8 "\n",
+ priv->pinset, priv->channel);
+
+ tlsr82_adc_config(priv);
/* The ADC device is ready */
@@ -944,9 +1194,29 @@ int tlsr82_adc_init(const char *devpath, int miror)
switch (miror)
{
- case 0:
+#ifdef CONFIG_TLSR82_ADC_CHAN0
+ case ADC_CHAN_0:
dev = &g_adc_chan0_dev;
break;
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_CHAN1
+ case ADC_CHAN_1:
+ dev = &g_adc_chan1_dev;
+ break;
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_CHAN2
+ case ADC_CHAN_2:
+ dev = &g_adc_chan2_dev;
+ break;
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_VBAT
+ case ADC_CHAN_VBAT:
+ dev = &g_adc_chanbat_dev;
+ break;
+#endif
default:
{
diff --git a/arch/arm/src/tlsr82/tlsr82_adc.h b/arch/arm/src/tlsr82/tlsr82_adc.h
index ea42fe60ad..d7dbafad63 100644
--- a/arch/arm/src/tlsr82/tlsr82_adc.h
+++ b/arch/arm/src/tlsr82/tlsr82_adc.h
@@ -29,6 +29,22 @@
#include "hardware/tlsr82_adc.h"
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define ADC_CHAN_0 0
+#define ADC_CHAN_1 1
+#define ADC_CHAN_2 2
+#define ADC_CHAN_3 3
+#define ADC_CHAN_4 4
+#define ADC_CHAN_5 5
+#define ADC_CHAN_6 6
+#define ADC_CHAN_7 7
+#define ADC_CHAN_TEMP 253
+#define ADC_CHAN_VBAT 254
+#define ADC_CHAN_NONE 255
+
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
diff --git a/arch/arm/src/tlsr82/tlsr82_timer.h b/arch/arm/src/tlsr82/tlsr82_timer.h
index 6bd50649e3..3fe0f87b22 100644
--- a/arch/arm/src/tlsr82/tlsr82_timer.h
+++ b/arch/arm/src/tlsr82/tlsr82_timer.h
@@ -120,6 +120,20 @@ struct tlsr82_timer_ops_s
int (*checkint)(struct tlsr82_timer_dev_s *dev);
};
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+static inline uint32_t tlsr82_time(void)
+{
+ return SYSTIMER_TICK_REG;
+}
+
+static inline bool tlsr82_time_exceed(uint32_t start, uint32_t us)
+{
+ return ((uint32_t)(tlsr82_time() - start) > us * 16);
+}
+
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
diff --git a/boards/arm/tlsr82/tlsr8278adk80d/src/tlsr8278_bringup.c b/boards/arm/tlsr82/tlsr8278adk80d/src/tlsr8278_bringup.c
index f74afe662c..10e3c4b5e4 100644
--- a/boards/arm/tlsr82/tlsr8278adk80d/src/tlsr8278_bringup.c
+++ b/boards/arm/tlsr82/tlsr8278adk80d/src/tlsr8278_bringup.c
@@ -134,7 +134,9 @@ int tlsr8278_bringup(void)
#endif /* CONFIG_TLSR82_PWM */
#ifdef CONFIG_TLSR82_ADC
- ret = tlsr82_adc_init("/dev/adc0", 0);
+
+#ifdef CONFIG_TLSR82_ADC_CHAN0
+ ret = tlsr82_adc_init("/dev/adc0", ADC_CHAN_0);
if (ret < 0)
{
syslog(LOG_ERR,
@@ -142,6 +144,41 @@ int tlsr8278_bringup(void)
ret);
return ret;
}
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_CHAN1
+ ret = tlsr82_adc_init("/dev/adc1", ADC_CHAN_1);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR,
+ "ERROR: Failed to initialize adc1 driver: %d\n",
+ ret);
+ return ret;
+ }
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_CHAN2
+ ret = tlsr82_adc_init("/dev/adc2", ADC_CHAN_2);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR,
+ "ERROR: Failed to initialize adc2 driver: %d\n",
+ ret);
+ return ret;
+ }
+#endif
+
+#ifdef CONFIG_TLSR82_ADC_VBAT
+ ret = tlsr82_adc_init("/dev/adcvbat", ADC_CHAN_VBAT);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR,
+ "ERROR: Failed to initialize adcbat driver: %d\n",
+ ret);
+ return ret;
+ }
+#endif
+
#endif /* CONFIG_TLSR82_ADC */
#ifdef CONFIG_TLSR82_FLASH