Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Continuous ADC stops working while BLE Mesh is on (IDFGH-14171) #14972

Closed
3 tasks done
UncleBigLu opened this issue Dec 3, 2024 · 2 comments
Closed
3 tasks done

Continuous ADC stops working while BLE Mesh is on (IDFGH-14171) #14972

UncleBigLu opened this issue Dec 3, 2024 · 2 comments
Assignees
Labels
Status: Opened Issue is new Type: Bug bugs in IDF

Comments

@UncleBigLu
Copy link

UncleBigLu commented Dec 3, 2024

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

IDF version.

v5.4-dev-4375-gf420609c33

Espressif SoC revision.

ESP32-S3 (QFN56) (revision v0.2)

Operating System used.

Linux

How did you build your project?

Command line with idf.py

If you are using Windows, please specify command line type.

None

Development Kit.

Custom board

Power Supply used.

USB

What is the expected behavior?

The adc_continuous_evt_cbs_t::on_conv_done events keeps triggering when data available.

What is the actual behavior?

If I enable a task that periodically send BLE message via esp_ble_mesh_client_model_send_msg, the adc stops working after around 10 seconds.

Steps to reproduce.

/* main.c - Application main entry point */

/*
 * SPDX-FileCopyrightText: 2017 Intel Corporation
 * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "esp_err.h"
#include "freertos/idf_additions.h"
#include "mesh/access.h"
#include "portmacro.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>

#include "esp_log.h"
#include "nvs_flash.h"

#include "esp_ble_mesh_common_api.h"
#include "esp_ble_mesh_provisioning_api.h"
#include "esp_ble_mesh_networking_api.h"
#include "esp_ble_mesh_config_model_api.h"
#include "esp_ble_mesh_generic_model_api.h"
#include "esp_ble_mesh_local_data_operation_api.h"

#include "ble_mesh_example_init.h"
#include "ble_mesh_example_nvs.h"

#include "freertos/semphr.h"

#include "esp_random.h"

#include <sys/types.h>

#include <math.h>

#include "esp_adc/adc_continuous.h"
#include "esp_dsp.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "sdkconfig.h"

#define EXAMPLE_ADC_UNIT ADC_UNIT_1
#define _EXAMPLE_ADC_UNIT_STR(unit) #unit
#define EXAMPLE_ADC_UNIT_STR(unit) _EXAMPLE_ADC_UNIT_STR(unit)
#define EXAMPLE_ADC_CONV_MODE ADC_CONV_SINGLE_UNIT_1
#define EXAMPLE_ADC_ATTEN ADC_ATTEN_DB_0
#define EXAMPLE_ADC_BIT_WIDTH SOC_ADC_DIGI_MAX_BITWIDTH

#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#define EXAMPLE_ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE1
#define EXAMPLE_ADC_GET_CHANNEL(p_data) ((p_data)->type1.channel)
#define EXAMPLE_ADC_GET_DATA(p_data) ((p_data)->type1.data)
#else
#define EXAMPLE_ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE2
#define EXAMPLE_ADC_GET_CHANNEL(p_data) ((p_data)->type2.channel)
#define EXAMPLE_ADC_GET_DATA(p_data) ((p_data)->type2.data)
#endif

#define TAG "main"

#define FFT_POINTS 2048
/* Size of ADC conversion frame
 * Number of ADC result per frame equals to
 * ADC_CONV_FRAME_SZ/SOC_ADC_DIGI_RESULT_BYTES
 */
#define ADC_CONV_FRAME_SZ 256
#define ADC_SAMPLE_RATE 20e3
#define ADC_MAX_STORE_BUF_SZ 1024

#define TARGET_FREQ 2e3
#define UNWANTED_FREQ 1e3

#define ADC_READ_CHECK(x)                                   \
    do {                                                    \
        esp_err_t err_rc_ = (x);                            \
        if (err_rc_ == ESP_ERR_INVALID_STATE) {             \
            ESP_LOGW(TAG, "ADC internal buf full.");        \
        } else if (err_rc_ == ESP_ERR_TIMEOUT) {            \
            ESP_LOGW(TAG, "ADC reports NO data available"); \
        }                                                   \
    } while (0)

struct ble_packet {
    uint8_t id;
    float fftrst;
    int8_t arr[12];
} __attribute__((packed));

extern SemaphoreHandle_t ble_packet_mutex;
// As we're using ESP32S3...
// Only one channel is required
// Should map to GPIO 3
static adc_channel_t channel[1] = { ADC_CHANNEL_2 };

static TaskHandle_t s_task_handle;

// Hann window for FFT
static float wind[FFT_POINTS] __attribute__((aligned(16)));
static uint8_t adc_buf[FFT_POINTS * SOC_ADC_DIGI_RESULT_BYTES] = { 0 };
// fft_buf[2 * i + 0] contains real, fft_buf[2 * i + 1] contains imaginary
static float fft_buf[2 * FFT_POINTS] __attribute__((aligned(16)));
static float spectrum[FFT_POINTS / 2] __attribute__((aligned(16)));

static float findmax(float *arr, size_t len)
{
    assert(arr);
    float ret = arr[0];
    for (size_t i = 0; i < len; ++i) {
        if (arr[i] > ret)
            ret = arr[i];
    }
    return ret;
}

static bool IRAM_ATTR s_conv_done_cb(adc_continuous_handle_t handle,
                                     const adc_continuous_evt_data_t *edata,
                                     void *user_data)
{
    BaseType_t mustYield = pdFALSE;
    // Notify that ADC continuous driver has done enough number of
    // conversions
    vTaskNotifyGiveFromISR(s_task_handle, &mustYield);
    return (mustYield == pdTRUE);
}

static void continuous_adc_init(adc_channel_t *channel, uint8_t channel_num,
                                adc_continuous_handle_t *out_handle)
{
    esp_err_t ret;

    adc_continuous_handle_t handle = NULL;

    adc_continuous_handle_cfg_t adc_config = {
        .max_store_buf_size = ADC_MAX_STORE_BUF_SZ,
        .conv_frame_size = ADC_CONV_FRAME_SZ,
    };
    ret = adc_continuous_new_handle(&adc_config, &handle);
    switch (ret) {
    case ESP_ERR_NO_MEM:
        ESP_LOGE(TAG, "out of memory");
        break;
    case ESP_ERR_NOT_FOUND:
        ESP_LOGE(TAG, "not found");
        break;
    case ESP_ERR_INVALID_ARG:
        ESP_LOGE(TAG, "invalid arg");
        break;
    }

    adc_continuous_config_t dig_cfg = {
        .sample_freq_hz = ADC_SAMPLE_RATE,
        .conv_mode = EXAMPLE_ADC_CONV_MODE,
        .format = EXAMPLE_ADC_OUTPUT_TYPE,
    };

    adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = { 0 };
    dig_cfg.pattern_num = channel_num;
    for (int i = 0; i < channel_num; i++) {
        adc_pattern[i].atten = EXAMPLE_ADC_ATTEN;
        adc_pattern[i].channel = channel[i] & 0x7;
        adc_pattern[i].unit = EXAMPLE_ADC_UNIT;
        adc_pattern[i].bit_width = EXAMPLE_ADC_BIT_WIDTH;

        ESP_LOGI(TAG, "adc_pattern[%d].atten is :%" PRIx8, i,
                 adc_pattern[i].atten);
        ESP_LOGI(TAG, "adc_pattern[%d].channel is :%" PRIx8, i,
                 adc_pattern[i].channel);
        ESP_LOGI(TAG, "adc_pattern[%d].unit is :%" PRIx8, i,
                 adc_pattern[i].unit);
    }
    dig_cfg.adc_pattern = adc_pattern;
    ESP_ERROR_CHECK(adc_continuous_config(handle, &dig_cfg));

    *out_handle = handle;
}

static void fft_init(void)
{
    ESP_ERROR_CHECK(dsps_fft2r_init_fc32(NULL, CONFIG_DSP_MAX_FFT_SIZE));
    ESP_ERROR_CHECK(dsps_fft4r_init_fc32(NULL, CONFIG_DSP_MAX_FFT_SIZE));
    // Generate hann window
    dsps_wind_hann_f32(wind, FFT_POINTS);
}

static void adc_fft_task(void *pvParameters)
{
    size_t i;
    uint32_t ret_num = 0, tot_read_num = 0;
    memset(adc_buf, 0xcc, FFT_POINTS * SOC_ADC_DIGI_RESULT_BYTES);
    uint32_t unwanted_freq_idx =
        (uint32_t)(UNWANTED_FREQ * FFT_POINTS / ADC_SAMPLE_RATE);

    uint32_t target_freq_idx =
        (uint32_t)(TARGET_FREQ * FFT_POINTS / ADC_SAMPLE_RATE);
    ESP_LOGI(TAG, "idx: %lu", target_freq_idx);

    float tmprst;

    s_task_handle = xTaskGetCurrentTaskHandle();

    fft_init();

    /* ADC initial */
    adc_continuous_handle_t adc_handle = NULL;
    continuous_adc_init(channel, sizeof(channel) / sizeof(adc_channel_t),
                        &adc_handle);

    /* Register conversion done callback */
    adc_continuous_evt_cbs_t cbs = {
        .on_conv_done = s_conv_done_cb,
    };
    ESP_ERROR_CHECK(
        adc_continuous_register_event_callbacks(adc_handle, &cbs, NULL));
    /* Start ADC */
    ESP_ERROR_CHECK(adc_continuous_start(adc_handle));

    while (1) {
        // Read ADC and fill fft buffer
        do {
            ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
            ADC_READ_CHECK(adc_continuous_read(
                adc_handle, adc_buf + tot_read_num,
                FFT_POINTS * SOC_ADC_DIGI_RESULT_BYTES - tot_read_num, &ret_num,
                0));
            tot_read_num += ret_num;
        } while (tot_read_num < FFT_POINTS * SOC_ADC_DIGI_RESULT_BYTES);
        tot_read_num = 0;

        for (i = 0; i < FFT_POINTS * SOC_ADC_DIGI_RESULT_BYTES;
             i += SOC_ADC_DIGI_RESULT_BYTES) {
            adc_digi_output_data_t *p = (adc_digi_output_data_t *)&adc_buf[i];
            uint32_t chan_num = EXAMPLE_ADC_GET_CHANNEL(p);
            if (chan_num >= SOC_ADC_CHANNEL_NUM(EXAMPLE_ADC_UNIT)) {
                ESP_LOGW(TAG, "invalid data");
                continue;
            }
            // Real part of signal
            fft_buf[2 * (i / SOC_ADC_DIGI_RESULT_BYTES) + 0] =
                (float)EXAMPLE_ADC_GET_DATA(p) *
                wind[i / SOC_ADC_DIGI_RESULT_BYTES];
            // Only real part
            fft_buf[2 * (i / SOC_ADC_DIGI_RESULT_BYTES) + 1] = 0;
        }
        // FFT Radix-2
        dsps_fft2r_fc32(fft_buf, FFT_POINTS);
        dsps_bit_rev2r_fc32(fft_buf, FFT_POINTS);
        dsps_cplx2real_fc32(fft_buf, FFT_POINTS);

        for (i = 0; i < FFT_POINTS / 2; ++i) {
            if (i < unwanted_freq_idx) {
                // I don't need DC and low frequency component so remove it
                spectrum[i] = 0;
                continue;
            }
            spectrum[i] = sqrtf(fft_buf[i * 2] * fft_buf[i * 2] +
                                fft_buf[i * 2 + 1] * fft_buf[i * 2 + 1]) /
                          FFT_POINTS;
            // ESP_LOGI(TAG, "spectrum[%u]: %f", i, spectrum[i]);
        }
        tmprst = findmax(&spectrum[target_freq_idx - 2], 4);
        ESP_LOGI(TAG, "tmprst: %f", tmprst);

        // Do not starve watch dog as print is slow
        vTaskDelay(1);
    }
}

#define ESP_BLE_MESH_VND_MODEL_OP_SEND ESP_BLE_MESH_MODEL_OP_3(0x00, CID_ESP)
#define ESP_BLE_MESH_VND_MODEL_OP_STATUS ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP)

#define ESP_BLE_MESH_VND_MODEL_ID_SERVER 0x0001
#define ESP_BLE_MESH_VND_MODEL_ID_CLIENT 0x0000

#define MSG_TIMEOUT 0

#define CID_ESP 0x02E5

// All rx EXCEPT the center node subscribe to this address
#define RX_GROUP_ADDR 0xC000

/* Remember to use different NODE_ID to indentify different ESP32
* For now NODE_ID should from 0 to 11
*/
const uint32_t NODE_ID = 0;

static uint8_t dev_uuid[16] = { 0xdd, 0xdd };

struct example_info_store {
    uint16_t net_idx; /* NetKey Index */
    uint16_t app_idx; /* AppKey Index */
} __attribute__((packed));

static struct example_info_store store = {
    .net_idx = ESP_BLE_MESH_KEY_UNUSED,
    .app_idx = ESP_BLE_MESH_KEY_UNUSED,
};


struct ble_packet my_ble_packet = {
    .id = (uint8_t) NODE_ID,
};

SemaphoreHandle_t ble_packet_mutex;

static nvs_handle_t NVS_HANDLE;
static const char *NVS_KEY = "onoff_client";

static esp_ble_mesh_cfg_srv_t config_server = {
    /* 3 transmissions with 20ms interval */
    .net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
    .relay = ESP_BLE_MESH_RELAY_DISABLED,
    .beacon = ESP_BLE_MESH_BEACON_ENABLED,
#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER)
    .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED,
#else
    .gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED,
#endif
#if defined(CONFIG_BLE_MESH_FRIEND)
    .friend_state = ESP_BLE_MESH_FRIEND_ENABLED,
#else
    .friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED,
#endif
    .default_ttl = 0,
};

static esp_ble_mesh_model_t root_models[] = {
    ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
};

static const esp_ble_mesh_client_op_pair_t vnd_op_pair[] = {
    { ESP_BLE_MESH_VND_MODEL_OP_SEND, ESP_BLE_MESH_VND_MODEL_OP_STATUS },
};

static esp_ble_mesh_client_t vendor_client = {
    .op_pair_size = ARRAY_SIZE(vnd_op_pair),
    .op_pair = vnd_op_pair,
};

static esp_ble_mesh_model_op_t vnd_server_op[] = {
    ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_SEND, 2),
    ESP_BLE_MESH_MODEL_OP_END,
};

static esp_ble_mesh_model_op_t vnd_cli_op[] = {
    ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_STATUS, 2),
    ESP_BLE_MESH_MODEL_OP_END,
};

static esp_ble_mesh_model_t vnd_models[] = {
    ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_SERVER,
                              vnd_server_op, NULL, NULL),
    ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_CLIENT,
                              vnd_cli_op, NULL, &vendor_client),
};

static esp_ble_mesh_elem_t elements[] = {
    ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models),
};

static esp_ble_mesh_comp_t composition = {
    .cid = CID_ESP,
    .element_count = ARRAY_SIZE(elements),
    .elements = elements,
};

/* Disable OOB security for SILabs Android app */
static esp_ble_mesh_prov_t provision = {
    .uuid = dev_uuid,
#if 0
    .output_size = 4,
    .output_actions = ESP_BLE_MESH_DISPLAY_NUMBER,
    .input_size = 4,
    .input_actions = ESP_BLE_MESH_PUSH,
#else
    .output_size = 0,
    .output_actions = 0,
#endif
};

static void mesh_example_info_store(void)
{
    ble_mesh_nvs_store(NVS_HANDLE, NVS_KEY, &store, sizeof(store));
}

static void example_ble_mesh_send_vendor_message(uint8_t target)
{
    esp_ble_mesh_msg_ctx_t ctx = { 0 };
    uint32_t opcode;
    esp_err_t err = ESP_OK;

    ctx.net_idx = store.net_idx;
    ctx.app_idx = store.app_idx;
    ctx.addr = target == 0 ? RX_GROUP_ADDR : 0x0003;
    ctx.send_ttl = 0;
    opcode = ESP_BLE_MESH_VND_MODEL_OP_SEND;

    if (ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED ||
        ctx.app_idx == ESP_BLE_MESH_KEY_UNUSED || vendor_client.model == NULL) {
        if (vendor_client.model == NULL) {
            ESP_LOGE(TAG, "NULL client model");
        }
        return;
    }
    if (target == 0) {
        err = esp_ble_mesh_client_model_send_msg(vendor_client.model, &ctx,
                                                 opcode, sizeof(NODE_ID),
                                                 (uint8_t *)&NODE_ID,
                                                 MSG_TIMEOUT, false, ROLE_NODE);
        vTaskDelay(1);
    } else {
        xSemaphoreTake(ble_packet_mutex, portMAX_DELAY);
        err = esp_ble_mesh_client_model_send_msg(vendor_client.model, &ctx,
                                                 opcode, sizeof(my_ble_packet),
                                                 (uint8_t *)&my_ble_packet,
                                                 MSG_TIMEOUT, false, ROLE_NODE);
        ESP_LOGI(TAG, "tmprst: %.2f", my_ble_packet.fftrst);
        xSemaphoreGive(ble_packet_mutex);
        vTaskDelay(1);
    }
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to send vendor message 0x%06" PRIx32, opcode);
        ESP_LOGE(TAG, "target == %u", target);
        vTaskDelay(2000 / portMAX_DELAY);
        return;
    }
}

static void broadcast_task(void *pvParameters)
{
    static uint8_t cnt = 0;
    uint32_t r;
    while (1) {
        // Broadcast
        // I don't know if BLE Mesh have something like CSMA/CA or not
        // If all nodes broadcast message at same time, it seems some send operation would fail
        // Here I'll simply delay a random time
        // I don't know would this do the trick but let's have a try
        r = esp_random() % 600 + 400;
        vTaskDelay(r / portTICK_PERIOD_MS);

        example_ble_mesh_send_vendor_message(0);
        if (++cnt >= 2) {
            cnt = 0;
            vTaskDelay(100 / portTICK_PERIOD_MS);
            example_ble_mesh_send_vendor_message(1);
        }
    }
}

static void mesh_example_info_restore(void)
{
    esp_err_t err = ESP_OK;
    bool exist = false;

    err = ble_mesh_nvs_restore(NVS_HANDLE, NVS_KEY, &store, sizeof(store),
                               &exist);
    if (err != ESP_OK) {
        return;
    }

    if (exist) {
        ESP_LOGI(TAG, "Restore, net_idx 0x%04x, app_idx 0x%04x", store.net_idx,
                 store.app_idx);
    }
}

static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags,
                          uint32_t iv_index)
{
    ESP_LOGI(TAG, "net_idx: 0x%04x, addr: 0x%04x", net_idx, addr);
    ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08" PRIx32, flags, iv_index);
    store.net_idx = net_idx;
    /* mesh_example_info_store() shall not be invoked here, because if the device
     * is restarted and goes into a provisioned state, then the following events
     * will come:
     * 1st: ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT
     * 2nd: ESP_BLE_MESH_PROV_REGISTER_COMP_EVT
     * So the store.net_idx will be updated here, and if we store the mesh example
     * info here, the wrong app_idx (initialized with 0xFFFF) will be stored in nvs
     * just before restoring it.
     */
}

static void
example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event,
                                 esp_ble_mesh_prov_cb_param_t *param)
{
    switch (event) {
    case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT:
        ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code %d",
                 param->prov_register_comp.err_code);
        mesh_example_info_restore(); /* Restore proper mesh example info */
        break;
    case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT:
        ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code %d",
                 param->node_prov_enable_comp.err_code);
        break;
    case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT:
        ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer %s",
                 param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ?
                     "PB-ADV" :
                     "PB-GATT");
        break;
    case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT:
        ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer %s",
                 param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ?
                     "PB-ADV" :
                     "PB-GATT");
        break;
    case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:
        ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT");
        prov_complete(param->node_prov_complete.net_idx,
                      param->node_prov_complete.addr,
                      param->node_prov_complete.flags,
                      param->node_prov_complete.iv_index);
        break;
    case ESP_BLE_MESH_NODE_PROV_RESET_EVT:
        break;
    case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT:
        ESP_LOGI(TAG,
                 "ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, err_code %d",
                 param->node_set_unprov_dev_name_comp.err_code);
        break;
    default:
        break;
    }
}

static void
example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t event,
                                  esp_ble_mesh_cfg_server_cb_param_t *param)
{
    if (event == ESP_BLE_MESH_CFG_SERVER_STATE_CHANGE_EVT) {
        switch (param->ctx.recv_op) {
        case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD:
            ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD");
            ESP_LOGI(TAG, "net_idx 0x%04x, app_idx 0x%04x",
                     param->value.state_change.appkey_add.net_idx,
                     param->value.state_change.appkey_add.app_idx);
            ESP_LOG_BUFFER_HEX(
                "AppKey", param->value.state_change.appkey_add.app_key, 16);
            break;
        case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND:
            ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND");
            ESP_LOGI(
                TAG,
                "elem_addr 0x%04x, app_idx 0x%04x, cid 0x%04x, mod_id 0x%04x",
                param->value.state_change.mod_app_bind.element_addr,
                param->value.state_change.mod_app_bind.app_idx,
                param->value.state_change.mod_app_bind.company_id,
                param->value.state_change.mod_app_bind.model_id);

            store.app_idx = param->value.state_change.mod_app_bind.app_idx;
            mesh_example_info_store(); /* Store proper mesh example info */

            ESP_ERROR_CHECK(esp_ble_mesh_model_subscribe_group_addr(
                esp_ble_mesh_get_primary_element_address(), CID_ESP,
                ESP_BLE_MESH_VND_MODEL_ID_SERVER, RX_GROUP_ADDR));

            xTaskCreate(broadcast_task, "broadcast_task", 4096, NULL, 3, NULL);
            break;
        default:
            break;
        }
    }
}

static void
server_ble_mesh_custom_model_cb(esp_ble_mesh_model_cb_event_t event,
                                esp_ble_mesh_model_cb_param_t *param)
{
    switch (event) {
    case ESP_BLE_MESH_MODEL_OPERATION_EVT:
        if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_SEND) {
            uint32_t tmp =
                *(uint32_t *)param->model_operation.msg;

            if (tmp == NODE_ID) {
                break;
            }
            xSemaphoreTake(ble_packet_mutex, portMAX_DELAY);
            my_ble_packet.arr[tmp] =
                param->model_operation.ctx->recv_rssi;

            // ESP_LOGI(TAG, "id: %u, rssi %d", tmp.id, my_ble_packet.arr[tmp.id]);
            xSemaphoreGive(ble_packet_mutex);
        }
        break;
    default:
        break;
    }
}

static esp_err_t ble_mesh_init(void)
{
    esp_err_t err = ESP_OK;

    esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb);
    esp_ble_mesh_register_config_server_callback(
        example_ble_mesh_config_server_cb);
    esp_ble_mesh_register_custom_model_callback(
        server_ble_mesh_custom_model_cb);

    err = esp_ble_mesh_init(&provision, &composition);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize mesh stack (err %d)", err);
        return err;
    }

    err = esp_ble_mesh_client_model_init(&vnd_models[1]);
    if (err) {
        ESP_LOGE(TAG, "Failed to initialize vendor client");
        return err;
    }

    err = esp_ble_mesh_node_prov_enable(
        (esp_ble_mesh_prov_bearer_t)(ESP_BLE_MESH_PROV_ADV |
                                     ESP_BLE_MESH_PROV_GATT));
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to enable mesh node (err %d)", err);
        return err;
    }

    ESP_LOGI(TAG, "BLE Mesh Node initialized");

    return err;
}

void app_main(void)
{
    esp_err_t err;

    ESP_LOGI(TAG, "Node id %lu", NODE_ID);
    ESP_LOGI(TAG, "Initializing...");

    ble_packet_mutex = xSemaphoreCreateMutex();
    if (!ble_packet_mutex) {
        ESP_LOGE(TAG, "Create mutex failed, return");
        return;
    }

    my_ble_packet.fftrst = 0;
    for(uint8_t i = 0; i < 12; ++i) {
        my_ble_packet.arr[i] = 0;
    }

    err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);

    err = bluetooth_init();
    if (err) {
        ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err);
        return;
    }

    /* Open nvs namespace for storing/restoring mesh example info */
    err = ble_mesh_nvs_open(&NVS_HANDLE);
    if (err) {
        return;
    }

    ble_mesh_get_dev_uuid(dev_uuid);

    /* Initialize the Bluetooth Mesh Subsystem */
    err = ble_mesh_init();
    if (err) {
        ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err);
        return;
    }

    if (store.app_idx != ESP_BLE_MESH_KEY_UNUSED) {
        ESP_ERROR_CHECK(esp_ble_mesh_model_subscribe_group_addr(
            esp_ble_mesh_get_primary_element_address(), CID_ESP,
            ESP_BLE_MESH_VND_MODEL_ID_SERVER, RX_GROUP_ADDR));
        ESP_LOGI(TAG, "Start broadcast task");
        xTaskCreate(broadcast_task, "broadcast_task", 4096, NULL, 3, NULL);
    }

    ESP_LOGI(TAG, "Start ADC sampling and perform FFT");
    xTaskCreate(adc_fft_task, "adc_fft_task", 8192, NULL, 4, NULL);
}

Debug Logs.

No response

More Information.

No response

@UncleBigLu UncleBigLu added the Type: Bug bugs in IDF label Dec 3, 2024
@github-actions github-actions bot changed the title Continuous ADC stops working while BLE Mesh is on Continuous ADC stops working while BLE Mesh is on (IDFGH-14171) Dec 3, 2024
@espressif-bot espressif-bot added the Status: Opened Issue is new label Dec 3, 2024
@Haerteleric
Copy link

Faced the same problem. I Think you have to move the ADC Funcs into IRAM. There is a Menuconfig option for that:

CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE=y

@UncleBigLu
Copy link
Author

CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE=y

Well It works! Thanks Haerteleric :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Opened Issue is new Type: Bug bugs in IDF
Projects
None yet
Development

No branches or pull requests

4 participants