Skip to content

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

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

Closed
1 task done
savejeff opened this issue Aug 25, 2022 · 9 comments · Fixed by #7496
Closed
1 task done

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

savejeff opened this issue Aug 25, 2022 · 9 comments · Fixed by #7496
Assignees
Milestone

Comments

@savejeff
Copy link

savejeff commented Aug 25, 2022

Board

ESP32-S3 DevKitC-1, ESP32-C3 NodeMCU, ESP32DevKit

Device Description

plane ESP32-S3 DevKitC-1 with nothing attached
plane ESP32-C3 NodeMCU board
plane ESP32DevKit board

Hardware Configuration

.

Version

v2.0.4

IDE Name

Arduini IDE

Operating System

Windows 10

Flash frequency

80Mhz

PSRAM enabled

no

Upload speed

921600

Description

the Issued described in this issue is still not fixed for (at least) the ESP32-S3.
EDIT: i tested this with the ESP32DevKit and the same behavior can be observed but it somehow seems to be even worse.
EDIT2: i tested this with the ESP32-C3 and the same behavior can be observed.

The problem is with every CPU Freq below 80Mhz, the Baudrate must be adjusted up to compensate for slower clock speeds.

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

change CPU freq to 240
⸮Bŭk⸮⸮⸮
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⸮⸮⸮`��~⸮⸮
change my_bauds to 230400
Serial set to 230400
CPU Freq = 40 MHz
my_bauds = 230400

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

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

Other Bus Speeds

I2C and SPI might also be slowed down. This should be checked as well.

EDIT: I2C (on ESP32-C3) maintains clock speed. SPI does not. it slows down as the serial does

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

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@savejeff savejeff added the Status: Awaiting triage Issue is waiting for triage label Aug 25, 2022
@SuGlider SuGlider self-assigned this Aug 26, 2022
@SuGlider
Copy link
Collaborator

I see that it has not been implemented for C3. That's the issue.

@SuGlider SuGlider added this to the 2.1.0 milestone Aug 26, 2022
@SuGlider SuGlider added Status: To be implemented Selected for Development and removed Status: Awaiting triage Issue is waiting for triage labels Aug 26, 2022
@savejeff
Copy link
Author

savejeff commented Aug 26, 2022

What do you mean "for C3" ?
If you are talking about ESP32-C3: the problem is present with all variants from ESP32, ESP32-C3 and ESP32-S3.

About the I2C and SPI issue: i have only tested this on the C3. S3 and S might also have the same issues

@SuGlider
Copy link
Collaborator

SuGlider commented Aug 26, 2022

Just a quick question... Are you using any ESP at lower than 80MHz?

Please explain the usage.

We will verify it for all SoC.
But it is not sure that it will be implemented because there is recommendation from IDF regarding it.

C3 is RISC V and has a different internal structure regarding CPU Frequency.

S2 and S3, the same regarding different internal structure.

Therefore, I'm not sure if it is possible to solve this issue

@savejeff
Copy link
Author

savejeff commented Aug 27, 2022

Just a quick question... Are you using any ESP at lower than 80MHz?

Please explain the usage.

In general i don't think there needs to be an specific application when we talk about low level functions like these. they should IMHO work as expected to allow fast and reliable development without pitfalls.

But I have in fact an actual application: My device is battery-powered to record data. between recordings, the device moves into a standby mode where everything essential is kept running but with reduced power consumption. so i reduce the esp clock as low as possible where still the important measurements can be performed. at the start of the next recording, the clock is increased and everything runs on full steam again.

We will verify it for all SoC. But it is not sure that it will be implemented because there is recommendation from IDF regarding it.

C3 is RISC V and has a different internal structure regarding CPU Frequency.

S2 and S3, the same regarding different internal structure.

Therefore, I'm not sure if it is possible to solve this issue

Why would it not be possible? the code above is a working fix for all architectures.
For Serial, the simplest implementation would be to not directly change the baud/clock rates in the setCpuFrequencyMhz but in the updateBaudRate function of the serial class. here is only the simple fix

void HardwareSerial::updateBaudRate(unsigned long baud) {
  int Freq = getCpuFrequencyMhz();
  if (Freq < 80) {
    baud= 80 / Freq * baud;
  }

  [...]
}

needs to be used.

SPI is even simpler. SPI.beginTransaction receives the desired clock rate in the SPISettings parameter. so analog to the Serial fix, a simple correction of the clock speed would be sufficient I think.

I2C (at least on the C3 where i tested it) does not display slowdown in low CPU freqs

So a change below 80Mhz would look like this:


setCpuFrequencyMhz(20);
Serial.updateBaudRate(115200);

@SuGlider
Copy link
Collaborator

@savejeff - I use Arduino Core 2.0.4 and tested this sketch with ESP32, ESP32-S2, ESP32-S3 and ESP32-C3:

void setup() {
  int cpufreqs[6] = {240, 160, 80, 40, 20, 10};

  Serial.begin(115200);        // Attention dépend de la frequence CPU si elle est <80Mhz
  delay(1000); // just a second to make sure that we will get all messages in the Serial Terminal
  Serial.println("\n Starting...\n");
  Serial.flush();
  // initial information
  uint32_t 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");
  delay(500);
#ifdef CONFIG_IDF_TARGET_ESP32C3
  uint8_t firstFreq = 1;
#else
  uint8_t firstFreq = 0;
#endif
  for (uint8_t i = firstFreq; i < sizeof(cpufreqs) / sizeof(int); i++) {
    Serial.printf("\n------- Trying CPU Freq = %d ---------\n", cpufreqs[i]);
    Serial.flush();  // wait to empty the UART FIFO before changing the CPU Freq.
    setCpuFrequencyMhz(cpufreqs[i]);
    Serial.updateBaudRate(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");
    Serial.println("Moving to the fext frequency ... after pause of 2 seconds.");
    delay(2000);
  }
  Serial.println("\n-------------------\n");
  Serial.println("End of testing...");
  Serial.println("\n-------------------\n");
}
void loop() {
}

Results:

It works perfectly fine with ESP32 and ESP32-S2.
It fails with ESP32-S3 and ESP32-C3 under 40MHz.
Therefore, we must implement it for S3 and C3 only.

@SuGlider
Copy link
Collaborator

SuGlider commented Aug 27, 2022

It is necessary to check what is the source of Clock for SPI, I2C and others, in order to make sure it works fine under APB Freq (80MHz).
ESP32 family has many and different Clock Sources for the peripherals, therefore, it may be some work to fix it all.
We will verify the effort and time necessary and consider it into our roadmap.

Thanks.

@SuGlider
Copy link
Collaborator

So a change below 80Mhz would look like this:

setCpuFrequencyMhz(20);
Serial.updateBaudRate(115200);

As per the example above used for testing, this exactly how it will work for the UART peripheral.

@savejeff
Copy link
Author

savejeff commented Sep 2, 2022

int Freq = getCpuFrequencyMhz();
if (Freq < 80) {
baud= 80 / Freq * baud;
}

I think the most important thing is that Serial works as expected. i2C and SPI has a clock speed determined by the master, so the communication is not broken, just slowed down. A fix here would of course be best.

When i find time I'll check by what factor SPI is slowed down. maybe its as simple as with Serial.

Thanks for taking up the issue

@SuGlider
Copy link
Collaborator

@savejeff - PR #7496 fixes this UART issue. Please feel free to open a new issue regarding I2C and/or SPI, separately, if necessary.

@SuGlider SuGlider moved this from Todo to In Review in Arduino ESP32 Core Project Roadmap Nov 20, 2022
Repository owner moved this from In Review to Done in Arduino ESP32 Core Project Roadmap Dec 13, 2022
@VojtechBartoska VojtechBartoska added Status: Solved and removed Status: To be implemented Selected for Development labels Dec 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging a pull request may close this issue.

3 participants