forked from espressif/arduino-esp32
Compare commits
10 Commits
old_versio
...
remove-low
Author | SHA1 | Date | |
---|---|---|---|
c780d6fc58 | |||
362705c0e0 | |||
67af3a66d8 | |||
38efa465bf | |||
3fc82c0d34 | |||
fce5fc7bad | |||
745ccdeae8 | |||
1acd16f991 | |||
a4d8b2cf73 | |||
07f43ec91c |
@ -1,25 +1,9 @@
|
||||
set(CORE_SRCS
|
||||
cores/esp32/esp32-hal-adc.c
|
||||
cores/esp32/esp32-hal-cpu.c
|
||||
cores/esp32/esp32-hal-dac.c
|
||||
cores/esp32/esp32-hal-gpio.c
|
||||
cores/esp32/esp32-hal-i2c.c
|
||||
cores/esp32/esp32-hal-ledc.c
|
||||
cores/esp32/esp32-hal-matrix.c
|
||||
cores/esp32/esp32-hal-misc.c
|
||||
cores/esp32/esp32-hal-psram.c
|
||||
cores/esp32/esp32-hal-sigmadelta.c
|
||||
cores/esp32/esp32-hal-spi.c
|
||||
cores/esp32/esp32-hal-tinyusb.c
|
||||
cores/esp32/esp32-hal-touch.c
|
||||
cores/esp32/esp32-hal-rmt.c
|
||||
cores/esp32/FunctionalInterrupt.cpp
|
||||
cores/esp32/stdlib_noniso.c
|
||||
cores/esp32/USB.cpp
|
||||
cores/esp32/USBCDC.cpp
|
||||
cores/esp32/wiring_pulse.c
|
||||
cores/esp32/wiring_shift.c
|
||||
cores/esp32/WMath.cpp
|
||||
)
|
||||
|
||||
set(LIBRARY_SRCS
|
||||
@ -36,10 +20,11 @@ set(includedirs
|
||||
)
|
||||
|
||||
set(srcs ${CORE_SRCS} ${LIBRARY_SRCS} ${BLE_SRCS})
|
||||
set(requires spi_flash mbedtls esp_adc_cal wifi_provisioning)
|
||||
set(priv_requires nvs_flash bootloader_support tinyusb espcpputils fmt)
|
||||
set(requires spi_flash mbedtls wifi_provisioning driver)
|
||||
set(priv_requires nvs_flash bootloader_support espcpputils goefmt)
|
||||
|
||||
idf_component_register(INCLUDE_DIRS ${includedirs} PRIV_INCLUDE_DIRS ${priv_includes} SRCS ${srcs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires})
|
||||
set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 23)
|
||||
|
||||
if(IDF_TARGET STREQUAL "esp32")
|
||||
target_compile_options(${COMPONENT_TARGET} PUBLIC -DARDUINO=10812 -DARDUINO_ESP32_DEV -DARDUINO_ARCH_ESP32 -DARDUINO_BOARD="ESP32_DEV" -DARDUINO_VARIANT="esp32" -DESP32)
|
||||
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* FunctionalInterrupt.cpp
|
||||
*
|
||||
* Created on: 8 jul. 2018
|
||||
* Author: Herman
|
||||
*/
|
||||
|
||||
#include "FunctionalInterrupt.h"
|
||||
#include "esp32-hal.h"
|
||||
|
||||
typedef void (*voidFuncPtr)(void);
|
||||
typedef void (*voidFuncPtrArg)(void*);
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional);
|
||||
}
|
||||
|
||||
void ARDUINO_ISR_ATTR interruptFunctional(void* arg)
|
||||
{
|
||||
InterruptArgStructure* localArg = (InterruptArgStructure*)arg;
|
||||
if (localArg->interruptFunction)
|
||||
{
|
||||
localArg->interruptFunction();
|
||||
}
|
||||
}
|
||||
|
||||
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode)
|
||||
{
|
||||
// use the local interrupt routine which takes the ArgStructure as argument
|
||||
__attachInterruptFunctionalArg (pin, (voidFuncPtrArg)interruptFunctional, new InterruptArgStructure{intRoutine}, mode, true);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void cleanupFunctional(void* arg)
|
||||
{
|
||||
delete (InterruptArgStructure*)arg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* FunctionalInterrupt.h
|
||||
*
|
||||
* Created on: 8 jul. 2018
|
||||
* Author: Herman
|
||||
*/
|
||||
|
||||
#ifndef CORE_CORE_FUNCTIONALINTERRUPT_H_
|
||||
#define CORE_CORE_FUNCTIONALINTERRUPT_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
struct InterruptArgStructure {
|
||||
std::function<void(void)> interruptFunction;
|
||||
};
|
||||
|
||||
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode);
|
||||
|
||||
|
||||
#endif /* CORE_CORE_FUNCTIONALINTERRUPT_H_ */
|
@ -1,338 +0,0 @@
|
||||
// Copyright 2015-2020 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 "esp32-hal-tinyusb.h"
|
||||
#include "USB.h"
|
||||
#if CONFIG_USB_ENABLED
|
||||
|
||||
#ifndef USB_VID
|
||||
#define USB_VID USB_ESPRESSIF_VID
|
||||
#endif
|
||||
#ifndef USB_PID
|
||||
#define USB_PID 0x0002
|
||||
#endif
|
||||
#ifndef USB_MANUFACTURER
|
||||
#define USB_MANUFACTURER "Espressif Systems"
|
||||
#endif
|
||||
#ifndef USB_PRODUCT
|
||||
#define USB_PRODUCT ARDUINO_BOARD
|
||||
#endif
|
||||
#ifndef USB_SERIAL
|
||||
#define USB_SERIAL "0"
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include "tinyusb.h"
|
||||
}
|
||||
|
||||
#if CFG_TUD_DFU_RT
|
||||
static uint16_t load_dfu_descriptor(uint8_t * dst, uint8_t * itf)
|
||||
{
|
||||
#define DFU_ATTR_CAN_DOWNLOAD 1
|
||||
#define DFU_ATTR_CAN_UPLOAD 2
|
||||
#define DFU_ATTR_MANIFESTATION_TOLERANT 4
|
||||
#define DFU_ATTR_WILL_DETACH 8
|
||||
#define DFU_ATTRS (DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_CAN_UPLOAD | DFU_ATTR_MANIFESTATION_TOLERANT)
|
||||
|
||||
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB DFU_RT");
|
||||
uint8_t descriptor[TUD_DFU_RT_DESC_LEN] = {
|
||||
// Interface number, string index, attributes, detach timeout, transfer size */
|
||||
TUD_DFU_RT_DESCRIPTOR(*itf, str_index, DFU_ATTRS, 700, 64)
|
||||
};
|
||||
*itf+=1;
|
||||
memcpy(dst, descriptor, TUD_DFU_RT_DESC_LEN);
|
||||
return TUD_DFU_RT_DESC_LEN;
|
||||
}
|
||||
// Invoked on DFU_DETACH request to reboot to the bootloader
|
||||
void tud_dfu_rt_reboot_to_dfu(void)
|
||||
{
|
||||
usb_persist_restart(RESTART_BOOTLOADER_DFU);
|
||||
}
|
||||
#endif /* CFG_TUD_DFU_RT */
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(ARDUINO_USB_EVENTS);
|
||||
|
||||
static esp_event_loop_handle_t arduino_usb_event_loop_handle = NULL;
|
||||
|
||||
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait){
|
||||
if(arduino_usb_event_loop_handle == NULL){
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return esp_event_post_to(arduino_usb_event_loop_handle, event_base, event_id, event_data, event_data_size, ticks_to_wait);
|
||||
}
|
||||
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg){
|
||||
if(arduino_usb_event_loop_handle == NULL){
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return esp_event_handler_register_with(arduino_usb_event_loop_handle, event_base, event_id, event_handler, event_handler_arg);
|
||||
}
|
||||
|
||||
static bool tinyusb_device_mounted = false;
|
||||
static bool tinyusb_device_suspended = false;
|
||||
|
||||
// Invoked when device is mounted (configured)
|
||||
void tud_mount_cb(void){
|
||||
tinyusb_device_mounted = true;
|
||||
arduino_usb_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STARTED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
// Invoked when device is unmounted
|
||||
void tud_umount_cb(void){
|
||||
tinyusb_device_mounted = false;
|
||||
arduino_usb_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
// Invoked when usb bus is suspended
|
||||
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
|
||||
void tud_suspend_cb(bool remote_wakeup_en){
|
||||
tinyusb_device_suspended = true;
|
||||
arduino_usb_event_data_t p = {0};
|
||||
p.suspend.remote_wakeup_en = remote_wakeup_en;
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_SUSPEND_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
// Invoked when usb bus is resumed
|
||||
void tud_resume_cb(void){
|
||||
tinyusb_device_suspended = false;
|
||||
arduino_usb_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_RESUME_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
ESPUSB::ESPUSB(size_t task_stack_size, uint8_t event_task_priority)
|
||||
:vid(USB_VID)
|
||||
,pid(USB_PID)
|
||||
,product_name(USB_PRODUCT)
|
||||
,manufacturer_name(USB_MANUFACTURER)
|
||||
,serial_number(USB_SERIAL)
|
||||
,fw_version(0x0100)
|
||||
,usb_version(0x0200)// at least 2.1 or 3.x for BOS & webUSB
|
||||
,usb_class(TUSB_CLASS_MISC)
|
||||
,usb_subclass(MISC_SUBCLASS_COMMON)
|
||||
,usb_protocol(MISC_PROTOCOL_IAD)
|
||||
,usb_attributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED)
|
||||
,usb_power_ma(500)
|
||||
,webusb_enabled(false)
|
||||
,webusb_url("espressif.github.io/arduino-esp32/webusb.html")
|
||||
,_started(false)
|
||||
,_task_stack_size(task_stack_size)
|
||||
,_event_task_priority(event_task_priority)
|
||||
{
|
||||
if (!arduino_usb_event_loop_handle) {
|
||||
esp_event_loop_args_t event_task_args = {
|
||||
.queue_size = 5,
|
||||
.task_name = "arduino_usb_events",
|
||||
.task_priority = _event_task_priority,
|
||||
.task_stack_size = _task_stack_size,
|
||||
.task_core_id = tskNO_AFFINITY
|
||||
};
|
||||
if (esp_event_loop_create(&event_task_args, &arduino_usb_event_loop_handle) != ESP_OK) {
|
||||
log_e("esp_event_loop_create failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ESPUSB::~ESPUSB(){
|
||||
if (arduino_usb_event_loop_handle) {
|
||||
esp_event_loop_delete(arduino_usb_event_loop_handle);
|
||||
arduino_usb_event_loop_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ESPUSB::begin(){
|
||||
if(!_started){
|
||||
tinyusb_device_config_t tinyusb_device_config = {
|
||||
.vid = vid,
|
||||
.pid = pid,
|
||||
.product_name = product_name.c_str(),
|
||||
.manufacturer_name = manufacturer_name.c_str(),
|
||||
.serial_number = serial_number.c_str(),
|
||||
.fw_version = fw_version,
|
||||
.usb_version = usb_version,
|
||||
.usb_class = usb_class,
|
||||
.usb_subclass = usb_subclass,
|
||||
.usb_protocol = usb_protocol,
|
||||
.usb_attributes = usb_attributes,
|
||||
.usb_power_ma = usb_power_ma,
|
||||
.webusb_enabled = webusb_enabled,
|
||||
.webusb_url = webusb_url.c_str()
|
||||
};
|
||||
_started = tinyusb_init(&tinyusb_device_config) == ESP_OK;
|
||||
}
|
||||
return _started;
|
||||
}
|
||||
|
||||
void ESPUSB::onEvent(esp_event_handler_t callback){
|
||||
onEvent(ARDUINO_USB_ANY_EVENT, callback);
|
||||
}
|
||||
void ESPUSB::onEvent(arduino_usb_event_t event, esp_event_handler_t callback){
|
||||
arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, event, callback, this);
|
||||
}
|
||||
|
||||
ESPUSB::operator bool() const
|
||||
{
|
||||
return _started && tinyusb_device_mounted;
|
||||
}
|
||||
|
||||
bool ESPUSB::enableDFU(){
|
||||
#if CFG_TUD_DFU_RT
|
||||
return tinyusb_enable_interface(USB_INTERFACE_DFU, TUD_DFU_RT_DESC_LEN, load_dfu_descriptor) == ESP_OK;
|
||||
#endif /* CFG_TUD_DFU_RT */
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ESPUSB::VID(uint16_t v){
|
||||
if(!_started){
|
||||
vid = v;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint16_t ESPUSB::VID(void){
|
||||
return vid;
|
||||
}
|
||||
|
||||
bool ESPUSB::PID(uint16_t p){
|
||||
if(!_started){
|
||||
pid = p;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint16_t ESPUSB::PID(void){
|
||||
return pid;
|
||||
}
|
||||
|
||||
bool ESPUSB::firmwareVersion(uint16_t version){
|
||||
if(!_started){
|
||||
fw_version = version;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint16_t ESPUSB::firmwareVersion(void){
|
||||
return fw_version;
|
||||
}
|
||||
|
||||
bool ESPUSB::usbVersion(uint16_t version){
|
||||
if(!_started){
|
||||
usb_version = version;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint16_t ESPUSB::usbVersion(void){
|
||||
return usb_version;
|
||||
}
|
||||
|
||||
bool ESPUSB::usbPower(uint16_t mA){
|
||||
if(!_started){
|
||||
usb_power_ma = mA;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint16_t ESPUSB::usbPower(void){
|
||||
return usb_power_ma;
|
||||
}
|
||||
|
||||
bool ESPUSB::usbClass(uint8_t _class){
|
||||
if(!_started){
|
||||
usb_class = _class;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint8_t ESPUSB::usbClass(void){
|
||||
return usb_class;
|
||||
}
|
||||
|
||||
bool ESPUSB::usbSubClass(uint8_t subClass){
|
||||
if(!_started){
|
||||
usb_subclass = subClass;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint8_t ESPUSB::usbSubClass(void){
|
||||
return usb_subclass;
|
||||
}
|
||||
|
||||
bool ESPUSB::usbProtocol(uint8_t protocol){
|
||||
if(!_started){
|
||||
usb_protocol = protocol;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint8_t ESPUSB::usbProtocol(void){
|
||||
return usb_protocol;
|
||||
}
|
||||
|
||||
bool ESPUSB::usbAttributes(uint8_t attr){
|
||||
if(!_started){
|
||||
usb_attributes = attr;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint8_t ESPUSB::usbAttributes(void){
|
||||
return usb_attributes;
|
||||
}
|
||||
|
||||
bool ESPUSB::webUSB(bool enabled){
|
||||
if(!_started){
|
||||
webusb_enabled = enabled;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
bool ESPUSB::webUSB(void){
|
||||
return webusb_enabled;
|
||||
}
|
||||
|
||||
bool ESPUSB::productName(const char * name){
|
||||
if(!_started){
|
||||
product_name = name;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
const char * ESPUSB::productName(void){
|
||||
return product_name.c_str();
|
||||
}
|
||||
|
||||
bool ESPUSB::manufacturerName(const char * name){
|
||||
if(!_started){
|
||||
manufacturer_name = name;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
const char * ESPUSB::manufacturerName(void){
|
||||
return manufacturer_name.c_str();
|
||||
}
|
||||
|
||||
bool ESPUSB::serialNumber(const char * name){
|
||||
if(!_started){
|
||||
serial_number = name;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
const char * ESPUSB::serialNumber(void){
|
||||
return serial_number.c_str();
|
||||
}
|
||||
|
||||
bool ESPUSB::webUSBURL(const char * name){
|
||||
if(!_started){
|
||||
webusb_url = name;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
const char * ESPUSB::webUSBURL(void){
|
||||
return webusb_url.c_str();
|
||||
}
|
||||
|
||||
ESPUSB USB;
|
||||
|
||||
#endif /* CONFIG_USB_ENABLED */
|
@ -1,118 +0,0 @@
|
||||
// Copyright 2015-2020 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.
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_USB_ENABLED
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "USBCDC.h"
|
||||
|
||||
#include "esp_event.h"
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_EVENTS);
|
||||
|
||||
typedef enum {
|
||||
ARDUINO_USB_ANY_EVENT = ESP_EVENT_ANY_ID,
|
||||
ARDUINO_USB_STARTED_EVENT = 0,
|
||||
ARDUINO_USB_STOPPED_EVENT,
|
||||
ARDUINO_USB_SUSPEND_EVENT,
|
||||
ARDUINO_USB_RESUME_EVENT,
|
||||
ARDUINO_USB_MAX_EVENT,
|
||||
} arduino_usb_event_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
bool remote_wakeup_en;
|
||||
} suspend;
|
||||
} arduino_usb_event_data_t;
|
||||
|
||||
class ESPUSB {
|
||||
public:
|
||||
ESPUSB(size_t event_task_stack_size=2048, uint8_t event_task_priority=5);
|
||||
~ESPUSB();
|
||||
|
||||
void onEvent(esp_event_handler_t callback);
|
||||
void onEvent(arduino_usb_event_t event, esp_event_handler_t callback);
|
||||
|
||||
bool VID(uint16_t v);
|
||||
uint16_t VID(void);
|
||||
|
||||
bool PID(uint16_t p);
|
||||
uint16_t PID(void);
|
||||
|
||||
bool firmwareVersion(uint16_t version);
|
||||
uint16_t firmwareVersion(void);
|
||||
|
||||
bool usbVersion(uint16_t version);
|
||||
uint16_t usbVersion(void);
|
||||
|
||||
bool usbPower(uint16_t mA);
|
||||
uint16_t usbPower(void);
|
||||
|
||||
bool usbClass(uint8_t _class);
|
||||
uint8_t usbClass(void);
|
||||
|
||||
bool usbSubClass(uint8_t subClass);
|
||||
uint8_t usbSubClass(void);
|
||||
|
||||
bool usbProtocol(uint8_t protocol);
|
||||
uint8_t usbProtocol(void);
|
||||
|
||||
bool usbAttributes(uint8_t attr);
|
||||
uint8_t usbAttributes(void);
|
||||
|
||||
bool webUSB(bool enabled);
|
||||
bool webUSB(void);
|
||||
|
||||
bool productName(const char * name);
|
||||
const char * productName(void);
|
||||
|
||||
bool manufacturerName(const char * name);
|
||||
const char * manufacturerName(void);
|
||||
|
||||
bool serialNumber(const char * name);
|
||||
const char * serialNumber(void);
|
||||
|
||||
bool webUSBURL(const char * name);
|
||||
const char * webUSBURL(void);
|
||||
|
||||
bool enableDFU();
|
||||
bool begin();
|
||||
operator bool() const;
|
||||
|
||||
private:
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
String product_name;
|
||||
String manufacturer_name;
|
||||
String serial_number;
|
||||
uint16_t fw_version;
|
||||
uint16_t usb_version;
|
||||
uint8_t usb_class;
|
||||
uint8_t usb_subclass;
|
||||
uint8_t usb_protocol;
|
||||
uint8_t usb_attributes;
|
||||
uint16_t usb_power_ma;
|
||||
bool webusb_enabled;
|
||||
String webusb_url;
|
||||
|
||||
bool _started;
|
||||
size_t _task_stack_size;
|
||||
uint8_t _event_task_priority;
|
||||
};
|
||||
|
||||
extern ESPUSB USB;
|
||||
|
||||
#endif /* CONFIG_USB_ENABLED */
|
@ -1,338 +0,0 @@
|
||||
// Copyright 2015-2020 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 "esp32-hal-tinyusb.h"
|
||||
#include "USB.h"
|
||||
#include "USBCDC.h"
|
||||
#if CONFIG_USB_ENABLED
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(ARDUINO_USB_CDC_EVENTS);
|
||||
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait);
|
||||
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg);
|
||||
|
||||
extern "C" {
|
||||
#include "tinyusb.h"
|
||||
}
|
||||
|
||||
#if CFG_TUD_CDC
|
||||
#define MAX_USB_CDC_DEVICES 2
|
||||
USBCDC * devices[MAX_USB_CDC_DEVICES] = {NULL, NULL};
|
||||
|
||||
static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf)
|
||||
{
|
||||
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC");
|
||||
// Interface number, string index, attributes, detach timeout, transfer size */
|
||||
uint8_t descriptor[TUD_CDC_DESC_LEN] = {
|
||||
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
||||
TUD_CDC_DESCRIPTOR(*itf, str_index, 0x85, 64, 0x03, 0x84, 64)
|
||||
};
|
||||
*itf+=2;
|
||||
memcpy(dst, descriptor, TUD_CDC_DESC_LEN);
|
||||
return TUD_CDC_DESC_LEN;
|
||||
}
|
||||
|
||||
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
|
||||
{
|
||||
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
|
||||
devices[itf]->_onLineState(dtr, rts);
|
||||
}
|
||||
}
|
||||
|
||||
void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding)
|
||||
{
|
||||
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
|
||||
devices[itf]->_onLineCoding(p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits);
|
||||
}
|
||||
}
|
||||
|
||||
void tud_cdc_rx_cb(uint8_t itf)
|
||||
{
|
||||
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
|
||||
devices[itf]->_onRX();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static size_t tinyusb_cdc_write(uint8_t itf, const uint8_t *buffer, size_t size){
|
||||
if(itf >= MAX_USB_CDC_DEVICES){
|
||||
return 0;
|
||||
}
|
||||
if(!tud_cdc_n_connected(itf)){
|
||||
return 0;
|
||||
}
|
||||
size_t tosend = size, sofar = 0;
|
||||
while(tosend){
|
||||
uint32_t space = tud_cdc_n_write_available(itf);
|
||||
if(!space){
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
continue;
|
||||
}
|
||||
if(tosend < space){
|
||||
space = tosend;
|
||||
}
|
||||
uint32_t sent = tud_cdc_n_write(itf, buffer + sofar, space);
|
||||
if(!sent){
|
||||
return sofar;
|
||||
}
|
||||
sofar += sent;
|
||||
tosend -= sent;
|
||||
tud_cdc_n_write_flush(itf);
|
||||
}
|
||||
return sofar;
|
||||
}
|
||||
|
||||
static void ARDUINO_ISR_ATTR cdc0_write_char(char c)
|
||||
{
|
||||
tinyusb_cdc_write(0, (const uint8_t *)&c, 1);
|
||||
}
|
||||
|
||||
//void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
|
||||
|
||||
static void usb_unplugged_cb(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
|
||||
((USBCDC*)arg)->_onUnplugged();
|
||||
}
|
||||
|
||||
USBCDC::USBCDC(uint8_t itfn) : itf(itfn), bit_rate(0), stop_bits(0), parity(0), data_bits(0), dtr(false), rts(false), connected(false), reboot_enable(true), rx_queue(NULL) {
|
||||
tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor);
|
||||
if(itf < MAX_USB_CDC_DEVICES){
|
||||
devices[itf] = this;
|
||||
arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, usb_unplugged_cb, this);
|
||||
}
|
||||
}
|
||||
|
||||
void USBCDC::onEvent(esp_event_handler_t callback){
|
||||
onEvent(ARDUINO_USB_CDC_ANY_EVENT, callback);
|
||||
}
|
||||
void USBCDC::onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback){
|
||||
arduino_usb_event_handler_register_with(ARDUINO_USB_CDC_EVENTS, event, callback, this);
|
||||
}
|
||||
|
||||
size_t USBCDC::setRxBufferSize(size_t rx_queue_len){
|
||||
if(rx_queue){
|
||||
return 0;
|
||||
}
|
||||
rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t));
|
||||
if(!rx_queue){
|
||||
return 0;
|
||||
}
|
||||
return rx_queue_len;
|
||||
}
|
||||
|
||||
void USBCDC::begin(unsigned long baud)
|
||||
{
|
||||
setRxBufferSize(256);//default if not preset
|
||||
}
|
||||
|
||||
void USBCDC::end()
|
||||
{
|
||||
}
|
||||
|
||||
void USBCDC::_onUnplugged(void){
|
||||
if(connected){
|
||||
connected = false;
|
||||
dtr = false;
|
||||
rts = false;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
enum { CDC_LINE_IDLE, CDC_LINE_1, CDC_LINE_2, CDC_LINE_3 };
|
||||
void USBCDC::_onLineState(bool _dtr, bool _rts){
|
||||
static uint8_t lineState = CDC_LINE_IDLE;
|
||||
dtr = _dtr;
|
||||
rts = _rts;
|
||||
|
||||
if(reboot_enable){
|
||||
if(!dtr && rts){
|
||||
if(lineState == CDC_LINE_IDLE){
|
||||
lineState++;
|
||||
} else {
|
||||
lineState = CDC_LINE_IDLE;
|
||||
}
|
||||
} else if(dtr && rts){
|
||||
if(lineState == CDC_LINE_1){
|
||||
lineState++;
|
||||
} else {
|
||||
lineState = CDC_LINE_IDLE;
|
||||
}
|
||||
} else if(dtr && !rts){
|
||||
if(lineState == CDC_LINE_2){
|
||||
lineState++;
|
||||
} else {
|
||||
lineState = CDC_LINE_IDLE;
|
||||
}
|
||||
} else if(!dtr && !rts){
|
||||
if(lineState == CDC_LINE_3){
|
||||
usb_persist_restart(RESTART_BOOTLOADER);
|
||||
} else {
|
||||
lineState = CDC_LINE_IDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(lineState == CDC_LINE_IDLE){
|
||||
if(dtr && rts && !connected){
|
||||
connected = true;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_CONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
} else if(!dtr && !rts && connected){
|
||||
connected = false;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
arduino_usb_cdc_event_data_t l = {0};
|
||||
l.line_state.dtr = dtr;
|
||||
l.line_state.rts = rts;
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_STATE_EVENT, &l, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void USBCDC::_onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits){
|
||||
if(bit_rate != _bit_rate || data_bits != _data_bits || stop_bits != _stop_bits || parity != _parity){
|
||||
bit_rate = _bit_rate;
|
||||
data_bits = _data_bits;
|
||||
stop_bits = _stop_bits;
|
||||
parity = _parity;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
p.line_coding.bit_rate = bit_rate;
|
||||
p.line_coding.data_bits = data_bits;
|
||||
p.line_coding.stop_bits = stop_bits;
|
||||
p.line_coding.parity = parity;
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_CODING_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void USBCDC::_onRX(){
|
||||
uint8_t buf[CONFIG_USB_CDC_RX_BUFSIZE+1];
|
||||
uint32_t count = tud_cdc_n_read(itf, buf, CONFIG_USB_CDC_RX_BUFSIZE);
|
||||
for(uint32_t i=0; i<count; i++){
|
||||
if(rx_queue == NULL || !xQueueSend(rx_queue, buf+i, 0)){
|
||||
return;
|
||||
}
|
||||
}
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
p.rx.len = count;
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_RX_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
void USBCDC::enableReboot(bool enable){
|
||||
reboot_enable = enable;
|
||||
}
|
||||
bool USBCDC::rebootEnabled(void){
|
||||
return reboot_enable;
|
||||
}
|
||||
|
||||
int USBCDC::available(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
return uxQueueMessagesWaiting(rx_queue);
|
||||
}
|
||||
|
||||
int USBCDC::peek(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
uint8_t c;
|
||||
if(xQueuePeek(rx_queue, &c, 0)) {
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int USBCDC::read(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
uint8_t c = 0;
|
||||
if(xQueueReceive(rx_queue, &c, 0)) {
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t USBCDC::read(uint8_t *buffer, size_t size)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
uint8_t c = 0;
|
||||
size_t count = 0;
|
||||
while(count < size && xQueueReceive(rx_queue, &c, 0)){
|
||||
buffer[count++] = c;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void USBCDC::flush(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES){
|
||||
return;
|
||||
}
|
||||
tud_cdc_n_write_flush(itf);
|
||||
}
|
||||
|
||||
int USBCDC::availableForWrite(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES){
|
||||
return -1;
|
||||
}
|
||||
return tud_cdc_n_write_available(itf);
|
||||
}
|
||||
|
||||
size_t USBCDC::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
return tinyusb_cdc_write(itf, buffer, size);
|
||||
}
|
||||
|
||||
size_t USBCDC::write(uint8_t c)
|
||||
{
|
||||
return write(&c, 1);
|
||||
}
|
||||
|
||||
uint32_t USBCDC::baudRate()
|
||||
{
|
||||
return bit_rate;
|
||||
}
|
||||
|
||||
void USBCDC::setDebugOutput(bool en)
|
||||
{
|
||||
if(en) {
|
||||
uartSetDebug(NULL);
|
||||
ets_install_putc1((void (*)(char)) &cdc0_write_char);
|
||||
} else {
|
||||
ets_install_putc1(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
USBCDC::operator bool() const
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES){
|
||||
return false;
|
||||
}
|
||||
return connected;
|
||||
}
|
||||
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
USBCDC Serial(0);
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_USB_CDC_ENABLED */
|
||||
|
||||
#endif /* CONFIG_USB_ENABLED */
|
@ -1,132 +0,0 @@
|
||||
// Copyright 2015-2020 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.
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#if CONFIG_USB_CDC_ENABLED
|
||||
|
||||
#include "esp_event.h"
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_CDC_EVENTS);
|
||||
|
||||
typedef enum {
|
||||
ARDUINO_USB_CDC_ANY_EVENT = ESP_EVENT_ANY_ID,
|
||||
ARDUINO_USB_CDC_CONNECTED_EVENT = 0,
|
||||
ARDUINO_USB_CDC_DISCONNECTED_EVENT,
|
||||
ARDUINO_USB_CDC_LINE_STATE_EVENT,
|
||||
ARDUINO_USB_CDC_LINE_CODING_EVENT,
|
||||
ARDUINO_USB_CDC_RX_EVENT,
|
||||
ARDUINO_USB_CDC_MAX_EVENT,
|
||||
} arduino_usb_cdc_event_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
bool dtr;
|
||||
bool rts;
|
||||
} line_state;
|
||||
struct {
|
||||
uint32_t bit_rate;
|
||||
uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits
|
||||
uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space
|
||||
uint8_t data_bits; ///< can be 5, 6, 7, 8 or 16
|
||||
} line_coding;
|
||||
struct {
|
||||
size_t len;
|
||||
} rx;
|
||||
} arduino_usb_cdc_event_data_t;
|
||||
|
||||
class USBCDC
|
||||
{
|
||||
public:
|
||||
USBCDC(uint8_t itf=0);
|
||||
|
||||
void onEvent(esp_event_handler_t callback);
|
||||
void onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback);
|
||||
|
||||
size_t setRxBufferSize(size_t);
|
||||
void begin(unsigned long baud=0);
|
||||
void end();
|
||||
|
||||
int available(void);
|
||||
int availableForWrite(void);
|
||||
int peek(void);
|
||||
int read(void);
|
||||
size_t read(uint8_t *buffer, size_t size);
|
||||
size_t write(uint8_t);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
void flush(void);
|
||||
|
||||
inline size_t read(char * buffer, size_t size)
|
||||
{
|
||||
return read((uint8_t*) buffer, size);
|
||||
}
|
||||
inline size_t write(const char * buffer, size_t size)
|
||||
{
|
||||
return write((uint8_t*) buffer, size);
|
||||
}
|
||||
inline size_t write(const char * s)
|
||||
{
|
||||
return write((uint8_t*) s, strlen(s));
|
||||
}
|
||||
inline size_t write(unsigned long n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(long n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(unsigned int n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(int n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
uint32_t baudRate();
|
||||
void setDebugOutput(bool);
|
||||
operator bool() const;
|
||||
|
||||
void enableReboot(bool enable);
|
||||
bool rebootEnabled(void);
|
||||
|
||||
//internal methods
|
||||
void _onDFU(void);
|
||||
void _onLineState(bool _dtr, bool _rts);
|
||||
void _onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits);
|
||||
void _onRX(void);
|
||||
void _onUnplugged(void);
|
||||
|
||||
protected:
|
||||
uint8_t itf;
|
||||
uint32_t bit_rate;
|
||||
uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits
|
||||
uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space
|
||||
uint8_t data_bits; ///< can be 5, 6, 7, 8 or 16
|
||||
bool dtr;
|
||||
bool rts;
|
||||
bool connected;
|
||||
bool reboot_enable;
|
||||
xQueueHandle rx_queue;
|
||||
|
||||
};
|
||||
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
extern USBCDC Serial;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_USB_CDC_ENABLED */
|
@ -1,46 +0,0 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Wiring project - http://wiring.org.co
|
||||
Copyright (c) 2004-06 Hernando Barragan
|
||||
Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "esp_system.h"
|
||||
}
|
||||
|
||||
//long map(long x, long in_min, long in_max, long out_min, long out_max) {
|
||||
// const long dividend = out_max - out_min;
|
||||
// const long divisor = in_max - in_min;
|
||||
// const long delta = x - in_min;
|
||||
|
||||
// return (delta * dividend + (divisor / 2)) / divisor + out_min;
|
||||
//}
|
||||
|
||||
//unsigned int makeWord(unsigned int w)
|
||||
//{
|
||||
// return w;
|
||||
//}
|
||||
|
||||
//unsigned int makeWord(unsigned char h, unsigned char l)
|
||||
//{
|
||||
// return (h << 8) | l;
|
||||
//}
|
@ -1,281 +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 "esp32-hal-log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/sens_reg.h"
|
||||
|
||||
#include "driver/adc.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp_adc_cal.h"
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#define DEFAULT_VREF 1100
|
||||
static esp_adc_cal_characteristics_t *__analogCharacteristics[2] = {NULL, NULL};
|
||||
static uint16_t __analogVRef = 0;
|
||||
static uint8_t __analogVRefPin = 0;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
#include "esp32-hal-gpio.h"
|
||||
|
||||
static uint8_t __analogAttenuation = 3;//11db
|
||||
static uint8_t __analogWidth = 3;//12 bits
|
||||
static uint8_t __analogClockDiv = 1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
void __analogSetWidth(uint8_t bits){
|
||||
if(bits < 9){
|
||||
bits = 9;
|
||||
} else if(bits > 12){
|
||||
bits = 12;
|
||||
}
|
||||
__analogWidth = bits - 9;
|
||||
adc1_config_width(__analogWidth);
|
||||
}
|
||||
#endif
|
||||
|
||||
void __analogInit(){
|
||||
static bool initialized = false;
|
||||
if(initialized){
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
__analogSetClockDiv(__analogClockDiv);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
__analogSetWidth(__analogWidth + 9);//in bits
|
||||
#endif
|
||||
}
|
||||
|
||||
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){
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
} 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;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
__analogSetWidth(bits); // hadware from 9 to 12
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 CONFIG_IDF_TARGET_ESP32
|
||||
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(adc_vref_to_gpio(ADC_UNIT_2, __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]);
|
||||
#else
|
||||
uint16_t adc_reading = __analogRead(pin);
|
||||
uint16_t max_reading = 8191;
|
||||
uint16_t max_mv = 1100;
|
||||
switch(__analogAttenuation){
|
||||
case 3: max_mv = 3900; break;
|
||||
case 2: max_mv = 2200; break;
|
||||
case 1: max_mv = 1500; break;
|
||||
default: break;
|
||||
}
|
||||
return (adc_reading * max_mv) / max_reading;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
void __analogSetVRefPin(uint8_t pin){
|
||||
if(pin <25 || pin > 27){
|
||||
pin = 0;
|
||||
}
|
||||
__analogVRefPin = pin;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern uint16_t analogRead(uint8_t pin) __attribute__ ((weak, alias("__analogRead")));
|
||||
extern uint32_t analogReadMilliVolts(uint8_t pin) __attribute__ ((weak, alias("__analogReadMilliVolts")));
|
||||
extern void analogReadResolution(uint8_t bits) __attribute__ ((weak, alias("__analogReadResolution")));
|
||||
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 bool adcAttachPin(uint8_t pin) __attribute__ ((weak, alias("__adcAttachPin")));
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
extern void analogSetVRefPin(uint8_t pin) __attribute__ ((weak, alias("__analogSetVRefPin")));
|
||||
extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth")));
|
||||
extern int hallRead() __attribute__ ((weak, alias("__hallRead")));
|
||||
#endif
|
||||
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
Arduino.h - Main include file for the Arduino SDK
|
||||
Copyright (c) 2005-2013 Arduino Team. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MAIN_ESP32_HAL_ADC_H_
|
||||
#define MAIN_ESP32_HAL_ADC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
//#include "esp32-hal.h"
|
||||
|
||||
typedef enum {
|
||||
ADC_0db,
|
||||
ADC_2_5db,
|
||||
ADC_6db,
|
||||
ADC_11db
|
||||
} adc_attenuation_t;
|
||||
|
||||
/*
|
||||
* Get ADC value for pin
|
||||
* */
|
||||
uint16_t analogRead(uint8_t pin);
|
||||
|
||||
/*
|
||||
* Get MilliVolts value for pin
|
||||
* */
|
||||
uint32_t analogReadMilliVolts(uint8_t pin);
|
||||
|
||||
/*
|
||||
* Set the resolution of analogRead return values. Default is 12 bits (range from 0 to 4096).
|
||||
* If between 9 and 12, it will equal the set hardware resolution, else value will be shifted.
|
||||
* Range is 1 - 16
|
||||
*
|
||||
* Note: compatibility with Arduino SAM
|
||||
*/
|
||||
void analogReadResolution(uint8_t bits);
|
||||
|
||||
/*
|
||||
* Set the divider for the ADC clock.
|
||||
* Default is 1
|
||||
* Range is 1 - 255
|
||||
* */
|
||||
void analogSetClockDiv(uint8_t clockDiv);
|
||||
|
||||
/*
|
||||
* Set the attenuation for all channels
|
||||
* Default is 11db
|
||||
* */
|
||||
void analogSetAttenuation(adc_attenuation_t attenuation);
|
||||
|
||||
/*
|
||||
* Set the attenuation for particular pin
|
||||
* Default is 11db
|
||||
* */
|
||||
void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation);
|
||||
|
||||
/*
|
||||
* Attach pin to ADC (will also clear any other analog mode that could be on)
|
||||
* */
|
||||
bool adcAttachPin(uint8_t pin);
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/*
|
||||
* Sets the sample bits and read resolution
|
||||
* Default is 12bit (0 - 4095)
|
||||
* Range is 9 - 12
|
||||
* */
|
||||
void analogSetWidth(uint8_t bits);
|
||||
|
||||
/*
|
||||
* Set pin to use for ADC calibration if the esp is not already calibrated (25, 26 or 27)
|
||||
* */
|
||||
void analogSetVRefPin(uint8_t pin);
|
||||
|
||||
/*
|
||||
* Get value for HALL sensor (without LNA)
|
||||
* connected to pins 36(SVP) and 39(SVN)
|
||||
* */
|
||||
int hallRead();
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MAIN_ESP32_HAL_ADC_H_ */
|
@ -159,20 +159,20 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
|
||||
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);
|
||||
log_e("Bad frequency: %lu 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);
|
||||
log_e("Bad frequency: %lu MHz! Options are: 240, 160, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2, xtal/4);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
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);
|
||||
log_e("Bad frequency: %lu 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);
|
||||
log_e("Bad frequency: %lu MHz! Options are: 240, 160, 80, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -195,7 +195,7 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
|
||||
}
|
||||
//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);
|
||||
log_e("CPU clock could not be set to %lu MHz", cpu_freq_mhz);
|
||||
return false;
|
||||
}
|
||||
//Current APB
|
||||
|
@ -1,57 +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 "esp_attr.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/rtc_io_periph.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "soc/sens_struct.h"
|
||||
#include "driver/dac.h"
|
||||
#include "esp32-hal-gpio.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define DAC1 25
|
||||
#define DAC2 26
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define DAC1 17
|
||||
#define DAC2 18
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
|
||||
void ARDUINO_ISR_ATTR __dacWrite(uint8_t pin, uint8_t value)
|
||||
{
|
||||
if(pin < DAC1 || pin > DAC2){
|
||||
return;//not dac pin
|
||||
}
|
||||
pinMode(pin, ANALOG);
|
||||
uint8_t channel = pin - DAC1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_SW_TONE_EN);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
SENS.sar_dac_ctrl1.dac_clkgate_en = 1;
|
||||
#endif
|
||||
RTCIO.pad_dac[channel].dac_xpd_force = 1;
|
||||
RTCIO.pad_dac[channel].xpd_dac = 1;
|
||||
if (channel == 0) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en1 = 0;
|
||||
} else if (channel == 1) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en2 = 0;
|
||||
}
|
||||
RTCIO.pad_dac[channel].dac = value;
|
||||
}
|
||||
|
||||
extern void dacWrite(uint8_t pin, uint8_t value) __attribute__ ((weak, alias("__dacWrite")));
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
Arduino.h - Main include file for the Arduino SDK
|
||||
Copyright (c) 2005-2013 Arduino Team. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MAIN_ESP32_HAL_DAC_H_
|
||||
#define MAIN_ESP32_HAL_DAC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void dacWrite(uint8_t pin, uint8_t value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MAIN_ESP32_HAL_DAC_H_ */
|
@ -1,392 +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 "esp32-hal-gpio.h"
|
||||
#include "pins_arduino.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/gpio_struct.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/rtc_io_periph.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp32/rom/gpio.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#define GPIO_FUNC 2
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#include "esp32s2/rom/gpio.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#define GPIO_FUNC 1
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
const int8_t esp32_adc2gpio[20] = {36, 37, 38, 39, 32, 33, 34, 35, -1, -1, 4, 0, 2, 15, 13, 12, 14, 27, 25, 26};
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
const int8_t esp32_adc2gpio[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
|
||||
#endif
|
||||
|
||||
const DRAM_ATTR esp32_gpioMux_t esp32_gpioMux[SOC_GPIO_PIN_COUNT]={
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
{0x44, 11, 11, 1},
|
||||
{0x88, -1, -1, -1},
|
||||
{0x40, 12, 12, 2},
|
||||
{0x84, -1, -1, -1},
|
||||
{0x48, 10, 10, 0},
|
||||
{0x6c, -1, -1, -1},
|
||||
{0x60, -1, -1, -1},
|
||||
{0x64, -1, -1, -1},
|
||||
{0x68, -1, -1, -1},
|
||||
{0x54, -1, -1, -1},
|
||||
{0x58, -1, -1, -1},
|
||||
{0x5c, -1, -1, -1},
|
||||
{0x34, 15, 15, 5},
|
||||
{0x38, 14, 14, 4},
|
||||
{0x30, 16, 16, 6},
|
||||
{0x3c, 13, 13, 3},
|
||||
{0x4c, -1, -1, -1},
|
||||
{0x50, -1, -1, -1},
|
||||
{0x70, -1, -1, -1},
|
||||
{0x74, -1, -1, -1},
|
||||
{0x78, -1, -1, -1},
|
||||
{0x7c, -1, -1, -1},
|
||||
{0x80, -1, -1, -1},
|
||||
{0x8c, -1, -1, -1},
|
||||
{0, -1, -1, -1},
|
||||
{0x24, 6, 18, -1}, //DAC1
|
||||
{0x28, 7, 19, -1}, //DAC2
|
||||
{0x2c, 17, 17, 7},
|
||||
{0, -1, -1, -1},
|
||||
{0, -1, -1, -1},
|
||||
{0, -1, -1, -1},
|
||||
{0, -1, -1, -1},
|
||||
{0x1c, 9, 4, 8},
|
||||
{0x20, 8, 5, 9},
|
||||
{0x14, 4, 6, -1},
|
||||
{0x18, 5, 7, -1},
|
||||
{0x04, 0, 0, -1},
|
||||
{0x08, 1, 1, -1},
|
||||
{0x0c, 2, 2, -1},
|
||||
{0x10, 3, 3, -1}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
{0x04, 0, -1, -1},
|
||||
{0x08, 1, 0, 1},
|
||||
{0x0c, 2, 1, 2},
|
||||
{0x10, 3, 2, 3},
|
||||
{0x14, 4, 3, 4},
|
||||
{0x18, 5, 4, 5},
|
||||
{0x1c, 6, 5, 6},
|
||||
{0x20, 7, 6, 7},
|
||||
{0x24, 8, 7, 8},
|
||||
{0x28, 9, 8, 9},//FSPI_HD
|
||||
{0x2c, 10, 9, 10},//FSPI_CS0 / FSPI_D4
|
||||
{0x30, 11, 10, 11},//FSPI_D / FSPI_D5
|
||||
{0x34, 12, 11, 12},//FSPI_CLK / FSPI_D6
|
||||
{0x38, 13, 12, 13},//FSPI_Q / FSPI_D7
|
||||
{0x3c, 14, 13, 14},//FSPI_WP / FSPI_DQS
|
||||
{0x40, 15, 14, -1},//32K+ / RTS0
|
||||
{0x44, 16, 15, -1},//32K- / CTS0
|
||||
{0x48, 17, 16, -1},//DAC1 / TXD1
|
||||
{0x4c, 18, 17, -1},//DAC2 / RXD1
|
||||
{0x50, 19, 18, -1},//USB D- / RTS1
|
||||
{0x54, 20, 19, -1},//USB D+ / CTS1
|
||||
{0x58, 21, -1, -1},//SDA?
|
||||
{ 0, -1, -1, -1},//UNAVAILABLE
|
||||
{ 0, -1, -1, -1},//UNAVAILABLE
|
||||
{ 0, -1, -1, -1},//UNAVAILABLE
|
||||
{ 0, -1, -1, -1},//UNAVAILABLE
|
||||
{0x6c, -1, -1, -1},//RESERVED SPI_CS1
|
||||
{0x70, -1, -1, -1},//RESERVED SPI_HD
|
||||
{0x74, -1, -1, -1},//RESERVED SPI_WP
|
||||
{0x78, -1, -1, -1},//RESERVED SPI_CS0
|
||||
{0x7c, -1, -1, -1},//RESERVED SPI_CLK
|
||||
{0x80, -1, -1, -1},//RESERVED SPI_Q
|
||||
{0x84, -1, -1, -1},//RESERVED SPI_D
|
||||
{0x88, -1, -1, -1},//FSPI_HD
|
||||
{0x8c, -1, -1, -1},//FSPI_CS0
|
||||
{0x90, -1, -1, -1},//FSPI_D
|
||||
{0x94, -1, -1, -1},//FSPI_CLK
|
||||
{0x98, -1, -1, -1},//FSPI_Q
|
||||
{0x9c, -1, -1, -1},//FSPI_WP
|
||||
{0xa0, -1, -1, -1},//MTCK
|
||||
{0xa4, -1, -1, -1},//MTDO
|
||||
{0xa8, -1, -1, -1},//MTDI
|
||||
{0xac, -1, -1, -1},//MTMS
|
||||
{0xb0, -1, -1, -1},//TXD0
|
||||
{0xb4, -1, -1, -1},//RXD0
|
||||
{0xb8, -1, -1, -1},//SCL?
|
||||
{0xbc, -1, -1, -1},//INPUT ONLY
|
||||
{0, -1, -1, -1}
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef void (*voidFuncPtr)(void);
|
||||
typedef void (*voidFuncPtrArg)(void*);
|
||||
typedef struct {
|
||||
voidFuncPtr fn;
|
||||
void* arg;
|
||||
bool functional;
|
||||
} InterruptHandle_t;
|
||||
static InterruptHandle_t __pinInterruptHandlers[SOC_GPIO_PIN_COUNT] = {0,};
|
||||
|
||||
#include "driver/rtc_io.h"
|
||||
|
||||
extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode)
|
||||
{
|
||||
|
||||
if(!digitalPinIsValid(pin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int8_t rtc_io = esp32_gpioMux[pin].rtc;
|
||||
uint32_t rtc_reg = (rtc_io != -1)?rtc_io_desc[rtc_io].reg:0;
|
||||
if(mode == ANALOG) {
|
||||
if(!rtc_reg) {
|
||||
return;//not rtc pin
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
SENS.sar_io_mux_conf.iomux_clk_gate_en = 1;
|
||||
#endif
|
||||
SET_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, (rtc_io_desc[rtc_io].mux));
|
||||
SET_PERI_REG_BITS(rtc_io_desc[rtc_io].reg, RTC_IO_TOUCH_PAD1_FUN_SEL_V, 0, rtc_io_desc[rtc_io].func);
|
||||
|
||||
RTCIO.pin[rtc_io].pad_driver = 0;//OD = 1
|
||||
RTCIO.enable_w1tc.w1tc = (1U << rtc_io);
|
||||
CLEAR_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, rtc_io_desc[rtc_io].ie);
|
||||
|
||||
if (rtc_io_desc[rtc_io].pullup) {
|
||||
CLEAR_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, rtc_io_desc[rtc_io].pullup);
|
||||
}
|
||||
if (rtc_io_desc[rtc_io].pulldown) {
|
||||
CLEAR_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, rtc_io_desc[rtc_io].pulldown);
|
||||
}
|
||||
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = ((uint32_t)GPIO_FUNC << MCU_SEL_S) | ((uint32_t)2 << FUN_DRV_S) | FUN_IE;
|
||||
return;
|
||||
}
|
||||
|
||||
//RTC pins PULL settings
|
||||
if(rtc_reg) {
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].mux);
|
||||
if(mode & PULLUP) {
|
||||
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_io_desc[rtc_io].pullup) & ~(rtc_io_desc[rtc_io].pulldown);
|
||||
} else if(mode & PULLDOWN) {
|
||||
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_io_desc[rtc_io].pulldown) & ~(rtc_io_desc[rtc_io].pullup);
|
||||
} else {
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].pullup | rtc_io_desc[rtc_io].pulldown);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pinFunction = 0, pinControl = 0;
|
||||
|
||||
if(mode & INPUT) {
|
||||
if(pin < 32) {
|
||||
GPIO.enable_w1tc = ((uint32_t)1 << pin);
|
||||
} else {
|
||||
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
} else if(mode & OUTPUT) {
|
||||
if(pin >= NUM_OUPUT_PINS){
|
||||
return;
|
||||
} else if(pin < 32) {
|
||||
GPIO.enable_w1ts = ((uint32_t)1 << pin);
|
||||
} else {
|
||||
GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
}
|
||||
|
||||
if(mode & PULLUP) {
|
||||
pinFunction |= FUN_PU;
|
||||
} else if(mode & PULLDOWN) {
|
||||
pinFunction |= FUN_PD;
|
||||
}
|
||||
|
||||
pinFunction |= ((uint32_t)2 << FUN_DRV_S);//what are the drivers?
|
||||
pinFunction |= FUN_IE;//input enable but required for output as well?
|
||||
|
||||
if(mode & (INPUT | OUTPUT)) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
pinFunction |= ((uint32_t)2 << MCU_SEL_S);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
pinFunction |= ((uint32_t)1 << MCU_SEL_S);
|
||||
#endif
|
||||
} else if(mode == SPECIAL) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
pinFunction |= ((uint32_t)(((pin)==RX||(pin)==TX)?0:1) << MCU_SEL_S);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
pinFunction |= ((uint32_t)(((pin)==RX||(pin)==TX)?0:2) << MCU_SEL_S);
|
||||
#endif
|
||||
} else {
|
||||
pinFunction |= ((uint32_t)(mode >> 5) << MCU_SEL_S);
|
||||
}
|
||||
|
||||
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = pinFunction;
|
||||
|
||||
if(mode & OPEN_DRAIN) {
|
||||
pinControl = (1 << GPIO_PIN0_PAD_DRIVER_S);
|
||||
}
|
||||
|
||||
GPIO.pin[pin].val = pinControl;
|
||||
}
|
||||
|
||||
extern void ARDUINO_ISR_ATTR __digitalWrite(uint8_t pin, uint8_t val)
|
||||
{
|
||||
if(val) {
|
||||
if(pin < 32) {
|
||||
GPIO.out_w1ts = ((uint32_t)1 << pin);
|
||||
} else if(pin < NUM_OUPUT_PINS) {
|
||||
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
} else {
|
||||
if(pin < 32) {
|
||||
GPIO.out_w1tc = ((uint32_t)1 << pin);
|
||||
} else if(pin < NUM_OUPUT_PINS) {
|
||||
GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern int ARDUINO_ISR_ATTR __digitalRead(uint8_t pin)
|
||||
{
|
||||
if(pin < 32) {
|
||||
return (GPIO.in >> pin) & 0x1;
|
||||
} else if(pin < GPIO_PIN_COUNT) {
|
||||
return (GPIO.in1.val >> (pin - 32)) & 0x1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static intr_handle_t gpio_intr_handle = NULL;
|
||||
|
||||
static void ARDUINO_ISR_ATTR __onPinInterrupt()
|
||||
{
|
||||
uint32_t gpio_intr_status_l=0;
|
||||
uint32_t gpio_intr_status_h=0;
|
||||
|
||||
gpio_intr_status_l = GPIO.status;
|
||||
gpio_intr_status_h = GPIO.status1.val;
|
||||
GPIO.status_w1tc = gpio_intr_status_l;//Clear intr for gpio0-gpio31
|
||||
GPIO.status1_w1tc.val = gpio_intr_status_h;//Clear intr for gpio32-39
|
||||
|
||||
uint8_t pin=0;
|
||||
if(gpio_intr_status_l) {
|
||||
do {
|
||||
if(gpio_intr_status_l & ((uint32_t)1 << pin)) {
|
||||
if(__pinInterruptHandlers[pin].fn) {
|
||||
if(__pinInterruptHandlers[pin].arg){
|
||||
((voidFuncPtrArg)__pinInterruptHandlers[pin].fn)(__pinInterruptHandlers[pin].arg);
|
||||
} else {
|
||||
__pinInterruptHandlers[pin].fn();
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(++pin<32);
|
||||
}
|
||||
if(gpio_intr_status_h) {
|
||||
pin=32;
|
||||
do {
|
||||
if(gpio_intr_status_h & ((uint32_t)1 << (pin - 32))) {
|
||||
if(__pinInterruptHandlers[pin].fn) {
|
||||
if(__pinInterruptHandlers[pin].arg){
|
||||
((voidFuncPtrArg)__pinInterruptHandlers[pin].fn)(__pinInterruptHandlers[pin].arg);
|
||||
} else {
|
||||
__pinInterruptHandlers[pin].fn();
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(++pin<GPIO_PIN_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
extern void cleanupFunctional(void* arg);
|
||||
|
||||
extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional)
|
||||
{
|
||||
static bool interrupt_initialized = false;
|
||||
|
||||
if(!interrupt_initialized) {
|
||||
interrupt_initialized = true;
|
||||
esp_intr_alloc(ETS_GPIO_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, __onPinInterrupt, NULL, &gpio_intr_handle);
|
||||
}
|
||||
|
||||
// if new attach without detach remove old info
|
||||
if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg)
|
||||
{
|
||||
cleanupFunctional(__pinInterruptHandlers[pin].arg);
|
||||
}
|
||||
__pinInterruptHandlers[pin].fn = (voidFuncPtr)userFunc;
|
||||
__pinInterruptHandlers[pin].arg = arg;
|
||||
__pinInterruptHandlers[pin].functional = functional;
|
||||
|
||||
esp_intr_disable(gpio_intr_handle);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if(esp_intr_get_cpu(gpio_intr_handle)) { //APP_CPU
|
||||
#endif
|
||||
GPIO.pin[pin].int_ena = 1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
} else { //PRO_CPU
|
||||
GPIO.pin[pin].int_ena = 4;
|
||||
}
|
||||
#endif
|
||||
GPIO.pin[pin].int_type = intr_type;
|
||||
esp_intr_enable(gpio_intr_handle);
|
||||
}
|
||||
|
||||
extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type)
|
||||
{
|
||||
__attachInterruptFunctionalArg(pin, userFunc, arg, intr_type, false);
|
||||
}
|
||||
|
||||
extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type) {
|
||||
__attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, NULL, intr_type, false);
|
||||
}
|
||||
|
||||
extern void __detachInterrupt(uint8_t pin)
|
||||
{
|
||||
esp_intr_disable(gpio_intr_handle);
|
||||
if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg)
|
||||
{
|
||||
cleanupFunctional(__pinInterruptHandlers[pin].arg);
|
||||
}
|
||||
__pinInterruptHandlers[pin].fn = NULL;
|
||||
__pinInterruptHandlers[pin].arg = NULL;
|
||||
__pinInterruptHandlers[pin].functional = false;
|
||||
|
||||
GPIO.pin[pin].int_ena = 0;
|
||||
GPIO.pin[pin].int_type = 0;
|
||||
esp_intr_enable(gpio_intr_handle);
|
||||
}
|
||||
|
||||
|
||||
extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pinMode")));
|
||||
extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite")));
|
||||
extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead")));
|
||||
extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt")));
|
||||
extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void * arg, int mode) __attribute__ ((weak, alias("__attachInterruptArg")));
|
||||
extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt")));
|
||||
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
Arduino.h - Main include file for the Arduino SDK
|
||||
Copyright (c) 2005-2013 Arduino Team. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MAIN_ESP32_HAL_GPIO_H_
|
||||
#define MAIN_ESP32_HAL_GPIO_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3)
|
||||
#define NUM_OUPUT_PINS 45
|
||||
#define PIN_DAC1 17
|
||||
#define PIN_DAC2 18
|
||||
#else
|
||||
#define NUM_OUPUT_PINS 34
|
||||
#define PIN_DAC1 25
|
||||
#define PIN_DAC2 26
|
||||
#endif
|
||||
|
||||
#define LOW 0x0
|
||||
#define HIGH 0x1
|
||||
|
||||
//GPIO FUNCTIONS
|
||||
#define INPUT 0x01
|
||||
#define OUTPUT 0x02
|
||||
#define PULLUP 0x04
|
||||
#define INPUT_PULLUP 0x05
|
||||
#define PULLDOWN 0x08
|
||||
#define INPUT_PULLDOWN 0x09
|
||||
#define OPEN_DRAIN 0x10
|
||||
#define OUTPUT_OPEN_DRAIN 0x12
|
||||
#define SPECIAL 0xF0
|
||||
#define FUNCTION_1 0x00
|
||||
#define FUNCTION_2 0x20
|
||||
#define FUNCTION_3 0x40
|
||||
#define FUNCTION_4 0x60
|
||||
#define FUNCTION_5 0x80
|
||||
#define FUNCTION_6 0xA0
|
||||
#define ANALOG 0xC0
|
||||
|
||||
//Interrupt Modes
|
||||
#define DISABLED 0x00
|
||||
#define RISING 0x01
|
||||
#define FALLING 0x02
|
||||
#define CHANGE 0x03
|
||||
#define ONLOW 0x04
|
||||
#define ONHIGH 0x05
|
||||
#define ONLOW_WE 0x0C
|
||||
#define ONHIGH_WE 0x0D
|
||||
|
||||
typedef struct {
|
||||
uint8_t reg; /*!< GPIO register offset from DR_REG_IO_MUX_BASE */
|
||||
int8_t rtc; /*!< RTC GPIO number (-1 if not RTC GPIO pin) */
|
||||
int8_t adc; /*!< ADC Channel number (-1 if not ADC pin) */
|
||||
int8_t touch; /*!< Touch Channel number (-1 if not Touch pin) */
|
||||
} esp32_gpioMux_t;
|
||||
|
||||
extern const esp32_gpioMux_t esp32_gpioMux[SOC_GPIO_PIN_COUNT];
|
||||
extern const int8_t esp32_adc2gpio[20];
|
||||
|
||||
#define digitalPinIsValid(pin) ((pin) < SOC_GPIO_PIN_COUNT && esp32_gpioMux[(pin)].reg)
|
||||
#define digitalPinCanOutput(pin) ((pin) < NUM_OUPUT_PINS && esp32_gpioMux[(pin)].reg)
|
||||
#define digitalPinToRtcPin(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].rtc:-1)
|
||||
#define digitalPinToAnalogChannel(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].adc:-1)
|
||||
#define digitalPinToTouchChannel(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].touch:-1)
|
||||
#define digitalPinToDacChannel(pin) (((pin) == PIN_DAC1)?0:((pin) == PIN_DAC2)?1:-1)
|
||||
|
||||
void pinMode(uint8_t pin, uint8_t mode);
|
||||
void digitalWrite(uint8_t pin, uint8_t val);
|
||||
int digitalRead(uint8_t pin);
|
||||
|
||||
void attachInterrupt(uint8_t pin, void (*)(void), int mode);
|
||||
void attachInterruptArg(uint8_t pin, void (*)(void*), void * arg, int mode);
|
||||
void detachInterrupt(uint8_t pin);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MAIN_ESP32_HAL_GPIO_H_ */
|
@ -27,7 +27,6 @@
|
||||
#include "esp_attr.h"
|
||||
#include "esp32-hal-cpu.h" // cpu clock change support 31DEC2018
|
||||
#include "esp32-hal-log.h"
|
||||
#include "esp32-hal-gpio.h"
|
||||
#include "esp32-hal-matrix.h"
|
||||
#include "esp32-hal-misc.h"
|
||||
|
||||
@ -44,6 +43,8 @@
|
||||
#include "rom/ets_sys.h"
|
||||
#endif
|
||||
#include "driver/gpio.h"
|
||||
#include <esp_log.h>
|
||||
#define TAG "ARDUINO"
|
||||
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
@ -338,7 +339,7 @@ static void i2cDumpDqData(i2c_t * i2c)
|
||||
static void i2cDumpI2c(i2c_t * i2c)
|
||||
{
|
||||
log_e("i2c=%p",i2c);
|
||||
log_i("dev=%p date=%u",i2c->dev,i2c->dev->date);
|
||||
log_i("dev=%p date=%"PRIu32,i2c->dev,i2c->dev->date);
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
log_i("lock=%p",i2c->lock);
|
||||
#endif
|
||||
@ -346,14 +347,14 @@ static void i2cDumpI2c(i2c_t * i2c)
|
||||
log_i("mode=%d",i2c->mode);
|
||||
log_i("stage=%d",i2c->stage);
|
||||
log_i("error=%d",i2c->error);
|
||||
log_i("event=%p bits=%x",i2c->i2c_event,(i2c->i2c_event)?xEventGroupGetBits(i2c->i2c_event):0);
|
||||
log_i("event=%p bits=%lx",i2c->i2c_event,(i2c->i2c_event)?xEventGroupGetBits(i2c->i2c_event):0);
|
||||
log_i("intr_handle=%p",i2c->intr_handle);
|
||||
log_i("dq=%p",i2c->dq);
|
||||
log_i("queueCount=%d",i2c->queueCount);
|
||||
log_i("queuePos=%d",i2c->queuePos);
|
||||
log_i("errorByteCnt=%d",i2c->errorByteCnt);
|
||||
log_i("errorQueue=%d",i2c->errorQueue);
|
||||
log_i("debugFlags=0x%08X",i2c->debugFlags);
|
||||
log_i("debugFlags=0x%08" PRIu32 "X",i2c->debugFlags);
|
||||
if(i2c->dq) {
|
||||
i2cDumpDqData(i2c);
|
||||
}
|
||||
@ -479,7 +480,7 @@ static void i2cApbChangeCallback(void * arg, apb_change_ev_t ev_type, uint32_t o
|
||||
switch(ev_type){
|
||||
case APB_BEFORE_CHANGE :
|
||||
if(new_apb < 3000000) {// too slow
|
||||
log_e("apb speed %d too slow",new_apb);
|
||||
log_e("apb speed %lu too slow",new_apb);
|
||||
break;
|
||||
}
|
||||
I2C_MUTEX_LOCK(); // lock will spin until current transaction is completed
|
||||
@ -779,7 +780,7 @@ static void ARDUINO_ISR_ATTR emptyRxFifo(i2c_t * i2c)
|
||||
}
|
||||
|
||||
if(i2c->queuePos >= i2c->queueCount){ // bad stuff, rx data but no place to put it!
|
||||
log_e("no Storage location for %d",moveCnt);
|
||||
log_e("no Storage location for %lu",moveCnt);
|
||||
// discard
|
||||
while(moveCnt>0){
|
||||
d = i2c->dev->fifo_data.val;
|
||||
@ -795,7 +796,7 @@ static void ARDUINO_ISR_ATTR emptyRxFifo(i2c_t * i2c)
|
||||
moveCnt = (tdq->length - tdq->position);
|
||||
}
|
||||
} else {// error
|
||||
log_e("RxEmpty(%d) call on TxBuffer? dq=%d",moveCnt,i2c->queuePos);
|
||||
log_e("RxEmpty(%4lu) call on TxBuffer? dq=%d",moveCnt,i2c->queuePos);
|
||||
// discard
|
||||
while(moveCnt>0){
|
||||
d = i2c->dev->fifo_data.val;
|
||||
@ -1032,7 +1033,7 @@ static void ARDUINO_ISR_ATTR i2c_isr_handler_default(void* arg)
|
||||
|
||||
if(activeInt) { // clear unhandled if possible? What about Disabling interrupt?
|
||||
p_i2c->dev->int_clr.val = activeInt;
|
||||
log_e("unknown int=%x",activeInt);
|
||||
log_e("unknown int=%lx",activeInt);
|
||||
// disable unhandled IRQ,
|
||||
p_i2c->dev->int_ena.val = p_i2c->dev->int_ena.val & (~activeInt);
|
||||
}
|
||||
@ -1280,7 +1281,7 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
|
||||
}
|
||||
|
||||
if(ret!=ESP_OK) {
|
||||
log_e("install interrupt handler Failed=%d",ret);
|
||||
log_e("install interrupt handler Failed=%lu",ret);
|
||||
I2C_MUTEX_UNLOCK();
|
||||
return I2C_ERROR_MEMORY;
|
||||
}
|
||||
@ -1432,28 +1433,52 @@ static bool i2cCheckLineState(int8_t sda, int8_t scl){
|
||||
return false;//return false since there is nothing to do
|
||||
}
|
||||
// if the bus is not 'clear' try the cycling SCL until SDA goes High or 9 cycles
|
||||
digitalWrite(sda, HIGH);
|
||||
digitalWrite(scl, HIGH);
|
||||
pinMode(sda, PULLUP|OPEN_DRAIN|INPUT);
|
||||
pinMode(scl, PULLUP|OPEN_DRAIN|OUTPUT);
|
||||
gpio_set_level(sda, 1);
|
||||
gpio_set_level(scl, 1);
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = 1ULL << sda,
|
||||
.mode = GPIO_MODE_INPUT_OUTPUT_OD,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
|
||||
if(!digitalRead(sda) || !digitalRead(scl)) { // bus in busy state
|
||||
log_w("invalid state sda(%d)=%d, scl(%d)=%d", sda, digitalRead(sda), scl, digitalRead(scl));
|
||||
digitalWrite(scl, HIGH);
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = 1ULL << scl,
|
||||
.mode = GPIO_MODE_OUTPUT_OD,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
|
||||
if(!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state
|
||||
log_w("invalid state sda(%d)=%d, scl(%d)=%d", sda, gpio_get_level(sda), scl, gpio_get_level(scl));
|
||||
gpio_set_level(scl, 1);
|
||||
for(uint8_t a=0; a<9; a++) {
|
||||
delayMicroseconds(5);
|
||||
digitalWrite(scl, LOW);
|
||||
gpio_set_level(scl, 0);
|
||||
delayMicroseconds(5);
|
||||
digitalWrite(scl, HIGH);
|
||||
if(digitalRead(sda)){ // bus recovered
|
||||
gpio_set_level(scl, 1);
|
||||
if(gpio_get_level(sda)){ // bus recovered
|
||||
log_d("Recovered after %d Cycles",a+1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!digitalRead(sda) || !digitalRead(scl)) { // bus in busy state
|
||||
log_e("Bus Invalid State, TwoWire() Can't init sda=%d, scl=%d",digitalRead(sda),digitalRead(scl));
|
||||
if(!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state
|
||||
log_e("Bus Invalid State, TwoWire() Can't init sda=%d, scl=%d",gpio_get_level(sda),gpio_get_level(scl));
|
||||
return false; // bus is busy
|
||||
}
|
||||
return true;
|
||||
@ -1464,8 +1489,20 @@ i2c_err_t i2cAttachSCL(i2c_t * i2c, int8_t scl)
|
||||
if(i2c == NULL) {
|
||||
return I2C_ERROR_DEV;
|
||||
}
|
||||
digitalWrite(scl, HIGH);
|
||||
pinMode(scl, OPEN_DRAIN | PULLUP | INPUT | OUTPUT);
|
||||
gpio_set_level(scl, 1);
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = (1ULL << scl),
|
||||
.mode = GPIO_MODE_INPUT_OUTPUT_OD,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
pinMatrixOutAttach(scl, I2C_SCL_IDX(i2c->num), false, false);
|
||||
pinMatrixInAttach(scl, I2C_SCL_IDX(i2c->num), false);
|
||||
return I2C_ERROR_OK;
|
||||
@ -1478,7 +1515,19 @@ i2c_err_t i2cDetachSCL(i2c_t * i2c, int8_t scl)
|
||||
}
|
||||
pinMatrixOutDetach(scl, false, false);
|
||||
pinMatrixInDetach(I2C_SCL_IDX(i2c->num), false, false);
|
||||
pinMode(scl, INPUT | PULLUP);
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = (1ULL << scl),
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
return I2C_ERROR_OK;
|
||||
}
|
||||
|
||||
@ -1487,8 +1536,20 @@ i2c_err_t i2cAttachSDA(i2c_t * i2c, int8_t sda)
|
||||
if(i2c == NULL) {
|
||||
return I2C_ERROR_DEV;
|
||||
}
|
||||
digitalWrite(sda, HIGH);
|
||||
pinMode(sda, OPEN_DRAIN | PULLUP | INPUT | OUTPUT );
|
||||
gpio_set_level(sda, 1);
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = (1ULL << sda),
|
||||
.mode = GPIO_MODE_INPUT_OUTPUT_OD,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
pinMatrixOutAttach(sda, I2C_SDA_IDX(i2c->num), false, false);
|
||||
pinMatrixInAttach(sda, I2C_SDA_IDX(i2c->num), false);
|
||||
return I2C_ERROR_OK;
|
||||
@ -1501,7 +1562,19 @@ i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda)
|
||||
}
|
||||
pinMatrixOutDetach(sda, false, false);
|
||||
pinMatrixInDetach(I2C_SDA_IDX(i2c->num), false, false);
|
||||
pinMode(sda, INPUT | PULLUP);
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = (1ULL << sda),
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
return I2C_ERROR_OK;
|
||||
}
|
||||
|
||||
|
@ -1,319 +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 "esp32-hal-matrix.h"
|
||||
#include "esp32-hal-log.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/ledc_reg.h"
|
||||
#include "soc/ledc_struct.h"
|
||||
#include "esp32-hal-cpu.h"
|
||||
#include "esp32-hal-gpio.h"
|
||||
#include "esp32-hal-ledc.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#define LAST_CHAN (15)
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#define LAST_CHAN (7)
|
||||
#define LEDC_DIV_NUM_HSTIMER0_V LEDC_CLK_DIV_LSTIMER0_V
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#endif
|
||||
|
||||
#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)
|
||||
SemaphoreHandle_t _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 CONFIG_IDF_TARGET_ESP32
|
||||
if(group) {
|
||||
#endif
|
||||
LEDC_TIMER(group, timer).conf.low_speed_update = 1;//This bit is only useful for low speed timer channels, reserved for high speed timers
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
}
|
||||
#endif
|
||||
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 CONFIG_IDF_TARGET_ESP32
|
||||
if(group) {
|
||||
#endif
|
||||
LEDC_CHAN(group, channel).conf0.low_speed_update = 1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
} else {
|
||||
LEDC_CHAN(group, channel).conf0.clk_en = 0;
|
||||
}
|
||||
#endif
|
||||
LEDC_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)
|
||||
{
|
||||
if(chan > LAST_CHAN) {
|
||||
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 > LAST_CHAN) {
|
||||
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 CONFIG_IDF_TARGET_ESP32
|
||||
if(group) {
|
||||
#endif
|
||||
LEDC_CHAN(group, channel).conf0.low_speed_update = 1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
} else {
|
||||
LEDC_CHAN(group, channel).conf0.clk_en = 1;
|
||||
}
|
||||
#endif
|
||||
} 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 CONFIG_IDF_TARGET_ESP32
|
||||
if(group) {
|
||||
#endif
|
||||
LEDC_CHAN(group, channel).conf0.low_speed_update = 1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
} else {
|
||||
LEDC_CHAN(group, channel).conf0.clk_en = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
LEDC_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
uint32_t ledcRead(uint8_t chan)
|
||||
{
|
||||
if(chan > LAST_CHAN) {
|
||||
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 > LAST_CHAN) {
|
||||
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 > LAST_CHAN) {
|
||||
return;
|
||||
}
|
||||
pinMode(pin, OUTPUT);
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
pinMatrixOutAttach(pin, LEDC_LS_SIG_OUT0_IDX + chan, false, false);
|
||||
#else
|
||||
pinMatrixOutAttach(pin, ((chan/8)?LEDC_LS_SIG_OUT0_IDX:LEDC_HS_SIG_OUT0_IDX) + (chan%8), false, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ledcDetachPin(uint8_t pin)
|
||||
{
|
||||
pinMatrixOutDetach(pin, false, false);
|
||||
}
|
@ -1,44 +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.
|
||||
|
||||
#ifndef _ESP32_HAL_LEDC_H_
|
||||
#define _ESP32_HAL_LEDC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
NOTE_C, NOTE_Cs, NOTE_D, NOTE_Eb, NOTE_E, NOTE_F, NOTE_Fs, NOTE_G, NOTE_Gs, NOTE_A, NOTE_Bb, NOTE_B, NOTE_MAX
|
||||
} note_t;
|
||||
|
||||
//channel 0-15 resolution 1-16bits freq limits depend on resolution
|
||||
double ledcSetup(uint8_t channel, double freq, uint8_t resolution_bits);
|
||||
void ledcWrite(uint8_t channel, uint32_t duty);
|
||||
double ledcWriteTone(uint8_t channel, double freq);
|
||||
double ledcWriteNote(uint8_t channel, note_t note, uint8_t octave);
|
||||
uint32_t ledcRead(uint8_t channel);
|
||||
double ledcReadFreq(uint8_t channel);
|
||||
void ledcAttachPin(uint8_t pin, uint8_t channel);
|
||||
void ledcDetachPin(uint8_t pin);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ESP32_HAL_LEDC_H_ */
|
@ -45,22 +45,6 @@
|
||||
#include "rom/rtc.h"
|
||||
#endif
|
||||
|
||||
//Undocumented!!! Get chip temperature in Farenheit
|
||||
//Source: https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_int_temp_sensor/ESP32_int_temp_sensor.ino
|
||||
uint8_t temprature_sens_read();
|
||||
|
||||
float temperatureRead()
|
||||
{
|
||||
return (temprature_sens_read() - 32) / 1.8;
|
||||
}
|
||||
|
||||
void __yield()
|
||||
{
|
||||
vPortYield();
|
||||
}
|
||||
|
||||
void yield() __attribute__ ((weak, alias("__yield")));
|
||||
|
||||
unsigned long ARDUINO_ISR_ATTR micros()
|
||||
{
|
||||
return (unsigned long) (esp_timer_get_time());
|
||||
|
@ -1,138 +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 <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/spiram.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/spiram.h"
|
||||
#include "esp32s2/rom/cache.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "esp_spiram.h"
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
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;
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
extern void esp_config_data_cache_mode(void);
|
||||
esp_config_data_cache_mode();
|
||||
Cache_Enable_DCache(0);
|
||||
#endif
|
||||
if (esp_spiram_init() != ESP_OK) {
|
||||
spiramFailed = true;
|
||||
log_w("PSRAM init failed!");
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
pinMatrixOutDetach(16, false, false);
|
||||
pinMatrixOutDetach(17, false, false);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
esp_spiram_init_cache();
|
||||
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;
|
||||
}
|
||||
#if CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL && !CONFIG_ARDUINO_ISR_IRAM
|
||||
heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
|
||||
#endif
|
||||
#endif
|
||||
spiramDetected = true;
|
||||
log_d("PSRAM enabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ARDUINO_ISR_ATTR psramFound(){
|
||||
return spiramDetected;
|
||||
}
|
||||
|
||||
void ARDUINO_ISR_ATTR *ps_malloc(size_t size){
|
||||
if(!spiramDetected){
|
||||
return NULL;
|
||||
}
|
||||
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
}
|
||||
|
||||
void ARDUINO_ISR_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 ARDUINO_ISR_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 ARDUINO_ISR_ATTR psramFound(){
|
||||
return false;
|
||||
}
|
||||
|
||||
void ARDUINO_ISR_ATTR *ps_malloc(size_t size){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ARDUINO_ISR_ATTR *ps_calloc(size_t n, size_t size){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ARDUINO_ISR_ATTR *ps_realloc(void *ptr, size_t size){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,44 +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.
|
||||
|
||||
#ifndef _ESP32_HAL_PSRAM_H_
|
||||
#define _ESP32_HAL_PSRAM_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifndef BOARD_HAS_PSRAM
|
||||
#ifdef CONFIG_SPIRAM_SUPPORT
|
||||
#undef CONFIG_SPIRAM_SUPPORT
|
||||
#endif
|
||||
#ifdef CONFIG_SPIRAM
|
||||
#undef CONFIG_SPIRAM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool psramInit();
|
||||
bool psramFound();
|
||||
|
||||
void *ps_malloc(size_t size);
|
||||
void *ps_calloc(size_t n, size_t size);
|
||||
void *ps_realloc(void *ptr, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ESP32_HAL_PSRAM_H_ */
|
@ -1,878 +0,0 @@
|
||||
// Copyright 2018 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 "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "esp32-hal-log.h"
|
||||
#include "esp8266-compat.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/rmt_struct.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "hal/rmt_ll.h"
|
||||
#include "driver/rmt.h"
|
||||
#include "esp32-hal-rmt.h"
|
||||
#include "esp32-hal-gpio.h"
|
||||
#include "esp32-hal-matrix.h"
|
||||
|
||||
// RMTMEM address is declared in <target>.peripherals.ld
|
||||
extern rmt_mem_t RMTMEM;
|
||||
|
||||
/**
|
||||
* Internal macros
|
||||
*/
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#define MAX_CHANNELS 8
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define MAX_CHANNELS 4
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#define MAX_DATA_PER_CHANNEL 64
|
||||
#define MAX_DATA_PER_ITTERATION 62
|
||||
#define _ABS(a) (a>0?a:-a)
|
||||
#define _LIMIT(a,b) (a>b?b:a)
|
||||
#define __INT_TX_END (1)
|
||||
#define __INT_RX_END (2)
|
||||
#define __INT_ERROR (4)
|
||||
#define __INT_THR_EVNT (1<<24)
|
||||
|
||||
#define _INT_TX_END(channel) (__INT_TX_END<<(channel*3))
|
||||
#define _INT_RX_END(channel) (__INT_RX_END<<(channel*3))
|
||||
#define _INT_ERROR(channel) (__INT_ERROR<<(channel*3))
|
||||
#define _INT_THR_EVNT(channel) ((__INT_THR_EVNT)<<(channel))
|
||||
|
||||
#if CONFIG_DISABLE_HAL_LOCKS
|
||||
# define RMT_MUTEX_LOCK(channel)
|
||||
# define RMT_MUTEX_UNLOCK(channel)
|
||||
#else
|
||||
# define RMT_MUTEX_LOCK(channel) do {} while (xSemaphoreTake(g_rmt_objlocks[channel], portMAX_DELAY) != pdPASS)
|
||||
# define RMT_MUTEX_UNLOCK(channel) xSemaphoreGive(g_rmt_objlocks[channel])
|
||||
#endif /* CONFIG_DISABLE_HAL_LOCKS */
|
||||
|
||||
#define _RMT_INTERNAL_DEBUG
|
||||
#ifdef _RMT_INTERNAL_DEBUG
|
||||
# define DEBUG_INTERRUPT_START(pin) digitalWrite(pin, 1);
|
||||
# define DEBUG_INTERRUPT_END(pin) digitalWrite(pin, 0);
|
||||
#else
|
||||
# define DEBUG_INTERRUPT_START(pin)
|
||||
# define DEBUG_INTERRUPT_END(pin)
|
||||
#endif /* _RMT_INTERNAL_DEBUG */
|
||||
|
||||
/**
|
||||
* Typedefs for internal stuctures, enums
|
||||
*/
|
||||
typedef enum {
|
||||
E_NO_INTR = 0,
|
||||
E_TX_INTR = 1,
|
||||
E_TXTHR_INTR = 2,
|
||||
E_RX_INTR = 4,
|
||||
} intr_mode_t;
|
||||
|
||||
typedef enum {
|
||||
E_INACTIVE = 0,
|
||||
E_FIRST_HALF = 1,
|
||||
E_LAST_DATA = 2,
|
||||
E_END_TRANS = 4,
|
||||
E_SET_CONTI = 8,
|
||||
} transaction_state_t;
|
||||
|
||||
struct rmt_obj_s
|
||||
{
|
||||
bool allocated;
|
||||
EventGroupHandle_t events;
|
||||
int pin;
|
||||
int channel;
|
||||
bool tx_not_rx;
|
||||
int buffers;
|
||||
int data_size;
|
||||
uint32_t* data_ptr;
|
||||
intr_mode_t intr_mode;
|
||||
transaction_state_t tx_state;
|
||||
rmt_rx_data_cb_t cb;
|
||||
bool data_alloc;
|
||||
void * arg;
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal variables for channel descriptors
|
||||
*/
|
||||
static SemaphoreHandle_t g_rmt_objlocks[MAX_CHANNELS] = {
|
||||
NULL, NULL, NULL, NULL,
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
NULL, NULL, NULL, NULL
|
||||
#endif
|
||||
};
|
||||
|
||||
static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = {
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal variables for driver data
|
||||
*/
|
||||
static intr_handle_t intr_handle;
|
||||
|
||||
static bool periph_enabled = false;
|
||||
|
||||
static SemaphoreHandle_t g_rmt_block_lock = NULL;
|
||||
|
||||
/**
|
||||
* Internal method (private) declarations
|
||||
*/
|
||||
static void _initPin(int pin, int channel, bool tx_not_rx);
|
||||
|
||||
static bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size, bool continuous);
|
||||
|
||||
static void ARDUINO_ISR_ATTR _rmt_isr(void* arg);
|
||||
|
||||
static rmt_obj_t* _rmtAllocate(int pin, int from, int size);
|
||||
|
||||
static void _initPin(int pin, int channel, bool tx_not_rx);
|
||||
|
||||
static int ARDUINO_ISR_ATTR _rmt_get_mem_len(uint8_t channel);
|
||||
|
||||
static void ARDUINO_ISR_ATTR _rmt_tx_mem_first(uint8_t ch);
|
||||
|
||||
static void ARDUINO_ISR_ATTR _rmt_tx_mem_second(uint8_t ch);
|
||||
|
||||
|
||||
/**
|
||||
* Public method definitions
|
||||
*/
|
||||
bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t low, uint32_t high)
|
||||
{
|
||||
if (!rmt || low > 0xFFFF || high > 0xFFFF) {
|
||||
return false;
|
||||
}
|
||||
size_t channel = rmt->channel;
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
|
||||
RMT.carrier_duty_ch[channel].low = low;
|
||||
RMT.carrier_duty_ch[channel].high = high;
|
||||
RMT.conf_ch[channel].conf0.carrier_en = carrier_en;
|
||||
RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level;
|
||||
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level)
|
||||
{
|
||||
if (!rmt || filter_level > 0xFF) {
|
||||
return false;
|
||||
}
|
||||
size_t channel = rmt->channel;
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
|
||||
RMT.conf_ch[channel].conf1.rx_filter_thres = filter_level;
|
||||
RMT.conf_ch[channel].conf1.rx_filter_en = filter_en;
|
||||
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool rmtSetRxThreshold(rmt_obj_t* rmt, uint32_t value)
|
||||
{
|
||||
if (!rmt || value > 0xFFFF) {
|
||||
return false;
|
||||
}
|
||||
size_t channel = rmt->channel;
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
RMT.conf_ch[channel].conf0.idle_thres = value;
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool rmtDeinit(rmt_obj_t *rmt)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// sanity check
|
||||
if (rmt != &(g_rmt_objects[rmt->channel])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t from = rmt->channel;
|
||||
size_t to = rmt->buffers + rmt->channel;
|
||||
size_t i;
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(g_rmt_objlocks[from] != NULL) {
|
||||
vSemaphoreDelete(g_rmt_objlocks[from]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (g_rmt_objects[from].data_alloc) {
|
||||
free(g_rmt_objects[from].data_ptr);
|
||||
}
|
||||
|
||||
for (i = from; i < to; i++) {
|
||||
g_rmt_objects[i].allocated = false;
|
||||
}
|
||||
|
||||
g_rmt_objects[from].channel = 0;
|
||||
g_rmt_objects[from].buffers = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rmtLoop(rmt_obj_t* rmt, rmt_data_t* data, size_t size)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int allocated_size = MAX_DATA_PER_CHANNEL * rmt->buffers;
|
||||
|
||||
if (size > allocated_size) {
|
||||
return false;
|
||||
}
|
||||
return _rmtSendOnce(rmt, data, size, true);
|
||||
}
|
||||
|
||||
bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int channel = rmt->channel;
|
||||
int allocated_size = MAX_DATA_PER_CHANNEL * rmt->buffers;
|
||||
|
||||
if (size > allocated_size) {
|
||||
|
||||
int half_tx_nr = MAX_DATA_PER_ITTERATION/2;
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
// setup interrupt handler if not yet installed for half and full tx
|
||||
if (!intr_handle) {
|
||||
esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, _rmt_isr, NULL, &intr_handle);
|
||||
}
|
||||
|
||||
rmt->data_size = size - MAX_DATA_PER_ITTERATION;
|
||||
rmt->data_ptr = ((uint32_t*)data) + MAX_DATA_PER_ITTERATION;
|
||||
rmt->intr_mode = E_TX_INTR | E_TXTHR_INTR;
|
||||
rmt->tx_state = E_SET_CONTI | E_FIRST_HALF;
|
||||
|
||||
// init the tx limit for interruption
|
||||
RMT.tx_lim_ch[channel].limit = half_tx_nr+2;
|
||||
// reset memory pointer
|
||||
RMT.conf_ch[channel].conf1.apb_mem_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.apb_mem_rst = 0;
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 0;
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 0;
|
||||
|
||||
// set the tx end mark
|
||||
RMTMEM.chan[channel].data32[MAX_DATA_PER_ITTERATION].val = 0;
|
||||
|
||||
// clear and enable both Tx completed and half tx event
|
||||
RMT.int_clr.val = _INT_TX_END(channel);
|
||||
RMT.int_clr.val = _INT_THR_EVNT(channel);
|
||||
RMT.int_clr.val = _INT_ERROR(channel);
|
||||
|
||||
RMT.int_ena.val |= _INT_TX_END(channel);
|
||||
RMT.int_ena.val |= _INT_THR_EVNT(channel);
|
||||
RMT.int_ena.val |= _INT_ERROR(channel);
|
||||
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
// start the transation
|
||||
return _rmtSendOnce(rmt, data, MAX_DATA_PER_ITTERATION, false);
|
||||
} else {
|
||||
// use one-go mode if data fits one buffer
|
||||
return _rmtSendOnce(rmt, data, size, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
|
||||
if (g_rmt_objects[channel].buffers < size/MAX_DATA_PER_CHANNEL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
volatile uint32_t* rmt_mem_ptr = &(RMTMEM.chan[channel].data32[0].val);
|
||||
for (i=0; i<size; i++) {
|
||||
data[i] = *rmt_mem_ptr++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool rmtBeginReceive(rmt_obj_t* rmt)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
|
||||
RMT.int_clr.val = _INT_ERROR(channel);
|
||||
RMT.int_ena.val |= _INT_ERROR(channel);
|
||||
|
||||
RMT.conf_ch[channel].conf1.mem_owner = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rmtReceiveCompleted(rmt_obj_t* rmt)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
|
||||
if (RMT.int_raw.val&_INT_RX_END(channel)) {
|
||||
// RX end flag
|
||||
RMT.int_clr.val = _INT_RX_END(channel);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb, void * arg)
|
||||
{
|
||||
if (!rmt && !cb) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
rmt->arg = arg;
|
||||
rmt->intr_mode = E_RX_INTR;
|
||||
rmt->tx_state = E_FIRST_HALF;
|
||||
rmt->cb = cb;
|
||||
// allocate internally two buffers which would alternate
|
||||
if (!rmt->data_alloc) {
|
||||
rmt->data_ptr = (uint32_t*)malloc(2*MAX_DATA_PER_CHANNEL*(rmt->buffers)*sizeof(uint32_t));
|
||||
rmt->data_size = MAX_DATA_PER_CHANNEL*rmt->buffers;
|
||||
rmt->data_alloc = true;
|
||||
}
|
||||
|
||||
RMT.conf_ch[channel].conf1.mem_owner = 1;
|
||||
|
||||
RMT.int_clr.val = _INT_RX_END(channel);
|
||||
RMT.int_clr.val = _INT_ERROR(channel);
|
||||
|
||||
RMT.int_ena.val |= _INT_RX_END(channel);
|
||||
RMT.int_ena.val |= _INT_ERROR(channel);
|
||||
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
|
||||
RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rmtEnd(rmt_obj_t* rmt) {
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
|
||||
if (g_rmt_objects[channel].buffers < size/MAX_DATA_PER_CHANNEL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (eventFlag) {
|
||||
xEventGroupClearBits(eventFlag, RMT_FLAGS_ALL);
|
||||
rmt->events = eventFlag;
|
||||
}
|
||||
|
||||
if (data && size>0) {
|
||||
rmt->data_ptr = (uint32_t*)data;
|
||||
rmt->data_size = size;
|
||||
}
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
rmt->intr_mode = E_RX_INTR;
|
||||
|
||||
RMT.conf_ch[channel].conf1.mem_owner = 1;
|
||||
|
||||
RMT.int_clr.val = _INT_RX_END(channel);
|
||||
RMT.int_clr.val = _INT_ERROR(channel);
|
||||
|
||||
RMT.int_ena.val |= _INT_RX_END(channel);
|
||||
RMT.int_ena.val |= _INT_ERROR(channel);
|
||||
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
|
||||
RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
// wait for data if requested so
|
||||
if (waitForData && eventFlag) {
|
||||
uint32_t flags = xEventGroupWaitBits(eventFlag, RMT_FLAGS_ALL,
|
||||
pdTRUE /* clear on exit */, pdFALSE /* wait for all bits */, timeout);
|
||||
if (flags & RMT_FLAG_ERROR) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float rmtSetTick(rmt_obj_t* rmt, float tick)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
divider field span from 1 (smallest), 2, 3, ... , 0xFF, 0x00 (highest)
|
||||
* rmt tick from 1/80M -> 12.5ns (1x) div_cnt = 0x01
|
||||
3.2 us (256x) div_cnt = 0x00
|
||||
* rmt tick for 1 MHz -> 1us (1x) div_cnt = 0x01
|
||||
256us (256x) div_cnt = 0x00
|
||||
*/
|
||||
int apb_div = _LIMIT(tick/12.5, 256);
|
||||
int ref_div = _LIMIT(tick/1000, 256);
|
||||
|
||||
float apb_tick = 12.5 * apb_div;
|
||||
float ref_tick = 1000.0 * ref_div;
|
||||
|
||||
size_t channel = rmt->channel;
|
||||
|
||||
if (_ABS(apb_tick - tick) < _ABS(ref_tick - tick)) {
|
||||
RMT.conf_ch[channel].conf0.div_cnt = apb_div & 0xFF;
|
||||
RMT.conf_ch[channel].conf1.ref_always_on = 1;
|
||||
return apb_tick;
|
||||
} else {
|
||||
RMT.conf_ch[channel].conf0.div_cnt = ref_div & 0xFF;
|
||||
RMT.conf_ch[channel].conf1.ref_always_on = 0;
|
||||
return ref_tick;
|
||||
}
|
||||
}
|
||||
|
||||
rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize)
|
||||
{
|
||||
int buffers = memsize;
|
||||
rmt_obj_t* rmt;
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
// create common block mutex for protecting allocs from multiple threads
|
||||
if (!g_rmt_block_lock) {
|
||||
g_rmt_block_lock = xSemaphoreCreateMutex();
|
||||
}
|
||||
// lock
|
||||
while (xSemaphoreTake(g_rmt_block_lock, portMAX_DELAY) != pdPASS) {}
|
||||
|
||||
for (i=0; i<MAX_CHANNELS; i++) {
|
||||
for (j=0; j<buffers && i+j < MAX_CHANNELS; j++) {
|
||||
// if the space is ocupied break and continue on other channel
|
||||
if (g_rmt_objects[i+j].allocated) {
|
||||
i += j; // continue searching from latter channel
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == buffers) {
|
||||
// found a space in channel descriptors
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == MAX_CHANNELS || i+j > MAX_CHANNELS || j != buffers) {
|
||||
xSemaphoreGive(g_rmt_block_lock);
|
||||
return NULL;
|
||||
}
|
||||
rmt = _rmtAllocate(pin, i, buffers);
|
||||
|
||||
xSemaphoreGive(g_rmt_block_lock);
|
||||
|
||||
size_t channel = i;
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(g_rmt_objlocks[channel] == NULL) {
|
||||
g_rmt_objlocks[channel] = xSemaphoreCreateMutex();
|
||||
if(g_rmt_objlocks[channel] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
|
||||
rmt->pin = pin;
|
||||
rmt->tx_not_rx = tx_not_rx;
|
||||
rmt->buffers =buffers;
|
||||
rmt->channel = channel;
|
||||
rmt->arg = NULL;
|
||||
|
||||
_initPin(pin, channel, tx_not_rx);
|
||||
|
||||
// Initialize the registers in default mode:
|
||||
// - no carrier, filter
|
||||
// - timebase tick of 1us
|
||||
// - idle threshold set to 0x8000 (max pulse width + 1)
|
||||
RMT.conf_ch[channel].conf0.div_cnt = 1;
|
||||
RMT.conf_ch[channel].conf0.mem_size = buffers;
|
||||
RMT.conf_ch[channel].conf0.carrier_en = 0;
|
||||
RMT.conf_ch[channel].conf0.carrier_out_lv = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
RMT.conf_ch[channel].conf0.mem_pd = 0;
|
||||
#endif
|
||||
RMT.conf_ch[channel].conf0.idle_thres = 0x80;
|
||||
RMT.conf_ch[channel].conf1.rx_en = 0;
|
||||
RMT.conf_ch[channel].conf1.tx_conti_mode = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
RMT.conf_ch[channel].conf1.ref_cnt_rst = 0;
|
||||
#else
|
||||
RMT.conf_ch[channel].conf1.chk_rx_carrier_en = 0;
|
||||
#endif
|
||||
RMT.conf_ch[channel].conf1.rx_filter_en = 0;
|
||||
RMT.conf_ch[channel].conf1.rx_filter_thres = 0;
|
||||
RMT.conf_ch[channel].conf1.idle_out_lv = 0; // signal level for idle
|
||||
RMT.conf_ch[channel].conf1.idle_out_en = 1; // enable idle
|
||||
RMT.conf_ch[channel].conf1.ref_always_on = 0; // base clock
|
||||
|
||||
RMT.apb_conf.fifo_mask = 1;
|
||||
|
||||
if (tx_not_rx) {
|
||||
// RMT.conf_ch[channel].conf1.rx_en = 0;
|
||||
RMT.conf_ch[channel].conf1.mem_owner = 0;
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
} else {
|
||||
// RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_owner = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
}
|
||||
|
||||
// install interrupt if at least one channel is active
|
||||
if (!intr_handle) {
|
||||
esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, _rmt_isr, NULL, &intr_handle);
|
||||
}
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return rmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private methods definitions
|
||||
*/
|
||||
bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size, bool continuous)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
RMT.apb_conf.fifo_mask = 1;
|
||||
if (data && size>0) {
|
||||
size_t i;
|
||||
volatile uint32_t* rmt_mem_ptr = &(RMTMEM.chan[channel].data32[0].val);
|
||||
for (i = 0; i < size; i++) {
|
||||
*rmt_mem_ptr++ = data[i].val;
|
||||
}
|
||||
// tx end mark
|
||||
RMTMEM.chan[channel].data32[size].val = 0;
|
||||
}
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
RMT.conf_ch[channel].conf1.tx_conti_mode = continuous;
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.tx_start = 1;
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static rmt_obj_t* _rmtAllocate(int pin, int from, int size)
|
||||
{
|
||||
size_t i;
|
||||
// setup how many buffers shall we use
|
||||
g_rmt_objects[from].buffers = size;
|
||||
|
||||
for (i=0; i<size; i++) {
|
||||
// mark the block of channels as used
|
||||
g_rmt_objects[i+from].allocated = true;
|
||||
}
|
||||
return &(g_rmt_objects[from]);
|
||||
}
|
||||
|
||||
|
||||
static void _initPin(int pin, int channel, bool tx_not_rx)
|
||||
{
|
||||
if (!periph_enabled) {
|
||||
periph_enabled = true;
|
||||
periph_module_enable( PERIPH_RMT_MODULE );
|
||||
}
|
||||
if (tx_not_rx) {
|
||||
pinMode(pin, OUTPUT);
|
||||
pinMatrixOutAttach(pin, RMT_SIG_OUT0_IDX + channel, 0, 0);
|
||||
} else {
|
||||
pinMode(pin, INPUT);
|
||||
pinMatrixInAttach(pin, RMT_SIG_IN0_IDX + channel, 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ARDUINO_ISR_ATTR _rmt_isr(void* arg)
|
||||
{
|
||||
int intr_val = RMT.int_st.val;
|
||||
size_t ch;
|
||||
for (ch = 0; ch < MAX_CHANNELS; ch++) {
|
||||
|
||||
if (intr_val & _INT_RX_END(ch)) {
|
||||
// clear the flag
|
||||
RMT.int_clr.val = _INT_RX_END(ch);
|
||||
RMT.int_ena.val &= ~_INT_RX_END(ch);
|
||||
|
||||
if ((g_rmt_objects[ch].intr_mode) & E_RX_INTR) {
|
||||
if (g_rmt_objects[ch].events) {
|
||||
xEventGroupSetBits(g_rmt_objects[ch].events, RMT_FLAG_RX_DONE);
|
||||
}
|
||||
if (g_rmt_objects[ch].data_ptr && g_rmt_objects[ch].data_size > 0) {
|
||||
size_t i;
|
||||
uint32_t * data = g_rmt_objects[ch].data_ptr;
|
||||
// in case of callback, provide switching between memories
|
||||
if (g_rmt_objects[ch].cb) {
|
||||
if (g_rmt_objects[ch].tx_state & E_FIRST_HALF) {
|
||||
g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF;
|
||||
} else {
|
||||
g_rmt_objects[ch].tx_state |= E_FIRST_HALF;
|
||||
data += MAX_DATA_PER_CHANNEL*(g_rmt_objects[ch].buffers);
|
||||
}
|
||||
}
|
||||
uint32_t *data_received = data;
|
||||
for (i = 0; i < g_rmt_objects[ch].data_size; i++ ) {
|
||||
*data++ = RMTMEM.chan[ch].data32[i].val;
|
||||
}
|
||||
if (g_rmt_objects[ch].cb) {
|
||||
// actually received data ptr
|
||||
(g_rmt_objects[ch].cb)(data_received, _rmt_get_mem_len(ch), g_rmt_objects[ch].arg);
|
||||
|
||||
// restart the reception
|
||||
RMT.conf_ch[ch].conf1.mem_owner = 1;
|
||||
RMT.conf_ch[ch].conf1.mem_wr_rst = 1;
|
||||
RMT.conf_ch[ch].conf1.rx_en = 1;
|
||||
RMT.int_ena.val |= _INT_RX_END(ch);
|
||||
} else {
|
||||
// if not callback provide, expect only one Rx
|
||||
g_rmt_objects[ch].intr_mode &= ~E_RX_INTR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Report error and disable Rx interrupt
|
||||
log_e("Unexpected Rx interrupt!\n"); // TODO: eplace messages with log_X
|
||||
RMT.int_ena.val &= ~_INT_RX_END(ch);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (intr_val & _INT_ERROR(ch)) {
|
||||
// clear the flag
|
||||
RMT.int_clr.val = _INT_ERROR(ch);
|
||||
RMT.int_ena.val &= ~_INT_ERROR(ch);
|
||||
// report error
|
||||
log_e("RMT Error %d!\n", ch);
|
||||
if (g_rmt_objects[ch].events) {
|
||||
xEventGroupSetBits(g_rmt_objects[ch].events, RMT_FLAG_ERROR);
|
||||
}
|
||||
// reset memory
|
||||
RMT.conf_ch[ch].conf1.mem_rd_rst = 1;
|
||||
RMT.conf_ch[ch].conf1.mem_rd_rst = 0;
|
||||
RMT.conf_ch[ch].conf1.mem_wr_rst = 1;
|
||||
RMT.conf_ch[ch].conf1.mem_wr_rst = 0;
|
||||
}
|
||||
|
||||
if (intr_val & _INT_TX_END(ch)) {
|
||||
|
||||
RMT.int_clr.val = _INT_TX_END(ch);
|
||||
_rmt_tx_mem_second(ch);
|
||||
}
|
||||
|
||||
if (intr_val & _INT_THR_EVNT(ch)) {
|
||||
// clear the flag
|
||||
RMT.int_clr.val = _INT_THR_EVNT(ch);
|
||||
|
||||
// initial setup of continuous mode
|
||||
if (g_rmt_objects[ch].tx_state & E_SET_CONTI) {
|
||||
RMT.conf_ch[ch].conf1.tx_conti_mode = 1;
|
||||
g_rmt_objects[ch].intr_mode &= ~E_SET_CONTI;
|
||||
}
|
||||
_rmt_tx_mem_first(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ARDUINO_ISR_ATTR _rmt_tx_mem_second(uint8_t ch)
|
||||
{
|
||||
DEBUG_INTERRUPT_START(4)
|
||||
uint32_t* data = g_rmt_objects[ch].data_ptr;
|
||||
int half_tx_nr = MAX_DATA_PER_ITTERATION/2;
|
||||
int i;
|
||||
|
||||
RMT.tx_lim_ch[ch].limit = half_tx_nr+2;
|
||||
RMT.int_clr.val = _INT_THR_EVNT(ch);
|
||||
RMT.int_ena.val |= _INT_THR_EVNT(ch);
|
||||
|
||||
g_rmt_objects[ch].tx_state |= E_FIRST_HALF;
|
||||
|
||||
if (data) {
|
||||
int remaining_size = g_rmt_objects[ch].data_size;
|
||||
// will the remaining data occupy the entire halfbuffer
|
||||
if (remaining_size > half_tx_nr) {
|
||||
for (i = 0; i < half_tx_nr; i++) {
|
||||
RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i];
|
||||
}
|
||||
g_rmt_objects[ch].data_size -= half_tx_nr;
|
||||
g_rmt_objects[ch].data_ptr += half_tx_nr;
|
||||
} else {
|
||||
for (i = 0; i < half_tx_nr; i++) {
|
||||
if (i < remaining_size) {
|
||||
RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i];
|
||||
} else {
|
||||
RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F;
|
||||
}
|
||||
}
|
||||
g_rmt_objects[ch].data_ptr = NULL;
|
||||
|
||||
}
|
||||
} else if ((!(g_rmt_objects[ch].tx_state & E_LAST_DATA)) &&
|
||||
(!(g_rmt_objects[ch].tx_state & E_END_TRANS))) {
|
||||
for (i = 0; i < half_tx_nr; i++) {
|
||||
RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F;
|
||||
}
|
||||
RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0;
|
||||
g_rmt_objects[ch].tx_state |= E_LAST_DATA;
|
||||
RMT.conf_ch[ch].conf1.tx_conti_mode = 0;
|
||||
} else {
|
||||
log_d("RMT Tx finished %d!\n", ch);
|
||||
RMT.conf_ch[ch].conf1.tx_conti_mode = 0;
|
||||
RMT.int_ena.val &= ~_INT_TX_END(ch);
|
||||
RMT.int_ena.val &= ~_INT_THR_EVNT(ch);
|
||||
g_rmt_objects[ch].intr_mode = E_NO_INTR;
|
||||
g_rmt_objects[ch].tx_state = E_INACTIVE;
|
||||
}
|
||||
DEBUG_INTERRUPT_END(4);
|
||||
}
|
||||
|
||||
static void ARDUINO_ISR_ATTR _rmt_tx_mem_first(uint8_t ch)
|
||||
{
|
||||
DEBUG_INTERRUPT_START(2);
|
||||
uint32_t* data = g_rmt_objects[ch].data_ptr;
|
||||
int half_tx_nr = MAX_DATA_PER_ITTERATION/2;
|
||||
int i;
|
||||
RMT.int_ena.val &= ~_INT_THR_EVNT(ch);
|
||||
RMT.tx_lim_ch[ch].limit = 0;
|
||||
|
||||
if (data) {
|
||||
int remaining_size = g_rmt_objects[ch].data_size;
|
||||
|
||||
// will the remaining data occupy the entire halfbuffer
|
||||
if (remaining_size > half_tx_nr) {
|
||||
RMTMEM.chan[ch].data32[0].val = data[0] - 1;
|
||||
for (i = 1; i < half_tx_nr; i++) {
|
||||
RMTMEM.chan[ch].data32[i].val = data[i];
|
||||
}
|
||||
g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF;
|
||||
// turn off the treshold interrupt
|
||||
RMT.int_ena.val &= ~_INT_THR_EVNT(ch);
|
||||
RMT.tx_lim_ch[ch].limit = 0;
|
||||
g_rmt_objects[ch].data_size -= half_tx_nr;
|
||||
g_rmt_objects[ch].data_ptr += half_tx_nr;
|
||||
} else {
|
||||
RMTMEM.chan[ch].data32[0].val = data[0] - 1;
|
||||
for (i = 1; i < half_tx_nr; i++) {
|
||||
if (i < remaining_size) {
|
||||
RMTMEM.chan[ch].data32[i].val = data[i];
|
||||
} else {
|
||||
RMTMEM.chan[ch].data32[i].val = 0x000F000F;
|
||||
}
|
||||
}
|
||||
|
||||
g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF;
|
||||
g_rmt_objects[ch].data_ptr = NULL;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < half_tx_nr; i++) {
|
||||
RMTMEM.chan[ch].data32[i].val = 0x000F000F;
|
||||
}
|
||||
RMTMEM.chan[ch].data32[i].val = 0;
|
||||
|
||||
g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF;
|
||||
RMT.tx_lim_ch[ch].limit = 0;
|
||||
g_rmt_objects[ch].tx_state |= E_LAST_DATA;
|
||||
RMT.conf_ch[ch].conf1.tx_conti_mode = 0;
|
||||
}
|
||||
DEBUG_INTERRUPT_END(2);
|
||||
}
|
||||
|
||||
static int ARDUINO_ISR_ATTR _rmt_get_mem_len(uint8_t channel)
|
||||
{
|
||||
int block_num = RMT.conf_ch[channel].conf0.mem_size;
|
||||
int item_block_len = block_num * 64;
|
||||
volatile uint32_t* data = &RMTMEM.chan[channel].data32->val;
|
||||
int idx;
|
||||
for(idx = 0; idx < item_block_len; idx++) {
|
||||
rmt_item32_t helper;
|
||||
helper.val = data[idx];
|
||||
|
||||
if(helper.duration0 == 0) {
|
||||
return idx;
|
||||
} else if(helper.duration1 == 0) {
|
||||
return idx + 1;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef MAIN_ESP32_HAL_RMT_H_
|
||||
#define MAIN_ESP32_HAL_RMT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// notification flags
|
||||
#define RMT_FLAG_TX_DONE (1)
|
||||
#define RMT_FLAG_RX_DONE (2)
|
||||
#define RMT_FLAG_ERROR (4)
|
||||
#define RMT_FLAGS_ALL (RMT_FLAG_TX_DONE | RMT_FLAG_RX_DONE | RMT_FLAG_ERROR)
|
||||
|
||||
struct rmt_obj_s;
|
||||
|
||||
typedef enum {
|
||||
RMT_MEM_64 = 1,
|
||||
RMT_MEM_128 = 2,
|
||||
RMT_MEM_192 = 3,
|
||||
RMT_MEM_256 = 4,
|
||||
RMT_MEM_320 = 5,
|
||||
RMT_MEM_384 = 6,
|
||||
RMT_MEM_448 = 7,
|
||||
RMT_MEM_512 = 8,
|
||||
} rmt_reserve_memsize_t;
|
||||
|
||||
typedef struct rmt_obj_s rmt_obj_t;
|
||||
|
||||
typedef void (*rmt_rx_data_cb_t)(uint32_t *data, size_t len, void *arg);
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t duration0 :15;
|
||||
uint32_t level0 :1;
|
||||
uint32_t duration1 :15;
|
||||
uint32_t level1 :1;
|
||||
};
|
||||
uint32_t val;
|
||||
};
|
||||
} rmt_data_t;
|
||||
|
||||
/**
|
||||
* Initialize the object
|
||||
*
|
||||
*/
|
||||
rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize);
|
||||
|
||||
/**
|
||||
* Sets the clock/divider of timebase the nearest tick to the supplied value in nanoseconds
|
||||
* return the real actual tick value in ns
|
||||
*/
|
||||
float rmtSetTick(rmt_obj_t* rmt, float tick);
|
||||
|
||||
/**
|
||||
* Sending data in one-go mode or continual mode
|
||||
* (more data being send while updating buffers in interrupts)
|
||||
*
|
||||
*/
|
||||
bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size);
|
||||
|
||||
/**
|
||||
* Loop data up to the reserved memsize continuously
|
||||
*
|
||||
*/
|
||||
bool rmtLoop(rmt_obj_t* rmt, rmt_data_t* data, size_t size);
|
||||
|
||||
/**
|
||||
* Initiates async receive, event flag indicates data received
|
||||
*
|
||||
*/
|
||||
bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* Initiates async receive with automatic buffering
|
||||
* and callback with data from ISR
|
||||
*
|
||||
*/
|
||||
bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb, void * arg);
|
||||
|
||||
/***
|
||||
* Ends async receive started with rmtRead(); but does not
|
||||
* rmtDeInit().
|
||||
*/
|
||||
bool rmtEnd(rmt_obj_t* rmt);
|
||||
|
||||
/* Additional interface */
|
||||
|
||||
/**
|
||||
* Start reception
|
||||
*
|
||||
*/
|
||||
bool rmtBeginReceive(rmt_obj_t* rmt);
|
||||
|
||||
/**
|
||||
* Checks if reception completes
|
||||
*
|
||||
*/
|
||||
bool rmtReceiveCompleted(rmt_obj_t* rmt);
|
||||
|
||||
/**
|
||||
* Reads the data for particular channel
|
||||
*
|
||||
*/
|
||||
bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size);
|
||||
|
||||
/**
|
||||
* Setting threshold for Rx completed
|
||||
*/
|
||||
bool rmtSetRxThreshold(rmt_obj_t* rmt, uint32_t value);
|
||||
|
||||
/**
|
||||
* Setting carrier
|
||||
*/
|
||||
bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t low, uint32_t high);
|
||||
|
||||
/**
|
||||
* Setting input filter
|
||||
*/
|
||||
bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level);
|
||||
|
||||
/**
|
||||
* Deinitialize the driver
|
||||
*/
|
||||
bool rmtDeinit(rmt_obj_t *rmt);
|
||||
|
||||
// TODO:
|
||||
// * uninstall interrupt when all channels are deinit
|
||||
// * send only-conti mode with circular-buffer
|
||||
// * put sanity checks to some macro or inlines
|
||||
// * doxy comments
|
||||
// * error reporting
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MAIN_ESP32_HAL_RMT_H_ */
|
@ -1,133 +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 "esp32-hal-matrix.h"
|
||||
#include "soc/gpio_sd_reg.h"
|
||||
#include "soc/gpio_sd_struct.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp32-hal-cpu.h"
|
||||
#include "esp32-hal-gpio.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#endif
|
||||
|
||||
|
||||
#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)
|
||||
SemaphoreHandle_t _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();
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32
|
||||
SIGMADELTA.misc.function_clk_en = 1;
|
||||
#endif
|
||||
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,37 +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.
|
||||
|
||||
#ifndef _ESP32_HAL_SD_H_
|
||||
#define _ESP32_HAL_SD_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
//channel 0-7 freq 1220-312500 duty 0-255
|
||||
uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq);
|
||||
void sigmaDeltaWrite(uint8_t channel, uint8_t duty);
|
||||
uint8_t sigmaDeltaRead(uint8_t channel);
|
||||
void sigmaDeltaAttachPin(uint8_t pin, uint8_t channel);
|
||||
void sigmaDeltaDetachPin(uint8_t pin);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ESP32_HAL_SD_H_ */
|
@ -14,6 +14,10 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <esp_log.h>
|
||||
#define TAG "ARDUINO"
|
||||
|
||||
#include "esp32-hal-spi.h"
|
||||
#include "esp32-hal.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
@ -45,7 +49,6 @@
|
||||
#include "rom/gpio.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
#include "esp32-hal-gpio.h"
|
||||
#include "esp32-hal-matrix.h"
|
||||
#include "esp32-hal-cpu.h"
|
||||
|
||||
@ -146,7 +149,21 @@ void spiAttachSCK(spi_t * spi, int8_t sck)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pinMode(sck, OUTPUT);
|
||||
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = 1ULL << sck,
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
|
||||
pinMatrixOutAttach(sck, SPI_CLK_IDX(spi->num), false, false);
|
||||
}
|
||||
|
||||
@ -174,7 +191,21 @@ void spiAttachMISO(spi_t * spi, int8_t miso)
|
||||
#endif
|
||||
}
|
||||
SPI_MUTEX_LOCK();
|
||||
pinMode(miso, INPUT);
|
||||
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = (1ULL << miso),
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
|
||||
pinMatrixInAttach(miso, SPI_MISO_IDX(spi->num), false);
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
@ -202,7 +233,21 @@ void spiAttachMOSI(spi_t * spi, int8_t mosi)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pinMode(mosi, OUTPUT);
|
||||
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = (1ULL << mosi),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
|
||||
pinMatrixOutAttach(mosi, SPI_MOSI_IDX(spi->num), false, false);
|
||||
}
|
||||
|
||||
@ -230,7 +275,19 @@ void spiDetachSCK(spi_t * spi, int8_t sck)
|
||||
#endif
|
||||
}
|
||||
pinMatrixOutDetach(sck, false, false);
|
||||
pinMode(sck, INPUT);
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = (1ULL << sck),
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
}
|
||||
|
||||
void spiDetachMISO(spi_t * spi, int8_t miso)
|
||||
@ -257,7 +314,19 @@ void spiDetachMISO(spi_t * spi, int8_t miso)
|
||||
#endif
|
||||
}
|
||||
pinMatrixInDetach(SPI_MISO_IDX(spi->num), false, false);
|
||||
pinMode(miso, INPUT);
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = (1ULL << miso),
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
}
|
||||
|
||||
void spiDetachMOSI(spi_t * spi, int8_t mosi)
|
||||
@ -284,7 +353,19 @@ void spiDetachMOSI(spi_t * spi, int8_t mosi)
|
||||
#endif
|
||||
}
|
||||
pinMatrixOutDetach(mosi, false, false);
|
||||
pinMode(mosi, INPUT);
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = (1ULL << mosi),
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
}
|
||||
|
||||
void spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss)
|
||||
@ -314,7 +395,19 @@ void spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pinMode(ss, OUTPUT);
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = (1ULL << ss),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
pinMatrixOutAttach(ss, SPI_SS_IDX(spi->num, cs_num), false, false);
|
||||
spiEnableSSPins(spi, (1 << cs_num));
|
||||
}
|
||||
@ -343,7 +436,19 @@ void spiDetachSS(spi_t * spi, int8_t ss)
|
||||
#endif
|
||||
}
|
||||
pinMatrixOutDetach(ss, false, false);
|
||||
pinMode(ss, INPUT);
|
||||
{
|
||||
const gpio_config_t config = {
|
||||
.pin_bit_mask = (1ULL << ss),
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
|
||||
const int result = gpio_config(&config);
|
||||
if (result != ESP_OK)
|
||||
ESP_LOGE(TAG, "gpio_config() failed %s", esp_err_to_name(result));
|
||||
}
|
||||
}
|
||||
|
||||
void spiEnableSSPins(spi_t * spi, uint8_t cs_mask)
|
||||
@ -1278,7 +1383,7 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
|
||||
memcpy(&bestReg, ®, sizeof(bestReg));
|
||||
break;
|
||||
} else if(calFreq < (int32_t) freq) {
|
||||
if(abs(freq - calFreq) < abs(freq - bestFreq)) {
|
||||
if(freq - calFreq < freq - bestFreq) {
|
||||
bestFreq = calFreq;
|
||||
memcpy(&bestReg, ®, sizeof(bestReg));
|
||||
}
|
||||
|
@ -1,697 +0,0 @@
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_USB_ENABLED
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/usb_struct.h"
|
||||
#include "soc/usb_reg.h"
|
||||
#include "soc/usb_wrap_reg.h"
|
||||
#include "soc/usb_wrap_struct.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/system_reg.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
|
||||
#include "tinyusb.h"
|
||||
#include "esp32-hal.h"
|
||||
|
||||
#include "esp32-hal-tinyusb.h"
|
||||
#include "esp32s2/rom/usb/usb_persist.h"
|
||||
#include "esp32s2/rom/usb/usb_dc.h"
|
||||
#include "esp32s2/rom/usb/chip_usb_dw_wrapper.h"
|
||||
|
||||
typedef char tusb_str_t[127];
|
||||
|
||||
static bool WEBUSB_ENABLED = false;
|
||||
|
||||
static tusb_str_t WEBUSB_URL = "";
|
||||
static tusb_str_t USB_DEVICE_PRODUCT = "";
|
||||
static tusb_str_t USB_DEVICE_MANUFACTURER = "";
|
||||
static tusb_str_t USB_DEVICE_SERIAL = "";
|
||||
|
||||
static uint8_t USB_DEVICE_ATTRIBUTES = 0;
|
||||
static uint16_t USB_DEVICE_POWER = 0;
|
||||
|
||||
/*
|
||||
* Device Descriptor
|
||||
* */
|
||||
static tusb_desc_device_t tinyusb_device_descriptor = {
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0,
|
||||
.bDeviceClass = 0,
|
||||
.bDeviceSubClass = 0,
|
||||
.bDeviceProtocol = 0,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDOINT0_SIZE,
|
||||
|
||||
.idVendor = 0,
|
||||
.idProduct = 0,
|
||||
.bcdDevice = 0,
|
||||
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
/*
|
||||
* String Descriptors
|
||||
* */
|
||||
#define MAX_STRING_DESCRIPTORS 20
|
||||
static uint32_t tinyusb_string_descriptor_len = 4;
|
||||
static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = {
|
||||
// array of pointer to string descriptors
|
||||
"\x09\x04", // 0: is supported language is English (0x0409)
|
||||
USB_DEVICE_MANUFACTURER,// 1: Manufacturer
|
||||
USB_DEVICE_PRODUCT, // 2: Product
|
||||
USB_DEVICE_SERIAL, // 3: Serials, should use chip ID
|
||||
};
|
||||
|
||||
|
||||
/* Microsoft OS 2.0 registry property descriptor
|
||||
Per MS requirements https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx
|
||||
device should create DeviceInterfaceGUIDs. It can be done by driver and
|
||||
in case of real PnP solution device should expose MS "Microsoft OS 2.0
|
||||
registry property descriptor". Such descriptor can insert any record
|
||||
into Windows registry per device/configuration/interface. In our case it
|
||||
will insert "DeviceInterfaceGUIDs" multistring property.
|
||||
|
||||
GUID is freshly generated and should be OK to use.
|
||||
|
||||
https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/
|
||||
(Section Microsoft OS compatibility descriptors)
|
||||
*/
|
||||
|
||||
#define MS_OS_20_DESC_LEN 0xB2
|
||||
|
||||
static uint8_t const tinyusb_ms_os_20_descriptor[] =
|
||||
{
|
||||
// Set header: length, type, windows version, total length
|
||||
U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN),
|
||||
|
||||
// Configuration subset header: length, type, configuration index, reserved, configuration total length
|
||||
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A),
|
||||
|
||||
// Function Subset header: length, type, first interface, reserved, subset length
|
||||
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08),
|
||||
|
||||
// MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID
|
||||
U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible
|
||||
|
||||
// MS OS 2.0 Registry property descriptor: length, type
|
||||
U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY),
|
||||
U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
|
||||
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00,
|
||||
'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00,
|
||||
U16_TO_U8S_LE(0x0050), // wPropertyDataLength
|
||||
//bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”.
|
||||
'{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, 'D', 0x00, '9', 0x00, '-', 0x00,
|
||||
'0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00,
|
||||
'8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00,
|
||||
'8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(tinyusb_ms_os_20_descriptor) == MS_OS_20_DESC_LEN, "Incorrect size");
|
||||
|
||||
|
||||
/*
|
||||
* BOS Descriptor (required for webUSB)
|
||||
* */
|
||||
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
|
||||
|
||||
enum {
|
||||
VENDOR_REQUEST_WEBUSB = 1,
|
||||
VENDOR_REQUEST_MICROSOFT = 2
|
||||
};
|
||||
|
||||
static uint8_t const tinyusb_bos_descriptor[] = {
|
||||
// total length, number of device caps
|
||||
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2),
|
||||
|
||||
// Vendor Code, iLandingPage
|
||||
TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1),
|
||||
|
||||
// Microsoft OS 2.0 descriptor
|
||||
TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT)
|
||||
};
|
||||
|
||||
/*
|
||||
* URL Descriptor (required for webUSB)
|
||||
* */
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bScheme;
|
||||
char url[127];
|
||||
} tinyusb_desc_webusb_url_t;
|
||||
|
||||
static tinyusb_desc_webusb_url_t tinyusb_url_descriptor = {
|
||||
.bLength = 3,
|
||||
.bDescriptorType = 3, // WEBUSB URL type
|
||||
.bScheme = 1, // URL Scheme Prefix: 0: "http://", 1: "https://", 255: ""
|
||||
.url = ""
|
||||
};
|
||||
|
||||
/*
|
||||
* Configuration Descriptor
|
||||
* */
|
||||
|
||||
static tinyusb_descriptor_cb_t tinyusb_loaded_interfaces_callbacks[USB_INTERFACE_MAX];
|
||||
static uint32_t tinyusb_loaded_interfaces_mask = 0;
|
||||
static uint8_t tinyusb_loaded_interfaces_num = 0;
|
||||
static uint16_t tinyusb_config_descriptor_len = 0;
|
||||
static uint8_t * tinyusb_config_descriptor = NULL;
|
||||
|
||||
/*
|
||||
* Endpoint Usage Tracking
|
||||
* */
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t in:16;
|
||||
uint32_t out:16;
|
||||
};
|
||||
uint32_t val;
|
||||
} tinyusb_endpoints_usage_t;
|
||||
|
||||
static tinyusb_endpoints_usage_t tinyusb_endpoints;
|
||||
|
||||
|
||||
/*
|
||||
* TinyUSB Callbacks
|
||||
* */
|
||||
|
||||
/**
|
||||
* @brief Invoked when received GET CONFIGURATION DESCRIPTOR.
|
||||
*/
|
||||
uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
|
||||
{
|
||||
//log_d("%u", index);
|
||||
return tinyusb_config_descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Invoked when received GET DEVICE DESCRIPTOR.
|
||||
*/
|
||||
uint8_t const *tud_descriptor_device_cb(void)
|
||||
{
|
||||
//log_d("");
|
||||
return (uint8_t const *)&tinyusb_device_descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Invoked when received GET STRING DESCRIPTOR request.
|
||||
*/
|
||||
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||
{
|
||||
//log_d("%u (0x%x)", index, langid);
|
||||
static uint16_t _desc_str[127];
|
||||
uint8_t chr_count;
|
||||
|
||||
if (index == 0) {
|
||||
memcpy(&_desc_str[1], tinyusb_string_descriptor[0], 2);
|
||||
chr_count = 1;
|
||||
} else {
|
||||
// Convert ASCII string into UTF-16
|
||||
if (index >= tinyusb_string_descriptor_len) {
|
||||
return NULL;
|
||||
}
|
||||
const char *str = tinyusb_string_descriptor[index];
|
||||
// Cap at max char
|
||||
chr_count = strlen(str);
|
||||
if (chr_count > 126) {
|
||||
chr_count = 126;
|
||||
}
|
||||
for (uint8_t i = 0; i < chr_count; i++) {
|
||||
_desc_str[1 + i] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
// first byte is len, second byte is string type
|
||||
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
|
||||
|
||||
return _desc_str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Invoked when received GET BOS DESCRIPTOR request.
|
||||
*/
|
||||
uint8_t const * tud_descriptor_bos_cb(void)
|
||||
{
|
||||
//log_d("");
|
||||
return tinyusb_bos_descriptor;
|
||||
}
|
||||
|
||||
__attribute__ ((weak)) bool tinyusb_vendor_control_request_cb(uint8_t rhport, tusb_control_request_t const * request){ return false; }
|
||||
__attribute__ ((weak)) bool tinyusb_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const * request){ return true; }
|
||||
|
||||
/**
|
||||
* @brief Handle WebUSB and Vendor requests.
|
||||
*/
|
||||
bool tud_vendor_control_request_cb(uint8_t rhport, tusb_control_request_t const * request)
|
||||
{
|
||||
if(WEBUSB_ENABLED && (request->bRequest == VENDOR_REQUEST_WEBUSB
|
||||
|| (request->bRequest == VENDOR_REQUEST_MICROSOFT && request->wIndex == 7))){
|
||||
if(request->bRequest == VENDOR_REQUEST_WEBUSB){
|
||||
// match vendor request in BOS descriptor
|
||||
// Get landing page url
|
||||
tinyusb_url_descriptor.bLength = 3 + strlen(WEBUSB_URL);
|
||||
snprintf(tinyusb_url_descriptor.url, 127, "%s", WEBUSB_URL);
|
||||
return tud_control_xfer(rhport, request, (void*) &tinyusb_url_descriptor, tinyusb_url_descriptor.bLength);
|
||||
}
|
||||
// Get Microsoft OS 2.0 compatible descriptor
|
||||
uint16_t total_len;
|
||||
memcpy(&total_len, tinyusb_ms_os_20_descriptor + 8, 2);
|
||||
return tud_control_xfer(rhport, request, (void*) tinyusb_ms_os_20_descriptor, total_len);
|
||||
}
|
||||
return tinyusb_vendor_control_request_cb(rhport, request);
|
||||
}
|
||||
|
||||
bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const * request)
|
||||
{
|
||||
if(!WEBUSB_ENABLED || !(request->bRequest == VENDOR_REQUEST_WEBUSB
|
||||
|| (request->bRequest == VENDOR_REQUEST_MICROSOFT && request->wIndex == 7))){
|
||||
return tinyusb_vendor_control_complete_cb(rhport, request);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Required Callbacks
|
||||
* */
|
||||
#if CFG_TUD_HID
|
||||
__attribute__ ((weak)) const uint8_t * tud_hid_descriptor_report_cb(void){return NULL;}
|
||||
__attribute__ ((weak)) uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen){return 0;}
|
||||
__attribute__ ((weak)) void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, const uint8_t * buffer, uint16_t bufsize){}
|
||||
#endif
|
||||
#if CFG_TUD_MSC
|
||||
__attribute__ ((weak)) bool tud_msc_test_unit_ready_cb(uint8_t lun){return false;}
|
||||
__attribute__ ((weak)) void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]){}
|
||||
__attribute__ ((weak)) void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size){}
|
||||
__attribute__ ((weak)) int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){return -1;}
|
||||
__attribute__ ((weak)) int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){return -1;}
|
||||
__attribute__ ((weak)) int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize){return -1;}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Private API
|
||||
* */
|
||||
static bool usb_persist_enabled = false;
|
||||
static restart_type_t usb_persist_mode = RESTART_NO_PERSIST;
|
||||
|
||||
static bool tinyusb_reserve_in_endpoint(uint8_t endpoint){
|
||||
if(endpoint > 6 || (tinyusb_endpoints.in & BIT(endpoint)) != 0){
|
||||
return false;
|
||||
}
|
||||
tinyusb_endpoints.in |= BIT(endpoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool tinyusb_reserve_out_endpoint(uint8_t endpoint){
|
||||
if(endpoint > 6 || (tinyusb_endpoints.out & BIT(endpoint)) != 0){
|
||||
return false;
|
||||
}
|
||||
tinyusb_endpoints.out |= BIT(endpoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool tinyusb_has_available_fifos(void){
|
||||
uint8_t max_endpoints = 4, active_endpoints = 0;
|
||||
if (tinyusb_loaded_interfaces_mask & BIT(USB_INTERFACE_CDC)) {
|
||||
max_endpoints = 5; //CDC endpoint 0x85 is actually not linked to FIFO and not used
|
||||
}
|
||||
for(uint8_t i=1; i<7; i++){
|
||||
if((tinyusb_endpoints.in & BIT(i)) != 0){
|
||||
active_endpoints++;
|
||||
}
|
||||
}
|
||||
|
||||
return active_endpoints < max_endpoints;
|
||||
}
|
||||
|
||||
static uint16_t tinyusb_load_descriptor(tinyusb_interface_t interface, uint8_t * dst, uint8_t * itf)
|
||||
{
|
||||
if(tinyusb_loaded_interfaces_callbacks[interface]){
|
||||
return tinyusb_loaded_interfaces_callbacks[interface](dst, itf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool tinyusb_load_enabled_interfaces(){
|
||||
tinyusb_config_descriptor_len += TUD_CONFIG_DESC_LEN;
|
||||
tinyusb_config_descriptor = (uint8_t *)malloc(tinyusb_config_descriptor_len);
|
||||
if (tinyusb_config_descriptor == NULL) {
|
||||
log_e("Descriptor Malloc Failed");
|
||||
return false;
|
||||
}
|
||||
uint8_t * dst = tinyusb_config_descriptor + TUD_CONFIG_DESC_LEN;
|
||||
|
||||
for(int i=0; i<USB_INTERFACE_MAX; i++){
|
||||
if (tinyusb_loaded_interfaces_mask & (1U << i)) {
|
||||
uint16_t len = tinyusb_load_descriptor((tinyusb_interface_t)i, dst, &tinyusb_loaded_interfaces_num);
|
||||
if (!len) {
|
||||
log_e("Descriptor Load Failed");
|
||||
return false;
|
||||
} else {
|
||||
if(i == USB_INTERFACE_CDC){
|
||||
if(!tinyusb_reserve_out_endpoint(3) ||!tinyusb_reserve_in_endpoint(4) || !tinyusb_reserve_in_endpoint(5)){
|
||||
log_e("CDC Reserve Endpoints Failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
dst += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB Device");
|
||||
uint8_t descriptor[TUD_CONFIG_DESC_LEN] = {
|
||||
//num configs, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, tinyusb_loaded_interfaces_num, str_index, tinyusb_config_descriptor_len, USB_DEVICE_ATTRIBUTES, USB_DEVICE_POWER)
|
||||
};
|
||||
memcpy(tinyusb_config_descriptor, descriptor, TUD_CONFIG_DESC_LEN);
|
||||
if ((tinyusb_loaded_interfaces_mask == (BIT(USB_INTERFACE_CDC) | BIT(USB_INTERFACE_DFU))) || (tinyusb_loaded_interfaces_mask == BIT(USB_INTERFACE_CDC))) {
|
||||
usb_persist_enabled = true;
|
||||
log_d("USB Persist enabled");
|
||||
}
|
||||
log_d("Load Done: if_num: %u, descr_len: %u, if_mask: 0x%x", tinyusb_loaded_interfaces_num, tinyusb_config_descriptor_len, tinyusb_loaded_interfaces_mask);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline char nibble_to_hex_char(uint8_t b)
|
||||
{
|
||||
if (b < 0xa) {
|
||||
return '0' + b;
|
||||
} else {
|
||||
return 'a' + b - 0xa;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_usb_serial_num(void)
|
||||
{
|
||||
/* Get the MAC address */
|
||||
const uint32_t mac0 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_0_REG, EFUSE_MAC_0);
|
||||
const uint32_t mac1 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_1_REG, EFUSE_MAC_1);
|
||||
uint8_t mac_bytes[6];
|
||||
memcpy(mac_bytes, &mac0, 4);
|
||||
memcpy(mac_bytes + 4, &mac1, 2);
|
||||
|
||||
/* Convert to UTF16 string */
|
||||
uint8_t* srl = (uint8_t*)USB_DEVICE_SERIAL;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
uint8_t b = mac_bytes[5 - i]; /* printing from the MSB */
|
||||
if (i) {
|
||||
*srl++ = ':';
|
||||
}
|
||||
*srl++ = nibble_to_hex_char(b >> 4);
|
||||
*srl++ = nibble_to_hex_char(b & 0xf);
|
||||
}
|
||||
*srl++ = '\0';
|
||||
}
|
||||
|
||||
static void tinyusb_apply_device_config(tinyusb_device_config_t *config){
|
||||
if(config->product_name){
|
||||
snprintf(USB_DEVICE_PRODUCT, 126, "%s", config->product_name);
|
||||
}
|
||||
|
||||
if(config->manufacturer_name){
|
||||
snprintf(USB_DEVICE_MANUFACTURER, 126, "%s", config->manufacturer_name);
|
||||
}
|
||||
|
||||
if(config->serial_number && config->serial_number[0]){
|
||||
snprintf(USB_DEVICE_SERIAL, 126, "%s", config->serial_number);
|
||||
} else {
|
||||
set_usb_serial_num();
|
||||
}
|
||||
|
||||
if(config->webusb_url){
|
||||
snprintf(WEBUSB_URL, 126, "%s", config->webusb_url);
|
||||
}
|
||||
|
||||
WEBUSB_ENABLED = config->webusb_enabled;
|
||||
USB_DEVICE_ATTRIBUTES = config->usb_attributes;
|
||||
USB_DEVICE_POWER = config->usb_power_ma;
|
||||
|
||||
tinyusb_device_descriptor.bcdUSB = config->usb_version;
|
||||
tinyusb_device_descriptor.idVendor = config->vid;
|
||||
tinyusb_device_descriptor.idProduct = config->pid;
|
||||
tinyusb_device_descriptor.bcdDevice = config->fw_version;
|
||||
tinyusb_device_descriptor.bDeviceClass = config->usb_class;
|
||||
tinyusb_device_descriptor.bDeviceSubClass = config->usb_subclass;
|
||||
tinyusb_device_descriptor.bDeviceProtocol = config->usb_protocol;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR usb_persist_shutdown_handler(void)
|
||||
{
|
||||
if(usb_persist_mode != RESTART_NO_PERSIST){
|
||||
if (usb_persist_enabled) {
|
||||
usb_dc_prepare_persist();
|
||||
}
|
||||
if (usb_persist_mode == RESTART_BOOTLOADER) {
|
||||
//USB CDC Download
|
||||
if (usb_persist_enabled) {
|
||||
chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
|
||||
}
|
||||
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
|
||||
} else if (usb_persist_mode == RESTART_BOOTLOADER_DFU) {
|
||||
//DFU Download
|
||||
chip_usb_set_persist_flags(USBDC_BOOT_DFU);
|
||||
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
|
||||
} else if (usb_persist_enabled) {
|
||||
//USB Persist reboot
|
||||
chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// USB Device Driver task
|
||||
// This top level thread processes all usb events and invokes callbacks
|
||||
static void usb_device_task(void *param) {
|
||||
(void)param;
|
||||
while(1) tud_task(); // RTOS forever loop
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC API
|
||||
* */
|
||||
|
||||
esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb)
|
||||
{
|
||||
if((interface >= USB_INTERFACE_MAX) || (tinyusb_loaded_interfaces_mask & (1U << interface))){
|
||||
log_e("Interface %u not enabled", interface);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
tinyusb_loaded_interfaces_mask |= (1U << interface);
|
||||
tinyusb_config_descriptor_len += descriptor_len;
|
||||
tinyusb_loaded_interfaces_callbacks[interface] = cb;
|
||||
log_d("Interface %u enabled", interface);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
|
||||
static bool initialized = false;
|
||||
if(initialized){
|
||||
return ESP_OK;
|
||||
}
|
||||
initialized = true;
|
||||
|
||||
tinyusb_endpoints.val = 0;
|
||||
tinyusb_apply_device_config(config);
|
||||
if (!tinyusb_load_enabled_interfaces()) {
|
||||
initialized = false;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
bool usb_did_persist = (USB_WRAP.date.val == USBDC_PERSIST_ENA);
|
||||
|
||||
if(usb_did_persist && usb_persist_enabled){
|
||||
// Enable USB/IO_MUX peripheral reset, if coming from persistent reboot
|
||||
REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_IO_MUX_RESET_DISABLE);
|
||||
REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_USB_RESET_DISABLE);
|
||||
} else {
|
||||
// Reset USB module
|
||||
periph_module_reset(PERIPH_USB_MODULE);
|
||||
periph_module_enable(PERIPH_USB_MODULE);
|
||||
}
|
||||
|
||||
if (esp_register_shutdown_handler(usb_persist_shutdown_handler) != ESP_OK) {
|
||||
initialized = false;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false // In the most cases you need to use a `false` value
|
||||
};
|
||||
esp_err_t err = tinyusb_driver_install(&tusb_cfg);
|
||||
if (err != ESP_OK) {
|
||||
initialized = false;
|
||||
return err;
|
||||
}
|
||||
xTaskCreate(usb_device_task, "usbd", 4096, NULL, configMAX_PRIORITIES - 1, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
void usb_persist_restart(restart_type_t mode)
|
||||
{
|
||||
if (mode < RESTART_TYPE_MAX) {
|
||||
usb_persist_mode = mode;
|
||||
esp_restart();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t tinyusb_add_string_descriptor(const char * str){
|
||||
if(str == NULL || tinyusb_string_descriptor_len >= MAX_STRING_DESCRIPTORS){
|
||||
return 0;
|
||||
}
|
||||
uint8_t index = tinyusb_string_descriptor_len;
|
||||
tinyusb_string_descriptor[tinyusb_string_descriptor_len++] = (char*)str;
|
||||
return index;
|
||||
}
|
||||
|
||||
uint8_t tinyusb_get_free_duplex_endpoint(void){
|
||||
if(!tinyusb_has_available_fifos()){
|
||||
log_e("No available IN endpoints");
|
||||
return 0;
|
||||
}
|
||||
for(uint8_t i=1; i<7; i++){
|
||||
if((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) == 0){
|
||||
tinyusb_endpoints.in |= BIT(i);
|
||||
tinyusb_endpoints.out |= BIT(i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
log_e("No available duplex endpoints");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t tinyusb_get_free_in_endpoint(void){
|
||||
if(!tinyusb_has_available_fifos()){
|
||||
log_e("No available IN endpoints");
|
||||
return 0;
|
||||
}
|
||||
for(uint8_t i=1; i<7; i++){
|
||||
if((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) != 0){
|
||||
tinyusb_endpoints.in |= BIT(i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
for(uint8_t i=1; i<7; i++){
|
||||
if((tinyusb_endpoints.in & BIT(i)) == 0){
|
||||
tinyusb_endpoints.in |= BIT(i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t tinyusb_get_free_out_endpoint(void){
|
||||
for(uint8_t i=1; i<7; i++){
|
||||
if((tinyusb_endpoints.out & BIT(i)) == 0 && (tinyusb_endpoints.in & BIT(i)) != 0){
|
||||
tinyusb_endpoints.out |= BIT(i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
for(uint8_t i=1; i<7; i++){
|
||||
if((tinyusb_endpoints.out & BIT(i)) == 0){
|
||||
tinyusb_endpoints.out |= BIT(i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
void usb_dw_reg_dump(void)
|
||||
{
|
||||
#define USB_PRINT_REG(r) printf("USB0." #r " = 0x%x;\n", USB0.r)
|
||||
#define USB_PRINT_IREG(i, r) printf("USB0.in_ep_reg[%u]." #r " = 0x%x;\n", i, USB0.in_ep_reg[i].r)
|
||||
#define USB_PRINT_OREG(i, r) printf("USB0.out_ep_reg[%u]." #r " = 0x%x;\n", i, USB0.out_ep_reg[i].r)
|
||||
uint8_t i;
|
||||
USB_PRINT_REG(gotgctl);
|
||||
USB_PRINT_REG(gotgint);
|
||||
USB_PRINT_REG(gahbcfg);
|
||||
USB_PRINT_REG(gusbcfg);
|
||||
USB_PRINT_REG(grstctl);
|
||||
USB_PRINT_REG(gintsts);
|
||||
USB_PRINT_REG(gintmsk);
|
||||
USB_PRINT_REG(grxstsr);
|
||||
USB_PRINT_REG(grxstsp);
|
||||
USB_PRINT_REG(grxfsiz);
|
||||
USB_PRINT_REG(gnptxsts);
|
||||
USB_PRINT_REG(gpvndctl);
|
||||
USB_PRINT_REG(ggpio);
|
||||
USB_PRINT_REG(guid);
|
||||
USB_PRINT_REG(gsnpsid);
|
||||
USB_PRINT_REG(ghwcfg1);
|
||||
USB_PRINT_REG(ghwcfg2);
|
||||
USB_PRINT_REG(ghwcfg3);
|
||||
USB_PRINT_REG(ghwcfg4);
|
||||
USB_PRINT_REG(glpmcfg);
|
||||
USB_PRINT_REG(gpwrdn);
|
||||
USB_PRINT_REG(gdfifocfg);
|
||||
USB_PRINT_REG(gadpctl);
|
||||
USB_PRINT_REG(hptxfsiz);
|
||||
USB_PRINT_REG(hcfg);
|
||||
USB_PRINT_REG(hfir);
|
||||
USB_PRINT_REG(hfnum);
|
||||
USB_PRINT_REG(hptxsts);
|
||||
USB_PRINT_REG(haint);
|
||||
USB_PRINT_REG(haintmsk);
|
||||
USB_PRINT_REG(hflbaddr);
|
||||
USB_PRINT_REG(hprt);
|
||||
USB_PRINT_REG(dcfg);
|
||||
USB_PRINT_REG(dctl);
|
||||
USB_PRINT_REG(dsts);
|
||||
USB_PRINT_REG(diepmsk);
|
||||
USB_PRINT_REG(doepmsk);
|
||||
USB_PRINT_REG(daint);
|
||||
USB_PRINT_REG(daintmsk);
|
||||
USB_PRINT_REG(dtknqr1);
|
||||
USB_PRINT_REG(dtknqr2);
|
||||
USB_PRINT_REG(dvbusdis);
|
||||
USB_PRINT_REG(dvbuspulse);
|
||||
USB_PRINT_REG(dtknqr3_dthrctl);
|
||||
USB_PRINT_REG(dtknqr4_fifoemptymsk);
|
||||
USB_PRINT_REG(deachint);
|
||||
USB_PRINT_REG(deachintmsk);
|
||||
USB_PRINT_REG(pcgctrl);
|
||||
USB_PRINT_REG(pcgctrl1);
|
||||
USB_PRINT_REG(gnptxfsiz);
|
||||
for (i = 0; i < 4; i++) {
|
||||
printf("USB0.dieptxf[%u] = 0x%x;\n", i, USB0.dieptxf[i]);
|
||||
}
|
||||
// for (i = 0; i < 16; i++) {
|
||||
// printf("USB0.diepeachintmsk[%u] = 0x%x;\n", i, USB0.diepeachintmsk[i]);
|
||||
// }
|
||||
// for (i = 0; i < 16; i++) {
|
||||
// printf("USB0.doepeachintmsk[%u] = 0x%x;\n", i, USB0.doepeachintmsk[i]);
|
||||
// }
|
||||
for (i = 0; i < 7; i++) {
|
||||
printf("// EP %u:\n", i);
|
||||
USB_PRINT_IREG(i, diepctl);
|
||||
USB_PRINT_IREG(i, diepint);
|
||||
USB_PRINT_IREG(i, dieptsiz);
|
||||
USB_PRINT_IREG(i, diepdma);
|
||||
USB_PRINT_IREG(i, dtxfsts);
|
||||
USB_PRINT_OREG(i, doepctl);
|
||||
USB_PRINT_OREG(i, doepint);
|
||||
USB_PRINT_OREG(i, doeptsiz);
|
||||
USB_PRINT_OREG(i, doepdma);
|
||||
}
|
||||
}
|
||||
*/
|
||||
#endif /* CONFIG_USB_ENABLED */
|
@ -1,103 +0,0 @@
|
||||
// Copyright 2015-2020 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.
|
||||
#pragma once
|
||||
|
||||
#include "esp32-hal.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#if CONFIG_USB_ENABLED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "tinyusb.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
const char * product_name;
|
||||
const char * manufacturer_name;
|
||||
const char * serial_number;
|
||||
uint16_t fw_version;
|
||||
|
||||
uint16_t usb_version;
|
||||
uint8_t usb_class;
|
||||
uint8_t usb_subclass;
|
||||
uint8_t usb_protocol;
|
||||
uint8_t usb_attributes;
|
||||
uint16_t usb_power_ma;
|
||||
|
||||
bool webusb_enabled;
|
||||
const char * webusb_url;
|
||||
} tinyusb_device_config_t;
|
||||
|
||||
#define TINYUSB_CONFIG_DEFAULT() { \
|
||||
.vid = USB_ESPRESSIF_VID, \
|
||||
.pid = 0x0002, \
|
||||
.product_name = CONFIG_USB_DESC_PRODUCT_STRING, \
|
||||
.manufacturer_name = CONFIG_USB_DESC_MANUFACTURER_STRING, \
|
||||
.serial_number = CONFIG_USB_DESC_SERIAL_STRING, \
|
||||
.fw_version = CONFIG_USB_DESC_BCDDEVICE, \
|
||||
.usb_version = 0x0200, \
|
||||
.usb_class = TUSB_CLASS_MISC, \
|
||||
.usb_subclass = MISC_SUBCLASS_COMMON, \
|
||||
.usb_protocol = MISC_PROTOCOL_IAD, \
|
||||
.usb_attributes = TUSB_DESC_CONFIG_ATT_SELF_POWERED, \
|
||||
.usb_power_ma = 500, \
|
||||
.webusb_enabled = false, \
|
||||
.webusb_url = "espressif.github.io/arduino-esp32/webusb.html" \
|
||||
}
|
||||
|
||||
esp_err_t tinyusb_init(tinyusb_device_config_t *config);
|
||||
|
||||
/*
|
||||
* USB Persistence API
|
||||
* */
|
||||
typedef enum {
|
||||
RESTART_NO_PERSIST,
|
||||
RESTART_PERSIST,
|
||||
RESTART_BOOTLOADER,
|
||||
RESTART_BOOTLOADER_DFU,
|
||||
RESTART_TYPE_MAX
|
||||
} restart_type_t;
|
||||
|
||||
void usb_persist_restart(restart_type_t mode);
|
||||
|
||||
// The following definitions and functions are to be used only by the drivers
|
||||
typedef enum {
|
||||
USB_INTERFACE_CDC,
|
||||
USB_INTERFACE_DFU,
|
||||
USB_INTERFACE_HID,
|
||||
USB_INTERFACE_VENDOR,
|
||||
USB_INTERFACE_MSC,
|
||||
USB_INTERFACE_MIDI,
|
||||
USB_INTERFACE_CUSTOM,
|
||||
USB_INTERFACE_MAX
|
||||
} tinyusb_interface_t;
|
||||
|
||||
typedef uint16_t (*tinyusb_descriptor_cb_t)(uint8_t * dst, uint8_t * itf);
|
||||
|
||||
esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb);
|
||||
uint8_t tinyusb_add_string_descriptor(const char * str);
|
||||
uint8_t tinyusb_get_free_duplex_endpoint(void);
|
||||
uint8_t tinyusb_get_free_in_endpoint(void);
|
||||
uint8_t tinyusb_get_free_out_endpoint(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_USB_ENABLED */
|
||||
#endif /* CONFIG_IDF_TARGET_ESP32S2 */
|
@ -1,229 +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 "esp32-hal-touch.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "soc/sens_struct.h"
|
||||
#include "driver/touch_sensor.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
#include "esp32-hal-gpio.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 ARDUINO_ISR_ATTR __touchISR(void * arg)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
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]();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void __touchSetCycles(uint16_t measure, uint16_t sleep)
|
||||
{
|
||||
__touchSleepCycles = sleep;
|
||||
__touchMeasureCycles = measure;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
//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);
|
||||
#else
|
||||
touch_pad_set_meas_time(sleep, measure);
|
||||
#endif
|
||||
}
|
||||
|
||||
void __touchInit()
|
||||
{
|
||||
static bool initialized = false;
|
||||
if(initialized){
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
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);
|
||||
__touchSetCycles(__touchMeasureCycles, __touchSleepCycles);
|
||||
esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, __touchISR, NULL, &touch_intr_handle);
|
||||
#else
|
||||
touch_pad_init();
|
||||
touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_0V5);
|
||||
touch_pad_set_idle_channel_connect(TOUCH_PAD_CONN_GND);
|
||||
__touchSetCycles(__touchMeasureCycles, __touchSleepCycles);
|
||||
touch_pad_denoise_t denoise = {
|
||||
.grade = TOUCH_PAD_DENOISE_BIT4,
|
||||
.cap_level = TOUCH_PAD_DENOISE_CAP_L4,
|
||||
};
|
||||
touch_pad_denoise_set_config(&denoise);
|
||||
touch_pad_denoise_enable();
|
||||
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
|
||||
touch_pad_fsm_start();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t __touchRead(uint8_t pin)
|
||||
{
|
||||
int8_t pad = digitalPinToTouchChannel(pin);
|
||||
if(pad < 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
pinMode(pin, ANALOG);
|
||||
|
||||
__touchInit();
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
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;
|
||||
#else
|
||||
static uint32_t chan_mask = 0;
|
||||
uint32_t value = 0;
|
||||
if((chan_mask & (1 << pad)) == 0){
|
||||
if(touch_pad_set_thresh((touch_pad_t)pad, TOUCH_PAD_THRESHOLD_MAX) != ESP_OK){
|
||||
log_e("touch_pad_set_thresh failed");
|
||||
} else if(touch_pad_config((touch_pad_t)pad) != ESP_OK){
|
||||
log_e("touch_pad_config failed");
|
||||
} else {
|
||||
chan_mask |= (1 << pad);
|
||||
}
|
||||
}
|
||||
if((chan_mask & (1 << pad)) != 0) {
|
||||
if(touch_pad_read_raw_data((touch_pad_t)pad, &value) != ESP_OK){
|
||||
log_e("touch_pad_read_raw_data failed");
|
||||
}
|
||||
}
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
//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)));
|
||||
#else
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
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,56 +0,0 @@
|
||||
/*
|
||||
Arduino.h - Main include file for the Arduino SDK
|
||||
Copyright (c) 2005-2013 Arduino Team. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MAIN_ESP32_HAL_TOUCH_H_
|
||||
#define MAIN_ESP32_HAL_TOUCH_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Set cycles that measurement operation takes
|
||||
* The result from touchRead, threshold and detection
|
||||
* accuracy depend on these values. Defaults are
|
||||
* 0x1000 for measure and 0x1000 for sleep.
|
||||
* With default values touchRead takes 0.5ms
|
||||
* */
|
||||
void touchSetCycles(uint16_t measure, uint16_t sleep);
|
||||
|
||||
/*
|
||||
* Read touch pad (values close to 0 mean touch detected)
|
||||
* You can use this method to chose a good threshold value
|
||||
* to use as value for touchAttachInterrupt
|
||||
* */
|
||||
uint16_t touchRead(uint8_t pin);
|
||||
|
||||
/*
|
||||
* Set function to be called if touch pad value falls
|
||||
* below the given threshold. Use touchRead to determine
|
||||
* a proper threshold between touched and untouched state
|
||||
* */
|
||||
void touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t threshold);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MAIN_ESP32_HAL_TOUCH_H_ */
|
@ -1,161 +0,0 @@
|
||||
/*
|
||||
core_esp8266_noniso.c - nonstandard (but usefull) conversion functions
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Modified 03 April 2015 by Markus Sattler
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "stdlib_noniso.h"
|
||||
|
||||
void reverse(char* begin, char* end) {
|
||||
char *is = begin;
|
||||
char *ie = end - 1;
|
||||
while(is < ie) {
|
||||
char tmp = *ie;
|
||||
*ie = *is;
|
||||
*is = tmp;
|
||||
++is;
|
||||
--ie;
|
||||
}
|
||||
}
|
||||
|
||||
char* ltoa(long value, char* result, int base) {
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* out = result;
|
||||
long quotient = abs(value);
|
||||
|
||||
do {
|
||||
const long tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
|
||||
// Apply negative sign
|
||||
if(value < 0)
|
||||
*out++ = '-';
|
||||
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* ultoa(unsigned long value, char* result, int base) {
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* out = result;
|
||||
unsigned long quotient = value;
|
||||
|
||||
do {
|
||||
const unsigned long tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char * dtostrf(double number, signed char width, unsigned char prec, char *s) {
|
||||
bool negative = false;
|
||||
|
||||
if (isnan(number)) {
|
||||
strcpy(s, "nan");
|
||||
return s;
|
||||
}
|
||||
if (isinf(number)) {
|
||||
strcpy(s, "inf");
|
||||
return s;
|
||||
}
|
||||
|
||||
char* out = s;
|
||||
|
||||
int fillme = width; // how many cells to fill for the integer part
|
||||
if (prec > 0) {
|
||||
fillme -= (prec+1);
|
||||
}
|
||||
|
||||
// Handle negative numbers
|
||||
if (number < 0.0) {
|
||||
negative = true;
|
||||
fillme--;
|
||||
number = -number;
|
||||
}
|
||||
|
||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||
// I optimized out most of the divisions
|
||||
double rounding = 2.0;
|
||||
for (uint8_t i = 0; i < prec; ++i)
|
||||
rounding *= 10.0;
|
||||
rounding = 1.0 / rounding;
|
||||
|
||||
number += rounding;
|
||||
|
||||
// Figure out how big our number really is
|
||||
double tenpow = 1.0;
|
||||
int digitcount = 1;
|
||||
while (number >= 10.0 * tenpow) {
|
||||
tenpow *= 10.0;
|
||||
digitcount++;
|
||||
}
|
||||
|
||||
number /= tenpow;
|
||||
fillme -= digitcount;
|
||||
|
||||
// Pad unused cells with spaces
|
||||
while (fillme-- > 0) {
|
||||
*out++ = ' ';
|
||||
}
|
||||
|
||||
// Handle negative sign
|
||||
if (negative) *out++ = '-';
|
||||
|
||||
// Print the digits, and if necessary, the decimal point
|
||||
digitcount += prec;
|
||||
int8_t digit = 0;
|
||||
while (digitcount-- > 0) {
|
||||
digit = (int8_t)number;
|
||||
if (digit > 9) digit = 9; // insurance
|
||||
*out++ = (char)('0' | digit);
|
||||
if ((digitcount == prec) && (prec > 0)) {
|
||||
*out++ = '.';
|
||||
}
|
||||
number -= digit;
|
||||
number *= 10.0;
|
||||
}
|
||||
|
||||
// make sure the string is terminated
|
||||
*out = 0;
|
||||
return s;
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
stdlib_noniso.h - nonstandard (but usefull) conversion functions
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef STDLIB_NONISO_H
|
||||
#define STDLIB_NONISO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int atoi(const char *s);
|
||||
|
||||
long atol(const char* s);
|
||||
|
||||
double atof(const char* s);
|
||||
|
||||
char* itoa (int val, char *s, int radix);
|
||||
|
||||
char* ltoa (long val, char *s, int radix);
|
||||
|
||||
char* utoa (unsigned int val, char *s, int radix);
|
||||
|
||||
char* ultoa (unsigned long val, char *s, int radix);
|
||||
|
||||
char* dtostrf (double val, signed char width, unsigned char prec, char *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
pulse.c - wiring pulseIn implementation for esp8266
|
||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
//#include <limits.h>
|
||||
#include "wiring_private.h"
|
||||
#include "pins_arduino.h"
|
||||
|
||||
|
||||
extern uint32_t xthal_get_ccount();
|
||||
|
||||
#define WAIT_FOR_PIN_STATE(state) \
|
||||
while (digitalRead(pin) != (state)) { \
|
||||
if (xthal_get_ccount() - start_cycle_count > timeout_cycles) { \
|
||||
return 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
// max timeout is 27 seconds at 160MHz clock and 54 seconds at 80MHz clock
|
||||
//unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
|
||||
//{
|
||||
// const uint32_t max_timeout_us = clockCyclesToMicroseconds(UINT_MAX);
|
||||
// if (timeout > max_timeout_us) {
|
||||
// timeout = max_timeout_us;
|
||||
// }
|
||||
// const uint32_t timeout_cycles = microsecondsToClockCycles(timeout);
|
||||
// const uint32_t start_cycle_count = xthal_get_ccount();
|
||||
// WAIT_FOR_PIN_STATE(!state);
|
||||
// WAIT_FOR_PIN_STATE(state);
|
||||
// const uint32_t pulse_start_cycle_count = xthal_get_ccount();
|
||||
// WAIT_FOR_PIN_STATE(!state);
|
||||
// return clockCyclesToMicroseconds(xthal_get_ccount() - pulse_start_cycle_count);
|
||||
//}
|
||||
|
||||
//unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout)
|
||||
//{
|
||||
// return pulseIn(pin, state, timeout);
|
||||
//}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
wiring_shift.c - shiftOut() function
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
|
||||
*/
|
||||
|
||||
#include "wiring_shift.h"
|
||||
#include "esp32-hal.h"
|
||||
#include "wiring_private.h"
|
||||
#include "esp32-hal-gpio.h"
|
||||
|
||||
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
|
||||
uint8_t value = 0;
|
||||
uint8_t i;
|
||||
|
||||
for(i = 0; i < 8; ++i) {
|
||||
//digitalWrite(clockPin, HIGH);
|
||||
if(bitOrder == LSBFIRST)
|
||||
value |= digitalRead(dataPin) << i;
|
||||
else
|
||||
value |= digitalRead(dataPin) << (7 - i);
|
||||
digitalWrite(clockPin, HIGH);
|
||||
digitalWrite(clockPin, LOW);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) {
|
||||
uint8_t i;
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
if(bitOrder == LSBFIRST)
|
||||
digitalWrite(dataPin, !!(val & (1 << i)));
|
||||
else
|
||||
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
|
||||
|
||||
digitalWrite(clockPin, HIGH);
|
||||
digitalWrite(clockPin, LOW);
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define LSBFIRST 0
|
||||
#define MSBFIRST 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
|
||||
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
|
@ -30,7 +30,8 @@ extern "C" {
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <utility>
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include "goefmt.h"
|
||||
|
||||
#include "esp32-hal-i2c.h"
|
||||
#include "esp32-hal-log.h"
|
||||
@ -52,7 +53,7 @@ std::string toString(i2c_err_t val)
|
||||
case I2C_ERROR_NO_BEGIN: return "I2C_ERROR_NO_BEGIN";
|
||||
default:
|
||||
ESP_LOGW("WIRE", "unknown i2c_err_t(%i)", std::to_underlying(val));
|
||||
return fmt::format("Unknown i2c_err_t({})", std::to_underlying(val));
|
||||
return goe::format("Unknown i2c_err_t({})", std::to_underlying(val));
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,7 +225,7 @@ uint8_t TwoWire::requestFrom(uint16_t address, uint8_t size, bool sendStop)
|
||||
if(cnt < (I2C_BUFFER_LENGTH-1) && (size + cnt) <= I2C_BUFFER_LENGTH) { // any room left in rxBuffer
|
||||
rxQueued += size;
|
||||
} else { // no room to receive more!
|
||||
log_e("rxBuff overflow %d", cnt + size);
|
||||
log_e("rxBuff overflow %lu", cnt + size);
|
||||
cnt = 0;
|
||||
last_error = I2C_ERROR_MEMORY;
|
||||
flush();
|
||||
|
Reference in New Issue
Block a user