Arduino icon indicating copy to clipboard operation
Arduino copied to clipboard

Can we add an option to disable the F_CPU macro in arduino IDE?

Open pgrAm opened this issue 4 years ago • 4 comments

Currently the core does not provide any way to change the clock speed of the esp8266. The espressif sdk provides the function system_update_cpu_freq() but this does not play nice with the arduino core which seems to assume that the clock speed is set at compile time and never changes. Furthermore the core seems to be written to rely on the F_CPU macro, however if F_CPU is not defined there seems to be an alternate code path which would allow for speed changes on the fly. The problem is there is no way to disable this macro from inside the Arduino IDE, only to toggle it between 80 & 160 MHz.

Being able to change CPU speed at runtime would be a very useful feature especially for projects that need to conserve power but need to operate in AP mode.

I would like to ask why is changing CPU speed at runtime not supported? It would seem like all that would need to happen would be to add a third option to the "CPU Frequency" menu that disables the F_CPU macro allowing it to be toggled at runtime by system_update_cpu_freq(). Am I missing anything else that is needed?

pgrAm avatar Aug 15 '21 17:08 pgrAm

Indeed by some tests REG_SET_BIT(0x3ff00014, BIT(0)); ets_update_cpu_frequency(160); works, and system_get_cpu_freq() returns 160... if ran inmediately after. Some time after, it's reverted to 80.

asturcon3 avatar Sep 16 '21 12:09 asturcon3

The espressif sdk provides the function system_update_cpu_freq() but this does not play nice with the arduino core which seems to assume that the clock speed is set at compile time and never changes.

Some time after, it's reverted to 80.

Looking at the start-up & user task code https://github.com/esp8266/Arduino/blob/ac4af38c09c8bd4311bef4a4528885b624c5b9d4/cores/esp8266/core_esp8266_main.cpp#L93-L110

Right now, you follow the rules of the preloop func - it forcibly resets the CPU speed to either the value in the F_CPU or just updates the register based on the SDK info. But, I also kind of miss the purpose of resetting the frequency every time before the loop() is called, perhaps there was some issue discussing it. (i.e. why not just set F_CPU at boot and never try to change it again)

Notice that you can override the weakly-linked function from the core_esp8266_main.cpp, just declare it in the sketch as extern "C" void preloop_update_frequency() { ...stuff... } and it won't interfere with the user code anymore.

edit: pwm code might need updates though, as there's a constexpr math that depends on the F_CPU value https://github.com/esp8266/Arduino/blob/ac4af38c09c8bd4311bef4a4528885b624c5b9d4/cores/esp8266/core_esp8266_waveform_pwm.cpp#L183-L188 https://github.com/esp8266/Arduino/blob/ac4af38c09c8bd4311bef4a4528885b624c5b9d4/cores/esp8266/core_esp8266_waveform_phase.cpp#L62-L63

mcspr avatar Oct 24 '21 08:10 mcspr

But, I also kind of miss the purpose of resetting the frequency every time before the loop() is called, perhaps there was some issue discussing it. (i.e. why not just set F_CPU at boot and never try to change it again)

Long time ago (c) Espressif was changing the CPU frequency inside some of the closed-source libraries. For example, a WPA2 handshake was taking quite a long time so they added calls to raise frequency to 160 before the handshake, and lower it to 80 afterwards. Thing is, the frequency was lowered to 80 regardless of the original value before the handshake. No idea if that's still the case, I guess a simple way to check is to -Wl,--wrap the frequency switch function and see when it gets called and with what arguments.

igrr avatar Oct 24 '21 10:10 igrr

No idea if that's still the case, I guess a simple way to check is to -Wl,--wrap the frequency switch function and see when it gets called and with what arguments.

Debugging with the suggested wrapper and the default 2.2.2-dev(38a443e) aka NONOSDK22x_190703 from our tools/sdk/libs Making preloop() do nothing and manually placing calls to CPU2X & ets_update_cpu_frequency(), it seems to preserve the originally set frequency.

Normal boot, there is a single call with 160 arg when attempting connection as STA or when bringing up AP, but values are seem to be restored afterwards as it prints CPU2X and ets_get_cpu_frequency() values. When setup() calls 160 mode, attempting connect there are a bunch of calls with 80, around 25...30 times as it connects and then it stops increasing, and it will still print 160 & cpu2x bit as set.


static size_t cpu80 {0};
static size_t cpu160 {0};

// -Wl,-wrap,ets_update_cpu_frequency
extern "C" void __real_ets_update_cpu_frequency(uint32_t);
extern "C" void __wrap_ets_update_cpu_frequency(uint32_t ticks) {
    switch (ticks) {
    case 160:
        ++cpu160;
        break;
    case 80:
        ++cpu80;
        break;
    }

    __real_ets_update_cpu_frequency(ticks);
}

extern "C" uint32_t ets_get_cpu_frequency();
extern "C" void preloop_update_frequency() {
}

void callMeAtSetup() {
    // CPU2X |= 1UL;
    // __real_ets_update_cpu_frequency(160);
    // or, system_update_cpu_freq(160), which does both things
    static Ticker ticker;
    ticker.attach_ms(1000, []() {
         ::printf(":actually %u :cpu2x %u :cpu160 %u :cpu80 %u\n", ets_get_cpu_frequency(), CPU2X, cpu160, cpu80);
    });
}

It looks like it actually uses the ets_update_cpu_frequency() argument value i.e. calling with 0 will save it somewhere, and get() then returns the 0. Looking at RTOS code implementing the func, it ignores the argument and checks CPU2X value directly https://github.com/espressif/ESP8266_RTOS_SDK/blob/a683bd733715750e1aa19faaf6db9c6851466234/components/esp8266/source/system_api.c#L399-L412

I also noticed ets_cpu_update_frequency() referenced in the wps_attr_build.o and wps_enrollee.o, but I am not really able to test WPS (...and check whether it 'gets' the freq beforehand. there's no ets_get_cpu_frequency symbol in the headers until later versions of nonos, and idk what exactly to look for in the aforementioned files assembly).

mcspr avatar Oct 25 '21 14:10 mcspr