From 200109fd2869cfbbe558f9b7f8571e5c32ee8db4 Mon Sep 17 00:00:00 2001 From: wangbowen6 Date: Wed, 18 May 2022 22:53:27 +0800 Subject: [PATCH] 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 --- 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 | 624 +++++++++++++----- arch/arm/src/tlsr82/tlsr82_adc.h | 16 + arch/arm/src/tlsr82/tlsr82_timer.h | 14 + .../tlsr8278adk80d/src/tlsr8278_bringup.c | 39 +- 7 files changed, 682 insertions(+), 178 deletions(-) create mode 100644 arch/arm/src/tlsr82/hardware/tlsr82_dfifo.h 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 +#include + +#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; + 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; - /* Stop the adc sample */ + /* Clear the data buffer and config */ - tlsr82_analog_modify(ADC_CTRL1_REG, ADC_CTRL1_SAMP_MASK, - ADC_CTRL1_SAMP_OFF); + memset((void *)data_buf, 0, ADC_FILT_NUM); - /* Get adc sample value */ + tlsr82_adc_dfifo_config((uint8_t *)data_buf, ADC_FILT_NUM); - adc_misc_data_l = tlsr82_analog_read(ADC_DATAL_REG); - adc_misc_data_h = tlsr82_analog_read(ADC_DATAH_REG); + /* Enable DFIFO 2 */ - /* Restart the adc sample */ + tlsr82_adc_dfifo_enable(); - tlsr82_analog_modify(ADC_CTRL1_REG, ADC_CTRL1_SAMP_MASK, - ADC_CTRL1_SAMP_ON); + /* Wait at least 2 sample cycle, frequency = 96k, T = 10.4us */ - /* Combine the adc sample value and process */ + currtime = tlsr82_time(); + while (!tlsr82_time_exceed(currtime, 25)); - adc_misc_data = (adc_misc_data_h << 8 | adc_misc_data_l); - - 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; + } - adc_misc_data &= 0x1fff; + sum += tmp; + + if (tmp > max) + { + max = tmp; + } + + 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) + uint32_t base_vref; + uint32_t vbat_vref; + + memset((void *)cali_data, 0, sizeof(cali_data)); + tlsr82_flash_read_data(CONFIG_TLSR82_ADC_CALI_PARA_ADDR, cali_data, + sizeof(cali_data)); + + 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]); + + /* Calibration parameters format follow the telink sdk code */ + + /* Base/gpio mode calibration parameters read */ + + if (cali_data[4] <= 0x7f && cali_data[5] != 0xff && + cali_data[6] != 0xff) { - ainfo("Calibrate based on efuse data\n"); + /* 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 + */ - regval = read_efuse(ADC_CAL_BASE_REG, ADC_CAL_DATA_OFF, - ADC_CAL_DATA_LEN); - cali_val = regval + ADC_CAL_DATA_COMP; + 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 { - ainfo("Calibrate based on GND voltage\n"); + /* 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 + */ - /* Enable Vdef */ - - rom_i2c_writereg_mask(I2C_ADC, I2C_ADC_HOSTID, - I2C_ADC1_DEF, I2C_ADC1_DEF_MSB, - I2C_ADC1_DEF_LSB, 1); - - /* Start sampling */ - - adc_samplecfg(ADC_CAL_CHANNEL); - - /* Enable 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, 1); - - 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); + /* Vbat mode calibration parameters read */ - /* Set final calibration parameters */ - - 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 */ - /* Calibration */ + 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; + } + } + + /* 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 - tlsr82_adc_config(priv->pinset); + /* Config ADC hardware */ + + 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