Skip to content

[ESP32-C2] Flash chip speed set to 60 MHz, but SPI clock = 40 #8960

Closed
@TD-er

Description

@TD-er

Board

ESP32-C2

Device Description

4MB ESP32-C2

Hardware Configuration

Nothing attached

Version

latest master (checkout manually)

IDE Name

PlatformIO

Operating System

Windows 11

Flash frequency

60MHz

PSRAM enabled

no

Upload speed

115200

Description

Flash speed in the board definition is set to 60 MHz, but reported SPI clock speed is 40 MHz.

This is my code to get the SPI bus clock frequency:

// All ESP32-variants have the SPI flash wired to SPI peripheral 1
  const uint32_t spi_clock = REG_READ(SPI_CLOCK_REG(1));

  addLog(LOG_LEVEL_INFO,   strformat(
    F("SPI_clock: %x  Bit31: %d SPI_CLOCK_REG(1): %x"), 
    spi_clock, spi_clock & BIT(31), SPI_CLOCK_REG(1)));

  if (spi_clock & BIT(31)) {
    // spi_clk is equal to system clock
    return getApbFrequency();
  }
  return spiClockDivToFrequency(spi_clock);

Which returns this log on my (ESPEasy) system:

00:01:49.923 : (86316) Info   : SPI_clock: 7fc  Bit31: 0 SPI_CLOCK_REG(1): 6000200c

As can be seen, bit31 is not set to 0, and thus it is not equal to the system clock.
See:

typedef union {
uint32_t value;
struct {
uint32_t clkcnt_l: 6; /*it must be equal to spi_clkcnt_N.*/
uint32_t clkcnt_h: 6; /*it must be floor((spi_clkcnt_N+1)/2-1).*/
uint32_t clkcnt_n: 6; /*it is the divider of spi_clk. So spi_clk frequency is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/
#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
uint32_t clkdiv_pre: 4; /*it is pre-divider of spi_clk.*/
uint32_t reserved: 9; /*reserved*/
#else
uint32_t clkdiv_pre: 13; /*it is pre-divider of spi_clk.*/
#endif
uint32_t clk_equ_sysclk: 1; /*1: spi_clk is eqaul to system 0: spi_clk is divided from system clock.*/
};
} spiClk_t;
#define ClkRegToFreq(reg) (apb_freq / (((reg)->clkdiv_pre + 1) * ((reg)->clkcnt_n + 1)))
uint32_t spiClockDivToFrequency(uint32_t clockDiv)
{
uint32_t apb_freq = getApbFrequency();
spiClk_t reg = { clockDiv };
return ClkRegToFreq(&reg);
}

spi_clock register value of 0x7FC = 011111 111100 and thus only clkcnt_l and clkcnt_h are set, the rest is 0.
Meaning spiClockDivToFrequency() returns just the APB frequency, which is 40 MHz.

I also tested with SPI bus 0:

29.839 : (78896) Info   : SPI_clock: 0  Bit31: 0 SPI_CLOCK_REG(0): 6000300c

Here all bits of spi_clock are 0.

I wonder whether this calculation and/or register interpretation is correct for the C2. (and others?)
Or perhaps the reported APB frequency is incorrect?

See:

static uint32_t calculateApb(rtc_cpu_freq_config_t * conf){
#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2
return APB_CLK_FREQ;
#else
if(conf->freq_mhz >= 80){
return 80 * MHZ;
}
return (conf->source_freq_mhz * MHZ) / conf->div;
#endif
}

gijs@Imagine:/mnt/c/Users/gijsn/.platformio/packages/framework-arduinoespressif32$ grep APB_CLK_FREQ * -R|grep 1000000
tools/esp32-arduino-libs/esp32/include/soc/esp32/include/soc/soc.h:#define  APB_CLK_FREQ_ROM                            ( 26*1000000 )
tools/esp32-arduino-libs/esp32/include/soc/esp32/include/soc/soc.h:#define  APB_CLK_FREQ                                ( 80*1000000 )       //unit: Hz
tools/esp32-arduino-libs/esp32c2/include/soc/esp32c2/include/soc/soc.h:#define  APB_CLK_FREQ_ROM                            ( 40*1000000 )
tools/esp32-arduino-libs/esp32c2/include/soc/esp32c2/include/soc/soc.h:#define  APB_CLK_FREQ                                ( 40*1000000 )
tools/esp32-arduino-libs/esp32c3/include/soc/esp32c3/include/soc/soc.h:#define  APB_CLK_FREQ_ROM                            ( 40*1000000 )
tools/esp32-arduino-libs/esp32c3/include/soc/esp32c3/include/soc/soc.h:#define  APB_CLK_FREQ                                ( 80*1000000 )
tools/esp32-arduino-libs/esp32c6/include/soc/esp32c6/include/soc/soc.h:#define  APB_CLK_FREQ_ROM                            ( 40*1000000 )
tools/esp32-arduino-libs/esp32c6/include/soc/esp32c6/include/soc/soc.h:#define  APB_CLK_FREQ                                ( 40*1000000 )
tools/esp32-arduino-libs/esp32c6/include/soc/esp32c6/include/soc/soc.h:#define  MODEM_APB_CLK_FREQ                          ( 80*1000000 )
tools/esp32-arduino-libs/esp32h2/include/soc/esp32h2/include/soc/soc.h:#define  APB_CLK_FREQ_ROM                            ( 32*1000000 )
tools/esp32-arduino-libs/esp32h2/include/soc/esp32h2/include/soc/soc.h:#define  APB_CLK_FREQ                                ( 32*1000000 )
tools/esp32-arduino-libs/esp32h2/include/soc/esp32h2/include/soc/soc.h:#define  MODEM_APB_CLK_FREQ                          ( 32*1000000 )
tools/esp32-arduino-libs/esp32s2/include/soc/esp32s2/include/soc/soc.h:#define  APB_CLK_FREQ_ROM                            ( 40*1000000 )
tools/esp32-arduino-libs/esp32s2/include/soc/esp32s2/include/soc/soc.h:#define  APB_CLK_FREQ                                ( 80*1000000 )       //unit: Hz
tools/esp32-arduino-libs/esp32s2/include/soc/esp32s2/include/soc/soc.h:#define  MODEM_REQUIRED_MIN_APB_CLK_FREQ             ( 80*1000000 )
tools/esp32-arduino-libs/esp32s3/include/soc/esp32s3/include/soc/soc.h:#define  APB_CLK_FREQ_ROM                            (40*1000000)
tools/esp32-arduino-libs/esp32s3/include/soc/esp32s3/include/soc/soc.h:#define  APB_CLK_FREQ                                (80*1000000)
tools/esp32-arduino-libs/esp32s3/include/soc/esp32s3/include/soc/soc.h:#define  MODEM_REQUIRED_MIN_APB_CLK_FREQ             (80*1000000)

As can be seen with the H2, this can be something other than 40 or 80 MHz, which makes perfect sense given the H2 runs at 96 MHz CPU clock.
So I wonder whether the defined APB clock frequency for the C2 is correct.
Maybe this one should be 60 MHz?

The APB clock for the C6 seems a bit odd, as it is defined as 40 MHz, while MODEM_APB_CLK_FREQ is 80 MHz. For all other platforms (except the H2) the APB clock has a higher frequency than the ROM (boot?) frequency and the same frequency as MODEM_APB_CLK_FREQ when defined.

N.B. my recent PR on the ESP-IDF repo to fix address calculation for REG_SPI_BASE(i) was incorrectly merged by the IDF team.
So if you run it with the current implementation of the IDF code, you will get an out of bounds error as the base address always returns 0 with this incorrect code.

I'm using this for the REG_SPI_BASE:

cores/esp32/Esp.cpp:  #define REG_SPI_BASE(i)     (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 )))
tools/esp32-arduino-libs/esp32/include/soc/esp32/include/soc/spi_reg.h:#define REG_SPI_BASE(i)     (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 )))
tools/esp32-arduino-libs/esp32c2/include/soc/esp32c2/include/soc/soc.h:#define REG_SPI_BASE(i)                         (((i)==2) ? (DR_REG_SPI2_BASE) : (DR_REG_SPI0_BASE - ((i) * 0x1000))) // only one GPSPI
tools/esp32-arduino-libs/esp32c3/include/soc/esp32c3/include/soc/soc.h:#define REG_SPI_BASE(i)                         (((i)==2) ? (DR_REG_SPI2_BASE) : (DR_REG_SPI0_BASE - ((i) * 0x1000)))  // only one GPSPI
tools/esp32-arduino-libs/esp32c6/include/soc/esp32c6/include/soc/soc.h:#define REG_SPI_BASE(i)                         (((i)==2) ? (DR_REG_SPI2_BASE) : (DR_REG_SPI0_BASE - ((i) * 0x1000)))  // only one GPSPI on C6
tools/esp32-arduino-libs/esp32h2/include/soc/esp32h2/include/soc/soc.h:#define REG_SPI_BASE(i)                         (DR_REG_SPI2_BASE + (i - 2) * 0x1000)  // only one GPSPI
tools/esp32-arduino-libs/esp32s2/include/soc/esp32s2/include/soc/soc.h:#define REG_SPI_BASE(i)         (DR_REG_SPI2_BASE + (((i)>3) ? (((i-2)* 0x1000) + 0x10000) : ((i - 2)* 0x1000 )))
tools/esp32-arduino-libs/esp32s3/include/soc/esp32s3/include/soc/soc.h:#define REG_SPI_BASE(i)         (((i)==2) ? (DR_REG_SPI2_BASE) : (DR_REG_SPI0_BASE - ((i) * 0x1000)))  // GPSPI2 and GPSPI3

N.B.2 Not 100% sure about this for the ESP32-C6

Sketch

See above

Debug Message

See above

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions