feature(adc): add adc example

This commit is contained in:
XiongYu
2019-03-22 13:49:26 +08:00
parent 2105cf040a
commit cdc22f273c
9 changed files with 328 additions and 18 deletions

View File

@ -444,5 +444,16 @@ config ESP_PHY_INIT_DATA_IN_PARTITION
If unsure, choose 'n'.
config ESP_PHY_INIT_DATA_VDD33_CONST
int "vdd33_const value"
range 0 255
default 33
help
vdd33_const provides ADC mode settings, i.e. selecting system voltage or external voltage measurements.
When measuring system voltage, it must be set to 255.
To read the external voltage on TOUT(ADC) pin, vdd33_const need less than 255
When the ADC reference voltage is set to the actual VDD33 power supply voltage, the value range of vdd33_const is [18,36], the unit is 0.1V.
When the ADC reference voltage is set to the default value of 3.3V as the supply voltage, the range of vdd33_const is [0, 18] or (36, 255).
endmenu # PHY

View File

@ -12,19 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_phy_init.h"
#include "esp_heap_caps.h"
#include "driver/adc.h"
#define ENTER_CRITICAL() portENTER_CRITICAL()
#define EXIT_CRITICAL() portEXIT_CRITICAL()
static const char *TAG = "adc";
#define ADC_CHECK(a, str, ret_val) \
if (!(a)) { \
@ -36,19 +36,112 @@ extern uint16_t test_tout();
extern void phy_adc_read_fast(uint16_t *adc_addr, uint16_t adc_num, uint8_t adc_clk_div);
extern uint16_t phy_get_vdd33();
uint16_t adc_read()
typedef struct {
adc_config_t config;
SemaphoreHandle_t adc_mux;
} adc_handle_t;
adc_handle_t *adc_handle = NULL;
esp_err_t adc_read(uint16_t *data)
{
uint16_t ret = test_tout(0);
ADC_CHECK(data, "parameter pointer is empty", ESP_ERR_INVALID_ARG);
ADC_CHECK(adc_handle, "ADC has not been initialized yet.", ESP_FAIL);
uint16_t ret = 0;
xSemaphoreTake(adc_handle->adc_mux, portMAX_DELAY);
if (ret != 0xFFFF) {
// The working voltage of ADC is designed according to 1.1v. Later, the actual working voltage of ADC is increased to 1.2v, so this scale is added.
ret = ret * 12 / 11;
if (adc_handle->config.mode == ADC_READ_TOUT_MODE) {
ret = test_tout(0);
if (ret > 1023) {
// 10-bit precision ADC
ret = 1023;
if (ret != 0xFFFF) {
// The working voltage of ADC is designed according to 1.1v. Later, the actual working voltage of ADC is increased to 1.2v, so this scale is added.
ret = ret * 12 / 11;
if (ret > 1023) {
// 10-bit precision ADC
ret = 1023;
}
}
} else if (adc_handle->config.mode == ADC_READ_VDD_MODE) {
ret = phy_get_vdd33();
if (ret != 0xFFFF) {
// The working voltage of ADC is designed according to 1.1v. Later, the actual working voltage of ADC is increased to 1.2v, so this scale is added.
ret = ret * 12 / 11;
}
}
return ret;
*data = ret;
xSemaphoreGive(adc_handle->adc_mux);
return ESP_OK;
}
esp_err_t adc_read_fast(uint16_t *data, uint16_t len)
{
ADC_CHECK(data && len > 0, "parameter pointer is empty", ESP_ERR_INVALID_ARG);
ADC_CHECK(adc_handle, "ADC has not been initialized yet.", ESP_FAIL);
ADC_CHECK(adc_handle->config.mode == ADC_READ_TOUT_MODE, "adc_read_fast can only be used in ADC_READ_TOUT_MODE mode", ESP_ERR_INVALID_ARG);
ADC_CHECK(adc_handle->config.clk_div >= 8 && adc_handle->config.clk_div <= 32, "ADC sample collection clock=80M/clk_div, range[8, 32]", ESP_FAIL);
uint16_t i;
uint16_t ret;
xSemaphoreTake(adc_handle->adc_mux, portMAX_DELAY);
phy_adc_read_fast(data, len, adc_handle->config.clk_div);
for (i = 0; i < len; i++) {
ret = data[i];
if (ret != 0xFFFF) {
// The working voltage of ADC is designed according to 1.1v. Later, the actual working voltage of ADC is increased to 1.2v, so this scale is added.
ret = ret * 12 / 11;
if (ret > 1023) {
// 10-bit precision ADC
ret = 1023;
}
}
data[i] = ret;
}
xSemaphoreGive(adc_handle->adc_mux);
return ESP_OK;
}
esp_err_t adc_deinit()
{
ADC_CHECK(adc_handle, "ADC has not been initialized yet.", ESP_FAIL);
if (adc_handle->adc_mux) {
vSemaphoreDelete(adc_handle->adc_mux);
}
heap_caps_free(adc_handle);
adc_handle = NULL;
return ESP_OK;
}
esp_err_t adc_init(adc_config_t *config)
{
ADC_CHECK(config, "config error", ESP_ERR_INVALID_ARG);
ADC_CHECK(NULL == adc_handle, "adc has been initialized", ESP_FAIL);
uint8_t vdd33_const;
esp_phy_init_data_t *phy_init_data;
phy_init_data = (esp_phy_init_data_t *)esp_phy_get_init_data();
vdd33_const = phy_init_data->params[107];
ADC_CHECK((config->mode == ADC_READ_TOUT_MODE) ? (vdd33_const <= 255) : true, "To read the external voltage on TOUT(ADC) pin, vdd33_const need less than 255", ESP_FAIL);
ADC_CHECK((config->mode == ADC_READ_VDD_MODE) ? (vdd33_const == 255) : true, "When adc measuring system voltage, vdd33_const must be set to 255,", ESP_FAIL);
adc_handle = heap_caps_malloc(sizeof(adc_handle_t), MALLOC_CAP_8BIT);
ADC_CHECK(adc_handle, "adc handle malloc error", ESP_ERR_NO_MEM);
memcpy(&adc_handle->config, config, sizeof(adc_config_t));
adc_handle->adc_mux = xSemaphoreCreateMutex();
if (NULL == adc_handle->adc_mux) {
adc_deinit();
ADC_CHECK(false, "Semaphore create fail", ESP_ERR_NO_MEM);
}
return ESP_OK;
}

View File

@ -21,13 +21,79 @@
extern "C" {
#endif
/**
* @brief ADC working mode enumeration
*/
typedef enum {
ADC_READ_TOUT_MODE,
ADC_READ_VDD_MODE
} adc_mode_t;
/**
* @brief Measure the input voltage of TOUT pin 6, unit : 1/1023 V.
* @brief ADC initialization parameter structure type definition
*/
typedef struct {
adc_mode_t mode;
uint8_t clk_div; // ADC sample collection clock=80M/clk_div, range[8, 32]
} adc_config_t;
/**
* @brief Single measurement of TOUT(ADC) pin, unit : 1/1023 V or VDD pin, uint: 1 mV
*
* @return Input voltage of TOUT pin 6, unit : 1/1023 V
* @note When measuring VDD pin voltage, the TOUT(ADC) pin must be left floating.
*
* @param data Pointer to accept adc value.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL adc has not been initialized yet
*/
uint16_t adc_read();
esp_err_t adc_read(uint16_t *data);
/**
* @brief Measure the input voltage of TOUT(ADC) pin, unit : 1/1023 V.
*
* @note Wi-Fi and interrupts need to be turned off.
*
* @param data Pointer to accept adc value. Input voltage of TOUT(ADC) pin, unit : 1/1023 V
* @param len Receiving length of ADC value, range [1, 65535]
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL adc has not been initialized yet
*/
esp_err_t adc_read_fast(uint16_t *data, uint16_t len);
/**
* @brief Deinit the adc
*
* @return
* - ESP_OK Success
* - ESP_FAIL adc has not been initialized yet
*/
esp_err_t adc_deinit();
/**
* @brief Initialize the adc
*
* @note First modify menuconfig->Component config->PHY->vdd33_const value, vdd33_const provides ADC mode settings,
* i.e. selecting system voltage or external voltage measurements.
* When measuring system voltage, it must be set to 255.
* To read the external voltage on TOUT(ADC) pin, vdd33_const need less than 255
* When the ADC reference voltage is set to the actual VDD33 power supply voltage, the value range of vdd33_const is [18,36], the unit is 0.1V.
* When the ADC reference voltage is set to the default value of 3.3V as the supply voltage, the range of vdd33_const is [0, 18] or (36, 255).
*
* @param config Pointer to deliver initialize configuration parameter
*
* @return
* - ESP_OK Success
* - ESP_ERR_NO_MEM malloc fail
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL adc has been initialized
*/
esp_err_t adc_init(adc_config_t *config);
#ifdef __cplusplus
}

View File

@ -132,7 +132,11 @@ static const esp_phy_init_data_t phy_init_data= { {
0x00,
0x00,
0x00,
#ifdef CONFIG_ESP_PHY_INIT_DATA_VDD33_CONST
CONFIG_ESP_PHY_INIT_DATA_VDD33_CONST,
#else
0x00,
#endif
0x00,
0x00,
0x00,

View File

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := adc_example
include $(IDF_PATH)/make/project.mk

View File

@ -0,0 +1,69 @@
# _ADC Example_
_This is a example for reading ADC values._
1. An analog-to-digital converter (ADC) is used to convert analog signals into digital forms. ESP8266 has a built-in 10-bit ADC, only one ADC channel.
2. ADC channel in ESP8266 is multiplexed with system voltage. Therefore, we can set it to measure system voltage or external voltage. When reading the external voltage, the input voltage range of TOUT(ADC) pin are 0-1.0V.
3. ` menuconfig - > Component config - > PHY - > vdd33_const value ` provides the setting of ADC mode, that is, whether the system voltage or external voltage is being measured.
4. ` Menuconfig - > Component config - > PHY - > vdd33_const value ` must be set to 255 to read the system voltage, that is, the voltage on the VDD pin of ESP8266. To read the external voltage on TOUT(ADC) pin, vdd33_const need less than 255
When the ADC reference voltage is set to the actual VDD33 power supply voltage, the value range of vdd33_const is [18,36], the unit is 0.1V.
When the ADC reference voltage is set to the default value of 3.3V as the supply voltage, the range of vdd33_const is [0, 18] or (36, 255).
## How to use example
### Hardware Required
1. To support external voltage range (0-3.3V), connect TOUT(ADC) pin to resistance divider network (R1 220K and R2 100K)
![adc](adc.png)
2. When measuring VDD pin voltage, the TOUT(ADC) pin must be left floating. At this point, resistance divider networks R1, R2 need to be removed.
### Configure the project
```
make menuconfig
```
* Set serial port under Serial Flasher Options.
* `make monitor` baud rate set to what you set in the example.
* Modify `menuconfig->Component config->PHY->vdd33_const value`, vdd33_const provides ADC mode settings
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
make -j4 flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
```
I (482) adc example: adc read: 29
I (482) adc example: adc read fast:
29
29
30
29
29
29
29
29
29
29
29
29
29
29
29
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 KiB

View File

@ -0,0 +1,55 @@
/* adc example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/adc.h"
#include "esp_log.h"
static const char *TAG = "adc example";
static void adc_task()
{
int x;
uint16_t adc_data[100];
while (1) {
if (ESP_OK == adc_read(&adc_data[0])) {
ESP_LOGI(TAG, "adc read: %d\r\n", adc_data[0]);
}
ESP_LOGI(TAG, "adc read fast:\r\n");
if (ESP_OK == adc_read_fast(adc_data, 100)) {
for (x = 0; x < 100; x++) {
printf("%d\n", adc_data[x]);
}
}
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
void app_main()
{
// 1. init adc
adc_config_t adc_config;
// Depend on menuconfig->Component config->PHY->vdd33_const value
// When measuring system voltage(ADC_READ_VDD_MODE), vdd33_const must be set to 255.
adc_config.mode = ADC_READ_TOUT_MODE;
adc_config.clk_div = 8; // ADC sample collection clock = 80MHz/clk_div = 10MHz
ESP_ERROR_CHECK(adc_init(&adc_config));
// 2. Create a adc task to read adc value
xTaskCreate(adc_task, "adc_task", 1024, NULL, 5, NULL);
}

View File

@ -0,0 +1,3 @@
#
# Main Makefile. This is basically the same as a component makefile.
#