Skip to content
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

setCpuFrequencyMhz() changes Serial bauds if frequency<80Mhz #6032

Closed
1 task done
Leonleon33 opened this issue Dec 16, 2021 · 18 comments · Fixed by #6037
Closed
1 task done

setCpuFrequencyMhz() changes Serial bauds if frequency<80Mhz #6032

Leonleon33 opened this issue Dec 16, 2021 · 18 comments · Fixed by #6037
Assignees
Labels
Milestone

Comments

@Leonleon33
Copy link

Board

ESP32 Dev module

Device Description

ESP32 Dev module alone

Hardware Configuration

Nothing

Version

v2.0.1

IDE Name

Arduino IDE

Operating System

Ubuntu 20.04

Flash frequency

80Mhz

PSRAM enabled

no

Upload speed

921600

Description

When setting CPU frequency below 80Mhz, the serial monitor is garbage until I change the baud rate...
I manage to solve the problem by setting the Serial.begin(bauds) to : 80 / cpufreq * monitor_bauds
See sketch attached.

Sketch

uint32_t Freq = 0;
const int bauds = 115200;
int my_bauds;
int cpufreqs[6] = {240, 160, 80, 40, 20, 10};
int i = 0;

void setup() {
  Freq = getCpuFrequencyMhz();
  if (Freq < 80) {
    my_bauds = 80 / Freq * bauds;
  }
  else {
    my_bauds = bauds;
  }

  Serial.begin(my_bauds);        // Attention dépend de la frequence CPU si elle est <80Mhz 
  delay(500);
  //
  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() {
  Serial.print("\nchange CPU freq to ");
  Serial.println(cpufreqs[i]);
  delay(1000);
  setCpuFrequencyMhz(cpufreqs[i]);
  Freq = getCpuFrequencyMhz();
  Serial.print("Send to serial with my_bauds = ");
  Serial.println(my_bauds);
  Serial.print("CPU Freq = ");
  Serial.print(Freq);
  Serial.println(" MHz");
  //  Change bauds rate ?

  if (Freq < 80) {
    my_bauds = 80 / Freq * bauds;
  }
  else {
    my_bauds = bauds;
  }
  Serial.end();
  delay(1000);
  Serial.begin(my_bauds);
  delay(1000);
  Serial.print("\nchange my_bauds to ");
  Serial.println(my_bauds);
  Serial.print("Serial set to ");
  Serial.println(my_bauds);
  Serial.print("CPU Freq = ");
  Serial.print(Freq);
  Serial.println(" MHz");
  Serial.print("my_bauds = ");
  Serial.println(my_bauds);

  delay(1000);
  i++;
  i = i % 6;
}

Debug Message

No debug message, just monitor output set to 115200
CPU Freq = 240 MHz
XTAL Freq = 40 MHz
APB Freq = 80000000 Hz

change CPU freq to 240
Send to serial with my_bauds = 115200
CPU Freq = 240 MHz

change my_bauds to 115200
Serial set to 115200
CPU Freq = 240 MHz
my_bauds = 115200

change CPU freq to 160
Send to serial with my_bauds = 115200
CPU Freq = 160 MHz

change my_bauds to 115200
Serial set to 115200
CPU Freq = 160 MHz
my_bauds = 115200

change CPU freq to 80
Send to serial with my_bauds = 115200
CPU Freq = 80 MHz

change my_bauds to 115200
Serial set to 115200
CPU Freq = 80 MHz
my_bauds = 115200

change CPU freq to 40
�f⸮⸮⸮`                 AND OTHER GARBAGE
change my_bauds to 230400
Serial set to 230400
CPU Freq = 40 MHz
my_bauds = 230400

change CPU freq to 20
�f⸮⸮⸮`                 AND OTHER GARBAGE
change my_bauds to 460800
Serial set to 460800
CPU Freq = 20 MHz
my_bauds = 460800

change CPU freq to 10
�f⸮⸮⸮`                 AND OTHER GARBAGE
change my_bauds to 921600
Serial set to 921600
CPU Freq = 10 MHz
my_bauds = 921600

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.
@Leonleon33 Leonleon33 added the Status: Awaiting triage Issue is waiting for triage label Dec 16, 2021
@SuGlider SuGlider self-assigned this Dec 17, 2021
@SuGlider
Copy link
Collaborator

Thanks @Leonleon33 for reporting and solving the issue with your example.
The issue will be solved with the PR #6037
Great Job!

@SuGlider SuGlider added Type: Bug 🐛 All bugs and removed Status: Awaiting triage Issue is waiting for triage labels Dec 17, 2021
@SuGlider SuGlider added this to the 2.0.2 milestone Dec 17, 2021
@VojtechBartoska VojtechBartoska moved this from In Development to Development Complete in (Archived) Arduino Core ESP32 RoadMap Dec 21, 2021
@savejeff
Copy link

savejeff commented Aug 17, 2022

I encounter the same problem.
I was able to fix this in the same way.
Is the fix maybe not published on the main branch?

these are the firmware versions I'm using:


framework-arduinoespressif32 @ 3.20004.0 (2.0.4)
 - tool-esptoolpy @ 1.30300.0 (3.3.0)
 - tool-mkfatfs @ 2.0.1
 - tool-mklittlefs @ 1.203.210628 (2.3)
 - tool-mkspiffs @ 2.230.0 (2.30)
 - toolchain-riscv32-esp @ 8.4.0+2021r2-patch3
 - toolchain-xtensa-esp32s3 @ 8.4.0+2021r2-patch3

through PlatformIO with
platform = espressif32@5.1.0

with ESP32-S3

@SuGlider
Copy link
Collaborator

This PR is already merged and it is part of Arduino Core 2.0.2+
About PlatformIO, it is already in latest realease.
https://github.com/platformio/platform-espressif32/releases

@savejeff
Copy link

But why do i then need to ajust the baudrate in the way that was proposed by the issue creator?

What I'm doing is going into a different mode that is something like a standby mode. when setting a CpuFrq below 80Mhz i have to update the baudrate accordingly.

It also seems like I2C and SPI clocks are also slowed down. SD Card writes also stop working after the reduction of the CPU clock

@SuGlider
Copy link
Collaborator

If necessary, please open a new issue clarifying the Arduino Core Version, if this issue occurs with Arduino IDE, what is the SoC (ESP32 or the S2/S3/C3) and so on. Describe your issue and then add a minimum sketch that can be used to reproduce the issue.

@savejeff
Copy link

savejeff commented Aug 25, 2022

I have already supplied all these information. The original sketch provided by the Issue opened still works with the latest Arduino 2.0.4 and ESP32-S3 Devkit C-1.

But ill open a new issue

@kjw3898
Copy link

kjw3898 commented Oct 21, 2022

I have already supplied all these information. The original sketch provided by the Issue opened still works with the latest Arduino 2.0.4 and ESP32-S3 Devkit C-1.

But ill open a new issue

try this when change cpu frequency

 
Serial.begin(115200); // first init serial 
// ...  your code
Serial.end();    // when change cpu frequency
setCpuFrequencyMhz(40);
Serial.begin(115200);

@aeonSolutions
Copy link

That's quite a neat hack !!
I've done some clean up to the code and make it more usable . Here:

/*
* LAB: 8
* Name: ESP32 Read Default Clocks
* Author: Khaled Magdy
* For More Info Visit: https://deepbluembedded.com/esp32-change-cpu-speed-clock-frequency/
*/
 //function takes the following frequencies as valid values:
//  240, 160, 80    <<< For all XTAL types
//  40, 20, 10      <<< For 40MHz XTAL
//  26, 13          <<< For 26MHz XTAL
//  24, 12          <<< For 24MHz XTAL
// For More Info Visit: https://deepbluembedded.com/esp32-change-cpu-speed-clock-frequency/

#include "Wire.h"
 
uint32_t Freq = 0;
int MCU_FREQUENCY_SERIAL_SPEED=115200;
int SERIAL_DEFAULT_SPEED = 115200;

void changeMcuFreq(int Freq){
  delay(500);
  setCpuFrequencyMhz(Freq);
  changeSerialBaudRate(Freq);
  delay(500);
} 

void serialMcuFreq(){
  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/1000000);
  Serial.println(" MHz");  
}

void changeSerialBaudRate(uint32_t Freq){
    if (Freq < 80) {
      MCU_FREQUENCY_SERIAL_SPEED = 80 / Freq * SERIAL_DEFAULT_SPEED;
    }
    else {
      MCU_FREQUENCY_SERIAL_SPEED = SERIAL_DEFAULT_SPEED;
    }
    Serial.end();
    delay(1000);
    Serial.begin(MCU_FREQUENCY_SERIAL_SPEED);
    delay(1000);
    Serial.print("\nSerial Baud Rate Speed is ");
    Serial.println(MCU_FREQUENCY_SERIAL_SPEED);
}


void setup()
{

  Serial.begin(MCU_FREQUENCY_SERIAL_SPEED);
  
}
 
void loop()
{
  changeMcuFreq(240);
  serialMcuFreq();    
  delay(2000);
  
  changeMcuFreq(160);
  serialMcuFreq();    
  delay(2000);

  changeMcuFreq(80);
  serialMcuFreq();    
  delay(2000);

  changeMcuFreq(40);
  serialMcuFreq();    
  delay(2000);

  changeMcuFreq(20);
  serialMcuFreq();    
  delay(2000);

  changeMcuFreq(10);
  serialMcuFreq();    
  delay(2000);

}


@aeonSolutions
Copy link

aeonSolutions commented May 4, 2023

The above solution does not work for me. I get a crash on an ESP32 S3 8MB when I change to clock speed to 10MHz.

ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0xc (RTC_SW_CPU_RST),boot:0xf (SPI_FAST_FLASH_BOOT)
Saved PC:0x42120ca2
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3808,len:0x43c
load:0x403c9700,len:0xbec
load:0x403cc700,len:0x2a3c
entry 0x403c98d8

here's my code:

void changeMcuFreq(INTERFACE_CLASS* interface, int Freq){
  Serial.flush();
  Serial.end();
  interface->UARTserial->flush();
  delay(200);
  setCpuFrequencyMhz(Freq);
  interface->CURRENT_CLOCK_FREQUENCY=Freq;
  if (Freq < 80) {
    interface->MCU_FREQUENCY_SERIAL_SPEED = 80 / Freq * interface->SERIAL_DEFAULT_SPEED;
  } else {
    interface->MCU_FREQUENCY_SERIAL_SPEED = interface->SERIAL_DEFAULT_SPEED;
  }
  Serial.begin(interface->MCU_FREQUENCY_SERIAL_SPEED);
  interface->UARTserial->updateBaudRate(interface->MCU_FREQUENCY_SERIAL_SPEED);
  
  interface->UARTserial->print("The current Serial Baud speed on the UART Port is ");
  interface->UARTserial->println(interface->MCU_FREQUENCY_SERIAL_SPEED);
} 

the original code can be found here:
https://github.com/aeonSolutions/aeonlabs-ESP32-C-Base-Firmware-Libraries#readme

@SuGlider
Copy link
Collaborator

SuGlider commented May 5, 2023

Arduino Core 2.0.7+ sets the clock source of UART to UART_SCLK_XTAL in the ESP32-S3.
Therefore UART isn't affected when the CPU/APB frequency changes, even to 8 MHz.
Its baud rate won't need any change to comply with the CPU Frequency.

#if SOC_UART_SUPPORT_XTAL_CLK
// works independently of APB frequency
uart_config.source_clk = UART_SCLK_XTAL; // ESP32C3, ESP32S3
uart_config.baud_rate = baudrate;
#else
uart_config.source_clk = UART_SCLK_APB; // ESP32, ESP32S2
uart_config.baud_rate = _get_effective_baudrate(baudrate);
#endif
ESP_ERROR_CHECK(uart_driver_install(uart_nr, rx_buffer_size, tx_buffer_size, 20, &(uart->uart_event_queue), 0));

This change in the code was introduced at the end of 2022 by this commit 99f66d3 in the PR #7496

@aeonSolutions
Copy link

aeonSolutions commented May 5, 2023

So i read.
And i confirm it is working for serial send , Serial.print() command, however it is not working for Serial.read()
I'm currently testing at 10MHz same ESP32 S3 with 8MB and no Serial.read()

@JasonPittenger
Copy link

I just tried a sketch changing the clock speed from 240,160,80,40,26,24,20,13,12,10,5,4,2,1.
At 40 MHz, I had to use 2baud, but at 20 MHz and 10 MHz, it worked using 1baud.
Trying 26,24,13,12,5,4,2 or 1 all resulted in a clock speed of 10MHz.

@aeonSolutions
Copy link

Haven't tested at 2 baud ....or 1 .
brb

@JasonPittenger
Copy link

I had a typo. It was 2 x baud. IE, at 40 MHz, I had to set the serial port to 230400 to get 115200 output. All other settings I was able to use 115200 to get 115200.

@JasonPittenger
Copy link

I can confirm, serial baud is correct at 240, 160, 80, 20, and 10 MHz, but incorrect at 40 MHz. Serial.begin must be called after changing frequency to 10 MHz (and probably when changing to 20 as well).

@aeonSolutions
Copy link

aeonSolutions commented May 23, 2023

here's a draft of my code with @JasonPittenger's solution:

void changeMcuFreq(INTERFACE_CLASS* interface, int Freq){
  Serial.flush();
  delay(200);
  setCpuFrequencyMhz(Freq);
  interface->CURRENT_CLOCK_FREQUENCY=Freq;
  if (Freq < 80) {
    interface->MCU_FREQUENCY_SERIAL_SPEED = 2 * interface->SERIAL_DEFAULT_SPEED;                         //230400
  }else if (Freq < 40) {
    interface->MCU_FREQUENCY_SERIAL_SPEED = interface->SERIAL_DEFAULT_SPEED;                             //115200
    Serial.end();
    Serial.begin( interface->SERIAL_DEFAULT_SPEED );  
} else {
    interface->MCU_FREQUENCY_SERIAL_SPEED = interface->SERIAL_DEFAULT_SPEED; 
  }

  interface->UARTserial->updateBaudRate(interface->MCU_FREQUENCY_SERIAL_SPEED);
  
  interface->UARTserial->print("The current Serial Baud speed on the UART Port is ");
  interface->UARTserial->println(interface->MCU_FREQUENCY_SERIAL_SPEED);
} 

the original code can be found here:
https://github.com/aeonSolutions/aeonlabs-ESP32-C-Base-Firmware-Libraries#readme

@JasonPittenger
Copy link

JasonPittenger commented May 23, 2023

if (Freq < 80) { interface->MCU_FREQUENCY_SERIAL_SPEED = 2 * interface->SERIAL_DEFAULT_SPEED; //230400 }

This will set the serial speed to 2 x for all speeds below 80, which isn't correct.
Also, I did have to restart the serial every time after changing speeds.
I didn't need to do a Serial.end(); before calling Serial.begin();

I think what you want is

if (Freq == 40) { interface->MCU_FREQUENCY_SERIAL_SPEED = 2 * interface->SERIAL_DEFAULT_SPEED; //230400 } else { interface->MCU_FREQUENCY_SERIAL_SPEED = interface->SERIAL_DEFAULT_SPEED; } Serial.begin( interface->SERIAL_DEFAULT_SPEED );

@aeonSolutions
Copy link

aeonSolutions commented May 24, 2023

Here's my code snippet updated with @JasonPittenger solution

void changeMcuFreq(INTERFACE_CLASS* interface, int Freq){
  Serial.flush();
  Serial.end();
  delay(200);
  setCpuFrequencyMhz(Freq);
  interface->CURRENT_CLOCK_FREQUENCY=Freq;

 if (Freq == 40) {
    interface->MCU_FREQUENCY_SERIAL_SPEED = 2*interface->SERIAL_DEFAULT_SPEED;                            
} else {
    interface->MCU_FREQUENCY_SERIAL_SPEED = interface->SERIAL_DEFAULT_SPEED; 
  }

  Serial.begin( interface->SERIAL_DEFAULT_SPEED );  
  interface->UARTserial->updateBaudRate(interface->MCU_FREQUENCY_SERIAL_SPEED);
  interface->UARTserial->print("The current Serial Baud speed on the UART Port is ");
  interface->UARTserial->println(interface->MCU_FREQUENCY_SERIAL_SPEED);
} 

the original code can be found here:
https://github.com/aeonSolutions/aeonlabs-ESP32-C-Base-Firmware-Libraries#readme

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
No open projects
Development

Successfully merging a pull request may close this issue.

6 participants