Setting CPU frequency

I have tried setting CPU frequency on esp32 using setCpuFrequencyMhz() which returns true and then reading it back and I get 240MHz no matter what I set it to. Its a TTGO-Display board with 40Mhz Crystal. I am sure I have successfully set the frequency previously.

I think I am missing something fundamental.

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino

I have a project working nicely on this board, I just wanted to cut down the CPU frequency if possible to help my battery life out as much as possible.

My knowledge gaps are surrounding the efuses and exactly if and how I look at that with platformio.

This is weird. The API call not working maybe? Have you tried it per documentation in the platformio.ini?

Thanks, good call, I was going for 40Mhz for no particular reason.

I tried 40000000L in the ini and the board did not like that at all.
But 160 and 80 work. So… I guess wherever I read that 40Mhz crystal can give you 40,20,10Mhz is probably wrong.

What’s the actual answer?

Well ESP32 Change CPU Speed (Clock Frequency) – DeepBlue agrees with you.

Can you try using the latest 2.0.2 core? Set

platform = https://github.com/Jason2866/platform-espressif32.git

instead of the old platform = espressif32 and try calling into the original setCpuFrequencyMhz(40); API again and see what getCpuFrequencyMhz() gives you back.

Starting…
Button Init
CPU Freq: 240
Old Freq: 240
New Freq: 240 1
Old Freq: 240
New Freq: 240 1
Old Freq: 240
New Freq: 240 1
Old Freq: 240
New Freq: 240 1
Old Freq: 240
New Freq: 240 1
Old Freq: 240
New Freq: 240 1

btn2.setPressedHandler([](Button2 &b)
                         {
                           if (true)
                           {
                             uint32_t f = getCpuFrequencyMhz();
                             sprintf(string,"Old Freq: %i",f);
                             TFT_printLine(string, true);

                             if(f == 80) f = 40;
                             if(f == 240) f = 40;
                             if(f == 40) f = 20;
                             if(f == 20) f = 10;
                             if(f == 10) f = 240;

                             bool retVal = setCpuFrequencyMhz(f);
                             f = getCpuFrequencyMhz();
                             sprintf(string,"New Freq: %i %d",f,retVal);
                              TFT_printLine(string);
                           } });

So it is using the new core and it does the same.
Is it the chip?

Using the build option.

Button Init
CPU Freq: 80
Old Freq: 80
New Freq: 240 1
Old Freq: 240
New Freq: 240 1
Old Freq: 240

Starts at 80M and any change makes it 240!

It is correct that setter is in megahertz and not hertz?

Looking at arduino-esp32/esp32-hal-cpu.c at master · espressif/arduino-esp32 · GitHub, what does it say on the serial when you add build_flags = -DCORE_DEBUG_LEVEL=5 to the platformio.ini? (for error logs)

Well for a start I’m a plonker because my quick fudge


                             if(f == 80) f = 40;
                             if(f == 240) f = 40;
                             if(f == 40) f = 20;
                             if(f == 20) f = 10;
                             if(f == 10) f = 240;

Will always set 240Mhz duh.

So just stuck f = 40;

Button Init
CPU Freq: 80
[ 4156][V][WiFiServer.h:42] WiFiServer(): WiFiServer::WiFiServer(port=23, …)
CPU Freq: 80
Trying Freq:40
[ ␀�␞␘�␞x�~�␆�f�fx␞␆�x␘��␘�␆␆��␞␆f~��␞�~␘��␘␞�f��fx�␆f~x��fx␆f~f��␞ff����␆����␘␘ff␆␆��␘␘␞␀␘��␀��␘��␘␘␞␀␘�␞␆��␆�␀�␀␆f��~␀␘␞␀␘␘␘␘␘␘␘␘��f���␆��␆~ff␆�␀␘␘fx␆�~␘␘␘�fx`�f␆f���������␞��

I’m guessing that the baudrate generator is affected by it.

Then it goes bang anyway:
rst:0xc (SW_CPU_RESET),boot:0x13 (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:DIO, clock div:2
load:0x3fff0030,len:184
load:0x40078000,len:12596
load:0x40080400,len:2916
entry 0x400805c4
[ 4][D][esp32-hal-cpu.c:214] setCpuFrequencyMhz(): PLL: 320 / 4 = 80 Mhz, APB: 80000000 Hz

Wake Reason
UNK: 0

On my LCD screen I can set that it says new frequency is 40Mhz because I guess SPI doesn’t care if its slows down as it has its own clock line.

But… it crashes after that.
It may be that I have to reset something afterwards or perhaps call it art the start of the setup so see if it sticks or breaks there.

Nah… so I have a setup() function and all it has is setCpuFrequency(40);
and that causes a problem.

abort() was called at PC 0x400e99e1 on core 0

Backtrace:0x40082f3d:0x3ffbedec |<-CORRUPTED

ELF file SHA256: 0000000000000000

Rebooting…
ets Jul 29 2019 12:21:46

rst:0xc (SW_CPU_RESET),boot:0x13 (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:DIO, clock div:2
load:0x3fff0030,len:184
load:0x40078000,len:12596
load:0x40080400,len:2916
entry 0x400805c4
[ 4][D][esp32-hal-cpu.c:214] setCpuFrequencyMhz(): PLL: 320 / 4 = 80 Mhz, APB: 80000000 Hz
[ ␀␘␘␘␘�~�␆`�f�fx␞␆�2-
Wake Reason
UNK: 0

Starting…
BATTERYMON_C00C
BATTERYMON_C00C
[ 887][D][WiFiGeneric.cpp:852] _eventCallback(): Arduino Event: 0 - WIFI_READY

abort() was called at PC 0x400e99e1 on core 0

Backtrace:0x40082f3d:0x3ffbedec |<-CORRUPTED

ELF file SHA256: 0000000000000000

Rebooting…
ets Jul 29 2019 12:21:46

rst:0xc (SW_CPU_RESET),boot:0x13 (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:DIO, clock div:2
load:0x3fff0030,len:184
load:0x40078000,len:12596
load:0x40080400,len:2916
entry 0x400805c4
[ 4][D][esp32-hal-cpu.c:214] setCpuFrequencyMhz(): PLL: 320 / 4 = 80 Mhz, APB: 80000000 Hz
[�␘␘␘␘␘�~�␆`�f�fx␞␆�2
Wake Reason
UNK: 0

You don’t think its something daft like nobody told the watchdog?

With the 80MHz set in the platform.ini I do get a reasonable saving its down to 60mA ish.

So I could live with that. But it annoys me that it doesn’t do what the documentation says its should do.
Maybe someone will know what the stuff in the abort() kernel panic means. I’m not sure what its saying except that the back trace is probably unreliable.

Do you have a minimal change CPU frequency sketch for 40MHz that also crashes in the Arduino IDE (with the Arduino-ESP32 2.0.2 core) but you think should work?

1 Like

I just realised I can’t program using the Arduino IDE… come back PIO!!!


char string[16];
uint32_t f;

void setup() {
  Serial.begin(115200);
  f = getCpuFrequencyMhz();
  sprintf(string, "CPU Freq: %i", f);
  Serial.println(string);
  //set to 40MHz
  setCpuFrequencyMhz(40);
}

void loop() {
  //read what it thinks it now is
  f = getCpuFrequencyMhz();
  sprintf(string, "CPU Freq: %i", f);
  Serial.println(string);
  delay (1000);
}

Prints

rst:0x1 (POWERON_RESET),boot:0x13 (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:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:10944
load:0x40080400,len:6388
entry 0x400806b4
CPU Freq: 240
CPU Freq: 40
CPU Freq: 40
CPU Freq: 40

Which looks correct to me.
Arduino board manager reports 1.0.6

Setting to 10M also works. The board draws 22mA at 40M and 18mA at 10M which suggests its working correctly.

I found I didn’t need to restart serial or anything seems to pretty carefree.

Alright so the problem in total is solved?

No, because it doesn’t work with a platformio project. It worked with Arduino IDE.
There will be some option I need to set or something but for now, it doesn’t work.

If I use a build flags, I can set 80Mhz but any other setting results in failure.
I will try the exact same code as I did for the Arduino just to check its not something dumb I did.

OK blank project.

rst:0x1 (POWERON_RESET),boot:0x13 (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:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:10124
load:0x40080400,len:5828
entry 0x400806a8
CPU Freq: 240
CPU Freq: 10
CPU Freq: 10
CPU Freq: 10

Working. Using code below.

platform = espressif32 <— works
platform = GitHub - Jason2866/platform-espressif32: Tasmota Espressif 32: development platform for PlatformIO <— spews crap out. May be working but the serial port speed looks like its wrong.

#include <Arduino.h>

char string[16];
uint32_t f;

void setup() {
  Serial.begin(115200);
  f = getCpuFrequencyMhz();
  sprintf(string, "CPU Freq: %i", f);
  Serial.println(string);
  //set to 40MHz
  setCpuFrequencyMhz(10);
}

void loop() {
  //read what it thinks it now is
  f = getCpuFrequencyMhz();
  sprintf(string, "CPU Freq: %i", f);
  Serial.println(string);
  delay (1000);
}

The difference between those is using Arduino-ESP32 1.0.6 or 2.0.3 (beta). If it works now via 1.0.6 that’s great. But if it did work in the Arduino IDE with core version 2.0.2 installed, that’s weird.

in my Arduino esp library the latest is installed which proports to be 1.0.6
How do I install version 2? I m sorry, I never ever use Arduino IDE!

In your Arduino IDE menu → Tools → Boards → Board manager you can search for ESP32 and then there should be an update button.

I just installed arduino and added https://dl.espressif.com/dl/package_esp32_index.json
Latest it shows is 1.0.6 - presumably there is a different json file I need?

Alternatively, this could all be irrelevant.
I have created a minimal test see above - and that appears to correctly set the board as low as 10M.

So I changed my code to call the setcpu speed to 10M before doing anything else in setup. If I do that it still doesn’t work. I think it may change it but the setup doesn’t complete and then it crashes.
So it doesn’t like something else I have done / a library.

#include <Arduino.h>
#include <Ticker.h>
#include <SPI.h>
#include <TFT_eSPI.h>
#include "esp_adc_cal.h"
#include <FS.h>
#include <WiFiUdp.h>
#include <DNSServer.h>
#include <HTTPClient.h>
#include "WiFiManager.h" //https://github.com/tzapu/WiFiManager

#include "Filter.h"
#include "global.h"
#include "ota.h"
#include "battery.h"
#include "lcd.h"
#include "Button2.h"

Suspects will be Ticker or TFT_eSPI.

I’ll see if I can work it out. I think my original question is whether I could indeed set the frequency using that function and that is yes. But the full answer is yes - sort of.