Handle APB frequency change (#2250)

* Add APB change callbacks and move cpu code to own file

* Properly set esp_timer and FreeRTOS tick dividers

* Improve updated devisors

* No need to update REF_TICK yet

* Add initial handling for UART baud change

* fix uartWriteBuf and uartDetectBaudrate

* trigger callbacks even when APB did not change

* toggle UART ISR on CPU change

* add XTAL freq getter and add cpu freq validation

* Support CPU frequency changes in I2C (#2287)

**esp32-hal-i2c.c**
* add callback for cpu frequency changes
* adjust fifo thresholds based on cpu frequency and i2c bus frequency
* reduce i2c bus frequency if differential is too small
**Wire.h**
* version to 1.1.0

* Implement clock change for the other peripherals

* remove bad CPU clock values from the menu

* Add note to CPU freqs that support WiFi and BT
This commit is contained in:
Me No Dev 2019-01-09 10:07:54 +01:00 committed by GitHub
parent ff18a211e4
commit 2fd39b1aff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 484 additions and 113 deletions

View File

@ -3,6 +3,7 @@ set(CORE_SRCS
cores/esp32/cbuf.cpp cores/esp32/cbuf.cpp
cores/esp32/esp32-hal-adc.c cores/esp32/esp32-hal-adc.c
cores/esp32/esp32-hal-bt.c cores/esp32/esp32-hal-bt.c
cores/esp32/esp32-hal-cpu.c
cores/esp32/esp32-hal-dac.c cores/esp32/esp32-hal-dac.c
cores/esp32/esp32-hal-gpio.c cores/esp32/esp32-hal-gpio.c
cores/esp32/esp32-hal-i2c.c cores/esp32/esp32-hal-i2c.c

View File

@ -50,11 +50,11 @@ esp32.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080
esp32.menu.PartitionScheme.fatflash=16M Fat esp32.menu.PartitionScheme.fatflash=16M Fat
esp32.menu.PartitionScheme.fatflash.build.partitions=ffat esp32.menu.PartitionScheme.fatflash.build.partitions=ffat
esp32.menu.CPUFreq.240=240MHz esp32.menu.CPUFreq.240=240MHz (WiFi/BT)
esp32.menu.CPUFreq.240.build.f_cpu=240000000L esp32.menu.CPUFreq.240.build.f_cpu=240000000L
esp32.menu.CPUFreq.160=160MHz esp32.menu.CPUFreq.160=160MHz (WiFi/BT)
esp32.menu.CPUFreq.160.build.f_cpu=160000000L esp32.menu.CPUFreq.160.build.f_cpu=160000000L
esp32.menu.CPUFreq.80=80MHz esp32.menu.CPUFreq.80=80MHz (WiFi/BT)
esp32.menu.CPUFreq.80.build.f_cpu=80000000L esp32.menu.CPUFreq.80.build.f_cpu=80000000L
esp32.menu.CPUFreq.40=40MHz (40MHz XTAL) esp32.menu.CPUFreq.40=40MHz (40MHz XTAL)
esp32.menu.CPUFreq.40.build.f_cpu=40000000L esp32.menu.CPUFreq.40.build.f_cpu=40000000L
@ -62,22 +62,10 @@ esp32.menu.CPUFreq.26=26MHz (26MHz XTAL)
esp32.menu.CPUFreq.26.build.f_cpu=26000000L esp32.menu.CPUFreq.26.build.f_cpu=26000000L
esp32.menu.CPUFreq.20=20MHz (40MHz XTAL) esp32.menu.CPUFreq.20=20MHz (40MHz XTAL)
esp32.menu.CPUFreq.20.build.f_cpu=20000000L esp32.menu.CPUFreq.20.build.f_cpu=20000000L
esp32.menu.CPUFreq.13=13MHz esp32.menu.CPUFreq.13=13MHz (26MHz XTAL)
esp32.menu.CPUFreq.13.build.f_cpu=13000000L esp32.menu.CPUFreq.13.build.f_cpu=13000000L
esp32.menu.CPUFreq.10=10MHz (40MHz XTAL) esp32.menu.CPUFreq.10=10MHz (40MHz XTAL)
esp32.menu.CPUFreq.10.build.f_cpu=10000000L 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=QIO
esp32.menu.FlashMode.qio.build.flash_mode=dio esp32.menu.FlashMode.qio.build.flash_mode=dio

211
cores/esp32/esp32-hal-cpu.c Normal file
View File

@ -0,0 +1,211 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "freertos/xtensa_timer.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "rom/rtc.h"
#include "soc/apb_ctrl_reg.h"
#include "esp32-hal.h"
#include "esp32-hal-cpu.h"
typedef struct apb_change_cb_s {
struct apb_change_cb_s * next;
void * arg;
apb_change_cb_t cb;
} apb_change_t;
const uint32_t MHZ = 1000000;
static apb_change_t * apb_change_callbacks = NULL;
static xSemaphoreHandle apb_change_lock = NULL;
static void initApbChangeCallback(){
static volatile bool initialized = false;
if(!initialized){
initialized = true;
apb_change_lock = xSemaphoreCreateMutex();
if(!apb_change_lock){
initialized = false;
}
}
}
static void triggerApbChangeCallback(apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
initApbChangeCallback();
xSemaphoreTake(apb_change_lock, portMAX_DELAY);
apb_change_t * r = apb_change_callbacks;
while(r != NULL){
r->cb(r->arg, ev_type, old_apb, new_apb);
r=r->next;
}
xSemaphoreGive(apb_change_lock);
}
bool addApbChangeCallback(void * arg, apb_change_cb_t cb){
initApbChangeCallback();
apb_change_t * c = (apb_change_t*)malloc(sizeof(apb_change_t));
if(!c){
log_e("Callback Object Malloc Failed");
return false;
}
c->next = NULL;
c->arg = arg;
c->cb = cb;
xSemaphoreTake(apb_change_lock, portMAX_DELAY);
if(apb_change_callbacks == NULL){
apb_change_callbacks = c;
} else {
apb_change_t * r = apb_change_callbacks;
if(r->cb != cb || r->arg != arg){
while(r->next){
r = r->next;
if(r->cb == cb && r->arg == arg){
free(c);
goto unlock_and_exit;
}
}
r->next = c;
}
}
unlock_and_exit:
xSemaphoreGive(apb_change_lock);
return true;
}
bool removeApbChangeCallback(void * arg, apb_change_cb_t cb){
initApbChangeCallback();
xSemaphoreTake(apb_change_lock, portMAX_DELAY);
apb_change_t * r = apb_change_callbacks;
if(r == NULL){
xSemaphoreGive(apb_change_lock);
return false;
}
if(r->cb == cb && r->arg == arg){
apb_change_callbacks = r->next;
free(r);
} else {
while(r->next && (r->next->cb != cb || r->next->arg != arg)){
r = r->next;
}
if(r->next == NULL || r->next->cb != cb || r->next->arg != arg){
xSemaphoreGive(apb_change_lock);
return false;
}
apb_change_t * c = r->next;
r->next = c->next;
free(c);
}
xSemaphoreGive(apb_change_lock);
return true;
}
static uint32_t calculateApb(rtc_cpu_freq_config_t * conf){
if(conf->freq_mhz >= 80){
return 80 * MHZ;
}
return (conf->source_freq_mhz * MHZ) / conf->div;
}
void esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us); //private in IDF
bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
rtc_cpu_freq_config_t conf, cconf;
uint32_t capb, apb;
//Get XTAL Frequency and calculate min CPU MHz
rtc_xtal_freq_t xtal = rtc_clk_xtal_freq_get();
uint32_t min_cpu_mhz = 10;
if(xtal > RTC_XTAL_FREQ_AUTO){
if(xtal < RTC_XTAL_FREQ_40M) {
min_cpu_mhz = xtal / 2; //13Mhz for 26Mhz XTAL
if(cpu_freq_mhz <= xtal && cpu_freq_mhz != xtal && cpu_freq_mhz != (xtal/2)){
log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2);
return false;
}
} else if(cpu_freq_mhz <= xtal && cpu_freq_mhz != xtal && cpu_freq_mhz != (xtal/2) && cpu_freq_mhz != (xtal/4)){
log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2, xtal/4);
return false;
}
}
if(cpu_freq_mhz > xtal && cpu_freq_mhz != 240 && cpu_freq_mhz != 160 && cpu_freq_mhz != 80){
if(xtal >= RTC_XTAL_FREQ_40M){
log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2, xtal/4);
} else {
log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2);
}
return false;
}
//Get current CPU clock configuration
rtc_clk_cpu_freq_get_config(&cconf);
//return if frequency has not changed
if(cconf.freq_mhz == cpu_freq_mhz){
return true;
}
//Get configuration for the new CPU frequency
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;
}
//Current APB
capb = calculateApb(&cconf);
//New APB
apb = calculateApb(&conf);
log_d("%s: %u / %u = %u Mhz, APB: %u Hz", (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, apb);
//Call peripheral functions before the APB change
if(apb_change_callbacks){
triggerApbChangeCallback(APB_BEFORE_CHANGE, capb, apb);
}
//Make the frequency change
rtc_clk_cpu_freq_set_config_fast(&conf);
if(capb != apb){
//Update REF_TICK (uncomment if REF_TICK is different than 1MHz)
//if(conf.freq_mhz < 80){
// ESP_REG(APB_CTRL_XTAL_TICK_CONF_REG) = conf.freq_mhz / (REF_CLK_FREQ / MHZ) - 1;
//}
//Update APB Freq REG
rtc_clk_apb_freq_update(apb);
//Update esp_timer divisor
esp_timer_impl_update_apb_freq(apb / MHZ);
}
//Update FreeRTOS Tick Divisor
uint32_t fcpu = (conf.freq_mhz >= 80)?(conf.freq_mhz * MHZ):(apb);
_xt_tick_divisor = fcpu / XT_TICK_PER_SEC;
//Call peripheral functions after the APB change
if(apb_change_callbacks){
triggerApbChangeCallback(APB_AFTER_CHANGE, capb, apb);
}
return true;
}
uint32_t getCpuFrequencyMhz(){
rtc_cpu_freq_config_t conf;
rtc_clk_cpu_freq_get_config(&conf);
return conf.freq_mhz;
}
uint32_t getXtalFrequencyMhz(){
return rtc_clk_xtal_freq_get();
}
uint32_t getApbFrequency(){
rtc_cpu_freq_config_t conf;
rtc_clk_cpu_freq_get_config(&conf);
return calculateApb(&conf);
}

View File

@ -0,0 +1,48 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP32_HAL_CPU_H_
#define _ESP32_HAL_CPU_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
typedef enum { APB_BEFORE_CHANGE, APB_AFTER_CHANGE } apb_change_ev_t;
typedef void (* apb_change_cb_t)(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
bool addApbChangeCallback(void * arg, apb_change_cb_t cb);
bool removeApbChangeCallback(void * arg, apb_change_cb_t cb);
//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
bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz);
uint32_t getCpuFrequencyMhz(); // In MHz
uint32_t getXtalFrequencyMhz(); // In MHz
uint32_t getApbFrequency(); // In Hz
#ifdef __cplusplus
}
#endif
#endif /* _ESP32_HAL_CPU_H_ */

View File

@ -24,7 +24,7 @@
#include "soc/i2c_struct.h" #include "soc/i2c_struct.h"
#include "soc/dport_reg.h" #include "soc/dport_reg.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "esp32-hal-cpu.h" // cpu clock change support 31DEC2018
//#define I2C_DEV(i) (volatile i2c_dev_t *)((i)?DR_REG_I2C1_EXT_BASE:DR_REG_I2C_EXT_BASE) //#define I2C_DEV(i) (volatile i2c_dev_t *)((i)?DR_REG_I2C1_EXT_BASE:DR_REG_I2C_EXT_BASE)
//#define I2C_DEV(i) ((i2c_dev_t *)(REG_I2C_BASE(i))) //#define I2C_DEV(i) ((i2c_dev_t *)(REG_I2C_BASE(i)))
#define I2C_SCL_IDX(p) ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0)) #define I2C_SCL_IDX(p) ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0))
@ -206,8 +206,8 @@ static i2c_t _i2c_bus_array[2] = {
{(volatile i2c_dev_t *)(DR_REG_I2C1_EXT_BASE_FIXED), 1, -1, -1,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0,0} {(volatile i2c_dev_t *)(DR_REG_I2C1_EXT_BASE_FIXED), 1, -1, -1,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0,0}
}; };
#else #else
#define I2C_MUTEX_LOCK() do {} while (xSemaphoreTake(i2c->lock, portMAX_DELAY) != pdPASS) #define I2C_MUTEX_LOCK() do {} while (xSemaphoreTakeRecursive(i2c->lock, portMAX_DELAY) != pdPASS)
#define I2C_MUTEX_UNLOCK() xSemaphoreGive(i2c->lock) #define I2C_MUTEX_UNLOCK() xSemaphoreGiveRecursive(i2c->lock)
static i2c_t _i2c_bus_array[2] = { static i2c_t _i2c_bus_array[2] = {
{(volatile i2c_dev_t *)(DR_REG_I2C_EXT_BASE_FIXED), NULL, 0, -1, -1, I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0,0,0}, {(volatile i2c_dev_t *)(DR_REG_I2C_EXT_BASE_FIXED), NULL, 0, -1, -1, I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0,0,0},
@ -445,6 +445,39 @@ static void IRAM_ATTR i2cTriggerDumps(i2c_t * i2c, uint8_t trigger, const char l
} }
// end of debug support routines // end of debug support routines
/* Start of CPU Clock change Support
*/
static void i2cApbChangeCallback(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
i2c_t* i2c = (i2c_t*) arg; // recover data
if(i2c == NULL) { // point to peripheral control block does not exits
return false;
}
uint32_t oldFreq=0;
switch(ev_type){
case APB_BEFORE_CHANGE :
if(new_apb < 3000000) {// too slow
log_e("apb speed %d too slow",new_apb);
break;
}
I2C_MUTEX_LOCK(); // lock will spin until current transaction is completed
break;
case APB_AFTER_CHANGE :
oldFreq = (i2c->dev->scl_low_period.period+i2c->dev->scl_high_period.period); //read old apbCycles
if(oldFreq>0) { // was configured with value
oldFreq = old_apb / oldFreq;
i2cSetFrequency(i2c,oldFreq);
}
I2C_MUTEX_UNLOCK();
break;
default :
log_e("unk ev %u",ev_type);
I2C_MUTEX_UNLOCK();
}
return;
}
/* End of CPU Clock change Support
*/
static void IRAM_ATTR i2cSetCmd(i2c_t * i2c, uint8_t index, uint8_t op_code, uint8_t byte_num, bool ack_val, bool ack_exp, bool ack_check) static void IRAM_ATTR i2cSetCmd(i2c_t * i2c, uint8_t index, uint8_t op_code, uint8_t byte_num, bool ack_val, bool ack_exp, bool ack_check)
{ {
I2C_COMMAND_t cmd; I2C_COMMAND_t cmd;
@ -1221,6 +1254,12 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
I2C_MUTEX_UNLOCK(); I2C_MUTEX_UNLOCK();
return I2C_ERROR_MEMORY; return I2C_ERROR_MEMORY;
} }
if( !addApbChangeCallback( i2c, i2cApbChangeCallback)) {
log_e("install apb Callback failed");
I2C_MUTEX_UNLOCK();
return I2C_ERROR_DEV;
}
} }
//hang until it completes. //hang until it completes.
@ -1352,6 +1391,9 @@ static void i2cReleaseISR(i2c_t * i2c)
if(i2c->intr_handle) { if(i2c->intr_handle) {
esp_intr_free(i2c->intr_handle); esp_intr_free(i2c->intr_handle);
i2c->intr_handle=NULL; i2c->intr_handle=NULL;
if (!removeApbChangeCallback( i2c, i2cApbChangeCallback)) {
log_e("unable to release apbCallback");
}
} }
} }
@ -1437,8 +1479,7 @@ i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda)
* PUBLIC API * PUBLIC API
* */ * */
// 24Nov17 only supports Master Mode // 24Nov17 only supports Master Mode
i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency) //before this is called, pins should be detached, else glitch i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency) {
{
log_v("num=%d sda=%d scl=%d freq=%d",i2c_num, sda, scl, frequency); log_v("num=%d sda=%d scl=%d freq=%d",i2c_num, sda, scl, frequency);
if(i2c_num > 1) { if(i2c_num > 1) {
return NULL; return NULL;
@ -1446,6 +1487,7 @@ i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency) //b
i2c_t * i2c = &_i2c_bus_array[i2c_num]; i2c_t * i2c = &_i2c_bus_array[i2c_num];
// pins should be detached, else glitch
if(i2c->sda >= 0){ if(i2c->sda >= 0){
i2cDetachSDA(i2c, i2c->sda); i2cDetachSDA(i2c, i2c->sda);
} }
@ -1457,7 +1499,7 @@ i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency) //b
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
if(i2c->lock == NULL) { if(i2c->lock == NULL) {
i2c->lock = xSemaphoreCreateMutex(); i2c->lock = xSemaphoreCreateRecursiveMutex();
if(i2c->lock == NULL) { if(i2c->lock == NULL) {
return NULL; return NULL;
} }
@ -1604,7 +1646,8 @@ i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, b
return last_error; return last_error;
} }
#define MIN_I2C_CLKS 100 #define MIN_I2C_CLKS 100 // minimum ratio between cpu and i2c Bus clocks
#define INTERRUPT_CYCLE_OVERHEAD 16000 // number of cpu clocks necessary to respond to interrupt
i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed) i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
{ {
if(i2c == NULL) { if(i2c == NULL) {
@ -1614,17 +1657,18 @@ i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
uint32_t period = (apb/clk_speed) / 2; uint32_t period = (apb/clk_speed) / 2;
if((apb/8192 > clk_speed)||(apb/MIN_I2C_CLKS < clk_speed)){ //out of bounds if((apb/8192 > clk_speed)||(apb/MIN_I2C_CLKS < clk_speed)){ //out of bounds
log_w("i2c freq(%d) out of bounds.vs APB Clock(%d), min=%d, max=%d",clk_speed,apb,(apb/8192),(apb/MIN_I2C_CLKS)); log_d("i2c freq(%d) out of bounds.vs APB Clock(%d), min=%d, max=%d",clk_speed,apb,(apb/8192),(apb/MIN_I2C_CLKS));
} }
if(period < (MIN_I2C_CLKS/2) ){ if(period < (MIN_I2C_CLKS/2) ){
period = (MIN_I2C_CLKS/2); period = (MIN_I2C_CLKS/2);
clk_speed = apb/(period*2); clk_speed = apb/(period*2);
log_w("APB Freq too slow, Reducing i2c Freq to %d Hz",clk_speed); log_d("APB Freq too slow, Reducing i2c Freq to %d Hz",clk_speed);
} else if ( period> 4095) { } else if ( period> 4095) {
period = 4095; period = 4095;
clk_speed = apb/(period*2); clk_speed = apb/(period*2);
log_w("APB Freq too fast, Increasing i2c Freq to %d Hz",clk_speed); log_d("APB Freq too fast, Increasing i2c Freq to %d Hz",clk_speed);
} }
log_v("freq=%dHz",clk_speed);
uint32_t halfPeriod = period/2; uint32_t halfPeriod = period/2;
uint32_t quarterPeriod = period/4; uint32_t quarterPeriod = period/4;
@ -1633,14 +1677,19 @@ i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
I2C_FIFO_CONF_t f; I2C_FIFO_CONF_t f;
// Adjust Fifo thresholds based on frequency
f.val = i2c->dev->fifo_conf.val; f.val = i2c->dev->fifo_conf.val;
uint32_t a = (clk_speed / 50000L )+1; /* Adjust Fifo thresholds based on differential between cpu frequency and bus clock.
if (a > 24) a=24; The fifo_delta is calculated such that at least INTERRUPT_CYCLE_OVERHEAD cpu clocks are
f.rx_fifo_full_thrhd = 32 - a; available when a Fifo interrupt is triggered. This allows enough room in the Fifo so that
f.tx_fifo_empty_thrhd = a; interrupt latency does not cause a Fifo overflow/underflow event.
*/
log_v("cpu Freq=%dMhz, i2c Freq=%dHz",getCpuFrequencyMhz(),clk_speed);
uint32_t fifo_delta = (INTERRUPT_CYCLE_OVERHEAD/((getCpuFrequencyMhz()*1000000 / clk_speed)*10))+1;
if (fifo_delta > 24) fifo_delta=24;
f.rx_fifo_full_thrhd = 32 - fifo_delta;
f.tx_fifo_empty_thrhd = fifo_delta;
i2c->dev->fifo_conf.val = f.val; // set thresholds i2c->dev->fifo_conf.val = f.val; // set thresholds
log_v("Fifo threshold=%d",a); log_v("Fifo delta=%d",fifo_delta);
//the clock num during SCL is low level //the clock num during SCL is low level
i2c->dev->scl_low_period.period = period; i2c->dev->scl_low_period.period = period;
@ -1696,6 +1745,8 @@ uint32_t i2cGetStatus(i2c_t * i2c){
} }
else return 0; else return 0;
} }
/* todo /* todo
22JUL18 22JUL18
need to add multi-thread capability, use dq.queueEvent as the group marker. When multiple threads need to add multi-thread capability, use dq.queueEvent as the group marker. When multiple threads

View File

@ -53,6 +53,33 @@ xSemaphoreHandle _ledc_sys_lock;
#define LEDC_CHAN(g,c) LEDC.channel_group[(g)].channel[(c)] #define LEDC_CHAN(g,c) LEDC.channel_group[(g)].channel[(c)]
#define LEDC_TIMER(g,t) LEDC.timer_group[(g)].timer[(t)] #define LEDC_TIMER(g,t) LEDC.timer_group[(g)].timer[(t)]
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
if(ev_type == APB_AFTER_CHANGE && old_apb != new_apb){
uint32_t iarg = (uint32_t)arg;
uint8_t chan = iarg;
uint8_t group=(chan/8), timer=((chan/2)%4);
old_apb /= 1000000;
new_apb /= 1000000;
if(LEDC_TIMER(group, timer).conf.tick_sel){
LEDC_MUTEX_LOCK();
uint32_t old_div = LEDC_TIMER(group, timer).conf.clock_divider;
uint32_t div_num = (new_apb * old_div) / old_apb;
if(div_num > LEDC_DIV_NUM_HSTIMER0_V){
new_apb = REF_CLK_FREQ / 1000000;
div_num = (new_apb * old_div) / old_apb;
if(div_num > LEDC_DIV_NUM_HSTIMER0_V) {
div_num = LEDC_DIV_NUM_HSTIMER0_V;//lowest clock possible
}
LEDC_TIMER(group, timer).conf.tick_sel = 0;
} else if(div_num < 256) {
div_num = 256;//highest clock possible
}
LEDC_TIMER(group, timer).conf.clock_divider = div_num;
LEDC_MUTEX_UNLOCK();
}
}
}
//uint32_t frequency = (80MHz or 1MHz)/((div_num / 256.0)*(1 << bit_num)); //uint32_t frequency = (80MHz or 1MHz)/((div_num / 256.0)*(1 << bit_num));
static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, bool apb_clk) static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, bool apb_clk)
{ {
@ -78,6 +105,8 @@ static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, boo
LEDC_TIMER(group, timer).conf.rst = 1;//This bit is used to reset timer the counter will be 0 after reset. LEDC_TIMER(group, timer).conf.rst = 1;//This bit is used to reset timer the counter will be 0 after reset.
LEDC_TIMER(group, timer).conf.rst = 0; LEDC_TIMER(group, timer).conf.rst = 0;
LEDC_MUTEX_UNLOCK(); LEDC_MUTEX_UNLOCK();
uint32_t iarg = chan;
addApbChangeCallback((void*)iarg, _on_apb_change);
} }
//max div_num 0x3FFFF (262143) //max div_num 0x3FFFF (262143)

View File

@ -27,6 +27,7 @@
#include <sys/time.h> #include <sys/time.h>
#include "soc/rtc.h" #include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h" #include "soc/rtc_cntl_reg.h"
#include "soc/apb_ctrl_reg.h"
#include "rom/rtc.h" #include "rom/rtc.h"
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
#include "esp32-hal.h" #include "esp32-hal.h"
@ -100,57 +101,19 @@ void disableCore1WDT(){
} }
#endif #endif
static uint32_t _cpu_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
static uint32_t _sys_time_multiplier = 1;
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;
}
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_fast(&conf);
_cpu_freq_mhz = conf.freq_mhz;
_sys_time_multiplier = 80000000 / getApbFrequency();
return true;
}
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() unsigned long IRAM_ATTR micros()
{ {
return (unsigned long) (esp_timer_get_time()) * _sys_time_multiplier; return (unsigned long) (esp_timer_get_time());
} }
unsigned long IRAM_ATTR millis() unsigned long IRAM_ATTR millis()
{ {
return (unsigned long) (micros() / 1000); return (unsigned long) (esp_timer_get_time() / 1000);
} }
void delay(uint32_t ms) void delay(uint32_t ms)
{ {
vTaskDelay((ms * _cpu_freq_mhz) / (portTICK_PERIOD_MS * 240)); vTaskDelay(ms / portTICK_PERIOD_MS);
} }
void IRAM_ATTR delayMicroseconds(uint32_t us) void IRAM_ATTR delayMicroseconds(uint32_t us)
@ -183,8 +146,10 @@ bool btInUse(){ return false; }
void initArduino() void initArduino()
{ {
//init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz)
//ESP_REG(APB_CTRL_PLL_TICK_CONF_REG) = APB_CLK_FREQ / REF_CLK_FREQ - 1;
#ifdef F_CPU #ifdef F_CPU
setCpuFrequency(F_CPU/1000000L); setCpuFrequencyMhz(F_CPU/1000000);
#endif #endif
#if CONFIG_SPIRAM_SUPPORT #if CONFIG_SPIRAM_SUPPORT
psramInit(); psramInit();

View File

@ -31,6 +31,26 @@
xSemaphoreHandle _sd_sys_lock; xSemaphoreHandle _sd_sys_lock;
#endif #endif
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
if(old_apb == new_apb){
return;
}
uint32_t iarg = (uint32_t)arg;
uint8_t channel = iarg;
if(ev_type == APB_BEFORE_CHANGE){
SIGMADELTA.cg.clk_en = 0;
} else {
old_apb /= 1000000;
new_apb /= 1000000;
SD_MUTEX_LOCK();
uint32_t old_prescale = SIGMADELTA.channel[channel].prescale + 1;
SIGMADELTA.channel[channel].prescale = ((new_apb * old_prescale) / old_apb) - 1;
SIGMADELTA.cg.clk_en = 0;
SIGMADELTA.cg.clk_en = 1;
SD_MUTEX_UNLOCK();
}
}
uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-312500 uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-312500
{ {
if(channel > 7) { if(channel > 7) {
@ -53,6 +73,8 @@ uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-31
SIGMADELTA.cg.clk_en = 0; SIGMADELTA.cg.clk_en = 0;
SIGMADELTA.cg.clk_en = 1; SIGMADELTA.cg.clk_en = 1;
SD_MUTEX_UNLOCK(); SD_MUTEX_UNLOCK();
uint32_t iarg = channel;
addApbChangeCallback((void*)iarg, _on_apb_change);
return apb_freq/((prescale + 1) * 256); return apb_freq/((prescale + 1) * 256);
} }

View File

@ -372,6 +372,18 @@ void spiSetBitOrder(spi_t * spi, uint8_t bitOrder)
SPI_MUTEX_UNLOCK(); SPI_MUTEX_UNLOCK();
} }
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb)
{
spi_t * spi = (spi_t *)arg;
if(ev_type == APB_BEFORE_CHANGE){
SPI_MUTEX_LOCK();
while(spi->dev->cmd.usr);
} else {
spi->dev->clock.val = spiFrequencyToClockDiv(old_apb / ((spi->dev->clock.clkdiv_pre + 1) * (spi->dev->clock.clkcnt_n + 1)));
SPI_MUTEX_UNLOCK();
}
}
void spiStopBus(spi_t * spi) void spiStopBus(spi_t * spi)
{ {
if(!spi) { if(!spi) {
@ -388,6 +400,7 @@ void spiStopBus(spi_t * spi)
spi->dev->ctrl2.val = 0; spi->dev->ctrl2.val = 0;
spi->dev->clock.val = 0; spi->dev->clock.val = 0;
SPI_MUTEX_UNLOCK(); SPI_MUTEX_UNLOCK();
removeApbChangeCallback(spi, _on_apb_change);
} }
spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder) spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder)
@ -434,6 +447,7 @@ spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_
} }
SPI_MUTEX_UNLOCK(); SPI_MUTEX_UNLOCK();
addApbChangeCallback(spi, _on_apb_change);
return spi; return spi;
} }
@ -1008,17 +1022,17 @@ void IRAM_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, size_t len){
* */ * */
typedef union { typedef union {
uint32_t regValue; uint32_t value;
struct { struct {
unsigned regL :6; uint32_t clkcnt_l: 6; /*it must be equal to spi_clkcnt_N.*/
unsigned regH :6; uint32_t clkcnt_h: 6; /*it must be floor((spi_clkcnt_N+1)/2-1).*/
unsigned regN :6; uint32_t clkcnt_n: 6; /*it is the divider of spi_clk. So spi_clk frequency is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/
unsigned regPre :13; uint32_t clkdiv_pre: 13; /*it is pre-divider of spi_clk.*/
unsigned regEQU :1; uint32_t clk_equ_sysclk: 1; /*1: spi_clk is eqaul to system 0: spi_clk is divided from system clock.*/
}; };
} spiClk_t; } spiClk_t;
#define ClkRegToFreq(reg) (apb_freq / (((reg)->regPre + 1) * ((reg)->regN + 1))) #define ClkRegToFreq(reg) (apb_freq / (((reg)->clkdiv_pre + 1) * ((reg)->clkcnt_n + 1)))
uint32_t spiClockDivToFrequency(uint32_t clockDiv) uint32_t spiClockDivToFrequency(uint32_t clockDiv)
{ {
@ -1038,7 +1052,7 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
const spiClk_t minFreqReg = { 0x7FFFF000 }; const spiClk_t minFreqReg = { 0x7FFFF000 };
uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg); uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg);
if(freq < minFreq) { if(freq < minFreq) {
return minFreqReg.regValue; return minFreqReg.value;
} }
uint8_t calN = 1; uint8_t calN = 1;
@ -1051,18 +1065,18 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
int32_t calPre; int32_t calPre;
int8_t calPreVari = -2; int8_t calPreVari = -2;
reg.regN = calN; reg.clkcnt_n = calN;
while(calPreVari++ <= 1) { while(calPreVari++ <= 1) {
calPre = (((apb_freq / (reg.regN + 1)) / freq) - 1) + calPreVari; calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari;
if(calPre > 0x1FFF) { if(calPre > 0x1FFF) {
reg.regPre = 0x1FFF; reg.clkdiv_pre = 0x1FFF;
} else if(calPre <= 0) { } else if(calPre <= 0) {
reg.regPre = 0; reg.clkdiv_pre = 0;
} else { } else {
reg.regPre = calPre; reg.clkdiv_pre = calPre;
} }
reg.regL = ((reg.regN + 1) / 2); reg.clkcnt_l = ((reg.clkcnt_n + 1) / 2);
calFreq = ClkRegToFreq(&reg); calFreq = ClkRegToFreq(&reg);
if(calFreq == (int32_t) freq) { if(calFreq == (int32_t) freq) {
memcpy(&bestReg, &reg, sizeof(bestReg)); memcpy(&bestReg, &reg, sizeof(bestReg));
@ -1079,6 +1093,6 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
} }
calN++; calN++;
} }
return bestReg.regValue; return bestReg.value;
} }

View File

@ -184,6 +184,18 @@ bool timerAlarmEnabled(hw_timer_t *timer){
return timer->dev->config.alarm_en; return timer->dev->config.alarm_en;
} }
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
hw_timer_t * timer = (hw_timer_t *)arg;
if(ev_type == APB_BEFORE_CHANGE){
timer->dev->config.enable = 0;
} else {
old_apb /= 1000000;
new_apb /= 1000000;
timer->dev->config.divider = (new_apb * timer->dev->config.divider) / old_apb;
timer->dev->config.enable = 1;
}
}
hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){ hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
if(num > 3){ if(num > 3){
return NULL; return NULL;
@ -205,12 +217,14 @@ hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
timerAttachInterrupt(timer, NULL, false); timerAttachInterrupt(timer, NULL, false);
timerWrite(timer, 0); timerWrite(timer, 0);
timer->dev->config.enable = 1; timer->dev->config.enable = 1;
addApbChangeCallback(timer, _on_apb_change);
return timer; return timer;
} }
void timerEnd(hw_timer_t *timer){ void timerEnd(hw_timer_t *timer){
timer->dev->config.enable = 0; timer->dev->config.enable = 0;
timerAttachInterrupt(timer, NULL, false); timerAttachInterrupt(timer, NULL, false);
removeApbChangeCallback(timer, _on_apb_change);
} }
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){ void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
@ -271,23 +285,23 @@ void timerDetachInterrupt(hw_timer_t *timer){
uint64_t timerReadMicros(hw_timer_t *timer){ uint64_t timerReadMicros(hw_timer_t *timer){
uint64_t timer_val = timerRead(timer); uint64_t timer_val = timerRead(timer);
uint16_t div = timerGetDivider(timer); uint16_t div = timerGetDivider(timer);
return timer_val * div / 80; return timer_val * div / (getApbFrequency() / 1000000);
} }
double timerReadSeconds(hw_timer_t *timer){ double timerReadSeconds(hw_timer_t *timer){
uint64_t timer_val = timerRead(timer); uint64_t timer_val = timerRead(timer);
uint16_t div = timerGetDivider(timer); uint16_t div = timerGetDivider(timer);
return (double)timer_val * div / 80000000; return (double)timer_val * div / getApbFrequency();
} }
uint64_t timerAlarmReadMicros(hw_timer_t *timer){ uint64_t timerAlarmReadMicros(hw_timer_t *timer){
uint64_t timer_val = timerAlarmRead(timer); uint64_t timer_val = timerAlarmRead(timer);
uint16_t div = timerGetDivider(timer); uint16_t div = timerGetDivider(timer);
return timer_val * div / 80; return timer_val * div / (getApbFrequency() / 1000000);
} }
double timerAlarmReadSeconds(hw_timer_t *timer){ double timerAlarmReadSeconds(hw_timer_t *timer){
uint64_t timer_val = timerAlarmRead(timer); uint64_t timer_val = timerAlarmRead(timer);
uint16_t div = timerGetDivider(timer); uint16_t div = timerGetDivider(timer);
return (double)timer_val * div / 80000000; return (double)timer_val * div / getApbFrequency();
} }

View File

@ -67,6 +67,8 @@ static uart_t _uart_bus_array[3] = {
}; };
#endif #endif
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
static void IRAM_ATTR _uart_isr(void *arg) static void IRAM_ATTR _uart_isr(void *arg)
{ {
uint8_t i, c; uint8_t i, c;
@ -216,6 +218,7 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
uartAttachTx(uart, txPin, inverted); uartAttachTx(uart, txPin, inverted);
} }
addApbChangeCallback(uart, uart_on_apb_change);
return uart; return uart;
} }
@ -224,11 +227,10 @@ void uartEnd(uart_t* uart)
if(uart == NULL) { if(uart == NULL) {
return; return;
} }
removeApbChangeCallback(uart, uart_on_apb_change);
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
if(uart->queue != NULL) { if(uart->queue != NULL) {
uint8_t c;
while(xQueueReceive(uart->queue, &c, 0));
vQueueDelete(uart->queue); vQueueDelete(uart->queue);
uart->queue = NULL; uart->queue = NULL;
} }
@ -248,8 +250,6 @@ size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
if(uart->queue != NULL) { if(uart->queue != NULL) {
uint8_t c;
while(xQueueReceive(uart->queue, &c, 0));
vQueueDelete(uart->queue); vQueueDelete(uart->queue);
uart->queue = xQueueCreate(new_size, sizeof(uint8_t)); uart->queue = xQueueCreate(new_size, sizeof(uint8_t));
if(uart->queue == NULL) { if(uart->queue == NULL) {
@ -319,10 +319,9 @@ void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
} }
UART_MUTEX_LOCK(); UART_MUTEX_LOCK();
while(len) { while(len) {
while(len && uart->dev->status.txfifo_cnt < 0x7F) { while(uart->dev->status.txfifo_cnt == 0x7F);
uart->dev->fifo.rw_byte = *data++; uart->dev->fifo.rw_byte = *data++;
len--; len--;
}
} }
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
} }
@ -359,13 +358,49 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
UART_MUTEX_UNLOCK(); UART_MUTEX_UNLOCK();
} }
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb)
{
uart_t* uart = (uart_t*)arg;
if(ev_type == APB_BEFORE_CHANGE){
UART_MUTEX_LOCK();
//disabple interrupt
uart->dev->int_ena.val = 0;
uart->dev->int_clr.val = 0xffffffff;
// read RX fifo
uint8_t c;
BaseType_t xHigherPriorityTaskWoken;
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
c = uart->dev->fifo.rw_byte;
if(uart->queue != NULL && !xQueueIsQueueFullFromISR(uart->queue)) {
xQueueSendFromISR(uart->queue, &c, &xHigherPriorityTaskWoken);
}
}
// wait TX empty
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
} else {
//todo:
// set baudrate
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
uint32_t baud_rate = ((old_apb<<4)/clk_div);
clk_div = ((new_apb<<4)/baud_rate);
uart->dev->clk_div.div_int = clk_div>>4 ;
uart->dev->clk_div.div_frag = clk_div & 0xf;
//enable interrupts
uart->dev->int_ena.rxfifo_full = 1;
uart->dev->int_ena.frm_err = 1;
uart->dev->int_ena.rxfifo_tout = 1;
uart->dev->int_clr.val = 0xffffffff;
UART_MUTEX_UNLOCK();
}
}
uint32_t uartGetBaudRate(uart_t* uart) uint32_t uartGetBaudRate(uart_t* uart)
{ {
if(uart == NULL) { if(uart == NULL) {
return 0; return 0;
} }
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F); uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
return ((UART_CLK_FREQ<<4)/clk_div); return ((getApbFrequency()<<4)/clk_div);
} }
static void IRAM_ATTR uart0_write_char(char c) static void IRAM_ATTR uart0_write_char(char c)
@ -505,7 +540,7 @@ uartDetectBaudrate(uart_t *uart)
uart->dev->auto_baud.en = 0; uart->dev->auto_baud.en = 0;
uartStateDetectingBaudrate = false; // Initialize for the next round uartStateDetectingBaudrate = false; // Initialize for the next round
unsigned long baudrate = UART_CLK_FREQ / divisor; unsigned long baudrate = getApbFrequency() / divisor;
static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400}; static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400};

View File

@ -62,6 +62,7 @@ void yield(void);
#include "esp32-hal-timer.h" #include "esp32-hal-timer.h"
#include "esp32-hal-bt.h" #include "esp32-hal-bt.h"
#include "esp32-hal-psram.h" #include "esp32-hal-psram.h"
#include "esp32-hal-cpu.h"
#ifndef BOARD_HAS_PSRAM #ifndef BOARD_HAS_PSRAM
#ifdef CONFIG_SPIRAM_SUPPORT #ifdef CONFIG_SPIRAM_SUPPORT
@ -87,15 +88,6 @@ void enableCore1WDT();
void disableCore1WDT(); void disableCore1WDT();
#endif #endif
//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 micros();
unsigned long millis(); unsigned long millis();
void delay(uint32_t); void delay(uint32_t);

View File

@ -30,7 +30,7 @@
#include "freertos/queue.h" #include "freertos/queue.h"
#include "Stream.h" #include "Stream.h"
#define STICKBREAKER V1.0.1 #define STICKBREAKER 'V1.1.0'
#define I2C_BUFFER_LENGTH 128 #define I2C_BUFFER_LENGTH 128
typedef void(*user_onRequest)(void); typedef void(*user_onRequest)(void);
typedef void(*user_onReceive)(uint8_t*, int); typedef void(*user_onReceive)(uint8_t*, int);
@ -138,6 +138,7 @@ extern TwoWire Wire1;
/* /*
V1.1.0 08JAN2019 Support CPU Clock frequency changes
V1.0.2 30NOV2018 stop returning I2C_ERROR_CONTINUE on ReSTART operations, regain compatibility with Arduino libs V1.0.2 30NOV2018 stop returning I2C_ERROR_CONTINUE on ReSTART operations, regain compatibility with Arduino libs
V1.0.1 02AUG2018 First Fix after release, Correct ReSTART handling, change Debug control, change begin() V1.0.1 02AUG2018 First Fix after release, Correct ReSTART handling, change Debug control, change begin()
to a function, this allow reporting if bus cannot be initialized, Wire.begin() can be used to recover to a function, this allow reporting if bus cannot be initialized, Wire.begin() can be used to recover