Skip to content

Commit

Permalink
CPU and APB Frequency support (#2220)
Browse files Browse the repository at this point in the history
* Add support to HAL for APB frequencies different than 80MHz

* Add support for CPU frequencies in the IDE board menu

* Switch to fast set_config

* Add method to uart so debug can be reassigned after apb frequency switch

* Return real APB frequency
  • Loading branch information
me-no-dev authored Dec 20, 2018
1 parent 1628f53 commit c827bb4
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 34 deletions.
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
4 changes: 2 additions & 2 deletions cores/esp32/esp32-hal-i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -1611,7 +1611,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 = (getApbFrequency()/clk_speed) / 2;
uint32_t halfPeriod = period/2;
uint32_t quarterPeriod = period/4;

Expand Down Expand Up @@ -1657,7 +1657,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 = getApbFrequency() / old_count;
} else {
result = 0;
}
Expand Down
4 changes: 2 additions & 2 deletions cores/esp32/esp32-hal-ledc.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,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 = getApbFrequency();
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 +117,7 @@ static double _ledcTimerRead(uint8_t chan)
LEDC_MUTEX_UNLOCK();
uint64_t clk_freq = 1000000;
if(apb_clk) {
clk_freq *= 80;
clk_freq = getApbFrequency();
}
clk_freq <<= 8;//div_num is 8 bit decimal
return (clk_freq >> bit_num) / (double)div_num;
Expand Down
35 changes: 28 additions & 7 deletions cores/esp32/esp32-hal-misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#endif //CONFIG_BT_ENABLED
#include <sys/time.h>
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "rom/rtc.h"
#include "esp32-hal.h"

//Undocumented!!! Get chip temperature in Farenheit
Expand All @@ -42,31 +44,47 @@ 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;
}
rtc_clk_cpu_freq_set_config(&conf);
#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_fast(&conf);
_cpu_freq_mhz = conf.freq_mhz;
_sys_time_multiplier = 80 / getApbFrequency();
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(){
rtc_cpu_freq_config_t conf;
rtc_clk_cpu_freq_get_config(&conf);
if(conf.freq_mhz >= 80){
return 80000000;
}
return (conf.source_freq_mhz * 1000000) / conf.div;
}

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 +127,9 @@ bool btInUse(){ return false; }

void initArduino()
{
#ifdef F_CPU
setCpuFrequency(F_CPU/1000000L);
#endif
#if CONFIG_SPIRAM_SUPPORT
psramInit();
#endif
Expand Down
5 changes: 3 additions & 2 deletions cores/esp32/esp32-hal-sigmadelta.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,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 = getApbFrequency();
uint32_t prescale = (apb_freq/(freq*256)) - 1;
if(prescale > 0xFF) {
prescale = 0xFF;
}
Expand All @@ -52,7 +53,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 = getApbFrequency();
spiClk_t reg = { clockDiv };
return ClkRegToFreq(&reg);
}

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

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
28 changes: 17 additions & 11 deletions 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 = ((getApbFrequency()<<4)/baud_rate);
uart->dev->clk_div.div_int = clk_div>>4 ;
uart->dev->clk_div.div_frag = clk_div & 0xf;
UART_MUTEX_UNLOCK();
Expand Down Expand Up @@ -385,17 +386,8 @@ static void IRAM_ATTR uart2_write_char(char c)
ESP_REG(DR_REG_UART2_BASE) = c;
}

void uartSetDebug(uart_t* uart)
void uart_install_putc()
{
if(uart == NULL || uart->num > 2) {
s_uart_debug_nr = -1;
ets_install_putc1(NULL);
return;
}
if(s_uart_debug_nr == uart->num) {
return;
}
s_uart_debug_nr = uart->num;
switch(s_uart_debug_nr) {
case 0:
ets_install_putc1((void (*)(char)) &uart0_write_char);
Expand All @@ -412,6 +404,20 @@ void uartSetDebug(uart_t* uart)
}
}

void uartSetDebug(uart_t* uart)
{
if(uart == NULL || uart->num > 2) {
s_uart_debug_nr = -1;
//ets_install_putc1(NULL);
//return;
} else
if(s_uart_debug_nr == uart->num) {
return;
} else
s_uart_debug_nr = uart->num;
uart_install_putc();
}

int uartGetDebug()
{
return s_uart_debug_nr;
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

4 comments on commit c827bb4

@MarkusAD
Copy link
Contributor

Choose a reason for hiding this comment

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

@me-no-dev Wondering if some changes are needed for the SPI clock with this commit. Several projects here with SPI TFT displays... they continue to work if I compile for 240MHz cpu clock but displays won't init with the 160 or 80MHz clocks. I didn't look at it with the logic analyzer yet. Could be a display library timing issue as well, though it just uses the normal SPI function calls.

Thanks always for all your excellent efforts.

@MarkusAD
Copy link
Contributor

Choose a reason for hiding this comment

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

@me-no-dev The display problems have been solved by @stickbreaker observation in #2225

In esp32-hal-misc.c I changed to:

_sys_time_multiplier = 80000000 / getApbFrequency();

And now displays behave correctly for all cpu clocks. Thank you @stickbreaker and @me-no-dev and Merry Christmas to both of you.

@me-no-dev
Copy link
Member Author

Choose a reason for hiding this comment

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

ahh totally missed that one...

@me-no-dev
Copy link
Member Author

Choose a reason for hiding this comment

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

fixed now :)

Please sign in to comment.