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

[ESP32 flash mode] Change flash mode board defs to use QIO for ESP32 #4200

Merged
merged 7 commits into from
Aug 18, 2022

Conversation

TD-er
Copy link
Member

@TD-er TD-er commented Aug 15, 2022

Mainly to continue discussion with @Jason2866 regarding flash mode.
See also: #4199 (comment)

@tonhuisman
Copy link
Contributor

This forum question seems directly related to this.

@Jason2866
Copy link
Contributor

Mhh, looking at this https://github.com/espressif/arduino-esp32/blob/master/tools/platformio-build-esp32c3.py#L301-L308
there is always the qio lib included, since i did not noticed an entry for this in any platformio boards manifest

@TD-er
Copy link
Member Author

TD-er commented Aug 15, 2022

I just tried printing the config for this in my build scripts and it failed when not supplying a default.
So I think you're upto something.

Now making a commit to include these in the ESP32 board defs.

@Jason2866
Copy link
Contributor

@TD-er CI has finished. Does it work?

@TD-er
Copy link
Member Author

TD-er commented Aug 15, 2022

@TD-er CI has finished. Does it work?

Still testing on my boards.
Problem is, I can't reproduce the issues reported by others very well.

@TD-er
Copy link
Member Author

TD-er commented Aug 15, 2022

Hmm this is still a bit tricky.

The board was flashed a while ago via serial. Then the flash_mode was set to DOUT.

Now I am building using dio and dio_qspi, but still when flashing via OTA, I get this:
image

Another (4M) board I flashed via serial is showing DIO on the sysinfo page.

@TD-er
Copy link
Member Author

TD-er commented Aug 15, 2022

OK, this is really tricky^2

OTA update on a device which I flashed a few hours ago works fine.
This one was flashed using DIO mode, thus it showed DIO in the sysinfo page.
However now that I flashed the same build via serial including the bootloader, it no longer can find the LittleFS filesystem.

So this is really really tricky and I have no idea how to proceed:

  • Continue using the faulty QIO_QSPI, which is apparently DIO
  • Change to DOUT or DIO, which may lead to lost filesystem (LittleFS)

The node with 4M flash and SPIFFS is running fine regardless of how I updated it.

@Jason2866
Copy link
Contributor

Jason2866 commented Aug 16, 2022

Oh my, this is really no fun. Maybe the time when the bootloader flash mode version convert was not in you factory firmware builder is doing weird stuff here now.
Hopefully the tests with Tasmota is not such a nightmare too.
The really strange thing is LittleFS is working with dout in Tasmota.

@TD-er
Copy link
Member Author

TD-er commented Aug 16, 2022

The really strange thing is LittleFS is working with dout in Tasmota.

I think it does use QIO calls when writing/reading the filesystem (with qio_qspi set), which maybe incompatible with the others (or at least dio_qspi). For example maybe some bits are flipped.

As far as I remember, Tasmota still only uses .ino files (and .h/.cpp for libs), so maybe that's what may save you here.
I'm afraid I may not have always this <memory_type>_qspi file included in my code, but perhaps a more generic one.
Then it might depend on compilation order of .cpp files which one may have been active. This would for sure explain compile differences among GH Actions builds and the ones I made on my PC and also ones made by Ton. Simply because of different amount of CPU cores and thus compilation threads.

I guess determinging the exact build which may have caused these issues is a bit tricky, but for now, I think I will remove the ESP32 builds from my latest builds (or at least rename the ZIP file with "Read Warning" or something like that)

Do you have any idea what xxxx_qspi mode was used before? (thus before PIO 5.1)
If this was QIO, then I guess we should all move to use QIO in the ESP32 builds as it apparently has wired all flash chips to allow QIO mode.
But then the question remains, should users update the bootloader?

What other things are changed in a build when running in DIO or DOUT vs. QIO?
Are there different timings involved?
Is this only set in the bootloader, or also in the sketch itself?

But to summarize, this is nothing less than a nightmare situation.

  • Keep using the old config => weird issues
  • Move to DIO or DOUT mode for xxxx_qspi => Filesystem existence at risk
  • Force move to QIO => need to update bootloader and thus flash via serial needed.

@TD-er
Copy link
Member Author

TD-er commented Aug 16, 2022

Thread found by @tonhuisman regarding the need for extra commands to set QIO mode on some chips.
Discussion of QIO DIO QOUT DOUT flash modes?
So perhaps my "corrupted" filesystem may be a result of the chip not being set to QIO mode?

@Jason2866
Copy link
Contributor

Jason2866 commented Aug 16, 2022

Looks different, since i do not manage to get mode qio nor qout working. I always end in mode dio or dout.
BUT FS never fails. For tests i removed the replace of flashing bootloader not in mode qio / qout. Device bootloops.
So the replace in which mode the firmware is flashed seems correctly. At the moment i doubt everything...
The post is kinda old. There is code in IDF for supporting Flash chips. So the support is not ROM based. Support for ALL flash chips is enabled in the builded libs. Imho it is nearly impossible we all have devices with flash chips not supported from IDF flash driver code.

@Jason2866
Copy link
Contributor

Espressif Docu https://docs.espressif.com/projects/esp-idf/en/release-v4.4/esp32/api-reference/storage/spi_flash.html

@TD-er
Copy link
Member Author

TD-er commented Aug 16, 2022

Another link to Espressif docs with very detailed info describing the different modes: https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/spi-flash-modes.html

@TD-er
Copy link
Member Author

TD-er commented Aug 16, 2022

Ah great minds ;)

@Jason2866
Copy link
Contributor

My C3 test victim has "Flash Chip Id = 0x164020". if i am not wrong this is XMC and is in QIO IDF support flash driver list.

@TD-er
Copy link
Member Author

TD-er commented Aug 16, 2022

Looks different, since i do not manage to get mode qio nor qout working. I always end in mode dio or dout.
BUT FS never fails. For tests i removed the replace of flashing bootloader not in mode qio / qout. Device bootloops.
So the replace in which mode the firmware is flashed seems correctly. At the moment i doubt everything...

See also this section: https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/spi-flash-modes.html#why-does-qout-dout-mode-work-but-qio-dio-mode-doesn-t-work

Apparently it is very much flash chip dependent and also the bootloader seems to be able to override settings at runtime.
This makes me think, what it is we're reading when querying the actual flash mode.
It seems this function is looking at the header, but this may not reflect the actual mode being used.

Not sure if we can work this out on our own without calling in the in-depth knowledge of those like @igrr
Also now there are essentially 2 issues discussing this.
Maybe the one in PlatformIO is better suited? platformio/platform-espressif32#877 (comment)

@Jason2866
Copy link
Contributor

Found this https://gitter.im/espressif/arduino-esp32?at=5ecee66b4c9b0f060d2a7634
It is a old story....

@TD-er
Copy link
Member Author

TD-er commented Aug 16, 2022

What I understand now is that the ESP32 only has limited support for QIO in its bootloader stage.
Thus this may work on some chips, but not all.
Then the bootloader has to detect and set the correct parameters to enable QIO mode on the flash chip.

Given that not all flash chips support DIO or QIO, while they support DOUT and QOUT, you may end up with a lot of combinations that may or may not work.
I have no idea whether having qio_qspi set in the sketch also enables the QIO mode on the flash chip, or maybe the bootloader is expected to enable this?
Also what happens if the chip is set to enable QIO but only supports QOUT? I guess it will mount the FS just fine, but corrupts it when writing.
Does the SPI code also check the actual mode of a chip? In other words, can a chip give feedback when it is set to QIO while it doesn't support it?
If so, then it could be that setting it to DOUT instead of DIO (which caused my filesystem to be not found) is the safest bet.
As far as I can see now, it seems that if a flash chip does support QOUT and not QIO, it will also not support DIO.

@Jason2866
Copy link
Contributor

You are probably right. This would fit to our experience with Tasmota. We always used dout as flash mode.
So we have no unknown dangerous combinations "in the field" and dout just works (always). NO FS corruption.

@TD-er
Copy link
Member Author

TD-er commented Aug 16, 2022

Yep, let's hope this hypothesis is correct, as I also always used DOUT (at least since switching to IDF 4.4)

@Jason2866
Copy link
Contributor

Jason2866 commented Aug 16, 2022

Well, upgrading devices from core < 2.0.4 which do not use mode dout maybe are dangerous.
Never tried to upgrade from core 1.0.x builds to 2.0.x. Probably a fun ride. Afaik espressif does not support cross updates between IDF versions.

@Jason2866
Copy link
Contributor

Jason2866 commented Aug 16, 2022

You can use the build (latest dev Arduino/IDF version) with the enabled bootloader logging:

platform = https://github.com/Jason2866/platform-espressif32.git
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/934/framework-arduinoespressif32-443_esp421-9ce849ce72.tar.gz

@Jason2866
Copy link
Contributor

My test C3 does now work with Tasmota in all 4 flash modes without an issue!
It would be great if espressif does the needed changes in Arduino Lib Builder.
I am a noob in bash scripting.
These are the needed changes https://github.com/espressif/arduino-esp32/pull/7141/files which needs to be done here https://github.com/espressif/esp32-arduino-lib-builder/blob/master/tools/copy-libs.sh#L375-L402 since the files are generated from the arduino lib builder.
Since i use my fork for building the frameworks for Tasmota Arduino ESP32 core. I could implement asap here

With this change the current boards manifest can be used and are working with the old and new core without a change

@TD-er
Copy link
Member Author

TD-er commented Aug 16, 2022

The first draft PR is perfectly clear to me.
The bash stuff, I need to have a more thorough look at to grasp what it is doing.
I'm not a noob at bash scripting, but I never really liked it and found it always taking quite a bit more time consuming compared to other scripting languages.

For example I have to google this syntax, as I have no clue (yet) what it does:

rel_f=${f#*$item}
rel_p=${rel_f%/*}

I know it is about env variables parsing, but I don't know what the #* and %/* does.

@TD-er
Copy link
Member Author

TD-er commented Aug 16, 2022

Ah....
rel_f=${f#*$item} means it takes the word ending with whatever is in $item
rel_p=${rel_f%/*} means it takes the word starting with /

See 10.3.3.2. Removing substrings

@TD-er
Copy link
Member Author

TD-er commented Aug 18, 2022

I think I'll leave it to the temporary one you made until the 2.0.5 is out.
Just to be sure we're not building using cached platform files.
Not sure if GH Actions will cache this.

@sobolkz
Copy link

sobolkz commented Aug 18, 2022

You can also disable ethernet in the settings. If there is an ethernet chip connected, then those pins should not be used as this can still affect the functionality of the pins. Also you can destroy the LAN chip when setting the wrong "high level" signals to some pins while the chip is not "on".

Build 3260 was tested - looks good. As minimum I can add plugins without crashes. But load from backup still going to crash board and bootloop. Now at SPI init step:

160685 : Info : Upload: START, filename: config.dat
160725 : Info : Upload: WRITE, Bytes: 1436
160731 : Info : Upload: WRITE, Bytes: 1436
160789 : Info : Upload: WRITE, Bytes: 1436
160796 : Info : Upload: WRITE, Bytes: 1436
160801 : Info : Upload: WRITE, Bytes: 1436
160895 : Info : Upload: WRITE, Bytes: 1436
160900 : Info : Upload: WRITE, Bytes: 1436
160908 : Info : Upload: WRITE, Bytes: 1436
160963 : Info : Upload: WRITE, Bytes: 1436
160969 : Info : Upload: WRITE, Bytes: 1436
160975 : Info : Upload: WRITE, Bytes: 1436
161030 : Info : Upload: WRITE, Bytes: 1436
161036 : Info : Upload: WRITE, Bytes: 1436
161041 : Info : Upload: WRITE, Bytes: 1436
161099 : Info : Upload: WRITE, Bytes: 1436
161105 : Info : Upload: WRITE, Bytes: 1436
161110 : Info : Upload: WRITE, Bytes: 1436
161165 : Info : Upload: WRITE, Bytes: 1436
161171 : Info : Upload: WRITE, Bytes: 1436
161226 : Info : Upload: WRITE, Bytes: 1436
161232 : Info : Upload: WRITE, Bytes: 1436
161236 : Info : Upload: WRITE, Bytes: 1436
161292 : Info : Upload: WRITE, Bytes: 1436
161299 : Info : Upload: WRITE, Bytes: 1436
161304 : Info : Upload: WRITE, Bytes: 1436
161360 : Info : Upload: WRITE, Bytes: 1436
161366 : Info : Upload: WRITE, Bytes: 1436
161371 : Info : Upload: WRITE, Bytes: 1436
161427 : Info : Upload: WRITE, Bytes: 1436
161433 : Info : Upload: WRITE, Bytes: 1436
161438 : Info : Upload: WRITE, Bytes: 1436
161493 : Info : Upload: WRITE, Bytes: 1436
161499 : Info : Upload: WRITE, Bytes: 1436
161505 : Info : Upload: WRITE, Bytes: 1436
161560 : Info : Upload: WRITE, Bytes: 1436
161569 : Info : Upload: WRITE, Bytes: 1436
161574 : Info : Upload: WRITE, Bytes: 1436
161629 : Info : Upload: WRITE, Bytes: 1436
161634 : Info : Upload: WRITE, Bytes: 1436
161689 : Info : Upload: WRITE, Bytes: 1436
161696 : Info : Upload: WRITE, Bytes: 1436
161702 : Info : Upload: WRITE, Bytes: 1436
161757 : Info : Upload: WRITE, Bytes: 1436
161765 : Info : Upload: WRITE, Bytes: 1436
161770 : Info : Upload: WRITE, Bytes: 1436
161827 : Info : Upload: WRITE, Bytes: 1436
161833 : Info : Upload: WRITE, Bytes: 1436
161837 : Info : Upload: WRITE, Bytes: 1436
161898 : Info : Upload: WRITE, Bytes: 1436
161904 : Info : Upload: WRITE, Bytes: 1436
161910 : Info : Upload: WRITE, Bytes: 1436
161965 : Info : Upload: WRITE, Bytes: 1436
161972 : Info : Upload: WRITE, Bytes: 1436
161979 : Info : Upload: WRITE, Bytes: 1436
162035 : Info : Upload: WRITE, Bytes: 1436
162040 : Info : Upload: WRITE, Bytes: 1436
162046 : Info : Upload: WRITE, Bytes: 1436
162101 : Info : Upload: WRITE, Bytes: 1436
162108 : Info : Upload: WRITE, Bytes: 1436
162163 : Info : Upload: WRITE, Bytes: 1436
162169 : Info : Upload: WRITE, Bytes: 1436
162176 : Info : Upload: WRITE, Bytes: 1436
162231 : Info : Upload: WRITE, Bytes: 1436
162236 : Info : Upload: WRITE, Bytes: 1436
162242 : Info : Upload: WRITE, Bytes: 1436
162297 : Info : Upload: WRITE, Bytes: 1436
162303 : Info : Upload: WRITE, Bytes: 1436
162308 : Info : Upload: WRITE, Bytes: 1436
162364 : Info : Upload: WRITE, Bytes: 1436
162369 : Info : Upload: WRITE, Bytes: 1436
162375 : Info : Upload: WRITE, Bytes: 1436
162432 : Info : Upload: WRITE, Bytes: 1436
162437 : Info : Upload: WRITE, Bytes: 1436
162442 : Info : Upload: WRITE, Bytes: 1436
162498 : Info : Upload: WRITE, Bytes: 1436
162504 : Info : Upload: WRITE, Bytes: 1436
162510 : Info : Upload: WRITE, Bytes: 1436
162565 : Info : Upload: WRITE, Bytes: 1436
162571 : Info : Upload: WRITE, Bytes: 1436
162626 : Info : Upload: WRITE, Bytes: 1436
162633 : Info : Upload: WRITE, Bytes: 1436
162638 : Info : Upload: WRITE, Bytes: 1436
162694 : Info : Upload: WRITE, Bytes: 1436
162700 : Info : Upload: WRITE, Bytes: 1436
162703 : Info : Upload: WRITE, Bytes: 1436
162757 : Info : Upload: WRITE, Bytes: 1436
162765 : Info : Upload: WRITE, Bytes: 1436
162769 : Info : Upload: WRITE, Bytes: 1436
162829 : Info : Upload: WRITE, Bytes: 1436
162834 : Info : Upload: WRITE, Bytes: 1436
162837 : Info : Upload: WRITE, Bytes: 1436
162890 : Info : Upload: WRITE, Bytes: 396
162894 : Info : Upload: END, Size: 131072
162916 : Debug dev : sendcontent free: 182420 chunk size:1360
162924 : Debug dev : sendcontent free: 175740 chunk size:1360
162936 : Debug dev : sendcontent free: 182424 chunk size:1360
162947 : Debug dev : sendcontent free: 180632 chunk size:1360
162960 : Debug dev : sendcontent free: 183956 chunk size:1360
162973 : Info : Webserver 1 Arguments: 0: 'edit' length: 1
163037 : Info : CRC : SecuritySettings CRC ...OK
172785 : Info : Webserver 1 Arguments: 0: 'cmd' length: 6
172786 : Info : : Rebooting...
174207 : Info : WIFI : Set WiFi to OFF
174215 : Info : WiFi : STA Stoppedets Jul 29 2019 12:21:46

rst:0xc (SW_CPU_RESET),boot:0x17 (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:DOUT, clock div:2
load:0x3fff0030,len:184
load:0x40078000,len:12616
load:0x40080400,len:2916
entry 0x400805c4
▒U47 : Info :

INIT : Booting version: HEAD_75aa094 (ESP32 SDK v4.4.3-149-g10ab11e815)
48 : Info : INIT : Free RAM:266900
50 : Info : INIT : Soft Reboot #2 Last Action before Reboot: Intended Reboot: CommandReboot Last systime: 1660835355 - Restart Reason: CPU0: Software reset CPU CPU1: Software reset CPU
51 : Info : FS : Mounting...
98 : Info : FS : Mount successful, used 151552 bytes of 8318976
168 : Info : CRC : SecuritySettings CRC ...OK
194 : Info : INIT : I2C
196 : Info : INIT : SPI Init (without CS)Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.

Core 1 register dump:
PC : 0x40093c42 PS : 0x00060c30 A0 : 0x80094296 A1 : 0x3ffb2560
A2 : 0xffffffff A3 : 0x0000002f A4 : 0x000000ff A5 : 0x003d0900
A6 : 0x3f42392d A7 : 0x00000000 A8 : 0x00000015 A9 : 0xffffffff
A10 : 0x00000008 A11 : 0x0000693c A12 : 0x00000011 A13 : 0x00000000
A14 : 0x3ffb316c A15 : 0x00000000 SAR : 0x00000009 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000033 LBEG : 0x4008b629 LEND : 0x4008b64b LCOUNT : 0xffffffff

Backtrace: 0x40093c3f:0x3ffb2560 0x40094293:0x3ffb2580 0x40094500:0x3ffb25a0 0x400849a6:0x3ffb25c0 0x40084a7b:0x3ffb25e0 0x40220751:0x3ffb2630 0x402216f4:0x3ffb2650 0x4011ac73:0x3ffb26f0 0x40119fe0:0x3ffb2730 0x401b17b8:0x3ffb2760 0x4018debe:0x3ffb27a0 0x40125ffb:0x3ffb2800 0x401ec5e2:0x3ffb2820

ELF file SHA256: 0000000000000000

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

rst:0xc (SW_CPU_RESET),boot:0x17 (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:DOUT, clock div:2
load:0x3fff0030,len:184
load:0x40078000,len:12616
load:0x40080400,len:2916
entry 0x400805c4
▒U47 : Info :

INIT : Booting version: HEAD_75aa094 (ESP32 SDK v4.4.3-149-g10ab11e815)
48 : Info : INIT : Free RAM:266900
50 : Info : INIT : Soft Reboot #3 Last Action before Reboot: Intended Reboot: CommandReboot Last systime: 1660835355 - Restart Reason: CPU0: Software reset CPU CPU1: Software reset CPU
51 : Info : FS : Mounting...
98 : Info : FS : Mount successful, used 151552 bytes of 8318976
168 : Info : CRC : SecuritySettings CRC ...OK
194 : Info : INIT : I2C
196 : Info : INIT : SPI Init (without CS)Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.

Core 1 register dump:
PC : 0x40093c42 PS : 0x00060e30 A0 : 0x80094296 A1 : 0x3ffb2560
A2 : 0xffffffff A3 : 0x0000002f A4 : 0x000000ff A5 : 0x003d0900
A6 : 0x3f42392d A7 : 0x00000000 A8 : 0x00000015 A9 : 0xffffffff
A10 : 0x00000008 A11 : 0x0000693c A12 : 0x00000011 A13 : 0x00000000
A14 : 0x3ffb316c A15 : 0x00000000 SAR : 0x00000009 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000033 LBEG : 0x4008b629 LEND : 0x4008b64b LCOUNT : 0xffffffff

Backtrace: 0x40093c3f:0x3ffb2560 0x40094293:0x3ffb2580 0x40094500:0x3ffb25a0 0x400849a6:0x3ffb25c0 0x40084a7b:0x3ffb25e0 0x40220751:0x3ffb2630 0x402216f4:0x3ffb2650 0x4011ac73:0x3ffb26f0 0x40119fe0:0x3ffb2730 0x401b17b8:0x3ffb2760 0x4018debe:0x3ffb27a0 0x40125ffb:0x3ffb2800 0x401ec5e2:0x3ffb2820

ELF file SHA256: 0000000000000000

@TD-er
Copy link
Member Author

TD-er commented Aug 18, 2022

Maybe we should split this debugging into a new issue as it doesn't seem to be related to the SPI flash mode.

@sobolkz
Copy link

sobolkz commented Aug 18, 2022

Maybe we should split this debugging into a new issue as it doesn't seem to be related to the SPI flash mode.

I can rename initial issue for example to "ESP32 16M 8M doesn't work from build 220809"?

@TD-er
Copy link
Member Author

TD-er commented Aug 18, 2022

Maybe we should split this debugging into a new issue as it doesn't seem to be related to the SPI flash mode.

I can rename initial issue for example to "ESP32 16M 8M doesn't work from build 220809"?

That's not describing what's happening to your node.
You seem to have issues with VSPI and/or the PMSx003 plugin.
Just stating some build is not working since XXX is maybe technically correct and for sure useful info in the description.
But as a title it is by no means descriptive of what's happening.

@TD-er TD-er merged commit 59b4f15 into letscontrolit:mega Aug 18, 2022
@TD-er TD-er deleted the bugfix/boarddef_QIO_mode branch August 18, 2022 22:17
@Jason2866
Copy link
Contributor

@TD-er Maybe it interrests you...
IDF function call to get real flash size does only work when in mode dout
The Arduino function get flash size is a hoax since it just tells what was set in boards manifest (from image header). Opened a issue espressif/arduino-esp32#7157
See the funny flash size from Info page
Bildschirmfoto_2022-08-19_um_18 28 12

@TD-er
Copy link
Member Author

TD-er commented Aug 20, 2022

I knew Tasmota was quite a bit smaller, but fitting on 2k... Wow ! ;)

@Jason2866
Copy link
Contributor

Jason2866 commented Aug 21, 2022

@TD-er Staars fixed the flash size issue and found a way to show the real used Flash Mode
See Tasmota PR https://github.com/arendst/Tasmota/pull/16280/files

Tasmota Info
"ProgramFlashSize":4096,"FlashSize":4096,"FlashChipId":"164020","FlashFrequency":80,"FlashMode":"QIO"

@TD-er
Copy link
Member Author

TD-er commented Aug 21, 2022

Thanks, will look into it and let me "inspire" to create a PR for ESPEasy too ;)

@Jason2866
Copy link
Contributor

I like it a lot that the projects helps each other and both gets better from this work together!

@TD-er
Copy link
Member Author

TD-er commented Aug 21, 2022

Yep for sure.
It is a great synergy.

@TD-er
Copy link
Member Author

TD-er commented Aug 21, 2022

The Arduino function get flash size is a hoax since it just tells what was set in boards manifest (from image header). Opened a issue espressif/arduino-esp32#7157

I was just looking into both pieces of code you linked.
This part to get the flash chip ID, was already present in the ESPEasy code for 8 months.
See:

uint32_t getFlashChipId() {
// Cache since size does not change
static uint32_t flashChipId = 0;
if (flashChipId == 0) {
#ifdef ESP32
uint32_t tmp = g_rom_flashchip.device_id;
for (int i = 0; i < 3; ++i) {
flashChipId = flashChipId << 8;
flashChipId |= (tmp & 0xFF);
tmp = tmp >> 8;
}
// esp_flash_read_id(nullptr, &flashChipId);
#elif defined(ESP8266)
flashChipId = ESP.getFlashChipId();
#endif // ifdef ESP32
}
return flashChipId;
}

This is what I now made from the other code you linked:

const __FlashStringHelper * getFlashChipMode() {
#if ESP8266
  switch (ESP.getFlashChipMode()) {
      case FM_QIO:   return F("QIO");
      case FM_QOUT:  return F("QOUT");
      case FM_DIO:   return F("DIO");
      case FM_DOUT:  return F("DOUT");
  }
  return F("Unknown");
#else
  // Source: https://github.com/letscontrolit/ESPEasy/pull/4200#issuecomment-1221607332
  const uint32_t spi_ctrl = REG_READ(SPI_CTRL_REG(0));
  /* Not all of the following constants are already defined in older versions of spi_reg.h, so do it manually for now*/
  if (spi_ctrl & BIT(24)) { //SPI_FREAD_QIO
      return F("QIO");
  } else if (spi_ctrl & BIT(20)) { //SPI_FREAD_QUAD
      return F("QOUT");
  } else if (spi_ctrl &  BIT(23)) { //SPI_FREAD_DIO
      return F("DIO");
  } else if (spi_ctrl & BIT(14)) { // SPI_FREAD_DUAL
      return F("DOUT");
  } else if (spi_ctrl & BIT(13)) { //SPI_FASTRD_MODE
      return F("Fast");
  } else {
      return F("Slow");
  }
  return F("DOUT");
#endif
}

@TD-er
Copy link
Member Author

TD-er commented Aug 21, 2022

And for completeness, I just wrote the function to get the flash freq.

uint32_t getFlashChipSpeed() {
  #ifdef ESP8266
  return ESP.getFlashChipSpeed();
  #else
  const uint32_t spi_clock = REG_READ(SPI_CLOCK_REG(0));
  if (spi_clock & BIT(31)) {
    // spi_clk is equal to system clock
    return APB_CLK_FREQ;
  }
  /* SPI_CLKCNT_N : R/W ;bitpos:[17:12] ;default: 6'h3 ; */
  /*description: In the master mode it is the divider of spi_clk. So spi_clk frequency
  is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/
  const uint32_t spi_clkdiv_pre = (spi_clock >> 18) & 0x1FFF;
  const uint32_t spi_clkcnt_n = (spi_clock >> 12) & 0x3F;
  const uint32_t spi_clkcnt_h = (spi_clock >> 6) & 0x3F;
  const uint32_t spi_clkcnt_l = (spi_clock) & 0x3F;

  String log = F("Flash freq: APB_CLK_FREQ = ");
  log += APB_CLK_FREQ;
  log += F(" spi_clkdiv_pre = ");
  log += spi_clkdiv_pre;
  log += F(" spi_clkcnt_n = ");
  log += spi_clkcnt_n;
  log += F(" spi_clkcnt_h = ");
  log += spi_clkcnt_h;
  log += F(" spi_clkcnt_l = ");
  log += spi_clkcnt_l;
  addLog(LOG_LEVEL_INFO, log);

  return (APB_CLK_FREQ / (spi_clkdiv_pre + 1)) / (spi_clkcnt_n + 1);
  #endif
}

@TD-er
Copy link
Member Author

TD-er commented Aug 22, 2022

Also computing the ABP freq:

#ifdef ESP32
uint32_t getAbpFrequency() {
  #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
	return APB_CLK_FREQ;
  #else
  rtc_cpu_freq_config_t conf;

  //Get current CPU clock configuration
  rtc_clk_cpu_freq_get_config(&conf);
    String log = F("getAbpFrequency: source = ");
  log += conf.source;
  log += F(" source_freq_mhz = ");
  log += conf.source_freq_mhz;
  log += F(" div = ");
  log += conf.div;
  log += F(" freq_mhz = ");
  log += conf.freq_mhz;
  addLog(LOG_LEVEL_INFO, log);

  if(conf.freq_mhz >= 80){
    return 80 * 1000000;
  }
  return (conf.source_freq_mhz * 1000000) / conf.div;
  #endif
}
#endif


uint32_t getFlashChipSpeed() {
  #ifdef ESP8266
  return ESP.getFlashChipSpeed();
  #else
  const uint32_t spi_clock = REG_READ(SPI_CLOCK_REG(0));


  if (spi_clock & BIT(31)) {
    // spi_clk is equal to system clock
    return getAbpFrequency();
  }
  /* SPI_CLKCNT_N : R/W ;bitpos:[17:12] ;default: 6'h3 ; */
  /*description: In the master mode it is the divider of spi_clk. So spi_clk frequency
  is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/
  const uint32_t spi_clkdiv_pre = (spi_clock >> 18) & 0x1FFF;
  const uint32_t spi_clkcnt_n = (spi_clock >> 12) & 0x3F;
  const uint32_t spi_clkcnt_h = (spi_clock >> 6) & 0x3F;
  const uint32_t spi_clkcnt_l = (spi_clock) & 0x3F;

  String log = F("Flash freq: APB_CLK_FREQ = ");
  log += getAbpFrequency();
  log += F(" spi_clkdiv_pre = ");
  log += spi_clkdiv_pre;
  log += F(" spi_clkcnt_n = ");
  log += spi_clkcnt_n;
  log += F(" spi_clkcnt_h = ");
  log += spi_clkcnt_h;
  log += F(" spi_clkcnt_l = ");
  log += spi_clkcnt_l;
  addLog(LOG_LEVEL_INFO, log);

  return (getAbpFrequency() / (spi_clkdiv_pre + 1)) / (spi_clkcnt_n + 1);
  #endif
}

With the log:

21053 : Info   : getAbpFrequency: source = 1 source_freq_mhz = 480 div = 2 freq_mhz = 240
21054 : Info   : Flash freq: APB_CLK_FREQ = 80000000 spi_clkdiv_pre = 0 spi_clkcnt_n = 1 spi_clkcnt_h = 0 spi_clkcnt_l = 1
21055 : Info   : getAbpFrequency: source = 1 source_freq_mhz = 480 div = 2 freq_mhz = 240

The clock source is also nice to checkout:

typedef enum {
    RTC_CPU_FREQ_SRC_XTAL,  //!< XTAL
    RTC_CPU_FREQ_SRC_PLL,   //!< PLL (480M or 320M)
    RTC_CPU_FREQ_SRC_8M,    //!< Internal 8M RTC oscillator
    RTC_CPU_FREQ_SRC_APLL   //!< APLL
} rtc_cpu_freq_src_t;

Edit:
There was already a function to do exactly this....

uint32_t getCpuFrequencyMhz();  // In MHz
uint32_t getXtalFrequencyMhz(); // In MHz
uint32_t getApbFrequency();     // In Hz

... but I have no idea what I should include to access this function.

@TD-er
Copy link
Member Author

TD-er commented Aug 22, 2022

N.B. Also found this old PR, which does have an exceptional elaborate description giving more insight into the boot process of the ESP32.
espressif/esp-idf@8399ed9

@Jason2866
Copy link
Contributor

Thx, for the active sharing!

@Jason2866
Copy link
Contributor

Jason2866 commented Aug 22, 2022

This is working

#include <Arduino.h>
#include "soc/soc.h"
#include "soc/spi_reg.h"

#if CONFIG_IDF_TARGET_ESP32
  #include "esp32/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32S2  // ESP32-S2
  #include "esp32s2/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32S3  // ESP32-S3
  #include "esp32s3/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32C3  // ESP32-C3
  #include "esp32c3/rom/spi_flash.h"
#endif

#ifndef REG_SPI_BASE
#define REG_SPI_BASE(i)     (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 )))
#endif

String ESP_getFlashChipMode(void) {
const uint32_t spi_ctrl = REG_READ(SPI_CTRL_REG(0));
/* Not all of the following constants are already defined in older versions of spi_reg.h, so do it manually for now*/
if (spi_ctrl & BIT(24)) { //SPI_FREAD_QIO
    return F("QIO");
} else if (spi_ctrl & BIT(20)) { //SPI_FREAD_QUAD
    return F("QOUT");
} else if (spi_ctrl &  BIT(23)) { //SPI_FREAD_DIO
    return F("DIO");
} else if (spi_ctrl & BIT(14)) { // SPI_FREAD_DUAL
    return F("DOUT");
} else if (spi_ctrl & BIT(13)) { //SPI_FASTRD_MODE
    return F("Fast");
} else {
    return F("Slow");
}
return F("DOUT");
}

uint32_t ESP_getFlashChipId(void)
{
  uint32_t id = g_rom_flashchip.device_id;
  id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00);
  return id;
}

uint32_t ESP_getFlashChipRealSize(void)
{
  uint32_t id = (ESP_getFlashChipId() >> 16) & 0xFF;
  return 2 << (id - 1);
}

void setup() {

  Serial.begin(115200);
  ps_malloc(550 * 1024);
  uint8_t * buf = (uint8_t*)malloc(500 * 1024);
  if (buf == NULL)
    Serial.println("can't allocate memory with malloc\n");

    Serial.print("ESP32 SDK: "); Serial.println(ESP.getSdkVersion());
    Serial.print("ESP32 CPU FREQ: "); Serial.print(getCpuFrequencyMhz()); Serial.println(" MHz");
    Serial.print("ESP32 XTAL FREQ: "); Serial.print(getXtalFrequencyMhz()); Serial.println(" MHz");
    Serial.print("ESP32 APB FREQ: "); Serial.print(getApbFrequency() / 1000000.0, 1); Serial.println(" MHz");
    Serial.print("ESP32 FLASH CHIP ID: "); Serial.println(ESP_getFlashChipId());
    Serial.print("ESP32 FLASH REAL SIZE: "); Serial.print(ESP_getFlashChipRealSize() / (1024.0 * 1024), 2); Serial.println(" MB");
    Serial.print("ESP32 FLASH SIZE (MAGIC BYTE): "); Serial.print(ESP.getFlashChipSize() / (1024.0 * 1024), 2); Serial.println(" MB");
    Serial.print("ESP32 FLASH REAL MODE: "); Serial.println(ESP_getFlashChipMode());
    Serial.print("ESP32 FLASH (MAGIC BYTE): "); Serial.print(ESP.getFlashChipMode()); Serial.println(", 0=QIO, 1=QOUT, 2=DIO, 3=DOUT");
    Serial.print("ESP32 RAM SIZE: "); Serial.print(ESP.getHeapSize() / 1024.0, 2); Serial.println(" KB");
    Serial.print("ESP32 FREE RAM: "); Serial.print(ESP.getFreeHeap() / 1024.0, 2); Serial.println(" KB");
    Serial.print("ESP32 MAX RAM ALLOC: "); Serial.print(ESP.getMaxAllocHeap() / 1024.0, 2); Serial.println(" KB");
    Serial.print("ESP32 FREE PSRAM: "); Serial.print(ESP.getFreePsram() / 1024.0, 2); Serial.println(" KB");
}

void loop() {
}

@TD-er
Copy link
Member Author

TD-er commented Aug 22, 2022

Ah found the reason why I could not get it to compile before.

getApbFrequency != getAbpFrequency ;)
I need some coffee ;)

@Jason2866
Copy link
Contributor

fyi The upcoming new Tasmota framework32 core 2.0.5 will NOT support mode dout anymore. Support for will be removed. With the knowledge know how the bootloader stuff is working we decided to deprecate dout. Reason EVERY esp32 and the newer MCUs do support mode dio. Choosing mode dout for initial flash prevents later to switch to a faster mode. All devices are locked to dout. NO OTA update can change this (needs replacing the bootloader).
In my test no device failed when uploaded a new firmware no matter in which flash mode is was build.

@TD-er
Copy link
Member Author

TD-er commented Aug 23, 2022

OK, so when we switch to 2.0.5 too, all existing users can perform an OTA update?
Only limitation then is that the flash will not work at the same speed as with nodes flashed via serial updating the bootloader.

Which default mode will you be using? DIO?
What about the newer ESP32's like the S3 and those C-versions? For those you will choose the lowest available I assume?

Do you also plan on changing the flash frequency?

@Jason2866
Copy link
Contributor

Jason2866 commented Aug 23, 2022

OK, so when we switch to 2.0.5 too, all existing users can perform an OTA update?
Only limitation then is that the flash will not work at the same speed as with nodes flashed via serial updating the bootloader.

Yes

Which default mode will you be using? DIO?

Yes

What about the newer ESP32's like the S3 and those C-versions? For those you will choose the lowest available I assume?

All S3 boards have at least qio capable FLASH/PSRAM. Slowest mode (default) is qio
NO slower mode will be supported. For S2 and C3 default will be dio

Do you also plan on changing the flash frequency?

No, since i had boards failing with clock > 40 Mhz.

@TD-er
Copy link
Member Author

TD-er commented Aug 23, 2022

Do you also plan on changing the flash frequency?

No, since i had boards failing with clock > 40 Mhz.

Saw here that the newer boards apparently even support > 80 MHz SPI?
Not sure why you should want to have that on boards where most even struggle on 80 MHz, probably due to poor component choices.
But even the good old ESP32 does seem to have an internal PLL running at 480 MHz so it might be usefull I guess.

@Jason2866
Copy link
Contributor

Jason2866 commented Aug 23, 2022

80 Mhz is supported from the framework (now and core 2.0.5). It is just not a default.
You can set for a known working device for which you have a env in platformio.
For example:

[env:tasmota32-denky]
extends                 = env:tasmota32_base
board                   = esp32_8M
upload_port             = /dev/cu.usbserial-denky_A7A8
upload_speed            = 2000000
board_build.flash_mode  = qio
board_build.f_flash     = 80000000L
board_build.f_cpu       = 240000000L
build_flags             = ${env:tasmota32_base.build_flags}

This board is fast as hell ;-)

@Jason2866
Copy link
Contributor

Since you are now deep in SPI "stuff". Maybe there is a way for overclocking? There is for sure some "space" in MCU clock (for good devices). Like ESP32 pico v3.

@TD-er
Copy link
Member Author

TD-er commented Aug 23, 2022

I did notice that there are very elaborate flash settings, like timing delays in (APB) clock cycles.
Also there is also some info about the max. attainable clock frequencies based on which pins are used.
For example if you're using the SPI bus without remapping the pins via the GPIO matrix, you gain some speed (or at least not adding some delays when switching via the GPIO matrix).
See: https://docs.espressif.com/projects/esp-idf/en/v4.4.1/esp32/api-reference/peripherals/spi_master.html#timing-considerations

As you can see on that link, there might even be quite a speed improvement by using a lower SPI clock (when using the GPIO matrix).
Upto 26.6 MHz on the GPIO matrix and upto 80 MHz for the IO_MUX (essentially the default SPI pins and HW chip select pin) you can use DMA. This will probably save quite a lot as transations may be done quite a bit faster.
N.B. there was some warning somewhere about on which core you allocate this memory for DMA and service it.

Also there seems to be some preparation for DDR-like behavior, but not sure if there's already hardware available which may support it. Maybe for future silicon?

For some ST7789 display I have here, I noticed that I was not able to go over 11.something MHz, so it seems the delay was already around 75 ns. Not sure what caused the delay (I was using the IO_MUX pins as far as I know). May have to look into it a bit more.

@Jason2866
Copy link
Contributor

Tried to flash my S3 with 120Mhz flash freq. Seems esptool needs a update (using already v4.2.1)

usage: esptool elf2image [-h] [--output OUTPUT] [--version {1,2,3}]
                         [--min-rev {0, ... 255}] [--secure-pad]
                         [--secure-pad-v2]
                         [--elf-sha256-offset ELF_SHA256_OFFSET]
                         [--dont-append-digest] [--use_segments]
                         [--flash-mmu-page-size {64KB,32KB,16KB}]
                         [--flash_freq {80m,60m,48m,40m,30m,26m,24m,20m,16m,15m,12m}]
                         [--flash_mode {qio,qout,dio,dout}]
                         [--flash_size {256KB,512KB,1MB,2MB,2MB-c1,4MB,4MB-c1,8MB,16MB,32MB,64MB,128MB}]
                         [--spi-connection SPI_CONNECTION]
                         input
esptool elf2image: error: argument --flash_freq/-ff: invalid choice: '120m' (choose from '80m', '60m', '48m', '40m', '30m', '26m', '24m', '20m', '16m', '15m', '12m')
*** [.pio/build/tasmota32s3/firmware.bin] Error 2

@Jason2866
Copy link
Contributor

Well, Arduino is lacking this support. Tried IDF and the config with 120 Mhz can be choosen and gets flashed.
It dont understand the sdkconfig for. So many settings! Maybe i dive into tomorrow...

#
# Serial flasher config
#
CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y
CONFIG_ESPTOOLPY_FLASHMODE="dio"
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
CONFIG_ESPTOOLPY_FLASHFREQ="80m"
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
CONFIG_ESPTOOLPY_BEFORE_RESET=y
CONFIG_ESPTOOLPY_BEFORE="default_reset"
CONFIG_ESPTOOLPY_AFTER_RESET=y
CONFIG_ESPTOOLPY_AFTER="hard_reset"

CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
# end of Serial flasher config

@TD-er
Copy link
Member Author

TD-er commented Aug 23, 2022

The ESP32 does have an internal PLL which (at least on my unit) was running at 480 MHz (12x crystal freq)
As far as I could see, the max. SPI freq. is the APB freq.
All SPI timings seem to be derived from this APB.
80 MHz is perfectly fine to be generated from 480 MHz PLL, but so is 120 MHz.
So this could mean the S3 does allow for 120 MHz APB.
A lot of other stuff relates to this frequency, so it looks to me like those units could be quite a bit more suitable for timing critical real time stuff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants