Reduce the cpu freq dinamicly, not working

Hi, i am using ESP32-c3 and i want to reduce the cpu frequency to 10 mhz after a while and when user press a button the cpu will change to 160 mhz so the esp can connect to wifi if needed.

But I don't get the correct output in uart to know if the cpu is getting to 10 mhz or not.


// For Display turn off
unsigned long DELAY_TIME = 6000; // 6 sec
unsigned long delayStart = 0; // the time the delay started
 
static bool upState = 0;
const int LITE = 6;
const int UP = 1;

uint32_t Freq = 0;
 
void setup()
{
  pinMode(UP, INPUT_PULLUP);
  Serial.begin(115200);
  Freq = getCpuFrequencyMhz();
  Serial.print("CPU Freq = ");
  Serial.print(Freq);
  Serial.println(" MHz");
  Freq = getXtalFrequencyMhz();
  Serial.print("XTAL Freq = ");
  Serial.print(Freq);
  Serial.println(" MHz");
  Freq = getApbFrequency();
  Serial.print("APB Freq = ");
  Serial.print(Freq);
  Serial.println(" Hz");
}
 
void loop()
{
  /* power off the display after 6s */
  if ((millis() - delayStart) >= DELAY_TIME) {
      digitalWrite(LITE, LOW);
      setCpuFrequencyMhz(10);
      Freq = getCpuFrequencyMhz();
      Serial.print("CPU Freq = ");
      Serial.print(Freq);
      Serial.println(" MHz");
      Freq = getXtalFrequencyMhz();
      Serial.print("XTAL Freq = ");
      Serial.print(Freq);
      Serial.println(" MHz");
      Freq = getApbFrequency();
      Serial.print("APB Freq = ");
      Serial.print(Freq);
      Serial.println(" Hz");
  }


  if (!digitalRead(UP)) {
    Serial.println("UP_BTN");
      digitalWrite(LITE, HIGH);
    delayStart = millis();
    setCpuFrequencyMhz(160);
    Freq = getCpuFrequencyMhz();
    Serial.print("CPU Freq = ");
    Serial.print(Freq);
    Serial.println(" MHz");
    Freq = getXtalFrequencyMhz();
    Serial.print("XTAL Freq = ");
    Serial.print(Freq);
    Serial.println(" MHz");
    Freq = getApbFrequency();
    Serial.print("APB Freq = ");
    Serial.print(Freq);
    Serial.println(" Hz");
  }
}

this is the output

SHA-256 comparison failed:
Calculated: e0c357829f601add6a50d6ea19f89687ec5acf531610506a38b33d09b4a71c7e
Expected: 77332826ec7bc491df854452f675071e3a094e80858dd7d91dd7e27940204216
Attempting to boot anyway...
entry 0x403ce000
CPU Freq = 160 MHz
XTAL Freq = 40 MHz
APB Freq = 80000000 Hz
⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮

Also do you think when the cpu freq is reduced to 10mhz it will keep the internal time correctly?

The preferred solution is putting the CPU asleep until some (button...) event.

In c3 there is no external wake up. so i can't use a button.

From the ESP32-c3 data sheet:

• Deep-sleep mode: CPU and most peripherals are powered down. Only the RTC memory is powered on.
Wi-Fi connection data are stored in the RTC memory. The RTC timer or the RTC GPIOs can wake up the
chip from the Deep-sleep mode.

It's likely that the UART baud rate generator gets its clock from the clock you are altering. By reducing the clock like you are, you throw off the baud rate. It's probably 1/16th of what you set it to. So 9600 baud @ 160 MHz is probably 600 baud @ 10MHz.

You may be able to choose a lower frequency and then rewrite the baud rate dividers to compensate, but what about other hardware units like the timers? You would have to sort them out as well.

Better to go with a CPU sleep as already suggested.

It looks like the highest Serial Monitor baud rate that are an exact factor of 16 apart are 2400 and 38400. In your sketch set the baud rate to 38400 and then try Serial Monitor at both 38400 and 2400. If the conjecture is correct, at 38400 you will see the 160 MHz output and at 2400 you will see the 10 MHz output.

@johnwasser this worked, the 10mhz shows in 4800bud rate. thanks

but i am getting this error or somthing

UP_BTN
CPU Freq = 80 MHz
XTAL Freq = 40 MHz
APB Freq = 80000000 Hz
1
E (152241) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (152241) task_wdt:  - IDLE (CPU 0)
E (152241) task_wdt: Tasks currently running:
E (152241) task_wdt: CPU 0: loopTask

Here is the full code. before I just included that is related to the topic

// firmware V1.5 for mutantW v1
// Install this libs before building the firmware
#include <Adafruit_ST7789.h> 
#include <SPI.h>
#include <WiFi.h>
#include <esp_now.h>
#include "time.h"

// Set the hotspot pass you will use to get the time from the internet
const char* ssid     = "DESKTOP";
const char* password = "84r19+H8";

// You can change the gmtOffset_sec to set your local time
const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = -14400;
const int   daylightOffset_sec = 0;

// For LCD
#define TFT_CS         2
#define TFT_RST        10
#define TFT_DC         0
#define TFT_MOSI       18  // Data out
#define TFT_SCLK       19  // Clock out

// For buttons and others
const int LITE = 6;
const int UP = 1;
const int DOWN = 3;
const int VIBRATION = 7;

// For LCD
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

// For buttons and others
int touchState = 1;    
static bool upState = 0;
static bool downState = 1;
static uint16_t powered_on = 10000;

// For Display turn off
unsigned long DELAY_TIME = 10000; // 10 sec
unsigned long delayStart = 0; // the time the delay started


static void notification_Vibration(void)
{
  Serial.println("notification_Buzzer");
  digitalWrite(VIBRATION, HIGH);
  delay(1000);
  digitalWrite(VIBRATION, LOW);
  delay(800);
  digitalWrite(VIBRATION, HIGH);
  delay(1000);
  digitalWrite(VIBRATION, LOW);
}

void watchFace() {
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }

  tft.setCursor(80, 30);
  tft.fillScreen(ST77XX_BLACK);
  tft.setTextColor(ST77XX_RED);
  tft.setTextSize(13.5);
  tft.println(&timeinfo, "%H");
  tft.setTextColor(ST77XX_YELLOW);
  tft.setTextSize(13.5);
  tft.println(&timeinfo, ":%M");
}

void secondFace() {
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }

  tft.setCursor(0, 30);
  tft.fillScreen(ST77XX_BLACK);
  tft.setTextColor(ST77XX_RED);
  tft.setTextSize(2);
  tft.println(&timeinfo, "%A");
  tft.setTextColor(ST77XX_YELLOW);
  tft.setTextSize(2);
  tft.println(&timeinfo, "%B");
  tft.setTextColor(ST77XX_GREEN);
  tft.setTextSize(3);
  tft.println(&timeinfo, "%d");
  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(2);
  tft.println(&timeinfo, "%Y");
  tft.setTextSize(3);
  tft.setTextColor(ST77XX_GREEN);
  tft.setTextSize(5);
  tft.println(&timeinfo, "%H:%M:%S");
  tft.setTextColor(ST77XX_BLUE);
  tft.setTextSize(4);
//  tft.println("Voltage= ");
//  tft.println(value);
}

// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
  char a[32];
  char b[32];
} struct_message;

// Create a struct_message called myData
struct_message myData;

// callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  Serial.print("Char: ");
  Serial.println(myData.a);
  Serial.print("Char: ");
  Serial.println(myData.b);
  
  delayStart = millis();
  turnDisplayON();
  notificationFace();
//  notification_Vibration();
  downState =1;
}

void notificationFace() {
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  
  tft.setCursor(10, 30);
  tft.fillScreen(ST77XX_BLACK);
  
  tft.setTextColor(ST77XX_BLUE);
  tft.setTextSize(2);
  tft.println(&timeinfo, "%H:%M:%S");
  
  tft.setTextColor(ST77XX_RED);
  tft.setTextSize(2);
  tft.println( myData.a);
  
  tft.setTextColor(ST77XX_YELLOW);
  tft.setTextSize(2);
  tft.println( myData.b);
}

void setupWIFITime(){
  tft.setCursor(0, 30);
  tft.fillScreen(ST77XX_BLACK);
  tft.setTextColor(ST77XX_RED);
  tft.setTextSize(1);
  // Connect to Wi-Fi
  Serial.print("Connecting to ");
  tft.println("Connecting to ");
  tft.println(ssid);
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    tft.print(".");
  }
  Serial.println("");
  tft.println("");
  tft.println("WiFi connected.");
  Serial.println("WiFi connected.");

  // Init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  watchFace();

  //disconnect WiFi as it's no longer needed
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
}

static void turnDisplayON(void)
{
  if (!digitalRead(LITE)) {
    digitalWrite(LITE, HIGH);
  }
}

void CPUinfo(void) {
    uint32_t Freq = 0;
    Freq = getCpuFrequencyMhz();
    Serial.print("CPU Freq = ");
    Serial.print(Freq);
    Serial.println(" MHz");
    Freq = getXtalFrequencyMhz();
    Serial.print("XTAL Freq = ");
    Serial.print(Freq);
    Serial.println(" MHz");
    Freq = getApbFrequency();
    Serial.print("APB Freq = ");
    Serial.print(Freq);
    Serial.println(" Hz");
}
  
void setup(void) {
  Serial.begin(38400);

  delayStart = millis();

  pinMode(UP, INPUT_PULLUP);
  pinMode(DOWN, INPUT_PULLUP);
  pinMode(LITE, OUTPUT);
  pinMode(VIBRATION, OUTPUT);

  // Set Switch State
  digitalWrite(LITE, HIGH);

  tft.init(240, 280);           // Init ST7789 240x240
  tft.setTextWrap(false);
  tft.fillScreen(ST77XX_BLACK);
  
  setupWIFITime();

  //----------------------------------------------------------------------------
  // For reciving notification
  // Set device as a Wi-Fi Station 
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_register_recv_cb(OnDataRecv);
  
}

void loop() {
  /* power off the display after 6s */
  if ((millis() - delayStart) >= DELAY_TIME) {
      digitalWrite(LITE, LOW);
      upState =1;
      downState=1;
      setCpuFrequencyMhz(10);
  }

  if (!digitalRead(UP)) {
    setCpuFrequencyMhz(80);
    Serial.println("UP_BTN");
    CPUinfo();
    delayStart = millis();
    turnDisplayON();
    if (upState == 1){
      Serial.println("1");
      upState =0;
      watchFace();
      delay(500);
    } else{
      upState =1;
      digitalWrite(LITE, LOW);
      Serial.println("0");
      delay(500);
    }
  }

  if (!digitalRead(DOWN)) {
    setCpuFrequencyMhz(80);
    Serial.println("UP_DOWN");
    CPUinfo();
    delayStart = millis();
    turnDisplayON();
    if (downState == 1){
      Serial.println("1");
      downState =0;
      secondFace();
      delay(500);
    } else{
      downState =1;
      notificationFace();
      Serial.println("0");
      delay(500);
    }
  }
}

Also the power consumption is not reduced.

when i set the CPU to 10mhz in the Arduino IDE and flash the code the power consumption is around 50milAh and when using the code to reduce the 10mhz then it does not go below 100milAh.

Watchdog type implementations usually run from a separate clock source to the main application. By slowing the clock down to 1/16th, maybe the watchdog check in is now taking 16x longer before it occurs. You may need to adjust your watchdog timeout to account for this.

when cpu is in 10 mhz, only thing in the code is running is the internal clock that keeps the time. Is watchdog related to that, i am not familiar with the advance coding. if so then how to fix the watchdog as you said.

Unfortunately i have limited experience of using an ESP32. The fact that you get a message with the word task in it suggests that there is more support code running that is hidden from view than what is present in your sketch.

This might help:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/wdts.html

Much easier to use deep sleep and a button to wake the processor.

Trouble is, you are trying to do an advanced thing.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.