-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Conversation
This forum question seems directly related to this. |
Mhh, looking at this https://github.com/espressif/arduino-esp32/blob/master/tools/platformio-build-esp32c3.py#L301-L308 |
I just tried printing the config for this in my build scripts and it failed when not supplying a default. Now making a commit to include these in the ESP32 board defs. |
@TD-er CI has finished. Does it work? |
Still testing on my boards. |
OK, this is really tricky^2 OTA update on a device which I flashed a few hours ago works fine. So this is really really tricky and I have no idea how to proceed:
The node with 4M flash and SPIFFS is running fine regardless of how I updated it. |
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. |
I think it does use QIO calls when writing/reading the filesystem (with 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 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 What other things are changed in a build when running in DIO or DOUT vs. QIO? But to summarize, this is nothing less than a nightmare situation.
|
Thread found by @tonhuisman regarding the need for extra commands to set QIO mode on some chips. |
Looks different, since i do not manage to get mode |
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 |
Ah great minds ;) |
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. |
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. Not sure if we can work this out on our own without calling in the in-depth knowledge of those like @igrr |
Found this https://gitter.im/espressif/arduino-esp32?at=5ecee66b4c9b0f060d2a7634 |
What I understand now is that the ESP32 only has limited support for QIO in its bootloader stage. 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. |
You are probably right. This would fit to our experience with Tasmota. We always used |
Yep, let's hope this hypothesis is correct, as I also always used DOUT (at least since switching to IDF 4.4) |
Well, upgrading devices from core < 2.0.4 which do not use mode |
You can use the build (latest dev Arduino/IDF version) with the enabled bootloader logging:
|
My test C3 does now work with Tasmota in all 4 flash modes without an issue! With this change the current boards manifest can be used and are working with the old and new core without a change |
The first draft PR is perfectly clear to me. For example I have to google this syntax, as I have no clue (yet) what it does:
I know it is about env variables parsing, but I don't know what the |
Ah.... |
I think I'll leave it to the temporary one you made until the 2.0.5 is out. |
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:
|
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. |
@TD-er Maybe it interrests you... |
I knew Tasmota was quite a bit smaller, but fitting on 2k... Wow ! ;) |
@TD-er Staars fixed the flash size issue and found a way to show the real used Flash Mode Tasmota Info |
Thanks, will look into it and let me "inspire" to create a PR for ESPEasy too ;) |
I like it a lot that the projects helps each other and both gets better from this work together! |
Yep for sure. |
I was just looking into both pieces of code you linked. ESPEasy/src/src/Helpers/Hardware.cpp Lines 582 to 602 in c76faa4
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
} |
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
} |
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:
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: 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. |
N.B. Also found this old PR, which does have an exceptional elaborate description giving more insight into the boot process of the ESP32. |
Thx, for the active sharing! |
This is working
|
Ah found the reason why I could not get it to compile before.
|
fyi The upcoming new Tasmota framework32 core 2.0.5 will NOT support mode |
OK, so when we switch to 2.0.5 too, all existing users can perform an OTA update? Which default mode will you be using? DIO? Do you also plan on changing the flash frequency? |
Yes
Yes
All S3 boards have at least qio capable FLASH/PSRAM. Slowest mode (default) is
No, since i had boards failing with clock > 40 Mhz. |
Saw here that the newer boards apparently even support > 80 MHz SPI? |
80 Mhz is supported from the framework (now and core 2.0.5). It is just not a default.
This board is fast as hell ;-) |
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. |
I did notice that there are very elaborate flash settings, like timing delays in (APB) clock cycles. 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). 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. |
Tried to flash my S3 with 120Mhz flash freq. Seems esptool needs a update (using already v4.2.1)
|
Well, Arduino is lacking this support. Tried IDF and the config with 120 Mhz can be choosen and gets flashed.
|
The ESP32 does have an internal PLL which (at least on my unit) was running at 480 MHz (12x crystal freq) |
Mainly to continue discussion with @Jason2866 regarding flash mode.
See also: #4199 (comment)