Page 1 of 1

Buffer size limits

Posted: Fri Jun 23, 2023 6:46 am
by TomasCZ
Hello guys, I would like to ask you if there is some limit of the buffer size of the I2C_SLAVE_RX_BUF_LEN 2048. We are trying to read I2C data sent from a master device to an OLED display. If we increase the buffer size over 2048 the code starts to work incorrectly and if it is more than 3344 the board starts to restart itself after flash continously.

e.g. if I increase the buffer size to 4096 the following messages appear continously round and round.

Code: Select all

Rebooting...
ets Jul 29 2019 12:21:46

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:6940
ho 0 tail 12 room 4
load:0x40078000,len:15500
load:0x40080400,len:3844
0x40080400: _init at ??:?

entry 0x4008064c
I (29) boot: ESP-IDF v5.0.2 2nd stage bootloader
I (29) boot: compile time 16:23:53
I (29) boot: chip revision: v3.0
I (32) boot.esp32: SPI Speed      : 40MHz
I (37) boot.esp32: SPI Mode       : DIO
I (41) boot.esp32: SPI Flash Size : 2MB
I (46) boot: Enabling RNG early entropy source...
I (51) boot: Partition Table:
I (55) boot: ## Label            Usage          Type ST Offset   Length
I (62) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (70) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (77) boot:  2 factory          factory app      00 00 00010000 00100000
I (85) boot: End of partition table
I (89) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=09de4h ( 40420) map
I (112) esp_image: segment 1: paddr=00019e0c vaddr=3ffb0000 size=01f14h (  7956) load
I (115) esp_image: segment 2: paddr=0001bd28 vaddr=40080000 size=042f0h ( 17136) load
I (125) esp_image: segment 3: paddr=00020020 vaddr=400d0020 size=1779ch ( 96156) map
I (161) esp_image: segment 4: paddr=000377c4 vaddr=400842f0 size=08bc8h ( 35784) load
I (182) boot: Loaded app from partition at offset 0x10000
I (182) boot: Disabling RNG early entropy source...
I (194) cpu_start: Pro cpu up.
I (194) cpu_start: Starting app cpu, entry point is 0x40081160
0x40081160: call_start_cpu1 at C:/Users/konec/esp/esp-idf/components/esp_system/port/cpu_start.c:141

I (180) cpu_start: App cpu up.
I (208) cpu_start: Pro cpu start user code
I (208) cpu_start: cpu freq: 160000000 Hz
I (208) cpu_start: Application information:
I (213) cpu_start: Project name:     Sniffer_test
I (219) cpu_start: App version:      1
I (223) cpu_start: Compile time:     Jun 16 2023 16:23:24
I (229) cpu_start: ELF file SHA256:  52b45009886ec246...
I (235) cpu_start: ESP-IDF:          v5.0.2
I (240) cpu_start: Min chip rev:     v0.0
I (245) cpu_start: Max chip rev:     v3.99
I (249) cpu_start: Chip rev:         v3.0
I (254) heap_init: Initializing. RAM available for dynamic allocation:
I (262) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (267) heap_init: At 3FFB2810 len 0002D7F0 (181 KiB): DRAM
I (274) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (280) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (286) heap_init: At 4008CEB8 len 00013148 (76 KiB): IRAM
I (294) spi_flash: detected chip: generic
I (297) spi_flash: flash io: dio
W (301) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (315) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (326) i2c-slave: I2C Slave initialized successfully

***ERROR*** A stack overflow in task main has been detected.


Backtrace: 0x40081bea:0x3ffb3810 0x40086a6d:0x3ffb3830 0x400897ae:0x3ffb3850 0x4008864f:0x3ffb38d0 0x40086b68:0x3ffb38f0 0x40086b1a:0xa5a5a5a5 |<-CORRUPTED
0x40081bea: panic_abort at C:/Users/konec/esp/esp-idf/components/esp_system/panic.c:423

0x40086a6d: esp_system_abort at C:/Users/konec/esp/esp-idf/components/esp_system/esp_system.c:153

0x400897ae: vApplicationStackOverflowHook at C:/Users/konec/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:391

0x4008864f: vTaskSwitchContext at C:/Users/konec/esp/esp-idf/components/freertos/FreeRTOS-Kernel/tasks.c:3647

0x40086b68: _frxt_dispatch at C:/Users/konec/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S:418

0x40086b1a: _frxt_int_exit at C:/Users/konec/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S:213





ELF file SHA256: 52b45009886ec246



The code:

Code: Select all

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include "esp_log.h"
#include "driver/i2c.h"
#include "rom/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

static const char *TAG = "i2c-slave";

#define I2C_SLAVE_SCL_IO 22               /*!< gpio number for I2C master clock */
#define I2C_SLAVE_SDA_IO 21               /*!< gpio number for I2C master data  */
#define I2C_SLAVE_FREQ_HZ 100000        /*!< I2C master clock frequency */
#define I2C_SLAVE_TX_BUF_LEN 255                        /*!< I2C master doesn't need buffer */
#define I2C_SLAVE_RX_BUF_LEN 2048                           /*!< I2C master doesn't need buffer */
#define ESP_SLAVE_ADDR 0x3C

#define WRITE_BIT I2C_MASTER_WRITE              /*!< I2C master write */
#define READ_BIT I2C_MASTER_READ                /*!< I2C master read */
#define ACK_CHECK_EN 0x0                        /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0                       /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x1                             /*!< I2C ack value */
#define NACK_VAL 0x1                            /*!< I2C nack value */

#define portTICK_PERIOD_MS ( ( TickType_t ) ( 1000 / configTICK_RATE_HZ ) )
#define CONFIG_FREERTOS_HZ 1000

int i2c_slave_port = 1;
static esp_err_t i2c_slave_init(void)
{
  
    i2c_config_t conf_slave = {
    .sda_io_num = I2C_SLAVE_SDA_IO,          // select GPIO specific to your project
    .sda_pullup_en = GPIO_PULLUP_ENABLE,
    .scl_io_num = I2C_SLAVE_SCL_IO,          // select GPIO specific to your project
    .scl_pullup_en = GPIO_PULLUP_ENABLE,
    .mode = I2C_MODE_SLAVE,
    .slave.addr_10bit_en = 0,
    .slave.slave_addr = ESP_SLAVE_ADDR,      // address of your project
    .clk_flags = 0,
    };
    esp_err_t err = i2c_param_config(i2c_slave_port, &conf_slave);
    if (err != ESP_OK) {
        return err;
    }
    return i2c_driver_install(i2c_slave_port, conf_slave.mode, I2C_SLAVE_RX_BUF_LEN, I2C_SLAVE_TX_BUF_LEN, 0);
}

char * hex_bytes(size_t len, unsigned char * data)
{
	size_t reslen = len * 3 + 5;
	char * result = (char * ) malloc(reslen);
	char buf[5];
	result[0] = 0;
	
	for (int i = 0; i < len; i++)
	{
			snprintf(buf, 5, " %02X", data[i]);
			strcat(result, buf);
	}
	return result;
}

void app_main(void)
{
    uint8_t  received_data[I2C_SLAVE_RX_BUF_LEN] = {0};
    
    ESP_ERROR_CHECK(i2c_slave_init());
    ESP_LOGI(TAG, "I2C Slave initialized successfully");
    
    while(1)
    {
    int len = i2c_slave_read_buffer(i2c_slave_port, received_data, I2C_SLAVE_RX_BUF_LEN, 10 / portTICK_PERIOD_MS);
    if (len > 0)
    {
        received_data[len] = 0;
               
        char * str = hex_bytes(len, received_data);
        ESP_LOGI(TAG, "Received %s\n", str);
        free(str);

    }
    //ESP_LOGI(TAG, "Data Recived = %s", received_data);
    }
}

Re: Buffer size limits

Posted: Fri Jun 23, 2023 7:20 pm
by MicroController
***ERROR*** A stack overflow in task main has been detected.
Cause:

Code: Select all

void app_main(void)
{
    uint8_t  received_data[I2C_SLAVE_RX_BUF_LEN] = {0};
The variable "received_data" is allocated on the stack, because it's a local variable to the function. And the main task's stack of 3.5 kb (default) is not big enough for 2 or 4 kb of received_data and the other stuff it needs to hold.

Make received_data a (static) global variable or allocate it from the heap.

Re: Buffer size limits

Posted: Sun Jun 25, 2023 7:41 pm
by TomasCZ
The variable "received_data" is allocated on the stack, because it's a local variable to the function. And the main task's stack of 3.5 kb (default) is not big enough for 2 or 4 kb of received_data and the other stuff it needs to hold.

Make received_data a (static) global variable or allocate it from the heap.
Thanks a lot. Your post helped a lot. We used the heap way and 8k buffer and after several months of finding the way how to sniff the data we've got it. :D :D :D