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:
parent
ff18a211e4
commit
2fd39b1aff
@ -3,6 +3,7 @@ set(CORE_SRCS
|
||||
cores/esp32/cbuf.cpp
|
||||
cores/esp32/esp32-hal-adc.c
|
||||
cores/esp32/esp32-hal-bt.c
|
||||
cores/esp32/esp32-hal-cpu.c
|
||||
cores/esp32/esp32-hal-dac.c
|
||||
cores/esp32/esp32-hal-gpio.c
|
||||
cores/esp32/esp32-hal-i2c.c
|
||||
|
20
boards.txt
20
boards.txt
@ -50,11 +50,11 @@ 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=240MHz (WiFi/BT)
|
||||
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.80=80MHz
|
||||
esp32.menu.CPUFreq.80=80MHz (WiFi/BT)
|
||||
esp32.menu.CPUFreq.80.build.f_cpu=80000000L
|
||||
esp32.menu.CPUFreq.40=40MHz (40MHz XTAL)
|
||||
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.20=20MHz (40MHz XTAL)
|
||||
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.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
|
||||
|
211
cores/esp32/esp32-hal-cpu.c
Normal file
211
cores/esp32/esp32-hal-cpu.c
Normal 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);
|
||||
}
|
48
cores/esp32/esp32-hal-cpu.h
Normal file
48
cores/esp32/esp32-hal-cpu.h
Normal 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_ */
|
@ -24,7 +24,7 @@
|
||||
#include "soc/i2c_struct.h"
|
||||
#include "soc/dport_reg.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) ((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))
|
||||
@ -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}
|
||||
};
|
||||
#else
|
||||
#define I2C_MUTEX_LOCK() do {} while (xSemaphoreTake(i2c->lock, portMAX_DELAY) != pdPASS)
|
||||
#define I2C_MUTEX_UNLOCK() xSemaphoreGive(i2c->lock)
|
||||
#define I2C_MUTEX_LOCK() do {} while (xSemaphoreTakeRecursive(i2c->lock, portMAX_DELAY) != pdPASS)
|
||||
#define I2C_MUTEX_UNLOCK() xSemaphoreGiveRecursive(i2c->lock)
|
||||
|
||||
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},
|
||||
@ -445,6 +445,39 @@ static void IRAM_ATTR i2cTriggerDumps(i2c_t * i2c, uint8_t trigger, const char l
|
||||
}
|
||||
// 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)
|
||||
{
|
||||
I2C_COMMAND_t cmd;
|
||||
@ -1221,6 +1254,12 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
|
||||
I2C_MUTEX_UNLOCK();
|
||||
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.
|
||||
|
||||
@ -1352,6 +1391,9 @@ static void i2cReleaseISR(i2c_t * i2c)
|
||||
if(i2c->intr_handle) {
|
||||
esp_intr_free(i2c->intr_handle);
|
||||
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
|
||||
* */
|
||||
// 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);
|
||||
if(i2c_num > 1) {
|
||||
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];
|
||||
|
||||
// pins should be detached, else glitch
|
||||
if(i2c->sda >= 0){
|
||||
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(i2c->lock == NULL) {
|
||||
i2c->lock = xSemaphoreCreateMutex();
|
||||
i2c->lock = xSemaphoreCreateRecursiveMutex();
|
||||
if(i2c->lock == 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;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
|
||||
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) ){
|
||||
period = (MIN_I2C_CLKS/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) {
|
||||
period = 4095;
|
||||
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 quarterPeriod = period/4;
|
||||
@ -1633,14 +1677,19 @@ i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
|
||||
|
||||
I2C_FIFO_CONF_t f;
|
||||
|
||||
// Adjust Fifo thresholds based on frequency
|
||||
f.val = i2c->dev->fifo_conf.val;
|
||||
uint32_t a = (clk_speed / 50000L )+1;
|
||||
if (a > 24) a=24;
|
||||
f.rx_fifo_full_thrhd = 32 - a;
|
||||
f.tx_fifo_empty_thrhd = a;
|
||||
/* Adjust Fifo thresholds based on differential between cpu frequency and bus clock.
|
||||
The fifo_delta is calculated such that at least INTERRUPT_CYCLE_OVERHEAD cpu clocks are
|
||||
available when a Fifo interrupt is triggered. This allows enough room in the Fifo so that
|
||||
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
|
||||
log_v("Fifo threshold=%d",a);
|
||||
log_v("Fifo delta=%d",fifo_delta);
|
||||
|
||||
//the clock num during SCL is low level
|
||||
i2c->dev->scl_low_period.period = period;
|
||||
@ -1696,6 +1745,8 @@ uint32_t i2cGetStatus(i2c_t * i2c){
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
/* todo
|
||||
22JUL18
|
||||
need to add multi-thread capability, use dq.queueEvent as the group marker. When multiple threads
|
||||
|
@ -53,6 +53,33 @@ xSemaphoreHandle _ledc_sys_lock;
|
||||
#define LEDC_CHAN(g,c) LEDC.channel_group[(g)].channel[(c)]
|
||||
#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));
|
||||
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 = 0;
|
||||
LEDC_MUTEX_UNLOCK();
|
||||
uint32_t iarg = chan;
|
||||
addApbChangeCallback((void*)iarg, _on_apb_change);
|
||||
}
|
||||
|
||||
//max div_num 0x3FFFF (262143)
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <sys/time.h>
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/apb_ctrl_reg.h"
|
||||
#include "rom/rtc.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "esp32-hal.h"
|
||||
@ -100,57 +101,19 @@ void disableCore1WDT(){
|
||||
}
|
||||
#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()
|
||||
{
|
||||
return (unsigned long) (esp_timer_get_time()) * _sys_time_multiplier;
|
||||
return (unsigned long) (esp_timer_get_time());
|
||||
}
|
||||
|
||||
unsigned long IRAM_ATTR millis()
|
||||
{
|
||||
return (unsigned long) (micros() / 1000);
|
||||
return (unsigned long) (esp_timer_get_time() / 1000);
|
||||
}
|
||||
|
||||
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)
|
||||
@ -183,8 +146,10 @@ bool btInUse(){ return false; }
|
||||
|
||||
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
|
||||
setCpuFrequency(F_CPU/1000000L);
|
||||
setCpuFrequencyMhz(F_CPU/1000000);
|
||||
#endif
|
||||
#if CONFIG_SPIRAM_SUPPORT
|
||||
psramInit();
|
||||
|
@ -31,6 +31,26 @@
|
||||
xSemaphoreHandle _sd_sys_lock;
|
||||
#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
|
||||
{
|
||||
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 = 1;
|
||||
SD_MUTEX_UNLOCK();
|
||||
uint32_t iarg = channel;
|
||||
addApbChangeCallback((void*)iarg, _on_apb_change);
|
||||
return apb_freq/((prescale + 1) * 256);
|
||||
}
|
||||
|
||||
|
@ -372,6 +372,18 @@ void spiSetBitOrder(spi_t * spi, uint8_t bitOrder)
|
||||
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)
|
||||
{
|
||||
if(!spi) {
|
||||
@ -388,6 +400,7 @@ void spiStopBus(spi_t * spi)
|
||||
spi->dev->ctrl2.val = 0;
|
||||
spi->dev->clock.val = 0;
|
||||
SPI_MUTEX_UNLOCK();
|
||||
removeApbChangeCallback(spi, _on_apb_change);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
addApbChangeCallback(spi, _on_apb_change);
|
||||
return spi;
|
||||
}
|
||||
|
||||
@ -1008,17 +1022,17 @@ void IRAM_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, size_t len){
|
||||
* */
|
||||
|
||||
typedef union {
|
||||
uint32_t regValue;
|
||||
uint32_t value;
|
||||
struct {
|
||||
unsigned regL :6;
|
||||
unsigned regH :6;
|
||||
unsigned regN :6;
|
||||
unsigned regPre :13;
|
||||
unsigned regEQU :1;
|
||||
uint32_t clkcnt_l: 6; /*it must be equal to spi_clkcnt_N.*/
|
||||
uint32_t clkcnt_h: 6; /*it must be floor((spi_clkcnt_N+1)/2-1).*/
|
||||
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)*/
|
||||
uint32_t clkdiv_pre: 13; /*it is pre-divider of spi_clk.*/
|
||||
uint32_t clk_equ_sysclk: 1; /*1: spi_clk is eqaul to system 0: spi_clk is divided from system clock.*/
|
||||
};
|
||||
} 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)
|
||||
{
|
||||
@ -1038,7 +1052,7 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
|
||||
const spiClk_t minFreqReg = { 0x7FFFF000 };
|
||||
uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg);
|
||||
if(freq < minFreq) {
|
||||
return minFreqReg.regValue;
|
||||
return minFreqReg.value;
|
||||
}
|
||||
|
||||
uint8_t calN = 1;
|
||||
@ -1051,18 +1065,18 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
|
||||
int32_t calPre;
|
||||
int8_t calPreVari = -2;
|
||||
|
||||
reg.regN = calN;
|
||||
reg.clkcnt_n = calN;
|
||||
|
||||
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) {
|
||||
reg.regPre = 0x1FFF;
|
||||
reg.clkdiv_pre = 0x1FFF;
|
||||
} else if(calPre <= 0) {
|
||||
reg.regPre = 0;
|
||||
reg.clkdiv_pre = 0;
|
||||
} else {
|
||||
reg.regPre = calPre;
|
||||
reg.clkdiv_pre = calPre;
|
||||
}
|
||||
reg.regL = ((reg.regN + 1) / 2);
|
||||
reg.clkcnt_l = ((reg.clkcnt_n + 1) / 2);
|
||||
calFreq = ClkRegToFreq(®);
|
||||
if(calFreq == (int32_t) freq) {
|
||||
memcpy(&bestReg, ®, sizeof(bestReg));
|
||||
@ -1079,6 +1093,6 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
|
||||
}
|
||||
calN++;
|
||||
}
|
||||
return bestReg.regValue;
|
||||
return bestReg.value;
|
||||
}
|
||||
|
||||
|
@ -184,6 +184,18 @@ bool timerAlarmEnabled(hw_timer_t *timer){
|
||||
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){
|
||||
if(num > 3){
|
||||
return NULL;
|
||||
@ -205,12 +217,14 @@ hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
|
||||
timerAttachInterrupt(timer, NULL, false);
|
||||
timerWrite(timer, 0);
|
||||
timer->dev->config.enable = 1;
|
||||
addApbChangeCallback(timer, _on_apb_change);
|
||||
return timer;
|
||||
}
|
||||
|
||||
void timerEnd(hw_timer_t *timer){
|
||||
timer->dev->config.enable = 0;
|
||||
timerAttachInterrupt(timer, NULL, false);
|
||||
removeApbChangeCallback(timer, _on_apb_change);
|
||||
}
|
||||
|
||||
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 timer_val = timerRead(timer);
|
||||
uint16_t div = timerGetDivider(timer);
|
||||
return timer_val * div / 80;
|
||||
return timer_val * div / (getApbFrequency() / 1000000);
|
||||
}
|
||||
|
||||
double timerReadSeconds(hw_timer_t *timer){
|
||||
uint64_t timer_val = timerRead(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 timer_val = timerAlarmRead(timer);
|
||||
uint16_t div = timerGetDivider(timer);
|
||||
return timer_val * div / 80;
|
||||
return timer_val * div / (getApbFrequency() / 1000000);
|
||||
}
|
||||
|
||||
double timerAlarmReadSeconds(hw_timer_t *timer){
|
||||
uint64_t timer_val = timerAlarmRead(timer);
|
||||
uint16_t div = timerGetDivider(timer);
|
||||
return (double)timer_val * div / 80000000;
|
||||
return (double)timer_val * div / getApbFrequency();
|
||||
}
|
||||
|
@ -67,6 +67,8 @@ static uart_t _uart_bus_array[3] = {
|
||||
};
|
||||
#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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
addApbChangeCallback(uart, uart_on_apb_change);
|
||||
return uart;
|
||||
}
|
||||
|
||||
@ -224,11 +227,10 @@ void uartEnd(uart_t* uart)
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
}
|
||||
removeApbChangeCallback(uart, uart_on_apb_change);
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
if(uart->queue != NULL) {
|
||||
uint8_t c;
|
||||
while(xQueueReceive(uart->queue, &c, 0));
|
||||
vQueueDelete(uart->queue);
|
||||
uart->queue = NULL;
|
||||
}
|
||||
@ -248,8 +250,6 @@ size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
if(uart->queue != NULL) {
|
||||
uint8_t c;
|
||||
while(xQueueReceive(uart->queue, &c, 0));
|
||||
vQueueDelete(uart->queue);
|
||||
uart->queue = xQueueCreate(new_size, sizeof(uint8_t));
|
||||
if(uart->queue == NULL) {
|
||||
@ -319,10 +319,9 @@ void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
|
||||
}
|
||||
UART_MUTEX_LOCK();
|
||||
while(len) {
|
||||
while(len && uart->dev->status.txfifo_cnt < 0x7F) {
|
||||
uart->dev->fifo.rw_byte = *data++;
|
||||
len--;
|
||||
}
|
||||
while(uart->dev->status.txfifo_cnt == 0x7F);
|
||||
uart->dev->fifo.rw_byte = *data++;
|
||||
len--;
|
||||
}
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
@ -359,13 +358,49 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
|
||||
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)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
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)
|
||||
@ -505,7 +540,7 @@ uartDetectBaudrate(uart_t *uart)
|
||||
uart->dev->auto_baud.en = 0;
|
||||
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};
|
||||
|
||||
|
@ -62,6 +62,7 @@ void yield(void);
|
||||
#include "esp32-hal-timer.h"
|
||||
#include "esp32-hal-bt.h"
|
||||
#include "esp32-hal-psram.h"
|
||||
#include "esp32-hal-cpu.h"
|
||||
|
||||
#ifndef BOARD_HAS_PSRAM
|
||||
#ifdef CONFIG_SPIRAM_SUPPORT
|
||||
@ -87,15 +88,6 @@ void enableCore1WDT();
|
||||
void disableCore1WDT();
|
||||
#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 millis();
|
||||
void delay(uint32_t);
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include "freertos/queue.h"
|
||||
#include "Stream.h"
|
||||
|
||||
#define STICKBREAKER V1.0.1
|
||||
#define STICKBREAKER 'V1.1.0'
|
||||
#define I2C_BUFFER_LENGTH 128
|
||||
typedef void(*user_onRequest)(void);
|
||||
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.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
|
||||
|
Loading…
Reference in New Issue
Block a user