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

CPU and APB Frequency support #2220

Merged
merged 6 commits into from
Dec 20, 2018
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions boards.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
menu.UploadSpeed=Upload Speed
menu.CPUFreq=CPU Frequency
menu.FlashFreq=Flash Frequency
menu.FlashMode=Flash Mode
menu.FlashSize=Flash Size
Expand Down Expand Up @@ -49,6 +50,35 @@ esp32.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080
esp32.menu.PartitionScheme.fatflash=16M Fat
esp32.menu.PartitionScheme.fatflash.build.partitions=ffat

esp32.menu.CPUFreq.240=240MHz
esp32.menu.CPUFreq.240.build.f_cpu=240000000L
esp32.menu.CPUFreq.160=160MHz
esp32.menu.CPUFreq.160.build.f_cpu=160000000L
esp32.menu.CPUFreq.80=80MHz
esp32.menu.CPUFreq.80.build.f_cpu=80000000L
esp32.menu.CPUFreq.40=40MHz (40MHz XTAL)
esp32.menu.CPUFreq.40.build.f_cpu=40000000L
esp32.menu.CPUFreq.26=26MHz (26MHz XTAL)
esp32.menu.CPUFreq.26.build.f_cpu=26000000L
esp32.menu.CPUFreq.20=20MHz (40MHz XTAL)
esp32.menu.CPUFreq.20.build.f_cpu=20000000L
esp32.menu.CPUFreq.13=13MHz
esp32.menu.CPUFreq.13.build.f_cpu=13000000L
esp32.menu.CPUFreq.10=10MHz (40MHz XTAL)
esp32.menu.CPUFreq.10.build.f_cpu=10000000L
esp32.menu.CPUFreq.8=8MHz (40MHz XTAL)
esp32.menu.CPUFreq.8.build.f_cpu=8000000L
esp32.menu.CPUFreq.5=5MHz
esp32.menu.CPUFreq.5.build.f_cpu=5000000L
esp32.menu.CPUFreq.4=4MHz
esp32.menu.CPUFreq.4.build.f_cpu=4000000L
esp32.menu.CPUFreq.3=3MHz
esp32.menu.CPUFreq.3.build.f_cpu=3000000L
esp32.menu.CPUFreq.2=2MHz
esp32.menu.CPUFreq.2.build.f_cpu=2000000L
esp32.menu.CPUFreq.1=1MHz
esp32.menu.CPUFreq.1.build.f_cpu=1000000L

esp32.menu.FlashMode.qio=QIO
esp32.menu.FlashMode.qio.build.flash_mode=dio
esp32.menu.FlashMode.qio.build.boot=qio
Expand Down
5 changes: 3 additions & 2 deletions cores/esp32/esp32-hal-i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "soc/i2c_reg.h"
#include "soc/i2c_struct.h"
#include "soc/dport_reg.h"
#include "soc/rtc.h"
#include "esp_attr.h"

//#define I2C_DEV(i) (volatile i2c_dev_t *)((i)?DR_REG_I2C1_EXT_BASE:DR_REG_I2C_EXT_BASE)
Expand Down Expand Up @@ -1611,7 +1612,7 @@ i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
}
I2C_FIFO_CONF_t f;

uint32_t period = (APB_CLK_FREQ/clk_speed) / 2;
uint32_t period = (rtc_clk_apb_freq_get()/clk_speed) / 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried this mod a couple of weeks ago, the returned value didn't change, it stayed at 80,000,000. But the actual hardware clock changed speed, I could see the i2c bus speed change on my oscilloscope.

Have you changed the code inside rtc_clk_apb_freq_get() since Rc1 1.0.1 ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to me it changes now when you set the cpu frequency below 80MHz. I have not tested I2C, but tested other peripherals. Give it a go :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see private glitter

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An upper bounds needs to be applied to I2C bus freq versus CPU freq:

#define MIN_I2C_CLKS 100
    uint32_t period = (rtc_clk_apb_freq_get()/clk_speed) / 2;
    if(period < (MIN_I2C_CLKS/2) ){
      period = (MIN_I2C_CLKS/2);
      log_w("APB Freq too slow, Reducing i2c Freq to %d Hz",rtc_clk_apb_freq_get()/(period*2));
    }      

This limits it to 1/100th APB frequency so a 5MHz APB has a max i2c of 50KHz down to 10KHz at 1MHz. I tried up to 1/80 APB, I2C did not function. In my newer code I have other places I need MIN_I2C_CLKS.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good solution I think. Will also venture into dynamic cpu scaling and will see how we can manage that.

uint32_t halfPeriod = period/2;
uint32_t quarterPeriod = period/4;

Expand Down Expand Up @@ -1657,7 +1658,7 @@ uint32_t i2cGetFrequency(i2c_t * i2c)
uint32_t result = 0;
uint32_t old_count = (i2c->dev->scl_low_period.period+i2c->dev->scl_high_period.period);
if(old_count>0) {
result = APB_CLK_FREQ / old_count;
result = rtc_clk_apb_freq_get() / old_count;
} else {
result = 0;
}
Expand Down
5 changes: 3 additions & 2 deletions cores/esp32/esp32-hal-ledc.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "soc/dport_reg.h"
#include "soc/ledc_reg.h"
#include "soc/ledc_struct.h"
#include "soc/rtc.h"

#if CONFIG_DISABLE_HAL_LOCKS
#define LEDC_MUTEX_LOCK()
Expand Down Expand Up @@ -84,7 +85,7 @@ static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, boo
//max bit_num 0x1F (31)
static double _ledcSetupTimerFreq(uint8_t chan, double freq, uint8_t bit_num)
{
uint64_t clk_freq = APB_CLK_FREQ;
uint64_t clk_freq = rtc_clk_apb_freq_get();
clk_freq <<= 8;//div_num is 8 bit decimal
uint32_t div_num = (clk_freq >> bit_num) / freq;
bool apb_clk = true;
Expand Down Expand Up @@ -117,7 +118,7 @@ static double _ledcTimerRead(uint8_t chan)
LEDC_MUTEX_UNLOCK();
uint64_t clk_freq = 1000000;
if(apb_clk) {
clk_freq *= 80;
clk_freq = rtc_clk_apb_freq_get();
}
clk_freq <<= 8;//div_num is 8 bit decimal
return (clk_freq >> bit_num) / (double)div_num;
Expand Down
26 changes: 20 additions & 6 deletions cores/esp32/esp32-hal-misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,31 +42,42 @@ void yield()
vPortYield();
}

static uint32_t _cpu_freq_mhz = 240;
static uint32_t _cpu_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
static uint32_t _sys_time_multiplier = 1;

bool cpuFrequencySet(uint32_t cpu_freq_mhz){
if(_cpu_freq_mhz == cpu_freq_mhz){
bool setCpuFrequency(uint32_t cpu_freq_mhz){
rtc_cpu_freq_config_t conf, cconf;
rtc_clk_cpu_freq_get_config(&cconf);
if(cconf.freq_mhz == cpu_freq_mhz && _cpu_freq_mhz == cpu_freq_mhz){
return true;
}
rtc_cpu_freq_config_t conf;
if(!rtc_clk_cpu_freq_mhz_to_config(cpu_freq_mhz, &conf)){
log_e("CPU clock could not be set to %u MHz", cpu_freq_mhz);
return false;
}
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
log_i("%s: %u / %u = %u Mhz", (conf.source == RTC_CPU_FREQ_SRC_PLL)?"PLL":((conf.source == RTC_CPU_FREQ_SRC_APLL)?"APLL":((conf.source == RTC_CPU_FREQ_SRC_XTAL)?"XTAL":"8M")), conf.source_freq_mhz, conf.div, conf.freq_mhz);
delay(10);
#endif
rtc_clk_cpu_freq_set_config(&conf);
_cpu_freq_mhz = conf.freq_mhz;
_sys_time_multiplier = 80 / getApbFrequency();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will always set _sys_time_multiplier to 0 all the time?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how did I miss this :D

return true;
}

uint32_t cpuFrequencyGet(){
uint32_t getCpuFrequency(){
rtc_cpu_freq_config_t conf;
rtc_clk_cpu_freq_get_config(&conf);
return conf.freq_mhz;
}

uint32_t getApbFrequency(){
return rtc_clk_apb_freq_get() / 1000000;
}

unsigned long IRAM_ATTR micros()
{
return (unsigned long) ((esp_timer_get_time() * 240) / _cpu_freq_mhz);
return (unsigned long) (esp_timer_get_time()) * _sys_time_multiplier;
}

unsigned long IRAM_ATTR millis()
Expand Down Expand Up @@ -109,6 +120,9 @@ bool btInUse(){ return false; }

void initArduino()
{
#ifdef F_CPU
setCpuFrequency(F_CPU/1000000L);
#endif
#if CONFIG_SPIRAM_SUPPORT
psramInit();
#endif
Expand Down
6 changes: 4 additions & 2 deletions cores/esp32/esp32-hal-sigmadelta.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "esp32-hal-matrix.h"
#include "soc/gpio_sd_reg.h"
#include "soc/gpio_sd_struct.h"
#include "soc/rtc.h"


#if CONFIG_DISABLE_HAL_LOCKS
Expand All @@ -43,7 +44,8 @@ uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-31
_sd_sys_lock = xSemaphoreCreateMutex();
}
#endif
uint32_t prescale = (10000000/(freq*32)) - 1;
uint32_t apb_freq = rtc_clk_apb_freq_get();
uint32_t prescale = (apb_freq/(freq*256)) - 1;
if(prescale > 0xFF) {
prescale = 0xFF;
}
Expand All @@ -52,7 +54,7 @@ uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-31
SIGMADELTA.cg.clk_en = 0;
SIGMADELTA.cg.clk_en = 1;
SD_MUTEX_UNLOCK();
return 10000000/((prescale + 1) * 32);
return apb_freq/((prescale + 1) * 256);
}

void sigmaDeltaWrite(uint8_t channel, uint8_t duty) //chan 0-7 duty 8 bit
Expand Down
17 changes: 10 additions & 7 deletions cores/esp32/esp32-hal-spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "soc/io_mux_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/dport_reg.h"
#include "soc/rtc.h"

#define SPI_CLK_IDX(p) ((p==0)?SPICLK_OUT_IDX:((p==1)?SPICLK_OUT_IDX:((p==2)?HSPICLK_OUT_IDX:((p==3)?VSPICLK_OUT_IDX:0))))
#define SPI_MISO_IDX(p) ((p==0)?SPIQ_OUT_IDX:((p==1)?SPIQ_OUT_IDX:((p==2)?HSPIQ_OUT_IDX:((p==3)?VSPIQ_OUT_IDX:0))))
Expand Down Expand Up @@ -750,7 +751,7 @@ void spiEndTransaction(spi_t * spi)
SPI_MUTEX_UNLOCK();
}

void spiWriteByteNL(spi_t * spi, uint8_t data)
void IRAM_ATTR spiWriteByteNL(spi_t * spi, uint8_t data)
{
if(!spi) {
return;
Expand All @@ -776,7 +777,7 @@ uint8_t spiTransferByteNL(spi_t * spi, uint8_t data)
return data;
}

void spiWriteShortNL(spi_t * spi, uint16_t data)
void IRAM_ATTR spiWriteShortNL(spi_t * spi, uint16_t data)
{
if(!spi) {
return;
Expand Down Expand Up @@ -811,7 +812,7 @@ uint16_t spiTransferShortNL(spi_t * spi, uint16_t data)
return data;
}

void spiWriteLongNL(spi_t * spi, uint32_t data)
void IRAM_ATTR spiWriteLongNL(spi_t * spi, uint32_t data)
{
if(!spi) {
return;
Expand Down Expand Up @@ -959,7 +960,7 @@ void spiTransferBitsNL(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits)
}
}

void spiWritePixelsNL(spi_t * spi, const void * data_in, size_t len){
void IRAM_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, size_t len){
size_t longs = len >> 2;
if(len & 3){
longs++;
Expand Down Expand Up @@ -1017,18 +1018,20 @@ typedef union {
};
} spiClk_t;

#define ClkRegToFreq(reg) (CPU_CLK_FREQ / (((reg)->regPre + 1) * ((reg)->regN + 1)))
#define ClkRegToFreq(reg) (apb_freq / (((reg)->regPre + 1) * ((reg)->regN + 1)))

uint32_t spiClockDivToFrequency(uint32_t clockDiv)
{
uint32_t apb_freq = rtc_clk_apb_freq_get();
spiClk_t reg = { clockDiv };
return ClkRegToFreq(&reg);
}

uint32_t spiFrequencyToClockDiv(uint32_t freq)
{
uint32_t apb_freq = rtc_clk_apb_freq_get();

if(freq >= CPU_CLK_FREQ) {
if(freq >= apb_freq) {
return SPI_CLK_EQU_SYSCLK;
}

Expand All @@ -1051,7 +1054,7 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
reg.regN = calN;

while(calPreVari++ <= 1) {
calPre = (((CPU_CLK_FREQ / (reg.regN + 1)) / freq) - 1) + calPreVari;
calPre = (((apb_freq / (reg.regN + 1)) / freq) - 1) + calPreVari;
if(calPre > 0x1FFF) {
reg.regPre = 0x1FFF;
} else if(calPre <= 0) {
Expand Down
2 changes: 1 addition & 1 deletion cores/esp32/esp32-hal-timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void IRAM_ATTR __timerISR(void * arg){
i = 4;
//call callbacks
while(i--){
if(__timerInterruptHandlers[i] && status & (1 << i)){
if(__timerInterruptHandlers[i] && (status & (1 << i))){
__timerInterruptHandlers[i]();
}
}
Expand Down
3 changes: 2 additions & 1 deletion cores/esp32/esp32-hal-uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "soc/io_mux_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/dport_reg.h"
#include "soc/rtc.h"
#include "esp_intr_alloc.h"

#define UART_REG_BASE(u) ((u==0)?DR_REG_UART_BASE:( (u==1)?DR_REG_UART1_BASE:( (u==2)?DR_REG_UART2_BASE:0)))
Expand Down Expand Up @@ -352,7 +353,7 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
return;
}
UART_MUTEX_LOCK();
uint32_t clk_div = ((UART_CLK_FREQ<<4)/baud_rate);
uint32_t clk_div = ((rtc_clk_apb_freq_get()<<4)/baud_rate);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There needs to be some limits between APB freq and baud_rate. When I tested this at 4MHz, 3MHz (26MHz base clock) the serial monitor has garbage injected.

After change of clock to speed[7]=13
 rtc_clk_cpu_freq_get=1073470388, cpuFreq=13
 current apb freq =13000000, apbFreq=13
read 128 bytes

Error setting freq[8]=12MHZ


Error setting freq[9]=10MHZ


Error setting freq[10]=8MHZ


Error setting freq[11]=6MHZ

 After change of clock to speed[12]=5
 rtc_clk_cpu_freq_get=1073470388, cpuFreq=5
 current apb freq =5000000, apbFreq=5
read 127 bytes
⸮P�W⸮Achange of clock to⸮.⸮⸮⸮m⸮3]=4
 rtc_clk⸮,⸮}⸮ɕ⸮}⸮⸮⸮⸮1073470388,⸮,⸮�ɕ⸮⸮4
 current apb⸮⸮⸮⸮A=4000000, apbFreq=4
read 128⸮⸮ѕ⸮) After change of clock to⸮.⸮⸮⸮m⸮4]=3
⸮.⸮}⸮⸮⸮}⸮⸮⸮}⸮ɕ⸮}⸮⸮⸮⸮1073470388, cpuFreq=3
 current⸮X⸮Afreq =3000000, apbFreq=3
read⸮L&⸮bytes
 After change of clock to speed[15]=2
 rtc_clk_cpu_freq_get=4, cpuFreq=2
 current apb freq =2000000, apbFreq=2
read 127 bytes
 After change of clock to speed[16]=1
 rtc_clk_cpu_freq_get=1073470388, cpuFreq=1
 current apb freq =1000000, apbFreq=1
read 128 bytes

This is with Serial Monitor Baud set to 19200.

With Baud set to 115200 the ESP32 hangs when Frequency is changed to 1MHz.

 After change of clock to speed[12]=5
 rtc_clk_cpu_freq_get=1073470388, cpuFreq=5
 current apb freq =5000000, apbFreq=5
read 127 bytes
⸮P�W⸮Achange⸮⸮Aclock to speed[13]=4
⸮.⸮}⸮⸮⸮}⸮⸮⸮}⸮ɕ⸮}⸮⸮⸮⸮1073470388,⸮,⸮�ɕ⸮⸮4
 current apb freq⸮O�⸮⸮000, apbFreq=4
read 127⸮⸮ѕ⸮)⸮P�W⸮Achange⸮⸮Aclock⸮⸮�⸮⸮eed[14]=3
⸮.⸮}⸮⸮⸮}⸮⸮u⸮⸮⸮⸮}⸮⸮⸮⸮1073470388,⸮,⸮�ɕ⸮⸮3
⸮⸮⸮ɕ⸮⸮Aapb⸮⸮⸮⸮A=3000000,⸮X⸮�ɕ⸮⸮3
read⸮L⸮��⸮ѕ⸮) After change of clock to speed[15]=2
 rtc_clk_cpu_freq_get=4, cpuFreq=2
 current apb freq =2000000, apbFreq=2
read 128 bytes

Testing code:

uint8_t speeds[] ={240,160,80,40,26,24,20,13,12,10,8,6,5,4,3,2,1};
  
void loop() {
  static int c=0;

  c++;
  if(c>=sizeof(speeds)) c = 0;
  
  Serial.flush();
  
  if(!setCpuFrequency(speeds[c])){
     Serial.printf("\nError setting freq[%d]=%dMHZ\n\n",c,speeds[c]);
  } else{
    delay(100);
    Serial.begin(BAUD);
    Wire.begin(SDA,SCL,100000);
    Serial.printf(" After change of clock to speed[%d]=%d\n",c,speeds[c]);
    Serial.printf(" rtc_clk_cpu_freq_get=%d, cpuFreq=%d\n",rtc_clk_cpu_freq_get(),getCpuFrequency());
    Serial.printf(" current apb freq =%d, apbFreq=%d\n",rtc_clk_apb_freq_get(),getApbFrequency());
    runBlocks();
    delay(5000);
    }
}

Chuck.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested with 40MHz crystal :) and uart works fine. Thanks for testing 26MHz!

uart->dev->clk_div.div_int = clk_div>>4 ;
uart->dev->clk_div.div_frag = clk_div & 0xf;
UART_MUTEX_UNLOCK();
Expand Down
10 changes: 8 additions & 2 deletions cores/esp32/esp32-hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,14 @@ void yield(void);
//returns chip temperature in Celsius
float temperatureRead();

bool cpuFrequencySet(uint32_t cpu_freq_mhz);
uint32_t cpuFrequencyGet();
//function takes the following frequencies as valid values:
// 240, 160, 80 <<< For all XTAL types
// 40, 20, 13, 10, 8, 5, 4, 3, 2, 1 <<< For 40MHz XTAL
// 26, 13, 5, 4, 3, 2, 1 <<< For 26MHz XTAL
// 24, 12, 8, 6, 4, 3, 2, 1 <<< For 24MHz XTAL
bool setCpuFrequency(uint32_t cpu_freq_mhz);
uint32_t getCpuFrequency();
uint32_t getApbFrequency();

unsigned long micros();
unsigned long millis();
Expand Down