mirror of
https://github.com/bbulkow/FastLED-idf.git
synced 2025-08-02 12:15:12 +02:00
Remove unneeded files
This commit is contained in:
@@ -1,239 +0,0 @@
|
|||||||
// 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 "esp32-hal-adc.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "rom/ets_sys.h"
|
|
||||||
#include "esp_attr.h"
|
|
||||||
#include "esp_intr.h"
|
|
||||||
#include "soc/rtc_io_reg.h"
|
|
||||||
#include "soc/rtc_cntl_reg.h"
|
|
||||||
#include "soc/sens_reg.h"
|
|
||||||
|
|
||||||
#include "driver/adc.h"
|
|
||||||
#include "esp_adc_cal.h"
|
|
||||||
|
|
||||||
#define DEFAULT_VREF 1100
|
|
||||||
static esp_adc_cal_characteristics_t *__analogCharacteristics[2] = {NULL, NULL};
|
|
||||||
static uint8_t __analogAttenuation = 3;//11db
|
|
||||||
static uint8_t __analogWidth = 3;//12 bits
|
|
||||||
static uint8_t __analogClockDiv = 1;
|
|
||||||
static uint16_t __analogVRef = 0;
|
|
||||||
static uint8_t __analogVRefPin = 0;
|
|
||||||
|
|
||||||
void __analogSetWidth(uint8_t bits){
|
|
||||||
if(bits < 9){
|
|
||||||
bits = 9;
|
|
||||||
} else if(bits > 12){
|
|
||||||
bits = 12;
|
|
||||||
}
|
|
||||||
__analogWidth = bits - 9;
|
|
||||||
adc1_config_width(__analogWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __analogSetClockDiv(uint8_t clockDiv){
|
|
||||||
if(!clockDiv){
|
|
||||||
clockDiv = 1;
|
|
||||||
}
|
|
||||||
__analogClockDiv = clockDiv;
|
|
||||||
adc_set_clk_div(__analogClockDiv);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __analogSetAttenuation(adc_attenuation_t attenuation)
|
|
||||||
{
|
|
||||||
__analogAttenuation = attenuation & 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __analogInit(){
|
|
||||||
static bool initialized = false;
|
|
||||||
if(initialized){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
initialized = true;
|
|
||||||
__analogSetClockDiv(__analogClockDiv);
|
|
||||||
__analogSetWidth(__analogWidth + 9);//in bits
|
|
||||||
}
|
|
||||||
|
|
||||||
void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation)
|
|
||||||
{
|
|
||||||
int8_t channel = digitalPinToAnalogChannel(pin);
|
|
||||||
if(channel < 0 || attenuation > 3){
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
if(channel > 9){
|
|
||||||
adc2_config_channel_atten(channel - 10, attenuation);
|
|
||||||
} else {
|
|
||||||
adc1_config_channel_atten(channel, attenuation);
|
|
||||||
}
|
|
||||||
__analogInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool __adcAttachPin(uint8_t pin){
|
|
||||||
int8_t channel = digitalPinToAnalogChannel(pin);
|
|
||||||
if(channel < 0){
|
|
||||||
log_e("Pin %u is not ADC pin!", pin);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int8_t pad = digitalPinToTouchChannel(pin);
|
|
||||||
if(pad >= 0){
|
|
||||||
uint32_t touch = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG);
|
|
||||||
if(touch & (1 << pad)){
|
|
||||||
touch &= ~((1 << (pad + SENS_TOUCH_PAD_OUTEN2_S))
|
|
||||||
| (1 << (pad + SENS_TOUCH_PAD_OUTEN1_S))
|
|
||||||
| (1 << (pad + SENS_TOUCH_PAD_WORKEN_S)));
|
|
||||||
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, touch);
|
|
||||||
}
|
|
||||||
} else if(pin == 25){
|
|
||||||
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE);//stop dac1
|
|
||||||
} else if(pin == 26){
|
|
||||||
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC | RTC_IO_PDAC2_DAC_XPD_FORCE);//stop dac2
|
|
||||||
}
|
|
||||||
|
|
||||||
pinMode(pin, ANALOG);
|
|
||||||
__analogSetPinAttenuation(pin, __analogAttenuation);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __analogReadResolution(uint8_t bits)
|
|
||||||
{
|
|
||||||
if(!bits || bits > 16){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
__analogSetWidth(bits); // hadware from 9 to 12
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t __analogRead(uint8_t pin)
|
|
||||||
{
|
|
||||||
int8_t channel = digitalPinToAnalogChannel(pin);
|
|
||||||
int value = 0;
|
|
||||||
esp_err_t r = ESP_OK;
|
|
||||||
if(channel < 0){
|
|
||||||
log_e("Pin %u is not ADC pin!", pin);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
__adcAttachPin(pin);
|
|
||||||
if(channel > 9){
|
|
||||||
channel -= 10;
|
|
||||||
r = adc2_get_raw( channel, __analogWidth, &value);
|
|
||||||
if ( r == ESP_OK ) {
|
|
||||||
return value;
|
|
||||||
} else if ( r == ESP_ERR_INVALID_STATE ) {
|
|
||||||
log_e("GPIO%u: %s: ADC2 not initialized yet.", pin, esp_err_to_name(r));
|
|
||||||
} else if ( r == ESP_ERR_TIMEOUT ) {
|
|
||||||
log_e("GPIO%u: %s: ADC2 is in use by Wi-Fi.", pin, esp_err_to_name(r));
|
|
||||||
} else {
|
|
||||||
log_e("GPIO%u: %s", pin, esp_err_to_name(r));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return adc1_get_raw(channel);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __analogSetVRefPin(uint8_t pin){
|
|
||||||
if(pin <25 || pin > 27){
|
|
||||||
pin = 0;
|
|
||||||
}
|
|
||||||
__analogVRefPin = pin;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t __analogReadMilliVolts(uint8_t pin){
|
|
||||||
int8_t channel = digitalPinToAnalogChannel(pin);
|
|
||||||
if(channel < 0){
|
|
||||||
log_e("Pin %u is not ADC pin!", pin);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(!__analogVRef){
|
|
||||||
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
|
|
||||||
log_d("eFuse Two Point: Supported");
|
|
||||||
__analogVRef = DEFAULT_VREF;
|
|
||||||
}
|
|
||||||
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) {
|
|
||||||
log_d("eFuse Vref: Supported");
|
|
||||||
__analogVRef = DEFAULT_VREF;
|
|
||||||
}
|
|
||||||
if(!__analogVRef){
|
|
||||||
__analogVRef = DEFAULT_VREF;
|
|
||||||
if(__analogVRefPin){
|
|
||||||
esp_adc_cal_characteristics_t chars;
|
|
||||||
if(adc2_vref_to_gpio(__analogVRefPin) == ESP_OK){
|
|
||||||
__analogVRef = __analogRead(__analogVRefPin);
|
|
||||||
esp_adc_cal_characterize(1, __analogAttenuation, __analogWidth, DEFAULT_VREF, &chars);
|
|
||||||
__analogVRef = esp_adc_cal_raw_to_voltage(__analogVRef, &chars);
|
|
||||||
log_d("Vref to GPIO%u: %u", __analogVRefPin, __analogVRef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint8_t unit = 1;
|
|
||||||
if(channel > 9){
|
|
||||||
unit = 2;
|
|
||||||
}
|
|
||||||
uint16_t adc_reading = __analogRead(pin);
|
|
||||||
if(__analogCharacteristics[unit - 1] == NULL){
|
|
||||||
__analogCharacteristics[unit - 1] = calloc(1, sizeof(esp_adc_cal_characteristics_t));
|
|
||||||
if(__analogCharacteristics[unit - 1] == NULL){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, __analogAttenuation, __analogWidth, __analogVRef, __analogCharacteristics[unit - 1]);
|
|
||||||
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
|
|
||||||
log_i("ADC%u: Characterized using Two Point Value: %u\n", unit, __analogCharacteristics[unit - 1]->vref);
|
|
||||||
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
|
|
||||||
log_i("ADC%u: Characterized using eFuse Vref: %u\n", unit, __analogCharacteristics[unit - 1]->vref);
|
|
||||||
} else if(__analogVRef != DEFAULT_VREF){
|
|
||||||
log_i("ADC%u: Characterized using Vref to GPIO%u: %u\n", unit, __analogVRefPin, __analogCharacteristics[unit - 1]->vref);
|
|
||||||
} else {
|
|
||||||
log_i("ADC%u: Characterized using Default Vref: %u\n", unit, __analogCharacteristics[unit - 1]->vref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return esp_adc_cal_raw_to_voltage(adc_reading, __analogCharacteristics[unit - 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __hallRead() //hall sensor without LNA
|
|
||||||
{
|
|
||||||
int Sens_Vp0;
|
|
||||||
int Sens_Vn0;
|
|
||||||
int Sens_Vp1;
|
|
||||||
int Sens_Vn1;
|
|
||||||
|
|
||||||
pinMode(36, ANALOG);
|
|
||||||
pinMode(39, ANALOG);
|
|
||||||
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_XPD_HALL_FORCE_M); // hall sens force enable
|
|
||||||
SET_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_XPD_HALL); // xpd hall
|
|
||||||
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_HALL_PHASE_FORCE_M); // phase force
|
|
||||||
CLEAR_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_HALL_PHASE); // hall phase
|
|
||||||
Sens_Vp0 = __analogRead(36);
|
|
||||||
Sens_Vn0 = __analogRead(39);
|
|
||||||
SET_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_HALL_PHASE);
|
|
||||||
Sens_Vp1 = __analogRead(36);
|
|
||||||
Sens_Vn1 = __analogRead(39);
|
|
||||||
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 0, SENS_FORCE_XPD_SAR_S);
|
|
||||||
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_XPD_HALL_FORCE);
|
|
||||||
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_HALL_PHASE_FORCE);
|
|
||||||
return (Sens_Vp1 - Sens_Vp0) - (Sens_Vn1 - Sens_Vn0);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern uint16_t analogRead(uint8_t pin) __attribute__ ((weak, alias("__analogRead")));
|
|
||||||
extern void analogReadResolution(uint8_t bits) __attribute__ ((weak, alias("__analogReadResolution")));
|
|
||||||
extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth")));
|
|
||||||
extern void analogSetClockDiv(uint8_t clockDiv) __attribute__ ((weak, alias("__analogSetClockDiv")));
|
|
||||||
extern void analogSetAttenuation(adc_attenuation_t attenuation) __attribute__ ((weak, alias("__analogSetAttenuation")));
|
|
||||||
extern void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation) __attribute__ ((weak, alias("__analogSetPinAttenuation")));
|
|
||||||
extern int hallRead() __attribute__ ((weak, alias("__hallRead")));
|
|
||||||
|
|
||||||
extern bool adcAttachPin(uint8_t pin) __attribute__ ((weak, alias("__adcAttachPin")));
|
|
||||||
|
|
||||||
extern void analogSetVRefPin(uint8_t pin) __attribute__ ((weak, alias("__analogSetVRefPin")));
|
|
||||||
extern uint32_t analogReadMilliVolts(uint8_t pin) __attribute__ ((weak, alias("__analogReadMilliVolts")));
|
|
@@ -1,99 +0,0 @@
|
|||||||
// 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 "esp32-hal-bt.h"
|
|
||||||
|
|
||||||
#ifdef CONFIG_BT_ENABLED
|
|
||||||
|
|
||||||
bool btInUse(){ return true; }
|
|
||||||
|
|
||||||
#ifdef CONFIG_BLUEDROID_ENABLED
|
|
||||||
#include "esp_bt.h"
|
|
||||||
|
|
||||||
#ifdef CONFIG_CLASSIC_BT_ENABLED
|
|
||||||
#define BT_MODE ESP_BT_MODE_BTDM
|
|
||||||
#else
|
|
||||||
#define BT_MODE ESP_BT_MODE_BLE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool btStarted(){
|
|
||||||
return (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool btStart(){
|
|
||||||
esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
|
||||||
if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE){
|
|
||||||
esp_bt_controller_init(&cfg);
|
|
||||||
while(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE){}
|
|
||||||
}
|
|
||||||
if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED){
|
|
||||||
if (esp_bt_controller_enable(BT_MODE)) {
|
|
||||||
log_e("BT Enable failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
log_e("BT Start failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool btStop(){
|
|
||||||
if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED){
|
|
||||||
if (esp_bt_controller_disable()) {
|
|
||||||
log_e("BT Disable failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
while(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED);
|
|
||||||
}
|
|
||||||
if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED){
|
|
||||||
if (esp_bt_controller_deinit()) {
|
|
||||||
log_e("BT deint failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
vTaskDelay(1);
|
|
||||||
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
log_e("BT Stop failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
bool btStarted()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool btStart()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool btStop()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
@@ -1,230 +0,0 @@
|
|||||||
// 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 "soc/efuse_reg.h"
|
|
||||||
#include "esp32-hal.h"
|
|
||||||
#include "esp32-hal-cpu.h"
|
|
||||||
|
|
||||||
typedef struct apb_change_cb_s {
|
|
||||||
struct apb_change_cb_s * prev;
|
|
||||||
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;
|
|
||||||
if( r != NULL ){
|
|
||||||
if(ev_type == APB_BEFORE_CHANGE )
|
|
||||||
while(r != NULL){
|
|
||||||
r->cb(r->arg, ev_type, old_apb, new_apb);
|
|
||||||
r=r->next;
|
|
||||||
}
|
|
||||||
else { // run backwards through chain
|
|
||||||
while(r->next != NULL) r = r->next; // find first added
|
|
||||||
while( r != NULL){
|
|
||||||
r->cb(r->arg, ev_type, old_apb, new_apb);
|
|
||||||
r=r->prev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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->prev = 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;
|
|
||||||
// look for duplicate callbacks
|
|
||||||
while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next;
|
|
||||||
if (r) {
|
|
||||||
log_e("duplicate func=%08X arg=%08X",c->cb,c->arg);
|
|
||||||
free(c);
|
|
||||||
xSemaphoreGive(apb_change_lock);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
c->next = apb_change_callbacks;
|
|
||||||
apb_change_callbacks-> prev = c;
|
|
||||||
apb_change_callbacks = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
// look for matching callback
|
|
||||||
while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next;
|
|
||||||
if ( r == NULL ) {
|
|
||||||
log_e("not found func=%08X arg=%08X",cb,arg);
|
|
||||||
xSemaphoreGive(apb_change_lock);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// patch links
|
|
||||||
if(r->prev) r->prev->next = r->next;
|
|
||||||
else { // this is first link
|
|
||||||
apb_change_callbacks = r->next;
|
|
||||||
}
|
|
||||||
if(r->next) r->next->prev = r->prev;
|
|
||||||
free(r);
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
if(xtal > RTC_XTAL_FREQ_AUTO){
|
|
||||||
if(xtal < RTC_XTAL_FREQ_40M) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
//check if cpu supports the frequency
|
|
||||||
if(cpu_freq_mhz == 240){
|
|
||||||
//Check if ESP32 is rated for a CPU frequency of 160MHz only
|
|
||||||
if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_CPU_FREQ_RATED) &&
|
|
||||||
REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_CPU_FREQ_LOW)) {
|
|
||||||
log_e("Can not switch to 240 MHz! Chip CPU frequency rated for 160MHz.");
|
|
||||||
cpu_freq_mhz = 160;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//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);
|
|
||||||
}
|
|
@@ -1,54 +0,0 @@
|
|||||||
// 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 "esp32-hal-dac.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "rom/ets_sys.h"
|
|
||||||
#include "esp_attr.h"
|
|
||||||
#include "esp_intr.h"
|
|
||||||
#include "soc/rtc_io_reg.h"
|
|
||||||
#include "soc/rtc_cntl_reg.h"
|
|
||||||
#include "soc/sens_reg.h"
|
|
||||||
|
|
||||||
void IRAM_ATTR __dacWrite(uint8_t pin, uint8_t value)
|
|
||||||
{
|
|
||||||
if(pin < 25 || pin > 26){
|
|
||||||
return;//not dac pin
|
|
||||||
}
|
|
||||||
pinMode(pin, ANALOG);
|
|
||||||
uint8_t channel = pin - 25;
|
|
||||||
|
|
||||||
|
|
||||||
//Disable Tone
|
|
||||||
CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_SW_TONE_EN);
|
|
||||||
|
|
||||||
if (channel) {
|
|
||||||
//Disable Channel Tone
|
|
||||||
CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN2_M);
|
|
||||||
//Set the Dac value
|
|
||||||
SET_PERI_REG_BITS(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_DAC, value, RTC_IO_PDAC2_DAC_S); //dac_output
|
|
||||||
//Channel output enable
|
|
||||||
SET_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC | RTC_IO_PDAC2_DAC_XPD_FORCE);
|
|
||||||
} else {
|
|
||||||
//Disable Channel Tone
|
|
||||||
CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN1_M);
|
|
||||||
//Set the Dac value
|
|
||||||
SET_PERI_REG_BITS(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_DAC, value, RTC_IO_PDAC1_DAC_S); //dac_output
|
|
||||||
//Channel output enable
|
|
||||||
SET_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void dacWrite(uint8_t pin, uint8_t value) __attribute__ ((weak, alias("__dacWrite")));
|
|
@@ -1,280 +0,0 @@
|
|||||||
// 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 "esp32-hal.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "freertos/semphr.h"
|
|
||||||
#include "rom/ets_sys.h"
|
|
||||||
#include "esp32-hal-matrix.h"
|
|
||||||
#include "soc/dport_reg.h"
|
|
||||||
#include "soc/ledc_reg.h"
|
|
||||||
#include "soc/ledc_struct.h"
|
|
||||||
|
|
||||||
#if CONFIG_DISABLE_HAL_LOCKS
|
|
||||||
#define LEDC_MUTEX_LOCK()
|
|
||||||
#define LEDC_MUTEX_UNLOCK()
|
|
||||||
#else
|
|
||||||
#define LEDC_MUTEX_LOCK() do {} while (xSemaphoreTake(_ledc_sys_lock, portMAX_DELAY) != pdPASS)
|
|
||||||
#define LEDC_MUTEX_UNLOCK() xSemaphoreGive(_ledc_sys_lock)
|
|
||||||
xSemaphoreHandle _ledc_sys_lock = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* LEDC Chan to Group/Channel/Timer Mapping
|
|
||||||
** ledc: 0 => Group: 0, Channel: 0, Timer: 0
|
|
||||||
** ledc: 1 => Group: 0, Channel: 1, Timer: 0
|
|
||||||
** ledc: 2 => Group: 0, Channel: 2, Timer: 1
|
|
||||||
** ledc: 3 => Group: 0, Channel: 3, Timer: 1
|
|
||||||
** ledc: 4 => Group: 0, Channel: 4, Timer: 2
|
|
||||||
** ledc: 5 => Group: 0, Channel: 5, Timer: 2
|
|
||||||
** ledc: 6 => Group: 0, Channel: 6, Timer: 3
|
|
||||||
** ledc: 7 => Group: 0, Channel: 7, Timer: 3
|
|
||||||
** ledc: 8 => Group: 1, Channel: 0, Timer: 0
|
|
||||||
** ledc: 9 => Group: 1, Channel: 1, Timer: 0
|
|
||||||
** ledc: 10 => Group: 1, Channel: 2, Timer: 1
|
|
||||||
** ledc: 11 => Group: 1, Channel: 3, Timer: 1
|
|
||||||
** ledc: 12 => Group: 1, Channel: 4, Timer: 2
|
|
||||||
** ledc: 13 => Group: 1, Channel: 5, Timer: 2
|
|
||||||
** ledc: 14 => Group: 1, Channel: 6, Timer: 3
|
|
||||||
** ledc: 15 => Group: 1, Channel: 7, Timer: 3
|
|
||||||
*/
|
|
||||||
#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){
|
|
||||||
uint16_t iarg = *(uint16_t*)arg;
|
|
||||||
uint8_t chan = 0;
|
|
||||||
old_apb /= 1000000;
|
|
||||||
new_apb /= 1000000;
|
|
||||||
while(iarg){ // run though all active channels, adjusting timing configurations
|
|
||||||
if(iarg & 1) {// this channel is active
|
|
||||||
uint8_t group=(chan/8), timer=((chan/2)%4);
|
|
||||||
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){
|
|
||||||
div_num = ((REF_CLK_FREQ /1000000) * 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();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log_d("using REF_CLK chan=%d",chan);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
iarg = iarg >> 1;
|
|
||||||
chan++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//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)
|
|
||||||
{
|
|
||||||
uint8_t group=(chan/8), timer=((chan/2)%4);
|
|
||||||
static bool tHasStarted = false;
|
|
||||||
static uint16_t _activeChannels = 0;
|
|
||||||
if(!tHasStarted) {
|
|
||||||
tHasStarted = true;
|
|
||||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
|
|
||||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
|
|
||||||
LEDC.conf.apb_clk_sel = 1;//LS use apb clock
|
|
||||||
addApbChangeCallback((void*)&_activeChannels, _on_apb_change);
|
|
||||||
|
|
||||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
|
||||||
_ledc_sys_lock = xSemaphoreCreateMutex();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
LEDC_MUTEX_LOCK();
|
|
||||||
LEDC_TIMER(group, timer).conf.clock_divider = div_num;//18 bit (10.8) This register is used to configure parameter for divider in timer the least significant eight bits represent the decimal part.
|
|
||||||
LEDC_TIMER(group, timer).conf.duty_resolution = bit_num;//5 bit This register controls the range of the counter in timer. the counter range is [0 2**bit_num] the max bit width for counter is 20.
|
|
||||||
LEDC_TIMER(group, timer).conf.tick_sel = apb_clk;//apb clock
|
|
||||||
if(group) {
|
|
||||||
LEDC_TIMER(group, timer).conf.low_speed_update = 1;//This bit is only useful for low speed timer channels, reserved for high speed timers
|
|
||||||
}
|
|
||||||
LEDC_TIMER(group, timer).conf.pause = 0;
|
|
||||||
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();
|
|
||||||
_activeChannels |= (1 << chan); // mark as active for APB callback
|
|
||||||
}
|
|
||||||
|
|
||||||
//max div_num 0x3FFFF (262143)
|
|
||||||
//max bit_num 0x1F (31)
|
|
||||||
static double _ledcSetupTimerFreq(uint8_t chan, double freq, uint8_t bit_num)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
if(div_num > LEDC_DIV_NUM_HSTIMER0_V) {
|
|
||||||
clk_freq /= 80;
|
|
||||||
div_num = (clk_freq >> bit_num) / freq;
|
|
||||||
if(div_num > LEDC_DIV_NUM_HSTIMER0_V) {
|
|
||||||
div_num = LEDC_DIV_NUM_HSTIMER0_V;//lowest clock possible
|
|
||||||
}
|
|
||||||
apb_clk = false;
|
|
||||||
} else if(div_num < 256) {
|
|
||||||
div_num = 256;//highest clock possible
|
|
||||||
}
|
|
||||||
_ledcSetupTimer(chan, div_num, bit_num, apb_clk);
|
|
||||||
//log_i("Fin: %f, Fclk: %uMhz, bits: %u, DIV: %u, Fout: %f",
|
|
||||||
// freq, apb_clk?80:1, bit_num, div_num, (clk_freq >> bit_num) / (double)div_num);
|
|
||||||
return (clk_freq >> bit_num) / (double)div_num;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double _ledcTimerRead(uint8_t chan)
|
|
||||||
{
|
|
||||||
uint32_t div_num;
|
|
||||||
uint8_t bit_num;
|
|
||||||
bool apb_clk;
|
|
||||||
uint8_t group=(chan/8), timer=((chan/2)%4);
|
|
||||||
LEDC_MUTEX_LOCK();
|
|
||||||
div_num = LEDC_TIMER(group, timer).conf.clock_divider;//18 bit (10.8) This register is used to configure parameter for divider in timer the least significant eight bits represent the decimal part.
|
|
||||||
bit_num = LEDC_TIMER(group, timer).conf.duty_resolution;//5 bit This register controls the range of the counter in timer. the counter range is [0 2**bit_num] the max bit width for counter is 20.
|
|
||||||
apb_clk = LEDC_TIMER(group, timer).conf.tick_sel;//apb clock
|
|
||||||
LEDC_MUTEX_UNLOCK();
|
|
||||||
uint64_t clk_freq = 1000000;
|
|
||||||
if(apb_clk) {
|
|
||||||
clk_freq = getApbFrequency();
|
|
||||||
}
|
|
||||||
clk_freq <<= 8;//div_num is 8 bit decimal
|
|
||||||
return (clk_freq >> bit_num) / (double)div_num;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _ledcSetupChannel(uint8_t chan, uint8_t idle_level)
|
|
||||||
{
|
|
||||||
uint8_t group=(chan/8), channel=(chan%8), timer=((chan/2)%4);
|
|
||||||
LEDC_MUTEX_LOCK();
|
|
||||||
LEDC_CHAN(group, channel).conf0.timer_sel = timer;//2 bit Selects the timer to attach 0-3
|
|
||||||
LEDC_CHAN(group, channel).conf0.idle_lv = idle_level;//1 bit This bit is used to control the output value when channel is off.
|
|
||||||
LEDC_CHAN(group, channel).hpoint.hpoint = 0;//20 bit The output value changes to high when timer selected by channel has reached hpoint
|
|
||||||
LEDC_CHAN(group, channel).conf1.duty_inc = 1;//1 bit This register is used to increase the duty of output signal or decrease the duty of output signal for high speed channel
|
|
||||||
LEDC_CHAN(group, channel).conf1.duty_num = 1;//10 bit This register is used to control the number of increased or decreased times for channel
|
|
||||||
LEDC_CHAN(group, channel).conf1.duty_cycle = 1;//10 bit This register is used to increase or decrease the duty every duty_cycle cycles for channel
|
|
||||||
LEDC_CHAN(group, channel).conf1.duty_scale = 0;//10 bit This register controls the increase or decrease step scale for channel.
|
|
||||||
LEDC_CHAN(group, channel).duty.duty = 0;
|
|
||||||
LEDC_CHAN(group, channel).conf0.sig_out_en = 0;//This is the output enable control bit for channel
|
|
||||||
LEDC_CHAN(group, channel).conf1.duty_start = 0;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware.
|
|
||||||
if(group) {
|
|
||||||
LEDC_CHAN(group, channel).conf0.low_speed_update = 1;
|
|
||||||
} else {
|
|
||||||
LEDC_CHAN(group, channel).conf0.clk_en = 0;
|
|
||||||
}
|
|
||||||
LEDC_MUTEX_UNLOCK();
|
|
||||||
}
|
|
||||||
|
|
||||||
double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)
|
|
||||||
{
|
|
||||||
if(chan > 15) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
double res_freq = _ledcSetupTimerFreq(chan, freq, bit_num);
|
|
||||||
_ledcSetupChannel(chan, LOW);
|
|
||||||
return res_freq;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ledcWrite(uint8_t chan, uint32_t duty)
|
|
||||||
{
|
|
||||||
if(chan > 15) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uint8_t group=(chan/8), channel=(chan%8);
|
|
||||||
LEDC_MUTEX_LOCK();
|
|
||||||
LEDC_CHAN(group, channel).duty.duty = duty << 4;//25 bit (21.4)
|
|
||||||
if(duty) {
|
|
||||||
LEDC_CHAN(group, channel).conf0.sig_out_en = 1;//This is the output enable control bit for channel
|
|
||||||
LEDC_CHAN(group, channel).conf1.duty_start = 1;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware.
|
|
||||||
if(group) {
|
|
||||||
LEDC_CHAN(group, channel).conf0.low_speed_update = 1;
|
|
||||||
} else {
|
|
||||||
LEDC_CHAN(group, channel).conf0.clk_en = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LEDC_CHAN(group, channel).conf0.sig_out_en = 0;//This is the output enable control bit for channel
|
|
||||||
LEDC_CHAN(group, channel).conf1.duty_start = 0;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware.
|
|
||||||
if(group) {
|
|
||||||
LEDC_CHAN(group, channel).conf0.low_speed_update = 1;
|
|
||||||
} else {
|
|
||||||
LEDC_CHAN(group, channel).conf0.clk_en = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LEDC_MUTEX_UNLOCK();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ledcRead(uint8_t chan)
|
|
||||||
{
|
|
||||||
if(chan > 15) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return LEDC.channel_group[chan/8].channel[chan%8].duty.duty >> 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
double ledcReadFreq(uint8_t chan)
|
|
||||||
{
|
|
||||||
if(!ledcRead(chan)){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return _ledcTimerRead(chan);
|
|
||||||
}
|
|
||||||
|
|
||||||
double ledcWriteTone(uint8_t chan, double freq)
|
|
||||||
{
|
|
||||||
if(chan > 15) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(!freq) {
|
|
||||||
ledcWrite(chan, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
double res_freq = _ledcSetupTimerFreq(chan, freq, 10);
|
|
||||||
ledcWrite(chan, 0x1FF);
|
|
||||||
return res_freq;
|
|
||||||
}
|
|
||||||
|
|
||||||
double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
|
|
||||||
const uint16_t noteFrequencyBase[12] = {
|
|
||||||
// C C# D Eb E F F# G G# A Bb B
|
|
||||||
4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902
|
|
||||||
};
|
|
||||||
|
|
||||||
if(octave > 8 || note >= NOTE_MAX){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
double noteFreq = (double)noteFrequencyBase[note] / (double)(1 << (8-octave));
|
|
||||||
return ledcWriteTone(chan, noteFreq);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ledcAttachPin(uint8_t pin, uint8_t chan)
|
|
||||||
{
|
|
||||||
if(chan > 15) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pinMode(pin, OUTPUT);
|
|
||||||
pinMatrixOutAttach(pin, ((chan/8)?LEDC_LS_SIG_OUT0_IDX:LEDC_HS_SIG_OUT0_IDX) + (chan%8), false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ledcDetachPin(uint8_t pin)
|
|
||||||
{
|
|
||||||
pinMatrixOutDetach(pin, false, false);
|
|
||||||
}
|
|
@@ -1,47 +0,0 @@
|
|||||||
// 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 "esp32-hal-matrix.h"
|
|
||||||
#include "esp_attr.h"
|
|
||||||
#include "rom/gpio.h"
|
|
||||||
|
|
||||||
#define MATRIX_DETACH_OUT_SIG 0x100
|
|
||||||
#define MATRIX_DETACH_IN_LOW_PIN 0x30
|
|
||||||
#define MATRIX_DETACH_IN_LOW_HIGH 0x38
|
|
||||||
|
|
||||||
void IRAM_ATTR pinMatrixOutAttach(uint8_t pin, uint8_t function, bool invertOut, bool invertEnable)
|
|
||||||
{
|
|
||||||
gpio_matrix_out(pin, function, invertOut, invertEnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRAM_ATTR pinMatrixOutDetach(uint8_t pin, bool invertOut, bool invertEnable)
|
|
||||||
{
|
|
||||||
gpio_matrix_out(pin, MATRIX_DETACH_OUT_SIG, invertOut, invertEnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRAM_ATTR pinMatrixInAttach(uint8_t pin, uint8_t signal, bool inverted)
|
|
||||||
{
|
|
||||||
gpio_matrix_in(pin, signal, inverted);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRAM_ATTR pinMatrixInDetach(uint8_t signal, bool high, bool inverted)
|
|
||||||
{
|
|
||||||
gpio_matrix_in(high?MATRIX_DETACH_IN_LOW_HIGH:MATRIX_DETACH_IN_LOW_PIN, signal, inverted);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
void IRAM_ATTR intrMatrixAttach(uint32_t source, uint32_t inum){
|
|
||||||
intr_matrix_set(PRO_CPU_NUM, source, inum);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
@@ -1,98 +0,0 @@
|
|||||||
|
|
||||||
#include "esp32-hal.h"
|
|
||||||
|
|
||||||
#if CONFIG_SPIRAM_SUPPORT
|
|
||||||
#include "esp_spiram.h"
|
|
||||||
#include "soc/efuse_reg.h"
|
|
||||||
#include "esp_heap_caps.h"
|
|
||||||
|
|
||||||
static volatile bool spiramDetected = false;
|
|
||||||
static volatile bool spiramFailed = false;
|
|
||||||
|
|
||||||
bool psramInit(){
|
|
||||||
if (spiramDetected) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#ifndef CONFIG_SPIRAM_BOOT_INIT
|
|
||||||
if (spiramFailed) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG);
|
|
||||||
uint32_t pkg_ver = chip_ver & 0x7;
|
|
||||||
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 || pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) {
|
|
||||||
spiramFailed = true;
|
|
||||||
log_w("PSRAM not supported!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
esp_spiram_init_cache();
|
|
||||||
if (esp_spiram_init() != ESP_OK) {
|
|
||||||
spiramFailed = true;
|
|
||||||
log_w("PSRAM init failed!");
|
|
||||||
pinMatrixOutDetach(16, false, false);
|
|
||||||
pinMatrixOutDetach(17, false, false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!esp_spiram_test()) {
|
|
||||||
spiramFailed = true;
|
|
||||||
log_e("PSRAM test failed!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (esp_spiram_add_to_heapalloc() != ESP_OK) {
|
|
||||||
spiramFailed = true;
|
|
||||||
log_e("PSRAM could not be added to the heap!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
spiramDetected = true;
|
|
||||||
log_d("PSRAM enabled");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IRAM_ATTR psramFound(){
|
|
||||||
return spiramDetected;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRAM_ATTR *ps_malloc(size_t size){
|
|
||||||
if(!spiramDetected){
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRAM_ATTR *ps_calloc(size_t n, size_t size){
|
|
||||||
if(!spiramDetected){
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRAM_ATTR *ps_realloc(void *ptr, size_t size){
|
|
||||||
if(!spiramDetected){
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return heap_caps_realloc(ptr, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
bool psramInit(){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IRAM_ATTR psramFound(){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRAM_ATTR *ps_malloc(size_t size){
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRAM_ATTR *ps_calloc(size_t n, size_t size){
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRAM_ATTR *ps_realloc(void *ptr, size_t size){
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@@ -1,115 +0,0 @@
|
|||||||
// 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 "esp32-hal.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "freertos/semphr.h"
|
|
||||||
#include "rom/ets_sys.h"
|
|
||||||
#include "esp32-hal-matrix.h"
|
|
||||||
#include "soc/gpio_sd_reg.h"
|
|
||||||
#include "soc/gpio_sd_struct.h"
|
|
||||||
|
|
||||||
|
|
||||||
#if CONFIG_DISABLE_HAL_LOCKS
|
|
||||||
#define SD_MUTEX_LOCK()
|
|
||||||
#define SD_MUTEX_UNLOCK()
|
|
||||||
#else
|
|
||||||
#define SD_MUTEX_LOCK() do {} while (xSemaphoreTake(_sd_sys_lock, portMAX_DELAY) != pdPASS)
|
|
||||||
#define SD_MUTEX_UNLOCK() xSemaphoreGive(_sd_sys_lock)
|
|
||||||
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) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
|
||||||
static bool tHasStarted = false;
|
|
||||||
if(!tHasStarted) {
|
|
||||||
tHasStarted = true;
|
|
||||||
_sd_sys_lock = xSemaphoreCreateMutex();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
uint32_t apb_freq = getApbFrequency();
|
|
||||||
uint32_t prescale = (apb_freq/(freq*256)) - 1;
|
|
||||||
if(prescale > 0xFF) {
|
|
||||||
prescale = 0xFF;
|
|
||||||
}
|
|
||||||
SD_MUTEX_LOCK();
|
|
||||||
SIGMADELTA.channel[channel].prescale = prescale;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sigmaDeltaWrite(uint8_t channel, uint8_t duty) //chan 0-7 duty 8 bit
|
|
||||||
{
|
|
||||||
if(channel > 7) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
duty -= 128;
|
|
||||||
SD_MUTEX_LOCK();
|
|
||||||
SIGMADELTA.channel[channel].duty = duty;
|
|
||||||
SD_MUTEX_UNLOCK();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t sigmaDeltaRead(uint8_t channel) //chan 0-7
|
|
||||||
{
|
|
||||||
if(channel > 7) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
SD_MUTEX_LOCK();
|
|
||||||
uint8_t duty = SIGMADELTA.channel[channel].duty + 128;
|
|
||||||
SD_MUTEX_UNLOCK();
|
|
||||||
return duty;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sigmaDeltaAttachPin(uint8_t pin, uint8_t channel) //channel 0-7
|
|
||||||
{
|
|
||||||
if(channel > 7) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pinMode(pin, OUTPUT);
|
|
||||||
pinMatrixOutAttach(pin, GPIO_SD0_OUT_IDX + channel, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sigmaDeltaDetachPin(uint8_t pin)
|
|
||||||
{
|
|
||||||
pinMatrixOutDetach(pin, false, false);
|
|
||||||
}
|
|
@@ -1,94 +0,0 @@
|
|||||||
// 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 "esp32-hal.h"
|
|
||||||
#include "lwip/apps/sntp.h"
|
|
||||||
#include "tcpip_adapter.h"
|
|
||||||
|
|
||||||
static void setTimeZone(long offset, int daylight)
|
|
||||||
{
|
|
||||||
char cst[17] = {0};
|
|
||||||
char cdt[17] = "DST";
|
|
||||||
char tz[33] = {0};
|
|
||||||
|
|
||||||
if(offset % 3600){
|
|
||||||
sprintf(cst, "UTC%ld:%02u:%02u", offset / 3600, abs((offset % 3600) / 60), abs(offset % 60));
|
|
||||||
} else {
|
|
||||||
sprintf(cst, "UTC%ld", offset / 3600);
|
|
||||||
}
|
|
||||||
if(daylight != 3600){
|
|
||||||
long tz_dst = offset - daylight;
|
|
||||||
if(tz_dst % 3600){
|
|
||||||
sprintf(cdt, "DST%ld:%02u:%02u", tz_dst / 3600, abs((tz_dst % 3600) / 60), abs(tz_dst % 60));
|
|
||||||
} else {
|
|
||||||
sprintf(cdt, "DST%ld", tz_dst / 3600);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sprintf(tz, "%s%s", cst, cdt);
|
|
||||||
setenv("TZ", tz, 1);
|
|
||||||
tzset();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* configTime
|
|
||||||
* Source: https://github.com/esp8266/Arduino/blob/master/cores/esp8266/time.c
|
|
||||||
* */
|
|
||||||
void configTime(long gmtOffset_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3)
|
|
||||||
{
|
|
||||||
tcpip_adapter_init(); // Should not hurt anything if already inited
|
|
||||||
if(sntp_enabled()){
|
|
||||||
sntp_stop();
|
|
||||||
}
|
|
||||||
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
|
||||||
sntp_setservername(0, (char*)server1);
|
|
||||||
sntp_setservername(1, (char*)server2);
|
|
||||||
sntp_setservername(2, (char*)server3);
|
|
||||||
sntp_init();
|
|
||||||
setTimeZone(-gmtOffset_sec, daylightOffset_sec);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* configTzTime
|
|
||||||
* sntp setup using TZ environment variable
|
|
||||||
* */
|
|
||||||
void configTzTime(const char* tz, const char* server1, const char* server2, const char* server3)
|
|
||||||
{
|
|
||||||
tcpip_adapter_init(); // Should not hurt anything if already inited
|
|
||||||
if(sntp_enabled()){
|
|
||||||
sntp_stop();
|
|
||||||
}
|
|
||||||
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
|
||||||
sntp_setservername(0, (char*)server1);
|
|
||||||
sntp_setservername(1, (char*)server2);
|
|
||||||
sntp_setservername(2, (char*)server3);
|
|
||||||
sntp_init();
|
|
||||||
setenv("TZ", tz, 1);
|
|
||||||
tzset();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getLocalTime(struct tm * info, uint32_t ms)
|
|
||||||
{
|
|
||||||
uint32_t start = millis();
|
|
||||||
time_t now;
|
|
||||||
while((millis()-start) <= ms) {
|
|
||||||
time(&now);
|
|
||||||
localtime_r(&now, info);
|
|
||||||
if(info->tm_year > (2016 - 1900)){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
delay(10);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,308 +0,0 @@
|
|||||||
// 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 "esp32-hal-timer.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/xtensa_api.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "rom/ets_sys.h"
|
|
||||||
#include "soc/timer_group_struct.h"
|
|
||||||
#include "soc/dport_reg.h"
|
|
||||||
#include "esp_attr.h"
|
|
||||||
#include "esp_intr.h"
|
|
||||||
|
|
||||||
#define HWTIMER_LOCK() portENTER_CRITICAL(timer->lock)
|
|
||||||
#define HWTIMER_UNLOCK() portEXIT_CRITICAL(timer->lock)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
uint32_t reserved0: 10;
|
|
||||||
uint32_t alarm_en: 1; /*When set alarm is enabled*/
|
|
||||||
uint32_t level_int_en: 1; /*When set level type interrupt will be generated during alarm*/
|
|
||||||
uint32_t edge_int_en: 1; /*When set edge type interrupt will be generated during alarm*/
|
|
||||||
uint32_t divider: 16; /*Timer clock (T0/1_clk) pre-scale value.*/
|
|
||||||
uint32_t autoreload: 1; /*When set timer 0/1 auto-reload at alarming is enabled*/
|
|
||||||
uint32_t increase: 1; /*When set timer 0/1 time-base counter increment. When cleared timer 0 time-base counter decrement.*/
|
|
||||||
uint32_t enable: 1; /*When set timer 0/1 time-base counter is enabled*/
|
|
||||||
};
|
|
||||||
uint32_t val;
|
|
||||||
} config;
|
|
||||||
uint32_t cnt_low; /*Register to store timer 0/1 time-base counter current value lower 32 bits.*/
|
|
||||||
uint32_t cnt_high; /*Register to store timer 0 time-base counter current value higher 32 bits.*/
|
|
||||||
uint32_t update; /*Write any value will trigger a timer 0 time-base counter value update (timer 0 current value will be stored in registers above)*/
|
|
||||||
uint32_t alarm_low; /*Timer 0 time-base counter value lower 32 bits that will trigger the alarm*/
|
|
||||||
uint32_t alarm_high; /*Timer 0 time-base counter value higher 32 bits that will trigger the alarm*/
|
|
||||||
uint32_t load_low; /*Lower 32 bits of the value that will load into timer 0 time-base counter*/
|
|
||||||
uint32_t load_high; /*higher 32 bits of the value that will load into timer 0 time-base counter*/
|
|
||||||
uint32_t reload; /*Write any value will trigger timer 0 time-base counter reload*/
|
|
||||||
} hw_timer_reg_t;
|
|
||||||
|
|
||||||
typedef struct hw_timer_s {
|
|
||||||
hw_timer_reg_t * dev;
|
|
||||||
uint8_t num;
|
|
||||||
uint8_t group;
|
|
||||||
uint8_t timer;
|
|
||||||
portMUX_TYPE lock;
|
|
||||||
} hw_timer_t;
|
|
||||||
|
|
||||||
static hw_timer_t hw_timer[4] = {
|
|
||||||
{(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE),0,0,0,portMUX_INITIALIZER_UNLOCKED},
|
|
||||||
{(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x0024),1,0,1,portMUX_INITIALIZER_UNLOCKED},
|
|
||||||
{(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x1000),2,1,0,portMUX_INITIALIZER_UNLOCKED},
|
|
||||||
{(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x1024),3,1,1,portMUX_INITIALIZER_UNLOCKED}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void (*voidFuncPtr)(void);
|
|
||||||
static voidFuncPtr __timerInterruptHandlers[4] = {0,0,0,0};
|
|
||||||
|
|
||||||
void IRAM_ATTR __timerISR(void * arg){
|
|
||||||
uint32_t s0 = TIMERG0.int_st_timers.val;
|
|
||||||
uint32_t s1 = TIMERG1.int_st_timers.val;
|
|
||||||
TIMERG0.int_clr_timers.val = s0;
|
|
||||||
TIMERG1.int_clr_timers.val = s1;
|
|
||||||
uint8_t status = (s1 & 3) << 2 | (s0 & 3);
|
|
||||||
uint8_t i = 4;
|
|
||||||
//restart the timers that should autoreload
|
|
||||||
while(i--){
|
|
||||||
hw_timer_reg_t * dev = hw_timer[i].dev;
|
|
||||||
if((status & (1 << i)) && dev->config.autoreload){
|
|
||||||
dev->config.alarm_en = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i = 4;
|
|
||||||
//call callbacks
|
|
||||||
while(i--){
|
|
||||||
if(__timerInterruptHandlers[i] && (status & (1 << i))){
|
|
||||||
__timerInterruptHandlers[i]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t timerRead(hw_timer_t *timer){
|
|
||||||
timer->dev->update = 1;
|
|
||||||
uint64_t h = timer->dev->cnt_high;
|
|
||||||
uint64_t l = timer->dev->cnt_low;
|
|
||||||
return (h << 32) | l;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t timerAlarmRead(hw_timer_t *timer){
|
|
||||||
uint64_t h = timer->dev->alarm_high;
|
|
||||||
uint64_t l = timer->dev->alarm_low;
|
|
||||||
return (h << 32) | l;
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerWrite(hw_timer_t *timer, uint64_t val){
|
|
||||||
timer->dev->load_high = (uint32_t) (val >> 32);
|
|
||||||
timer->dev->load_low = (uint32_t) (val);
|
|
||||||
timer->dev->reload = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload){
|
|
||||||
timer->dev->alarm_high = (uint32_t) (alarm_value >> 32);
|
|
||||||
timer->dev->alarm_low = (uint32_t) alarm_value;
|
|
||||||
timer->dev->config.autoreload = autoreload;
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerSetConfig(hw_timer_t *timer, uint32_t config){
|
|
||||||
timer->dev->config.val = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t timerGetConfig(hw_timer_t *timer){
|
|
||||||
return timer->dev->config.val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerSetCountUp(hw_timer_t *timer, bool countUp){
|
|
||||||
timer->dev->config.increase = countUp;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool timerGetCountUp(hw_timer_t *timer){
|
|
||||||
return timer->dev->config.increase;
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerSetAutoReload(hw_timer_t *timer, bool autoreload){
|
|
||||||
timer->dev->config.autoreload = autoreload;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool timerGetAutoReload(hw_timer_t *timer){
|
|
||||||
return timer->dev->config.autoreload;
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerSetDivider(hw_timer_t *timer, uint16_t divider){//2 to 65536
|
|
||||||
if(!divider){
|
|
||||||
divider = 0xFFFF;
|
|
||||||
} else if(divider == 1){
|
|
||||||
divider = 2;
|
|
||||||
}
|
|
||||||
int timer_en = timer->dev->config.enable;
|
|
||||||
timer->dev->config.enable = 0;
|
|
||||||
timer->dev->config.divider = divider;
|
|
||||||
timer->dev->config.enable = timer_en;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t timerGetDivider(hw_timer_t *timer){
|
|
||||||
return timer->dev->config.divider;
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerStart(hw_timer_t *timer){
|
|
||||||
timer->dev->config.enable = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerStop(hw_timer_t *timer){
|
|
||||||
timer->dev->config.enable = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerRestart(hw_timer_t *timer){
|
|
||||||
timer->dev->config.enable = 0;
|
|
||||||
timer->dev->reload = 1;
|
|
||||||
timer->dev->config.enable = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool timerStarted(hw_timer_t *timer){
|
|
||||||
return timer->dev->config.enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerAlarmEnable(hw_timer_t *timer){
|
|
||||||
timer->dev->config.alarm_en = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerAlarmDisable(hw_timer_t *timer){
|
|
||||||
timer->dev->config.alarm_en = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
hw_timer_t * timer = &hw_timer[num];
|
|
||||||
if(timer->group) {
|
|
||||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP1_CLK_EN);
|
|
||||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP1_RST);
|
|
||||||
TIMERG1.int_ena.val &= ~BIT(timer->timer);
|
|
||||||
} else {
|
|
||||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP_CLK_EN);
|
|
||||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP_RST);
|
|
||||||
TIMERG0.int_ena.val &= ~BIT(timer->timer);
|
|
||||||
}
|
|
||||||
timer->dev->config.enable = 0;
|
|
||||||
timerSetDivider(timer, divider);
|
|
||||||
timerSetCountUp(timer, countUp);
|
|
||||||
timerSetAutoReload(timer, false);
|
|
||||||
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){
|
|
||||||
static bool initialized = false;
|
|
||||||
static intr_handle_t intr_handle = NULL;
|
|
||||||
if(intr_handle){
|
|
||||||
esp_intr_disable(intr_handle);
|
|
||||||
}
|
|
||||||
if(fn == NULL){
|
|
||||||
timer->dev->config.level_int_en = 0;
|
|
||||||
timer->dev->config.edge_int_en = 0;
|
|
||||||
timer->dev->config.alarm_en = 0;
|
|
||||||
if(timer->num & 2){
|
|
||||||
TIMERG1.int_ena.val &= ~BIT(timer->timer);
|
|
||||||
} else {
|
|
||||||
TIMERG0.int_ena.val &= ~BIT(timer->timer);
|
|
||||||
}
|
|
||||||
__timerInterruptHandlers[timer->num] = NULL;
|
|
||||||
} else {
|
|
||||||
__timerInterruptHandlers[timer->num] = fn;
|
|
||||||
timer->dev->config.level_int_en = edge?0:1;//When set, an alarm will generate a level type interrupt.
|
|
||||||
timer->dev->config.edge_int_en = edge?1:0;//When set, an alarm will generate an edge type interrupt.
|
|
||||||
int intr_source = 0;
|
|
||||||
if(!edge){
|
|
||||||
if(timer->group){
|
|
||||||
intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer->timer;
|
|
||||||
} else {
|
|
||||||
intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer->timer;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(timer->group){
|
|
||||||
intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer->timer;
|
|
||||||
} else {
|
|
||||||
intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer->timer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!initialized){
|
|
||||||
initialized = true;
|
|
||||||
esp_intr_alloc(intr_source, (int)(ESP_INTR_FLAG_IRAM|ESP_INTR_FLAG_LOWMED|ESP_INTR_FLAG_EDGE), __timerISR, NULL, &intr_handle);
|
|
||||||
} else {
|
|
||||||
intr_matrix_set(esp_intr_get_cpu(intr_handle), intr_source, esp_intr_get_intno(intr_handle));
|
|
||||||
}
|
|
||||||
if(timer->group){
|
|
||||||
TIMERG1.int_ena.val |= BIT(timer->timer);
|
|
||||||
} else {
|
|
||||||
TIMERG0.int_ena.val |= BIT(timer->timer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(intr_handle){
|
|
||||||
esp_intr_enable(intr_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerDetachInterrupt(hw_timer_t *timer){
|
|
||||||
timerAttachInterrupt(timer, NULL, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t timerReadMicros(hw_timer_t *timer){
|
|
||||||
uint64_t timer_val = timerRead(timer);
|
|
||||||
uint16_t div = timerGetDivider(timer);
|
|
||||||
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 / getApbFrequency();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t timerAlarmReadMicros(hw_timer_t *timer){
|
|
||||||
uint64_t timer_val = timerAlarmRead(timer);
|
|
||||||
uint16_t div = timerGetDivider(timer);
|
|
||||||
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 / getApbFrequency();
|
|
||||||
}
|
|
@@ -1,168 +0,0 @@
|
|||||||
// 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 "esp32-hal-touch.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "rom/ets_sys.h"
|
|
||||||
#include "esp_attr.h"
|
|
||||||
#include "esp_intr.h"
|
|
||||||
#include "soc/rtc_io_reg.h"
|
|
||||||
#include "soc/rtc_cntl_reg.h"
|
|
||||||
#include "soc/sens_reg.h"
|
|
||||||
|
|
||||||
static uint16_t __touchSleepCycles = 0x1000;
|
|
||||||
static uint16_t __touchMeasureCycles = 0x1000;
|
|
||||||
|
|
||||||
typedef void (*voidFuncPtr)(void);
|
|
||||||
static voidFuncPtr __touchInterruptHandlers[10] = {0,};
|
|
||||||
static intr_handle_t touch_intr_handle = NULL;
|
|
||||||
|
|
||||||
void IRAM_ATTR __touchISR(void * arg)
|
|
||||||
{
|
|
||||||
uint32_t pad_intr = READ_PERI_REG(SENS_SAR_TOUCH_CTRL2_REG) & 0x3ff;
|
|
||||||
uint32_t rtc_intr = READ_PERI_REG(RTC_CNTL_INT_ST_REG);
|
|
||||||
uint8_t i = 0;
|
|
||||||
//clear interrupt
|
|
||||||
WRITE_PERI_REG(RTC_CNTL_INT_CLR_REG, rtc_intr);
|
|
||||||
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN_CLR);
|
|
||||||
|
|
||||||
if (rtc_intr & RTC_CNTL_TOUCH_INT_ST) {
|
|
||||||
for (i = 0; i < 10; ++i) {
|
|
||||||
if ((pad_intr >> i) & 0x01) {
|
|
||||||
if(__touchInterruptHandlers[i]){
|
|
||||||
__touchInterruptHandlers[i]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void __touchSetCycles(uint16_t measure, uint16_t sleep)
|
|
||||||
{
|
|
||||||
__touchSleepCycles = sleep;
|
|
||||||
__touchMeasureCycles = measure;
|
|
||||||
//Touch pad SleepCycle Time
|
|
||||||
SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_SLEEP_CYCLES, __touchSleepCycles, SENS_TOUCH_SLEEP_CYCLES_S);
|
|
||||||
//Touch Pad Measure Time
|
|
||||||
SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_MEAS_DELAY, __touchMeasureCycles, SENS_TOUCH_MEAS_DELAY_S);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __touchInit()
|
|
||||||
{
|
|
||||||
static bool initialized = false;
|
|
||||||
if(initialized){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
initialized = true;
|
|
||||||
SET_PERI_REG_BITS(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS, 1, RTC_IO_TOUCH_XPD_BIAS_S);
|
|
||||||
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN_CLR);
|
|
||||||
//clear touch enable
|
|
||||||
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, 0x0);
|
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_TOUCH_SLP_TIMER_EN);
|
|
||||||
|
|
||||||
__touchSetCycles(__touchMeasureCycles, __touchSleepCycles);
|
|
||||||
|
|
||||||
esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, __touchISR, NULL, &touch_intr_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t __touchRead(uint8_t pin)
|
|
||||||
{
|
|
||||||
int8_t pad = digitalPinToTouchChannel(pin);
|
|
||||||
if(pad < 0){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pinMode(pin, ANALOG);
|
|
||||||
|
|
||||||
__touchInit();
|
|
||||||
|
|
||||||
uint32_t v0 = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG);
|
|
||||||
//Disable Intr & enable touch pad
|
|
||||||
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG,
|
|
||||||
(v0 & ~((1 << (pad + SENS_TOUCH_PAD_OUTEN2_S)) | (1 << (pad + SENS_TOUCH_PAD_OUTEN1_S))))
|
|
||||||
| (1 << (pad + SENS_TOUCH_PAD_WORKEN_S)));
|
|
||||||
|
|
||||||
SET_PERI_REG_MASK(SENS_SAR_TOUCH_ENABLE_REG, (1 << (pad + SENS_TOUCH_PAD_WORKEN_S)));
|
|
||||||
|
|
||||||
uint32_t rtc_tio_reg = RTC_IO_TOUCH_PAD0_REG + pad * 4;
|
|
||||||
WRITE_PERI_REG(rtc_tio_reg, (READ_PERI_REG(rtc_tio_reg)
|
|
||||||
& ~(RTC_IO_TOUCH_PAD0_DAC_M))
|
|
||||||
| (7 << RTC_IO_TOUCH_PAD0_DAC_S)//Touch Set Slope
|
|
||||||
| RTC_IO_TOUCH_PAD0_TIE_OPT_M //Enable Tie,Init Level
|
|
||||||
| RTC_IO_TOUCH_PAD0_START_M //Enable Touch Pad IO
|
|
||||||
| RTC_IO_TOUCH_PAD0_XPD_M); //Enable Touch Pad Power on
|
|
||||||
|
|
||||||
//force oneTime test start
|
|
||||||
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M);
|
|
||||||
|
|
||||||
SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_XPD_WAIT, 10, SENS_TOUCH_XPD_WAIT_S);
|
|
||||||
|
|
||||||
while (GET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_DONE) == 0) {};
|
|
||||||
|
|
||||||
uint16_t touch_value = READ_PERI_REG(SENS_SAR_TOUCH_OUT1_REG + (pad / 2) * 4) >> ((pad & 1) ? SENS_TOUCH_MEAS_OUT1_S : SENS_TOUCH_MEAS_OUT0_S);
|
|
||||||
|
|
||||||
//clear touch force ,select the Touch mode is Timer
|
|
||||||
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M);
|
|
||||||
|
|
||||||
//restore previous value
|
|
||||||
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, v0);
|
|
||||||
return touch_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t threshold)
|
|
||||||
{
|
|
||||||
int8_t pad = digitalPinToTouchChannel(pin);
|
|
||||||
if(pad < 0){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pinMode(pin, ANALOG);
|
|
||||||
|
|
||||||
__touchInit();
|
|
||||||
|
|
||||||
__touchInterruptHandlers[pad] = userFunc;
|
|
||||||
|
|
||||||
//clear touch force ,select the Touch mode is Timer
|
|
||||||
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M);
|
|
||||||
|
|
||||||
//interrupt when touch value < threshold
|
|
||||||
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_OUT_SEL);
|
|
||||||
//Intr will give ,when SET0 < threshold
|
|
||||||
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_OUT_1EN);
|
|
||||||
//Enable Rtc Touch Module Intr,the Interrupt need Rtc out Enable
|
|
||||||
SET_PERI_REG_MASK(RTC_CNTL_INT_ENA_REG, RTC_CNTL_TOUCH_INT_ENA);
|
|
||||||
|
|
||||||
//set threshold
|
|
||||||
uint8_t shift = (pad & 1) ? SENS_TOUCH_OUT_TH1_S : SENS_TOUCH_OUT_TH0_S;
|
|
||||||
SET_PERI_REG_BITS((SENS_SAR_TOUCH_THRES1_REG + (pad / 2) * 4), SENS_TOUCH_OUT_TH0, threshold, shift);
|
|
||||||
|
|
||||||
uint32_t rtc_tio_reg = RTC_IO_TOUCH_PAD0_REG + pad * 4;
|
|
||||||
WRITE_PERI_REG(rtc_tio_reg, (READ_PERI_REG(rtc_tio_reg)
|
|
||||||
& ~(RTC_IO_TOUCH_PAD0_DAC_M))
|
|
||||||
| (7 << RTC_IO_TOUCH_PAD0_DAC_S)//Touch Set Slope
|
|
||||||
| RTC_IO_TOUCH_PAD0_TIE_OPT_M //Enable Tie,Init Level
|
|
||||||
| RTC_IO_TOUCH_PAD0_START_M //Enable Touch Pad IO
|
|
||||||
| RTC_IO_TOUCH_PAD0_XPD_M); //Enable Touch Pad Power on
|
|
||||||
|
|
||||||
//Enable Digital rtc control :work mode and out mode
|
|
||||||
SET_PERI_REG_MASK(SENS_SAR_TOUCH_ENABLE_REG,
|
|
||||||
(1 << (pad + SENS_TOUCH_PAD_WORKEN_S)) | \
|
|
||||||
(1 << (pad + SENS_TOUCH_PAD_OUTEN2_S)) | \
|
|
||||||
(1 << (pad + SENS_TOUCH_PAD_OUTEN1_S)));
|
|
||||||
}
|
|
||||||
|
|
||||||
extern uint16_t touchRead(uint8_t pin) __attribute__ ((weak, alias("__touchRead")));
|
|
||||||
extern void touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t threshold) __attribute__ ((weak, alias("__touchAttachInterrupt")));
|
|
||||||
extern void touchSetCycles(uint16_t measure, uint16_t sleep) __attribute__ ((weak, alias("__touchSetCycles")));
|
|
@@ -1,615 +0,0 @@
|
|||||||
// 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 "esp32-hal-uart.h"
|
|
||||||
#include "esp32-hal.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "freertos/semphr.h"
|
|
||||||
#include "rom/ets_sys.h"
|
|
||||||
#include "esp_attr.h"
|
|
||||||
#include "esp_intr.h"
|
|
||||||
#include "rom/uart.h"
|
|
||||||
#include "soc/uart_reg.h"
|
|
||||||
#include "soc/uart_struct.h"
|
|
||||||
#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)))
|
|
||||||
#define UART_RXD_IDX(u) ((u==0)?U0RXD_IN_IDX:( (u==1)?U1RXD_IN_IDX:( (u==2)?U2RXD_IN_IDX:0)))
|
|
||||||
#define UART_TXD_IDX(u) ((u==0)?U0TXD_OUT_IDX:( (u==1)?U1TXD_OUT_IDX:( (u==2)?U2TXD_OUT_IDX:0)))
|
|
||||||
#define UART_INTR_SOURCE(u) ((u==0)?ETS_UART0_INTR_SOURCE:( (u==1)?ETS_UART1_INTR_SOURCE:((u==2)?ETS_UART2_INTR_SOURCE:0)))
|
|
||||||
|
|
||||||
static int s_uart_debug_nr = 0;
|
|
||||||
|
|
||||||
struct uart_struct_t {
|
|
||||||
uart_dev_t * dev;
|
|
||||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
|
||||||
xSemaphoreHandle lock;
|
|
||||||
#endif
|
|
||||||
uint8_t num;
|
|
||||||
xQueueHandle queue;
|
|
||||||
intr_handle_t intr_handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if CONFIG_DISABLE_HAL_LOCKS
|
|
||||||
#define UART_MUTEX_LOCK()
|
|
||||||
#define UART_MUTEX_UNLOCK()
|
|
||||||
|
|
||||||
static uart_t _uart_bus_array[3] = {
|
|
||||||
{(volatile uart_dev_t *)(DR_REG_UART_BASE), 0, NULL, NULL},
|
|
||||||
{(volatile uart_dev_t *)(DR_REG_UART1_BASE), 1, NULL, NULL},
|
|
||||||
{(volatile uart_dev_t *)(DR_REG_UART2_BASE), 2, NULL, NULL}
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
#define UART_MUTEX_LOCK() do {} while (xSemaphoreTake(uart->lock, portMAX_DELAY) != pdPASS)
|
|
||||||
#define UART_MUTEX_UNLOCK() xSemaphoreGive(uart->lock)
|
|
||||||
|
|
||||||
static uart_t _uart_bus_array[3] = {
|
|
||||||
{(volatile uart_dev_t *)(DR_REG_UART_BASE), NULL, 0, NULL, NULL},
|
|
||||||
{(volatile uart_dev_t *)(DR_REG_UART1_BASE), NULL, 1, NULL, NULL},
|
|
||||||
{(volatile uart_dev_t *)(DR_REG_UART2_BASE), NULL, 2, NULL, NULL}
|
|
||||||
};
|
|
||||||
#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;
|
|
||||||
BaseType_t xHigherPriorityTaskWoken;
|
|
||||||
uart_t* uart;
|
|
||||||
|
|
||||||
for(i=0;i<3;i++){
|
|
||||||
uart = &_uart_bus_array[i];
|
|
||||||
if(uart->intr_handle == NULL){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
uart->dev->int_clr.rxfifo_full = 1;
|
|
||||||
uart->dev->int_clr.frm_err = 1;
|
|
||||||
uart->dev->int_clr.rxfifo_tout = 1;
|
|
||||||
while(uart->dev->status.rxfifo_cnt || (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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xHigherPriorityTaskWoken) {
|
|
||||||
portYIELD_FROM_ISR();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartEnableInterrupt(uart_t* uart)
|
|
||||||
{
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
uart->dev->conf1.rxfifo_full_thrhd = 112;
|
|
||||||
uart->dev->conf1.rx_tout_thrhd = 2;
|
|
||||||
uart->dev->conf1.rx_tout_en = 1;
|
|
||||||
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;
|
|
||||||
|
|
||||||
esp_intr_alloc(UART_INTR_SOURCE(uart->num), (int)ESP_INTR_FLAG_IRAM, _uart_isr, NULL, &uart->intr_handle);
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartDisableInterrupt(uart_t* uart)
|
|
||||||
{
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
uart->dev->conf1.val = 0;
|
|
||||||
uart->dev->int_ena.val = 0;
|
|
||||||
uart->dev->int_clr.val = 0xffffffff;
|
|
||||||
|
|
||||||
esp_intr_free(uart->intr_handle);
|
|
||||||
uart->intr_handle = NULL;
|
|
||||||
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartDetachRx(uart_t* uart)
|
|
||||||
{
|
|
||||||
if(uart == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pinMatrixInDetach(UART_RXD_IDX(uart->num), false, false);
|
|
||||||
uartDisableInterrupt(uart);
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartDetachTx(uart_t* uart)
|
|
||||||
{
|
|
||||||
if(uart == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pinMatrixOutDetach(UART_TXD_IDX(uart->num), false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartAttachRx(uart_t* uart, uint8_t rxPin, bool inverted)
|
|
||||||
{
|
|
||||||
if(uart == NULL || rxPin > 39) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pinMode(rxPin, INPUT);
|
|
||||||
pinMatrixInAttach(rxPin, UART_RXD_IDX(uart->num), inverted);
|
|
||||||
uartEnableInterrupt(uart);
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartAttachTx(uart_t* uart, uint8_t txPin, bool inverted)
|
|
||||||
{
|
|
||||||
if(uart == NULL || txPin > 39) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pinMode(txPin, OUTPUT);
|
|
||||||
pinMatrixOutAttach(txPin, UART_TXD_IDX(uart->num), inverted, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted)
|
|
||||||
{
|
|
||||||
if(uart_nr > 2) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(rxPin == -1 && txPin == -1) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uart_t* uart = &_uart_bus_array[uart_nr];
|
|
||||||
|
|
||||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
|
||||||
if(uart->lock == NULL) {
|
|
||||||
uart->lock = xSemaphoreCreateMutex();
|
|
||||||
if(uart->lock == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(queueLen && uart->queue == NULL) {
|
|
||||||
uart->queue = xQueueCreate(queueLen, sizeof(uint8_t)); //initialize the queue
|
|
||||||
if(uart->queue == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(uart_nr == 1){
|
|
||||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN);
|
|
||||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART1_RST);
|
|
||||||
} else if(uart_nr == 2){
|
|
||||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART2_CLK_EN);
|
|
||||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART2_RST);
|
|
||||||
} else {
|
|
||||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART_CLK_EN);
|
|
||||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART_RST);
|
|
||||||
}
|
|
||||||
uartFlush(uart);
|
|
||||||
uartSetBaudRate(uart, baudrate);
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
uart->dev->conf0.val = config;
|
|
||||||
#define TWO_STOP_BITS_CONF 0x3
|
|
||||||
#define ONE_STOP_BITS_CONF 0x1
|
|
||||||
|
|
||||||
if ( uart->dev->conf0.stop_bit_num == TWO_STOP_BITS_CONF) {
|
|
||||||
uart->dev->conf0.stop_bit_num = ONE_STOP_BITS_CONF;
|
|
||||||
uart->dev->rs485_conf.dl1_en = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// tx_idle_num : idle interval after tx FIFO is empty(unit: the time it takes to send one bit under current baudrate)
|
|
||||||
// Setting it to 0 prevents line idle time/delays when sending messages with small intervals
|
|
||||||
uart->dev->idle_conf.tx_idle_num = 0; //
|
|
||||||
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
|
|
||||||
if(rxPin != -1) {
|
|
||||||
uartAttachRx(uart, rxPin, inverted);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(txPin != -1) {
|
|
||||||
uartAttachTx(uart, txPin, inverted);
|
|
||||||
}
|
|
||||||
addApbChangeCallback(uart, uart_on_apb_change);
|
|
||||||
return uart;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartEnd(uart_t* uart)
|
|
||||||
{
|
|
||||||
if(uart == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
removeApbChangeCallback(uart, uart_on_apb_change);
|
|
||||||
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
if(uart->queue != NULL) {
|
|
||||||
vQueueDelete(uart->queue);
|
|
||||||
uart->queue = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uart->dev->conf0.val = 0;
|
|
||||||
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
|
|
||||||
uartDetachRx(uart);
|
|
||||||
uartDetachTx(uart);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
|
|
||||||
if(uart == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
if(uart->queue != NULL) {
|
|
||||||
vQueueDelete(uart->queue);
|
|
||||||
uart->queue = xQueueCreate(new_size, sizeof(uint8_t));
|
|
||||||
if(uart->queue == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
|
|
||||||
return new_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t uartAvailable(uart_t* uart)
|
|
||||||
{
|
|
||||||
if(uart == NULL || uart->queue == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return (uxQueueMessagesWaiting(uart->queue) + uart->dev->status.rxfifo_cnt) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t uartAvailableForWrite(uart_t* uart)
|
|
||||||
{
|
|
||||||
if(uart == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 0x7f - uart->dev->status.txfifo_cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartRxFifoToQueue(uart_t* uart)
|
|
||||||
{
|
|
||||||
uint8_t c;
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
while(uart->dev->status.rxfifo_cnt || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
|
||||||
c = uart->dev->fifo.rw_byte;
|
|
||||||
xQueueSend(uart->queue, &c, 0);
|
|
||||||
}
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t uartRead(uart_t* uart)
|
|
||||||
{
|
|
||||||
if(uart == NULL || uart->queue == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
uint8_t c;
|
|
||||||
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
|
|
||||||
{
|
|
||||||
uartRxFifoToQueue(uart);
|
|
||||||
}
|
|
||||||
if(xQueueReceive(uart->queue, &c, 0)) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t uartPeek(uart_t* uart)
|
|
||||||
{
|
|
||||||
if(uart == NULL || uart->queue == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
uint8_t c;
|
|
||||||
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
|
|
||||||
{
|
|
||||||
uartRxFifoToQueue(uart);
|
|
||||||
}
|
|
||||||
if(xQueuePeek(uart->queue, &c, 0)) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartWrite(uart_t* uart, uint8_t c)
|
|
||||||
{
|
|
||||||
if(uart == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
while(uart->dev->status.txfifo_cnt == 0x7F);
|
|
||||||
uart->dev->fifo.rw_byte = c;
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
|
|
||||||
{
|
|
||||||
if(uart == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
while(len) {
|
|
||||||
while(uart->dev->status.txfifo_cnt == 0x7F);
|
|
||||||
uart->dev->fifo.rw_byte = *data++;
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartFlush(uart_t* uart)
|
|
||||||
{
|
|
||||||
uartFlushTxOnly(uart,false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartFlushTxOnly(uart_t* uart, bool txOnly)
|
|
||||||
{
|
|
||||||
if(uart == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
|
|
||||||
|
|
||||||
if( !txOnly ){
|
|
||||||
//Due to hardware issue, we can not use fifo_rst to reset uart fifo.
|
|
||||||
//See description about UART_TXFIFO_RST and UART_RXFIFO_RST in <<esp32_technical_reference_manual>> v2.6 or later.
|
|
||||||
|
|
||||||
// we read the data out and make `fifo_len == 0 && rd_addr == wr_addr`.
|
|
||||||
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
|
||||||
READ_PERI_REG(UART_FIFO_REG(uart->num));
|
|
||||||
}
|
|
||||||
|
|
||||||
xQueueReset(uart->queue);
|
|
||||||
}
|
|
||||||
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
|
|
||||||
{
|
|
||||||
if(uart == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
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 ) {
|
|
||||||
xQueueSend(uart->queue, &c, 1); //&xHigherPriorityTaskWoken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
|
|
||||||
// wait TX empty
|
|
||||||
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
|
|
||||||
} else {
|
|
||||||
//todo:
|
|
||||||
// set baudrate
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
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);
|
|
||||||
if(!clk_div) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((getApbFrequency()<<4)/clk_div);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void IRAM_ATTR uart0_write_char(char c)
|
|
||||||
{
|
|
||||||
while(((ESP_REG(0x01C+DR_REG_UART_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
|
|
||||||
ESP_REG(DR_REG_UART_BASE) = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void IRAM_ATTR uart1_write_char(char c)
|
|
||||||
{
|
|
||||||
while(((ESP_REG(0x01C+DR_REG_UART1_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
|
|
||||||
ESP_REG(DR_REG_UART1_BASE) = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void IRAM_ATTR uart2_write_char(char c)
|
|
||||||
{
|
|
||||||
while(((ESP_REG(0x01C+DR_REG_UART2_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
|
|
||||||
ESP_REG(DR_REG_UART2_BASE) = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uart_install_putc()
|
|
||||||
{
|
|
||||||
switch(s_uart_debug_nr) {
|
|
||||||
case 0:
|
|
||||||
ets_install_putc1((void (*)(char)) &uart0_write_char);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
ets_install_putc1((void (*)(char)) &uart1_write_char);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
ets_install_putc1((void (*)(char)) &uart2_write_char);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ets_install_putc1(NULL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int log_printf(const char *format, ...)
|
|
||||||
{
|
|
||||||
if(s_uart_debug_nr < 0){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static char loc_buf[64];
|
|
||||||
char * temp = loc_buf;
|
|
||||||
int len;
|
|
||||||
va_list arg;
|
|
||||||
va_list copy;
|
|
||||||
va_start(arg, format);
|
|
||||||
va_copy(copy, arg);
|
|
||||||
len = vsnprintf(NULL, 0, format, arg);
|
|
||||||
va_end(copy);
|
|
||||||
if(len >= sizeof(loc_buf)){
|
|
||||||
temp = (char*)malloc(len+1);
|
|
||||||
if(temp == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vsnprintf(temp, len+1, format, arg);
|
|
||||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
|
||||||
if(_uart_bus_array[s_uart_debug_nr].lock){
|
|
||||||
xSemaphoreTake(_uart_bus_array[s_uart_debug_nr].lock, portMAX_DELAY);
|
|
||||||
ets_printf("%s", temp);
|
|
||||||
xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock);
|
|
||||||
} else {
|
|
||||||
ets_printf("%s", temp);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
ets_printf("%s", temp);
|
|
||||||
#endif
|
|
||||||
va_end(arg);
|
|
||||||
if(len >= sizeof(loc_buf)){
|
|
||||||
free(temp);
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if enough pulses are detected return the minimum high pulse duration + minimum low pulse duration divided by two.
|
|
||||||
* This equals one bit period. If flag is true the function return inmediately, otherwise it waits for enough pulses.
|
|
||||||
*/
|
|
||||||
unsigned long uartBaudrateDetect(uart_t *uart, bool flg)
|
|
||||||
{
|
|
||||||
while(uart->dev->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num)
|
|
||||||
if(flg) return 0;
|
|
||||||
ets_delay_us(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
UART_MUTEX_LOCK();
|
|
||||||
unsigned long ret = ((uart->dev->lowpulse.min_cnt + uart->dev->highpulse.min_cnt) >> 1) + 12;
|
|
||||||
UART_MUTEX_UNLOCK();
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To start detection of baud rate with the uart the auto_baud.en bit needs to be cleared and set. The bit period is
|
|
||||||
* detected calling uartBadrateDetect(). The raw baudrate is computed using the UART_CLK_FREQ. The raw baudrate is
|
|
||||||
* rounded to the closed real baudrate.
|
|
||||||
*/
|
|
||||||
void uartStartDetectBaudrate(uart_t *uart) {
|
|
||||||
if(!uart) return;
|
|
||||||
|
|
||||||
uart->dev->auto_baud.glitch_filt = 0x08;
|
|
||||||
uart->dev->auto_baud.en = 0;
|
|
||||||
uart->dev->auto_baud.en = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long
|
|
||||||
uartDetectBaudrate(uart_t *uart)
|
|
||||||
{
|
|
||||||
static bool uartStateDetectingBaudrate = false;
|
|
||||||
|
|
||||||
if(!uartStateDetectingBaudrate) {
|
|
||||||
uart->dev->auto_baud.glitch_filt = 0x08;
|
|
||||||
uart->dev->auto_baud.en = 0;
|
|
||||||
uart->dev->auto_baud.en = 1;
|
|
||||||
uartStateDetectingBaudrate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long divisor = uartBaudrateDetect(uart, true);
|
|
||||||
if (!divisor) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uart->dev->auto_baud.en = 0;
|
|
||||||
uartStateDetectingBaudrate = false; // Initialize for the next round
|
|
||||||
|
|
||||||
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};
|
|
||||||
|
|
||||||
size_t i;
|
|
||||||
for (i = 1; i < sizeof(default_rates) / sizeof(default_rates[0]) - 1; i++) // find the nearest real baudrate
|
|
||||||
{
|
|
||||||
if (baudrate <= default_rates[i])
|
|
||||||
{
|
|
||||||
if (baudrate - default_rates[i - 1] < default_rates[i] - baudrate) {
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return default_rates[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the status of the RX state machine, if the value is non-zero the state machine is active.
|
|
||||||
*/
|
|
||||||
bool uartRxActive(uart_t* uart) {
|
|
||||||
return uart->dev->status.st_urx_out != 0;
|
|
||||||
}
|
|
Reference in New Issue
Block a user