espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
12.57k stars 7.02k forks source link

Using ESPIDF to program on ESP32-C6 for receiving data with SPI (IDFGH-12704) #13691

Closed Rickxiaoxin closed 2 weeks ago

Rickxiaoxin commented 2 weeks ago

Answers checklist.

IDF version.

5.2.1

Espressif SoC revision.

ESP32-C6

Operating System used.

Windows

How did you build your project?

VS Code IDE

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

PowerShell

Development Kit.

ESP32-C6-DevKitC-1

Power Supply used.

USB

What is the expected behavior?

can obtain stable data like this image

What is the actual behavior?

can't obtain stable data image

Steps to reproduce.

this is my code.

static void IRAM_ATTR gpio_isr_handler(void *arg)
{
    uint32_t gpio_num = (uint32_t)arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}

static void gpio_task(void *arg)
{
    uint32_t io_num;
    uint8_t val[9] = {0};
    for (;;)
    {
        if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY))
        {

            for (int i = 0; i < 9; i++)
            {
                val[i] = ads1292r_receive_data(spi_handle);
            }
            printf("%x %x %x %x %x %x %x %x %x \n", val[0], val[1], val[2],
                   val[3], val[4], val[5],
                   val[6], val[7], val[8]);
            usleep(3000);
        }
    }
}

void app_main(void)
{
    // gpio config
    gpio_config_t io_conf;
    io_conf.intr_type = GPIO_INTR_DISABLE;
    io_conf.mode = GPIO_MODE_OUTPUT;
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    io_conf.pull_down_en = 0;
    io_conf.pull_up_en = 0;
    gpio_config(&io_conf);
    io_conf.mode = GPIO_MODE_INPUT;
    io_conf.pin_bit_mask = BIT64(GPIO_DRDY);
    io_conf.pull_down_en = 0;
    io_conf.pull_up_en = 1;
    io_conf.intr_type = GPIO_INTR_NEGEDGE;
    gpio_config(&io_conf);

    // gpio isr
    gpio_evt_queue = xQueueCreate(100, sizeof(uint32_t));
    xTaskCreate(gpio_task, "gpio_task", 4096, NULL, 15, NULL);
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    gpio_isr_handler_add(GPIO_DRDY, gpio_isr_handler, (void *)GPIO_DRDY);

    // uart config
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
    };
    uart_driver_install(UART_NUM_0, 512 * 2, 0, 0, NULL, 0);
    uart_param_config(UART_NUM_0, &uart_config);
    uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    // spi config
    spi_bus_config_t spi_bus_cfg = {
        .mosi_io_num = GPIO_MOSI,
        .miso_io_num = GPIO_MISO,
        .sclk_io_num = GPIO_SCLK,
        .quadhd_io_num = -1,
        .quadwp_io_num = -1,
    };
    spi_bus_initialize(SPI2_HOST, &spi_bus_cfg, SPI_DMA_CH_AUTO);
    spi_device_interface_config_t dev_cfg = {
        .clock_speed_hz = 1 * 1000 * 1000,
        .mode = 1,
        .spics_io_num = -1,
        .queue_size = 1,
    };
    spi_bus_add_device(SPI2_HOST, &dev_cfg, &spi_handle);

    ads1292r_init(spi_handle);
}

Debug Logs.

no error was reported

More Information.

I'm using esp32-c6 and ads1292r to acquire ECG data. I have successfully established communication with the ADS1292R through SPI and am able to write to and read from the ADS1292R registers. I also use gpio interrupt to send queue, and create task to receive queue, then receive data from ads1292r. When I set sample rate to 125Hz, I can receive stable data from ads1292r without connecting to body. However, I can't obtain stable data when I set sample rate to 250Hz, and the received data is misaligned and wrong. I think this might be due to issues with FreeRTOS task scheduling,but I'm not certain and don't know how to address this problem.I want to achieve to obtain right data .I would appreciate it if someone could give me some help!

nopnop2002 commented 2 weeks ago

It's most likely a printf issue. What happens if you change printf to ESP_LOGx?

            printf("%x %x %x %x %x %x %x %x %x \n", val[0], val[1], val[2],
                   val[3], val[4], val[5],
                   val[6], val[7], val[8]);
wanckl commented 2 weeks ago
for (int i = 0; i < 9; i++)
    {
        val[i] = ads1292r_receive_data(spi_handle);
    }

Seems you using SPI read only 1 byte for 1 transaction, ,,there may some order issue, this chip should support read 1 pack(9 bytes) in one transaction, that should more stable.

And then, what the convention resolution you set for 250Hz, different resolution need different time to finish convention.

And SPI transaction also need time, refer to your datasheet bellow, you can also increase your SPI bus frequency. image

Rickxiaoxin commented 2 weeks ago

It's most likely a printf issue. What happens if you change printf to ESP_LOGx?

            printf("%x %x %x %x %x %x %x %x %x \n", val[0], val[1], val[2],
                   val[3], val[4], val[5],
                   val[6], val[7], val[8]);

@nopnop2002 I'm very sorry for the late response. I feel that the issue may lie in SPI communication. Currently, I'm using polling instead of interrupts for SPI communication and have lowered the sampling rate to ensure receiving correct information.I will try the method you mentioned and will reply later with the results.

Rickxiaoxin commented 2 weeks ago
for (int i = 0; i < 9; i++)
    {
        val[i] = ads1292r_receive_data(spi_handle);
    }

Seems you using SPI read only 1 byte for 1 transaction, ,,there may some order issue, this chip should support read 1 pack(9 bytes) in one transaction, that should more stable.

And then, what the convention resolution you set for 250Hz, different resolution need different time to finish convention.

And SPI transaction also need time, refer to your datasheet bellow, you can also increase your SPI bus frequency. image

@wanckl I'm very sorry for the late response.I previously used the same settings in STM32, and I could receive correct information. Initially, I was communicating by receiving 9 bytes at once, which also encountered the aforementioned issue. Later, I changed it to receive one byte at a time. The problem was resolved after I disabled the task watchdog and interrupt watchdog, and set FreeRTOS config tick=100 to 1000. However, I'm not sure why this resolved the issue.

nopnop2002 commented 2 weeks ago

I disabled the task watchdog and interrupt watchdog

usleep(10000) and vTaskDelay(1) both wait 10ms, but using usleep will cause a TaskWatchDog alert regardless of the wait time.

// TaskWatchDog alerts are not fired.
while(1) {
  vTaskDelay(1); // wait for 10mSec
}
// TaskWatchDog alerts are fired.
while(1) {
  usleep(10000); // wait for 10mSec
}

If you use usleep, you must disable task watchdog. If you disable TaskWatchDog, there is no need to wait at all.

static void gpio_task(void *arg)
{
    uint32_t io_num;
    uint8_t val[9] = {0};
    for (;;)
    {
        if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY))
        {

            for (int i = 0; i < 9; i++)
            {
                val[i] = ads1292r_receive_data(spi_handle);
            }
            printf("%x %x %x %x %x %x %x %x %x \n", val[0], val[1], val[2],
                   val[3], val[4], val[5],
                   val[6], val[7], val[8]);
            //usleep(3000);
        }
    }
}
Rickxiaoxin commented 2 weeks ago

I disabled the task watchdog and interrupt watchdog

usleep(10000) and vTaskDelay(1) both wait 10ms, but using usleep will cause a TaskWatchDog alert regardless of the wait time.

// TaskWatchDog alerts are not fired.
while(1) {
  vTaskDelay(1); // wait for 10mSec
}
// TaskWatchDog alerts are fired.
while(1) {
  usleep(10000); // wait for 10mSec
}

If you use usleep, you must disable task watchdog. If you disable TaskWatchDog, there is no need to wait at all.

static void gpio_task(void *arg)
{
    uint32_t io_num;
    uint8_t val[9] = {0};
    for (;;)
    {
        if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY))
        {

            for (int i = 0; i < 9; i++)
            {
                val[i] = ads1292r_receive_data(spi_handle);
            }
            printf("%x %x %x %x %x %x %x %x %x \n", val[0], val[1], val[2],
                   val[3], val[4], val[5],
                   val[6], val[7], val[8]);
            //usleep(3000);
        }
    }
}

@nopnop2002 Thank you very much. Now I know function usleep will trigger the task watchdog, I will try it!

nopnop2002 commented 2 weeks ago

Now I know function usleep will trigger the task watchdog

To be precise, usleep() cannot avoid TaskWatchDog alerts.

Rickxiaoxin commented 2 weeks ago

Now I know function usleep will trigger the task watchdog

To be precise, usleep() cannot avoid TaskWatchDog alerts.

So only the vTaskDelay() function can avoid TaskWatchDog alerts?

nopnop2002 commented 2 weeks ago

So only the vTaskDelay() function can avoid TaskWatchDog alerts?

Yes. You are right.

I think esp_task_wdt_reset() can also avoid TaskWatchDog alerts.