Dev-Branch

Musste gerade feststellen, dass ich das gleiche Problem habe. Ich kann den aktuellen DEV-Branch mit Port-Expander auch nicht mehr kompilieren. Das kriege ich mit „clean all“ auch nicht mehr eingefangen.

Das habe ich eben noch gefunden: "region `iram0_0_seg' overflowed" (when optimizations are off) but IRAM seems to be nearly not used (IDFGH-5133) · Issue #6914 · espressif/esp-idf · GitHub

Hat sich eventuell eine Lib im Hintergrund geändert die jetzt mehr RAM braucht. Werde heute Abend mal versuchen bisschen nachzuvollziehen was da passiert.
Lässt sich aber definitiv so nachstellen auch bei einer komplett neu aufgesetzten Umgebung.

Schonmal eine Erkenntnis:
Unsere Memory_Config sieht wie folgt aus:

Memory Configuration

Name             Origin             Length             Attributes
iram0_0_seg      0x0000000040080000 0x0000000000020000 xr
iram0_2_seg      0x00000000400d0020 0x000000000032ffe0 xr

Scheinbar wird alles was Lib ist wird in die Section iram0_0 gepackt.
Ohne den Portexpander haben wir noch etwa 1600 Bytes (von 128K) in dieser Sektion übrig.
Mit dann entsprechend weniger…
Die deutlich größere Sektion (iram0_2_seg) hat aber noch massenhaft platz.
Weiß jemand wo die Zusweisung der Sektionen stattfindet? Habe auf die Schnelle kein Linkerfile gefunden…

1 „Gefällt mir“

Es beruhigt mich schon mal, dass ich nicht der einzige bin. Gestern Abend war ich mir dann auch irgendwann immer sicherer, dass es kein komisches Phänomen sondern tatsächlich ein Überschreiten des Speicherbereichs sein muss.

1 „Gefällt mir“

Ich bekomme jetzt auch den Linker-Fehler. Habe einmal Bluetooth deaktiviert (das Modul ist ja Resourcen hungrig), danach klappt es. In Platform-IO Home/Inspect kann man sich den Speicherverbrauch anzeigen lasse. Ein Vergleich Master/Dev bei gleichen Settings:

Master :
.iram0.text	SHT_PROGBITS	AX	0x40080404	 95.6 KB

Dev-Branch :
.iram0.text	SHT_PROGBITS	WAX	0x40080400	126.8 KB

Wir sind bei 128KB anscheinend am Ende. Frage ist was da soviel IRAM-Speicher verbraucht und wie man das löst. Da kenne ich mich leider überhaupt nicht aus…

2 „Gefällt mir“

Das habe ich mir schon gedacht , weil es anders total unlogisch wäre.
Ich habe es heute nochmals getestet und zwar wie schon vorher mit meinem neuen Develboard und LiFePo4. Das läuft ohne Hardware (die Stiftleisten sind noch garnicht angelötet) und es spielt garantiert keine Musik ab, die Akkuspannug und die 3,3V hinter dem Buck-Boost-Converter sind auch absolut stabil . Die angezeigten Werte sind zeitgleich entnommen und schwanken auch nicht.
Ich hatte etwas ähnliches schon einmal angemerkt, konnte es aber dann nicht mehr richtig nachstellen.
Eigentlich ist es mir egal, aber mit LiFePo4 sind 0,5V schon einen Menge und führen dann evtl. zu einer fehlerhaften Spannungsanzeige der LED. Ich kann das leider selbst im Code nicht nachvollziehen.
VG

@laszloh
gleiche Hardware aber Master vom 8.3.2023

Freier PSRAM: 4169296
Aktuelle IP: 192.168.178.29
WLAN-Signalstaerke: -50 dBm
Aktuelle Batteriespannung: 3.29 V
Aktuelle Batterieladung: 95.55 %

[ 6217 ] ws[/ws][1] connect
[ 6305 ] no cover image for SD-card audio
[ 10006 ] Aktuelle Batteriespannung: 3.30 V
[ 10008 ] Aktuelle Batterieladung: 97.16 %
[ 11534 ] ws[/ws][1] disconnect
[ 30001 ] Keine Bootschleife erkannt. Wunderbar :slight_smile:

sieht doch gut aus

Gibt scheinbar verschiedene Optionen um den iram runter zu bekommen, ich bekomme diese Defines allerdings entweder nicht wirksam oder sie machen keinen Unterschied. Ein richtiges Linkerfile o.ä. scheint es nicht zu geben…

Vielleicht kann das weiterhelfen:
Siehe Kapitel: Optimizing IRAM Usage
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/performance/ram-usage.html

Ich habe mal gegen den Master gecheckt mit allen verfügbaren Funktionen PORT_EXPANDER_ENABLE + MDNS_ENABLE + MQTT_ENABLE + FTP_ENABLE + NEOPIXEL_ENABLE + BLUETOOTH_ENABLE. Das compiliert & linkt Alles fein im Master und genauso mit Arduino 1.0.6 (3.5.0) als auch 2.0.7,(6.0.1)

Klar sind wir mit all den Funktionen ziemlich am Limit der verfügbaren Resourcen. Aber im Dev-Branch ist scheinbar etwas verschlimmbessert worden?

Vielleicht hat Speicherexperte @laszloh dazu eine Idee?

Ja, bei mir kommt der Linkerfehler auch. Ich habe so zwei Stunden mit dem Ding mal rumgespielt.
Kurz auf österreichisch zusammengefasst: „Des is oarsch“

Der Linkerscript

@Joe91 Es gibt ein Linker script (eigentlich viele, die dnn im Build Prozess zusammengebaut werden). Das für uns interessante ist diese hier: %UserProfile%\.platformio\packages\framework-arduinoespressif32\tools\sdk\esp32\ld\esp32\memory.ld

Da kann man auf Zeile 46 die größe von iram0_0_seg zb auf 0x40000 erhöhen (Vorher ein Backup der Datei machen). Damit läuft der Build durch und man kann im Inspector von Platformio schauen. Aber laufen wird das Programm auf dem ESP nicht, da nach dem iram0 Segment der Heap kommt.

Zum lokalen testen könntet ihr das hier versuchen: How to modify IRAM memory size. (IDFGH-6201) · Issue #7876 · espressif/esp-idf · GitHub

Das verdoppelt das iram0 Segment und nimmt die darauf folgenden Speicherbereiche aus dem Heap raus. Wie und wo genau das in Arduino zu ändern ist habe ich aber noch nicht gefunden (in diesem commit wird auch in die SDK eingegriffen → keine Lösung für uns)

Der Segment iram0_2_seg ist der Memory Map vom Flash (also kein echter RAM, sondern da wird durch die MMU der Flash hinein gemappt). Der Name ist mMn schlecht gewählt, was auch in dem Linkerscript angemerkt ist :slight_smile: .

Auszug aus dem Linkerscript
  /* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
  of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
  are connected to the data port of the CPU and eg allow bytewise access. */
  /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
  iram0_0_seg (RX) : org = 0x40080000, len = 0x20000
  /* Even though the segment name is iram, it is actually mapped to flash
  */
  iram0_2_seg (RX) : org = 0x400D0020, len = 0x330000-0x20
  /*
    (0x20 offset above is a convenience for the app binary image generation.
    Flash cache has 64KB pages. The .bin file which is flashed to the chip
    has a 0x18 byte file header, and each segment has a 0x08 byte segment
    header. Setting this offset makes it simple to meet the flash cache MMU's
    constraint that (paddr % 64KB == vaddr % 64KB).)
  */

Wo ist der Speicher hin?

Was ich bis jetzt gefunden habe, das Segment iram0_0_seg ist 0x20000 (also 131.072 byte groß) besteht aber aus 2 Teilen, dem ISR vector mit 1024 byte und dem Rest (130.048 byte). In diesen gefinden sich alle Funktionen und Interrupt handler, die IRAM-Safe sein müssen.

Welche Funktionen das sind seht ihr (recht unübersichtlich) in der .pio/build/<target>/firmware.map (wird nur bei Arduino 2 generiert, bei 1 kann man es mit dem build_flag -Wl,-Map="out.map erzwingen, der liegt dan im Hauptordner vom Espuino). Dort nach den der adresse von IRAM0 suchen 0x00000000400[89]. Bereitet euch auf viel Scrollen vor, die Datei ist sehr wortreich. Wenn ihr es genau analysieren wollt, gibt es den MapViewer den habe ich aber nicht genauer angeschaut.

In dem IRAM finden sich zB alle Funktionen von FreeRTOS, duzende HW nahen libraries, wifi, bt, flash-spi, etc. Dann gibt es noch den SPI-RAM Bug (Workaround wird mit CONFIG_SPIRAM_CACHE_WORKAROUND aktiviert), der die C Library in den IRAM kopiert (statt die Funktionen im ROM zu verweden). Das wurde erst mit der Chip Revision v3 behoben (welche Version ihr habt seht ihr beim Flashen, dann steht da zB Chip is ESP32-D0WD-V3 (revision v3.0)).

Hier meine Settings:

settings.h

Target: lolin_d32_pro_sdmmc_pe

#ifndef __ESPUINO_SETTINGS_H__
    	#define __ESPUINO_SETTINGS_H__
        #include "Arduino.h"
        #include "values.h"
#if __has_include("settings-override.h")
    	#include "settings-override.h"
#else
	//######################### INFOS ####################################
	// This is the general configfile for ESPuino-configuration.

	//################## HARDWARE-PLATFORM ###############################
	/* Make sure to also edit the configfile, that is specific for your platform.
	If in doubts (your develboard is not listed) use HAL 1
	1: Wemos Lolin32                        => settings-lolin32.h
	2: ESP32-A1S Audiokit                   => settings-espa1s.h
	3: Wemos Lolin D32                      => settings-lolin_D32.h
	4: Wemos Lolin D32 pro                  => settings-lolin_D32_pro.h
	5: Lilygo T8 (V1.7)                     => settings-ttgo_t8.h
	6: ESPuino complete                     => settings-complete.h
	7: Lolin D32 pro SDMMC Port-Expander    => settings-lolin_d32_pro_sdmmc_pe.h
	8: AZDelivery ESP32 NodeMCU             => settings-azdelivery_sdmmc.h
	9: Lolin D32 SDMMC Port-Expander        => settings-lolin_d32_sdmmc_pe.h
	10: RASPIAUDIO Muse Proto               => settings-muse_proto.h
	99: custom                              => settings-custom.h
	more to come...
	*/
	#ifndef HAL             // Will be set by platformio.ini. If using Arduino-IDE you have to set HAL according your needs!
		#define HAL 1       // HAL 1 = LoLin32, 2 = ESP32-A1S-AudioKit, 3 = Lolin D32, 4 = Lolin D32 pro; ... 99 = custom
	#endif


	//########################## MODULES #################################
	#define PORT_EXPANDER_ENABLE          // When enabled, buttons can be connected via port-expander PCA9555 (https://forum.espuino.de/t/einsatz-des-port-expanders-pca9555/306)
	//#define I2S_COMM_FMT_LSB_ENABLE       // Enables FMT instead of MSB for I2S-communication-format. Used e.g. by PT2811. Don't enable for MAX98357a, AC101 or PCM5102A)
	#define MDNS_ENABLE                     // When enabled, you don't have to handle with ESPuino's IP-address. If hostname is set to "ESPuino", you can reach it via ESPuino.local
	//#define MQTT_ENABLE                   // Make sure to configure mqtt-server and (optionally) username+pwd
	#define FTP_ENABLE                      // Enables FTP-server; DON'T FORGET TO ACTIVATE AFTER BOOT BY PRESSING PAUSE + NEXT-BUTTONS (IN PARALLEL)!
	#define NEOPIXEL_ENABLE                 // Don't forget configuration of NUM_LEDS if enabled
	//#define NEOPIXEL_REVERSE_ROTATION     // Some Neopixels are adressed/soldered counter-clockwise. This can be configured here.
	#define LANGUAGE DE                     // DE = deutsch; EN = english
	//#define STATIC_IP_ENABLE              // Enables static IP-configuration (change static ip-section accordingly)
	#define HEADPHONE_ADJUST_ENABLE         // Used to adjust (lower) volume for optional headphone-pcb (refer maxVolumeSpeaker / maxVolumeHeadphone) and to enable stereo (if PLAY_MONO_SPEAKER is set)
	//#define PLAY_MONO_SPEAKER             // If only one speaker is used enabling mono should make sense. Please note: headphones is always stereo (if HEADPHONE_ADJUST_ENABLE is active)
	#define SHUTDOWN_IF_SD_BOOT_FAILS       // Will put ESP to deepsleep if boot fails due to SD. Really recommend this if there's in battery-mode no other way to restart ESP! Interval adjustable via deepsleepTimeAfterBootFails.
	#define MEASURE_BATTERY_VOLTAGE         // Enables battery-measurement via GPIO (ADC) and voltage-divider
	//#define MEASURE_BATTERY_MAX17055      // Enables battery-measurement via external fuel gauge (MAX17055)
	//#define SHUTDOWN_ON_BAT_CRITICAL      // Whether to turn off on critical battery-level (only used if MEASURE_BATTERY_XXX is active)
	//#define PLAY_LAST_RFID_AFTER_REBOOT   // When restarting ESPuino, the last RFID that was active before, is recalled and played
	//#define USE_LAST_VOLUME_AFTER_REBOOT  // Remembers the volume used at last shutdown after reboot
	#define USEROTARY_ENABLE                // If rotary-encoder is used (don't forget to review WAKEUP_BUTTON if you disable this feature!)
	#define BLUETOOTH_ENABLE                // If enabled and bluetooth-mode is active, you can stream to your ESPuino via bluetooth (a2dp-sink).
	//#define IR_CONTROL_ENABLE             // Enables remote control (https://forum.espuino.de/t/neues-feature-fernsteuerung-per-infrarot-fernbedienung/265)
	#define CACHED_PLAYLIST_ENABLE          // Enables playlist-caching (infos: https://forum.espuino.de/t/neues-feature-cached-playlist/515)
	//#define PAUSE_WHEN_RFID_REMOVED       // Playback starts when card is applied and pauses automatically, when card is removed (https://forum.espuino.de/t/neues-feature-pausieren-wenn-rfid-karte-entfernt-wurde/541)
	//#define PAUSE_ON_MIN_VOLUME           // When playback is active and volume is changed to zero, playback is paused automatically. Playback is continued if volume reaches 1. (https://forum.espuino.de/t/neues-feature-pausieren-wenn-rfid-karte-entfernt-wurde/541)
	//#define DONT_ACCEPT_SAME_RFID_TWICE   // RFID-reader doesn't accept the same RFID-tag twice in a row (unless it's a modification-card or RFID-tag is unknown in NVS). Flag will be ignored silently if PAUSE_WHEN_RFID_REMOVED is active. (https://forum.espuino.de/t/neues-feature-dont-accept-same-rfid-twice/1247)
	//#define SAVE_PLAYPOS_BEFORE_SHUTDOWN  // When playback is active and mode audiobook was selected, last play-position is saved automatically when shutdown is initiated
	//#define SAVE_PLAYPOS_WHEN_RFID_CHANGE // When playback is active and mode audiobook was selected, last play-position is saved automatically for old playlist when new RFID-tag is applied
	//#define HALLEFFECT_SENSOR_ENABLE      // Support for hallsensor. For fine-tuning please adjust HallEffectSensor.h Please note: only user-support provided (https://forum.espuino.de/t/magnetische-hockey-tags/1449/35)

	//################## set PAUSE_WHEN_RFID_REMOVED behaviour #############################
	#ifdef PAUSE_WHEN_RFID_REMOVED
		#define ACCEPT_SAME_RFID_AFTER_TRACK_END           // Accepts same RFID after playback has ended (https://forum.espuino.de/t/neues-feature-pausieren-wenn-rfid-karte-entfernt-wurde/541/2)
	#endif

	//################## select SD card mode #############################
	#define SD_MMC_1BIT_MODE              // run SD card in SD-MMC 1Bit mode (using GPIOs 15 + 14 + 2 is mandatory!)
	//#define SINGLE_SPI_ENABLE             // If only one SPI-instance should be used instead of two (not yet working!)


	//################## select RFID reader ##############################
	//#define RFID_READER_TYPE_MFRC522_SPI    // use MFRC522 via SPI
	#define RFID_READER_TYPE_MFRC522_I2C  // use MFRC522 via I2C
	//#define RFID_READER_TYPE_PN5180       // use PN5180 via SPI

	#ifdef RFID_READER_TYPE_MFRC522_I2C
		#define MFRC522_ADDR 0x28           // default I2C-address of MFRC522
	#endif

	#ifdef RFID_READER_TYPE_PN5180
		//#define PN5180_ENABLE_LPCD        // Wakes up ESPuino if RFID-tag was applied while deepsleep is active. Only ISO-14443-tags are supported for wakeup!
	#endif

	#if defined(RFID_READER_TYPE_MFRC522_I2C) || defined(RFID_READER_TYPE_MFRC522_SPI)
		constexpr uint8_t rfidGain = 0x07 << 4;      // Sensitivity of RC522. For possible values see reference: https://forum.espuino.de/uploads/default/original/1X/9de5f8d35cbc123c1378cad1beceb3f51035cec0.png
	#endif


	//############# Port-expander-configuration ######################
	#ifdef PORT_EXPANDER_ENABLE
		constexpr uint8_t expanderI2cAddress = 0x20;  // I2C-address of PCA9555 (0x20 is true if PCA's pins A0+A1+A2 are pulled to GND)
	#endif

	//################## BUTTON-Layout ##################################
	/* German documentation: https://forum.espuino.de/t/das-dynamische-button-layout/224
	Please note the following numbers as you need to know them in order to define actions for buttons.
	Even if you don't use all of them, their numbers won't change
		0: NEXT_BUTTON
		1: PREVIOUS_BUTTON
		2: PAUSEPLAY_BUTTON
		3: ROTARYENCODER_BUTTON
		4: BUTTON_4
		5: BUTTON_5

	Don't forget to enable/configure those buttons you want to use in your develboard-specific config (e.g. settings-custom.h)

	Single-buttons [can be long or short] (examples):
		BUTTON_0_SHORT => Button 0 (NEXT_BUTTON) pressed shortly
		BUTTON_3_SHORT => Button 3 (ROTARYENCODER_BUTTON) pressed shortly
		BUTTON_4_LONG => Button 4 (BUTTON_4) pressed long

	Multi-buttons [short only] (examples):
		BUTTON_MULTI_01 => Buttons 0+1 (NEXT_BUTTON + PREVIOUS_BUTTON) pressed in parallel
		BUTTON_MULTI_12 => Buttons 1+2 (PREV_BUTTON + PAUSEPLAY_BUTTON) pressed in parallel

	Actions:
		To all of those buttons, an action can be assigned freely.
		Please have a look at values.h to look up actions available (>=100 can be used)
		If you don't want to assign an action or you don't use a given button: CMD_NOTHING has to be set
	*/
	// *****BUTTON*****        *****ACTION*****
	#define BUTTON_0_SHORT    CMD_NEXTTRACK
	#define BUTTON_1_SHORT    CMD_PREVTRACK
	#define BUTTON_2_SHORT    CMD_PLAYPAUSE
	#define BUTTON_3_SHORT    CMD_MEASUREBATTERY
	#define BUTTON_4_SHORT    CMD_SEEK_BACKWARDS
	#define BUTTON_5_SHORT    CMD_SEEK_FORWARDS

	#define BUTTON_0_LONG     CMD_LASTTRACK
	#define BUTTON_1_LONG     CMD_FIRSTTRACK
	#define BUTTON_2_LONG     CMD_PLAYPAUSE
	#define BUTTON_3_LONG     CMD_SLEEPMODE
	#define BUTTON_4_LONG     CMD_VOLUMEUP
	#define BUTTON_5_LONG     CMD_VOLUMEDOWN

	#define BUTTON_MULTI_01   CMD_NOTHING   //CMD_TOGGLE_WIFI_STATUS (disabled now to prevent children from unwanted WiFi-disable)
	#define BUTTON_MULTI_02   CMD_ENABLE_FTP_SERVER
	#define BUTTON_MULTI_03   CMD_NOTHING
	#define BUTTON_MULTI_04   CMD_NOTHING
	#define BUTTON_MULTI_05   CMD_NOTHING
	#define BUTTON_MULTI_12   CMD_TELL_IP_ADDRESS
	#define BUTTON_MULTI_13   CMD_NOTHING
	#define BUTTON_MULTI_14   CMD_NOTHING
	#define BUTTON_MULTI_15   CMD_NOTHING
	#define BUTTON_MULTI_23   CMD_NOTHING
	#define BUTTON_MULTI_24   CMD_NOTHING
	#define BUTTON_MULTI_25   CMD_NOTHING
	#define BUTTON_MULTI_34   CMD_NOTHING
	#define BUTTON_MULTI_35   CMD_NOTHING
	#define BUTTON_MULTI_45   CMD_NOTHING

	//#################### Various settings ##############################

	// Serial-logging-configuration
	#define SERIAL_LOGLEVEL LOGLEVEL_DEBUG              // Current loglevel for serial console

	// Static ip-configuration
	#ifdef STATIC_IP_ENABLE
		#define LOCAL_IP   192,168,2,100                // ESPuino's IP
		#define GATEWAY_IP 192,168,2,1                  // IP of the gateway/router
		#define SUBNET_IP  255,255,255,0                // Netmask of your network (/24 => 255.255.255.0)
		#define DNS_IP     192,168,2,1                  // DNS-server of your network; in private networks it's usually the gatewy's IP
	#endif

	// Buttons (better leave unchanged if in doubts :-))
	constexpr uint8_t buttonDebounceInterval = 50;                // Interval in ms to software-debounce buttons
	constexpr uint16_t intervalToLongPress = 700;                 // Interval in ms to distinguish between short and long press of buttons

	//#define CONTROLS_LOCKED_BY_DEFAULT			// If set the controls are locked at boot
	#define INCLUDE_ROTARY_IN_CONTROLS_LOCK			// If set the rotary encoder is locked if controls are locked

	// RFID-RC522
	#define RFID_SCAN_INTERVAL 100                      // Interval-time in ms (how often is RFID read?)

	// Automatic restart
	#ifdef SHUTDOWN_IF_SD_BOOT_FAILS
		constexpr uint32_t deepsleepTimeAfterBootFails = 20;      // Automatic restart takes place if boot was not successful after this period (in seconds)
	#endif

	// FTP
	// Nothing to be configured here...
	// Default user/password is esp32/esp32 but can be changed via webgui

	// ESPuino will create a WiFi if joing existing WiFi was not possible. Name and password can be configured here.
	constexpr const char accessPointNetworkSSID[] PROGMEM = "ESPuino";     // Access-point's SSID
	constexpr const char accessPointNetworkPassword[] PROGMEM = "";        // Access-point's Password, at least 8 characters! Set to an empty string to spawn an open WiFi.

	// Bluetooth
	constexpr const char nameBluetoothSinkDevice[] PROGMEM = "ESPuino";        // Name of your ESPuino as Bluetooth-device
	constexpr const char nameBluetoothSourceDevice[] PROGMEM = "My POGS Wireless Headphone"; // Name of Bluetooth-device to connect to (BT-Headset name) (https://forum.espuino.de/t/neues-feature-bluetooth-kopfhoerer/1293/)

	// Where to store the backup-file for NVS-records
	constexpr const char backupFile[] PROGMEM = "/backup.txt"; // File is written every time a (new) RFID-assignment via GUI is done
	constexpr const char playlistCacheFile[] PROGMEM = "playlistcache.csv"; // Filename that is used for caching playlists

	//#################### Settings for optional Modules##############################
	// (optinal) Neopixel
	#ifdef NEOPIXEL_ENABLE
		#define NUM_LEDS			24          	// number of LEDs
		#define CHIPSET				WS2812B     	// type of Neopixel
		#define COLOR_ORDER			GRB
		#define NUM_LEDS_IDLE_DOTS		4           	// count of LEDs, which are shown when Idle
		#define OFFSET_PAUSE_LEDS		false		// if true the pause-leds are centered in the mid of the LED-Strip
		#define PROGRESS_HUE_START		85          	// Start and end hue of mulitple-LED progress indicator. Hue ranges from basically 0 - 255, but you can also set numbers outside this range to get the desired effect (e.g. 85-215 will go from green to purple via blue, 341-215 start and end at exactly the same color but go from green to purple via yellow and red)
		#define PROGRESS_HUE_END		-1
		#define DIMMABLE_STATES			50		// Number of dimmed values between two full LEDs (https://forum.espuino.de/t/led-verbesserungen-rework/1739)
		//#define LED_OFFSET                		0           	// shifts the starting LED in the original direction of the neopixel ring
	#endif

	#if defined(MEASURE_BATTERY_VOLTAGE) || defined(MEASURE_BATTERY_MAX17055)
		#define BATTERY_MEASURE_ENABLE                 // Don't change. Set automatically if any method of battery monitoring is selected.
		constexpr uint8_t s_batteryCheckInterval = 10; // How often battery is measured (in minutes) (can be changed via GUI!)
	#endif

	#ifdef MEASURE_BATTERY_VOLTAGE
		// (optional) Default-voltages for battery-monitoring via Neopixel; can be changed later via WebGUI
		constexpr float s_warningLowVoltage = 3.4;                      // If battery-voltage is <= this value, a cyclic warning will be indicated by Neopixel (can be changed via GUI!)
		constexpr float s_warningCriticalVoltage = 3.1;                 // If battery-voltage is <= this value, assume battery near-empty. Set to 0V to disable.
		constexpr float s_voltageIndicatorLow = 3.0;                    // Lower range for Neopixel-voltage-indication (0 leds) (can be changed via GUI!)
		constexpr float s_voltageIndicatorHigh = 4.2;                   // Upper range for Neopixel-voltage-indication (all leds) (can be changed via GUI!)
	#endif

	#ifdef MEASURE_BATTERY_MAX17055
		constexpr float s_batteryLow = 15.0;            // low percentage
		constexpr float s_batteryCritical = 5.0;        // critical percentage

		constexpr uint16_t s_batteryCapacity = 6000;    // design cap of battery (mAh)
		constexpr uint16_t s_emptyVoltage = 300;        // empty voltage in 10mV
		constexpr uint16_t s_recoveryVoltage = 360;     // recovery voltage in 10mV
		constexpr uint8_t  s_batteryChemistry = 0x60;   // 0 = Li-Ion, 0x20 = NCR, 0x60 = LiFePO4
		constexpr float s_resistSensor = 0.01;          // current sense resistor, currently non-default values might lead to problems
		constexpr bool s_vCharge = false;                   // true if charge voltage is greater than 4.275V
	#endif

	// enable I2C if necessary
	#if defined(RFID_READER_TYPE_MFRC522_I2C) || defined(PORT_EXPANDER_ENABLE) || defined(MEASURE_BATTERY_MAX17055)
		#define I2C_2_ENABLE
	#endif

	// (optinal) Headphone-detection (leave unchanged if in doubts...)
	#ifdef HEADPHONE_ADJUST_ENABLE
		constexpr uint16_t headphoneLastDetectionDebounce = 1000; // Debounce-interval in ms when plugging in headphone
	#endif

	// Seekmode-configuration
	constexpr uint8_t jumpOffset = 30;                            // Offset in seconds to jump for commands CMD_SEEK_FORWARDS / CMD_SEEK_BACKWARDS

	// (optional) Topics for MQTT
	#ifdef MQTT_ENABLE
		constexpr uint16_t mqttRetryInterval = 60;                // Try to reconnect to MQTT-server every (n) seconds if connection is broken
		constexpr uint8_t mqttMaxRetriesPerInterval = 1;          // Number of retries per time-interval (mqttRetryInterval). mqttRetryInterval 60 / mqttMaxRetriesPerInterval 1 => once every 60s
		#define DEVICE_HOSTNAME "ESP32-ESPuino"         // Name that is used for MQTT
		constexpr const char topicSleepCmnd[] PROGMEM = "Cmnd/ESPuino/Sleep";
		constexpr const char topicSleepState[] PROGMEM = "State/ESPuino/Sleep";
		constexpr const char topicRfidCmnd[] PROGMEM = "Cmnd/ESPuino/Rfid";
		constexpr const char topicRfidState[] PROGMEM = "State/ESPuino/Rfid";
		constexpr const char topicTrackState[] PROGMEM = "State/ESPuino/Track";
		constexpr const char topicTrackControlCmnd[] PROGMEM = "Cmnd/ESPuino/TrackControl";
		constexpr const char topicCoverChangedState[] PROGMEM = "State/ESPuino/CoverChanged";
		constexpr const char topicLoudnessCmnd[] PROGMEM = "Cmnd/ESPuino/Loudness";
		constexpr const char topicLoudnessState[] PROGMEM = "State/ESPuino/Loudness";
		constexpr const char topicSleepTimerCmnd[] PROGMEM = "Cmnd/ESPuino/SleepTimer";
		constexpr const char topicSleepTimerState[] PROGMEM = "State/ESPuino/SleepTimer";
		constexpr const char topicState[] PROGMEM = "State/ESPuino/State";
		constexpr const char topicCurrentIPv4IP[] PROGMEM = "State/ESPuino/IPv4";
		constexpr const char topicLockControlsCmnd[] PROGMEM ="Cmnd/ESPuino/LockControls";
		constexpr const char topicLockControlsState[] PROGMEM ="State/ESPuino/LockControls";
		constexpr const char topicPlaymodeState[] PROGMEM = "State/ESPuino/Playmode";
		constexpr const char topicRepeatModeCmnd[] PROGMEM = "Cmnd/ESPuino/RepeatMode";
		constexpr const char topicRepeatModeState[] PROGMEM = "State/ESPuino/RepeatMode";
		constexpr const char topicLedBrightnessCmnd[] PROGMEM = "Cmnd/ESPuino/LedBrightness";
		constexpr const char topicLedBrightnessState[] PROGMEM = "State/ESPuino/LedBrightness";
		constexpr const char topicWiFiRssiState[] PROGMEM = "State/ESPuino/WifiRssi";
		constexpr const char topicSRevisionState[] PROGMEM = "State/ESPuino/SoftwareRevision";
		#ifdef BATTERY_MEASURE_ENABLE
		constexpr const char topicBatteryVoltage[] PROGMEM = "State/ESPuino/Voltage";
		constexpr const char topicBatterySOC[] PROGMEM     = "State/ESPuino/Battery";
		#endif
	#endif

	// !!! MAKE SURE TO EDIT PLATFORM SPECIFIC settings-****.h !!!
	#if (HAL == 1)
		#include "settings-lolin32.h"                       // Contains all user-relevant settings for Wemos Lolin32
	#elif (HAL == 2)
		#include "settings-espa1s.h"                        // Contains all user-relevant settings for ESP32-A1S Audiokit
	#elif (HAL == 3)
		#include "settings-lolin_d32.h"                     // Contains all user-relevant settings for Wemos Lolin D32
	#elif (HAL == 4)
		#include "settings-lolin_d32_pro.h"                 // Contains all user-relevant settings for Wemos Lolin D32 pro
	#elif (HAL == 5)
		#include "settings-ttgo_t8.h"                       // Contains all user-relevant settings for Lilygo TTGO T8 1.7
	#elif (HAL == 6)
		#include "settings-complete.h"                      // Contains all user-relevant settings for ESPuino complete
	#elif (HAL == 7)
		#include "settings-lolin_d32_pro_sdmmc_pe.h"        // Pre-configured settings for ESPuino Lolin D32 pro with SDMMC + port-expander (https://forum.espuino.de/t/espuino-minid32pro-lolin-d32-pro-mit-sd-mmc-und-port-expander-smd/866)
	#elif (HAL == 8)
		#include "settings-azdelivery_sdmmc.h"              // Pre-configured settings for AZ Delivery ESP32 NodeMCU / Devkit C (https://forum.espuino.de/t/az-delivery-esp32-nodemcu-devkit-c-mit-sd-mmc-und-pn5180-als-rfid-leser/634)
	#elif (HAL == 9)
		#include "settings-lolin_d32_sdmmc_pe.h"            // Pre-configured settings for Lolin D32 (non-pro) with SDMMC + port-expander (https://forum.espuino.de/t/espuino-minid32-pro-lolin-d32-pro-mit-sd-mmc-und-port-expander-smd/866)
	#elif (HAL == 10)
		#include "settings-muse_proto.h"                     // Pre-configured settings for Raspiaudio ESPMuse Proto Board with I2C RFID Reader (https://raspiaudio.com/produit/muse-proto)
	#elif (HAL == 99)
		#include "settings-custom.h"                        // Contains all user-relevant settings custom-board
	#endif

	//#define ENABLE_ESPUINO_DEBUG                            // Needs modification of platformio.ini (https://forum.espuino.de/t/rfid-mit-oder-ohne-task/353/21); better don't enable unless you know what you're doing :-)
	#endif //settings_override
#endif

Tests (nur Kompilierung, keie Funktionstests):

Master mit Arduino 1

iram.text: 129.696

ohne Port Expander, ohne I2C: 127.240

Master mit Arduino 2

iram.text: overflow by 96 bytes

ohne Port Expander, mit I2C: 129.875
ohne Port Expander, ohne I2C: 128.295


Dev mit Arduino 2 (Ausgangssituation)

iram.text: overflow by 488 byte

Ohne PORT_EXPANDER_ENABLE, ohne RFID_READER_TYPE_MFRC522_I2C

iram.text: 125,8k

Ohne -mfix-esp32-psram-cache-issue

iram.text: overflow by 404 byte

Ohne PORT_EXPANDER_ENABLE, mit RFID_READER_TYPE_MFRC522_I2C

iram.text: overflow by 144 byte

Das deutet darauf hin, dass der TwoWire (bzw die ESP32 I2C-Hal) mit schuldig ist.

Mit PORT_EXPANDER_ENABLE, ohne PE_INTERRUPT_PIN_ENABLE

iram.text: 129.935

Damit haben wir hier sage und schreibe 113 bytes frei. Wahrscheinlich weniger, da Funktionen auf 32bit boundary positioniert werden müssen. Das ist verdammt wenig…

Der Interrupt scheint hier das Fass zum Überlaufen zu bringen. Eine mögliche Abhilfe wäre es hier statt dem Arudino attachInterrupt die IDF-version zu verwenden, diese sind normalerweise etwas schlanker. Oder kein Interrupt verwenden…

Müssten wir uns anschauen, aber das ist nur eine Notlösung, da es nur die Auswirkung vermindert und nicht das zugrunde liegende Problem löst.


Das Problem

Die Seite die @Niko verlinkt hat ist sehr gut (die kannte ich ncoh gar nicht). Die Flags, vor allem die Funktionen in den Flash zu verschieben würden uns definitiv weiter helfen.

Aber, wir verwenden arduino-esp32 und dieser kommt mit IDF in einer vor-kompilierten Library. Welche Menuconfig flags aktiv sind (oder nicht), könnt ihr in der sdkconfig sehen. Diese sind fest kompiliert und können nicht mehr geändert werden (da diese nur zum zeitpunkt wo die IDF SDK kompiliert wird relevant ist. Die sind so zu sagen in Stein gemeißelt.

Ich habe grob acht der Flags gesucht und alle sind deaktiviert (bzw im Falle von CONFIG_SPIRAM_CACHE_WORKAROUND aktiviert).

D.h. so lange wir nicht in den Sauren Ampfel beißen und die IDF in Arduino neu compileren (arduino-esp32/lib_builder.rst at 237a3fe96c451e5da88e8cfe9d850961f9bbe036 · espressif/arduino-esp32 · GitHub), können wir die Flags nicht verändern. Eine weitere Alternative wäre es IDF mit Arduino als Componente zu verwenden, hab ich aber noch nie gemacht.

Ehrlich gesagt habe ich bis jetzt keines der beiden Punkt auch nur ansatzweise angeschaut, ka was für Monster sich in dessen Tiefen verstecken.

5 „Gefällt mir“

Wow vielen Dank dir für die Erklärungen!! Das erklärt auch warum die Flags bei mir nicht gewirkt haben.
Können wir die Platform selbst kompilieren und diese dann ablegen?
Ich wäre auch interessiert die immer zu kompilieren. Vielleicht finden wir noch mehr Dinge die dort nicht optimal sind. Die Liste mit den Optimierungen ist ja sehr lang…

Ich habe das bei einem anderen ESP-Projekt schon mal so gemacht. Eben genau aus dem Grund, dass ich dann die Kconfig-Optionen (CONFIG_...) von ESP-IDF anpassen kann.

Aus meiner Sicht hätte das z. B. auch den schönen Nebeneffekt, dass man CMake nutzen kann um z. B. Source-Dateien abhängig von einem Preprocessor-Define zu bauen oder auszuklammern (was wieder einige #ifdefs im Code sparen würde).

Wenn wir das machen müsste ich einiges an meinem Kconfig Feature-Branch umbauen, da ja dann schon Kconfig vom ESP-IDF da wäre, aber das liese sich hoffentlich irgendwie in Einklang bringen.

1 „Gefällt mir“

@laszloh Vielen Dank für die ausführlichen Erklärungen, das ist sicher sehr hilfreich!!!

Was ich aber noch nicht verstehe ist

Master mit Arduino 2
iram.text: overflow by 96 bytes

Dev mit Arduino 2
iram.text: overflow by 488 byte

Also bei gleicher Arduinoversion und gleichen Einstellungen verschlimmern die DEV-Erweiterungen die Speicherknappheit. Woran kann das liegen? Ich sehe im DEV jetzt keine neu eingebundene Bibliotheken oder viel neuen Code, sehr wohl aber Änderungen an der Speicherverwaltung. Weil diesen Bereich haben wir in der eigenen Hand…

Ich habe es versucht bei mir nachzustellen (mein noramles Dev-Board hat kein Akku), ich musste ein zweitest Board kurz zusammenschustern. Das ist der Grund wieso ich erst jetzt drauf antworte :slight_smile:.

Kurz und knapp, ich kann es nicht nachstellen. Mit der aktuellen Dev-Branche belaufen sich bei mir die Unterschiede zwischen Monitor & Web-GUI auf 0,01V (mit dem 5s intervall checker):

Web:

WLAN-Signalstaerke: -63 dBm
Aktuelle Batteriespannung: 3.50 V
Aktuelle Batterieladung: 42.00 %

Monitor:

[ 582036 ]  Aktuelle Batteriespannung: 3.51 V
[ 582038 ]  Aktuelle Batterieladung: 42.61 %

Ich habe einige Fragen an dich um zu schauen, dass unsere Setups vergleichbar sind (bitte nicht als Kritik aufnehmen):

  1. Die Batteriespannung musst du vor dem Buck-Converter messen (genauer: an dem Anschluss der Batterie). Der Buck generiert aus den Batteriespannung (bzw der 5V wenn ein USB angeschlossen ist) die 3,3V für den ESP & SD-Karte, etc. Die müssen stabil sein, sonst hat das Board was :slight_smile:

  2. Als du die GUI angeschaut hast, war USB angesteckt? Weil sobald USB dran ist wird der Akku geladen. D.h. der Monitor liefert dir Werte während du lädst (zumindest ist das bei meinem TT-GO8 Dev-Board so). Die Werte sind immer höher sind als die normale Batteriespannung (sonst würde der Strom nicht in die Batterie fließen). *
    Wenn du beim Aufrufen der GUI kein USB dran hattest, würde es erklären, wieso die Werte unterschiedlich sind

  3. Hast du in der GUI ab und an F5 gedrückt? Diese aktualisiert sich nicht von selber, d.h. du musst die Seite neu laden damit du neue Werte bekommst.



*: Hier wird recht gut erklärt, wie das Laden von statten geht. Grob zusammengefasst, am Anfang ladest du mit 4,1V (oder 4,2V je anch Akku) und konstantem Strom (d.h. Strom begrenzt auf ~200mA und die Spannung steig langsam an), danach mit konstanter Spannung (der 4,1V) bis der Strom < 50mA wird und dann ist der Akku voll.

Zum Linkerfehler, das Problem scheint NICHT mit den Speicheränderungen im DEV-Branch zusammenzuhängen sondern kommen anscheinend von u.a. von Änderungen in der Audio-Bibliothek. Hier wurde wohl vor kurzem einer neuer opus-Decoder eingeführt.

ESP32-audioI2S 2.0.6 vom 22.11.2022:
region `iram0_0_seg’ overflowed by 40 bytes

ESP32-audioI2S 3.0.0 vom 10.02.2023:
region `iram0_0_seg’ overflowed by 200 bytes

Vielleicht kann @Wolle etwas dazu beitragen ob man den iram-Speicherbedarf verringern kann?

1 „Gefällt mir“

@fschrempf hast du gerade parat was man in der plattformio.ini ändern muss um die espressif32 platform direkt mit den build-flags kompilieren zu können?
Würde mir gerne die verschiedenen Einsparpotentiale anschauen…
Ganz unabhängig von den Ergebnissen bezüglich der anderen Libs könnte es ja bald nötig sein hier Schritte zu gehen.
Gerade auch so Dinge wie die minimale Version sollen auch schon Verbesserungen bringen ohne dass sich daraus für uns irgendein Nachteil ergeben würde…

Hallo tueddy,
das ist richtig, es sind zwei neue Dekoder hinzugekommen, das ist der OPUS und der VORBIS Dekoder. Und es wird auch indirekt etwas zusätzlicher Speicher im iram0 belegt (+116Bytes).

gemessen sieht es so aus:
iram0.text    61027           leerer Sketch
iram0.vectors 1027
-----------------------------------------------------
iram0.text    78455           Sketch mit WiFiMulti
iram0.vectors 1027
-----------------------------------------------------
iram0.text    79939           Sketch mit WiFiMulti und Audio (aktuelle Version)
iram0.vectors 1027       
-----------------------------------------------------
iram0.text    79823           Sketch mit WiFiMulti und Audio (Version vom 22.11.22)
iram0.vectors 1027        

Die Audio Lib belegt etwa 1400 Bytes im iram0

Und so ist iram_0_segm organisiert
image

Die ersten 64KB von den verfügbaren 192KB werden von den beiden Kernen begegt, da kann man nichts machen. Arduino selbst + den verwendeten Arduibo Libs belegen reichlich SRAM0, da kann man auch nichts machen.
Gibt es im Quelltext oder den verwendeten Libs das Makro IRAM_ATTR (für zeitkritische Bereiche), die SRAM0 verstopfen?

Du kannst in PlatformIO links auf die Ameise klicken und advanced/Verbose Buils auswählen. Bis das Ergebnis kommt kann es einige Minuten dauern. So habe ich auch die Werte ermittelt.

beste Grüße
Wolle

3 „Gefällt mir“

Hier mal ein schnell zusammengeflickter Commit mit den wesentlichen Änderungen. Ist nicht besonders viel. Allerdings übersetzt das so auch noch nicht ganz. Offenbar gibt es noch ein paar Warnings in den Libs, die jetzt als Errors behandelt werden. Wahrscheinlich muss man da noch an den Compiler-Flags schrauben.

In der sdkconfig.defaults können die vom Default abweichenden Optionen für ESP-IDF eingetragen werden. Mit pio run -t menuconfig kann man das Konfigurationsmenü für ESP-IDF aufrufen.

1 „Gefällt mir“

Ich habe mal geschaut, was so wie viel Speicher verbraucht:

Module Size Comment
esp-components 62,0k Da ist alles von FreeRTOS Funktionen bis HAL drin
libc 11,2k Die newlib library von gcc
WiFi+BT phy 9,1k WiFi phy Treiber (davon ~1k für BT)
ESPuino 0,9k Hier kommt das Meiste von ESP32RMTController
binary-blob 31k Funktionen aus Binary-Blobs von esp-idf, empirisch* ermittelt sind 27k von Bluetooth
Rest 9,5k Namenslose symbole, die von elf-size-analyse nicht erkannt werden Bug #4

Hier die unbearbeitete Ausgabe: unfiltered_output.zip (38,5 KB)


Wenn ihr das nachstellen möchtet, in Platformio Terminal elf-size-analyze installieren: python -m pip install elf-size-analyze. Danach mit folgender Commandozeile aufrufen:

elf-size-analyze.exe -S7 --no-color --toolchain-triplet=C:\Users\[username]\.platformio\packages\toolchain-xtensa-esp32\bin\xtensa-esp32-elf- .\.pio\build\[target]\firmware.elf >elf-size.txt

Wichtig ist, dass ihr den Pfad zu der xtensa Toolchain angibt (--toolchain-triplet, der Pfad im Beispiel ist für Arduino2) und natürlich die elf, die ihr analysieren wollt. -S7 begrenzt die detailierte Ausgabe auf iram0.text.

Als Ausgabe empfehle ich txt ohne Farben (--no-color) und dann mit notepad++ anschauen. HTML ist ein wenig buggy und JSON habe ich noch nicht ausprobiert.


*: Ich habe zwei elf verglichen, eines mit und eines ohne Bluetooth. Vor allem bei dem Binary blob (in elf-size.txt alles unter „?“) gibt es da ein Unterschied von 27k (31k vs 3,5k).

4 „Gefällt mir“

Vielen Dank dir! Sieht doch etwas komplexer aus.
Bin heute Abend jetzt leider nicht mehr dazu gekommen. Melde mich aber sobald ich es am Laufen habe und die Verbessungen des iram der Flags jeweils auflisten und testen kann.
Einen guten Wochenstart euch!