add some code
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(knob_power_save)
|
||||
@@ -0,0 +1,47 @@
|
||||
## Knob Power Save Example
|
||||
|
||||
This example demonstrates how to utilize the `knob` component in conjunction with the light sleep low-power mode.
|
||||
|
||||
* `knob` [Component Introduction](https://docs.espressif.com/projects/esp-iot-solution/en/latest/input_device/knob.html)
|
||||
|
||||
## Hardware
|
||||
|
||||
Any GPIO on any development board can be used in this example, for the default GPIO, please refer to the table below.
|
||||
|
||||
| Hardware | GPIO |
|
||||
| :-----------------: | :---: |
|
||||
| Encoder A (Phase A) | GPIO1 |
|
||||
| Encoder B (Phase B) | GPIO2 |
|
||||
|
||||
## Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run the monitor tool to view the serial output:
|
||||
|
||||
* Run `. ./export.sh` to set IDF environment
|
||||
* Run `idf.py set-target esp32xx` to set target chip
|
||||
* Run `idf.py -p PORT flash monitor` to build, flash and monitor the project
|
||||
|
||||
(To exit the serial monitor, type `Ctrl-]`.)
|
||||
|
||||
See the Getting Started Guide for all the steps to configure and use the ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (316) pm: Frequency switching config: CPU_MAX: 80, APB_MAX: 80, APB_MIN: 10, Light sleep: ENABLED
|
||||
I (322) sleep: Code start at 0x42000020, total 106515, data start at 0x3c020020, total 46384 Bytes
|
||||
I (331) gpio: GPIO[1]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (341) gpio: GPIO[2]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (350) Knob: Iot Knob Config Succeed, encoder A:1, encoder B:2, direction:0, Version: 0.1.4
|
||||
I (359) main_task: Returned from app_main()
|
||||
I (1503) knob_power_save: knob event KNOB_LEFT, -1
|
||||
I (1503) knob_power_save: Wake up from light sleep, reason 7
|
||||
I (1691) knob_power_save: knob event KNOB_LEFT, -2
|
||||
I (1691) knob_power_save: Wake up from light sleep, reason 7
|
||||
I (1860) knob_power_save: knob event KNOB_LEFT, -3
|
||||
I (1860) knob_power_save: Wake up from light sleep, reason 7
|
||||
I (1940) knob_power_save: knob event KNOB_LEFT, -4
|
||||
I (1940) knob_power_save: Wake up from light sleep, reason 7
|
||||
I (2017) knob_power_save: knob event KNOB_LEFT, -5
|
||||
I (2017) knob_power_save: Wake up from light sleep, reason 7
|
||||
```
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "knob_power_save.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,74 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice EXAMPLE_MAX_CPU_FREQ
|
||||
prompt "Maximum CPU frequency"
|
||||
default EXAMPLE_MAX_CPU_FREQ_80 if !IDF_TARGET_ESP32H2
|
||||
default EXAMPLE_MAX_CPU_FREQ_96 if IDF_TARGET_ESP32H2
|
||||
depends on PM_ENABLE
|
||||
help
|
||||
Maximum CPU frequency to use for dynamic frequency scaling.
|
||||
|
||||
config EXAMPLE_MAX_CPU_FREQ_80
|
||||
bool "80 MHz"
|
||||
config EXAMPLE_MAX_CPU_FREQ_96
|
||||
bool "96 MHz"
|
||||
depends on IDF_TARGET_ESP32H2
|
||||
config EXAMPLE_MAX_CPU_FREQ_120
|
||||
bool "120 MHz"
|
||||
depends on IDF_TARGET_ESP32C2
|
||||
config EXAMPLE_MAX_CPU_FREQ_160
|
||||
bool "160 MHz"
|
||||
depends on !IDF_TARGET_ESP32C2
|
||||
config EXAMPLE_MAX_CPU_FREQ_240
|
||||
bool "240 MHz"
|
||||
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_MAX_CPU_FREQ_MHZ
|
||||
int
|
||||
default 80 if EXAMPLE_MAX_CPU_FREQ_80
|
||||
default 96 if EXAMPLE_MAX_CPU_FREQ_96
|
||||
default 120 if EXAMPLE_MAX_CPU_FREQ_120
|
||||
default 160 if EXAMPLE_MAX_CPU_FREQ_160
|
||||
default 240 if EXAMPLE_MAX_CPU_FREQ_240
|
||||
|
||||
choice EXAMPLE_MIN_CPU_FREQ
|
||||
prompt "Minimum CPU frequency"
|
||||
default EXAMPLE_MIN_CPU_FREQ_10M if !IDF_TARGET_ESP32H2
|
||||
default EXAMPLE_MIN_CPU_FREQ_32M if IDF_TARGET_ESP32H2
|
||||
depends on PM_ENABLE
|
||||
help
|
||||
Minimum CPU frequency to use for dynamic frequency scaling.
|
||||
Should be set to XTAL frequency or XTAL frequency divided by integer.
|
||||
|
||||
config EXAMPLE_MIN_CPU_FREQ_40M
|
||||
bool "40 MHz (use with 40MHz XTAL)"
|
||||
depends on XTAL_FREQ_40 || XTAL_FREQ_AUTO || ESP32_XTAL_FREQ_40 || ESP32_XTAL_FREQ_AUTO || !IDF_TARGET_ESP32
|
||||
config EXAMPLE_MIN_CPU_FREQ_20M
|
||||
bool "20 MHz (use with 40MHz XTAL)"
|
||||
depends on XTAL_FREQ_40 || XTAL_FREQ_AUTO || ESP32_XTAL_FREQ_40 || ESP32_XTAL_FREQ_AUTO || !IDF_TARGET_ESP32
|
||||
config EXAMPLE_MIN_CPU_FREQ_10M
|
||||
bool "10 MHz (use with 40MHz XTAL)"
|
||||
depends on XTAL_FREQ_40 || XTAL_FREQ_AUTO || ESP32_XTAL_FREQ_40 || ESP32_XTAL_FREQ_AUTO || !IDF_TARGET_ESP32
|
||||
config EXAMPLE_MIN_CPU_FREQ_26M
|
||||
bool "26 MHz (use with 26MHz XTAL)"
|
||||
depends on XTAL_FREQ_26 || XTAL_FREQ_AUTO || ESP32_XTAL_FREQ_26 || ESP32_XTAL_FREQ_AUTO
|
||||
config EXAMPLE_MIN_CPU_FREQ_13M
|
||||
bool "13 MHz (use with 26MHz XTAL)"
|
||||
depends on XTAL_FREQ_26 || XTAL_FREQ_AUTO || ESP32_XTAL_FREQ_26 || ESP32_XTAL_FREQ_AUTO
|
||||
config EXAMPLE_MIN_CPU_FREQ_32M
|
||||
bool "32 MHz (use with 32MHz XTAL)"
|
||||
depends on IDF_TARGET_ESP32H2
|
||||
depends on XTAL_FREQ_32 || XTAL_FREQ_AUTO
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_MIN_CPU_FREQ_MHZ
|
||||
int
|
||||
default 40 if EXAMPLE_MIN_CPU_FREQ_40M
|
||||
default 20 if EXAMPLE_MIN_CPU_FREQ_20M
|
||||
default 10 if EXAMPLE_MIN_CPU_FREQ_10M
|
||||
default 26 if EXAMPLE_MIN_CPU_FREQ_26M
|
||||
default 13 if EXAMPLE_MIN_CPU_FREQ_13M
|
||||
default 32 if EXAMPLE_MIN_CPU_FREQ_32M
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,6 @@
|
||||
version: "0.0.1"
|
||||
dependencies:
|
||||
idf: ">=4.4"
|
||||
knob:
|
||||
version: "*"
|
||||
override_path: "../../../../components/knob"
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_pm.h"
|
||||
#include "iot_knob.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_idf_version.h"
|
||||
|
||||
#define ENCODER_A_GPIO 1
|
||||
#define ENCODER_B_GPIO 2
|
||||
|
||||
static const char *TAG = "knob_power_save";
|
||||
|
||||
static knob_handle_t knob = NULL;
|
||||
|
||||
const char *knob_event_table[] = {
|
||||
"KNOB_LEFT",
|
||||
"KNOB_RIGHT",
|
||||
"KNOB_H_LIM",
|
||||
"KNOB_L_LIM",
|
||||
"KNOB_ZERO",
|
||||
};
|
||||
|
||||
static void knob_event_cb(void *arg, void *data)
|
||||
{
|
||||
ESP_LOGI(TAG, "knob event %s, %d", knob_event_table[(knob_event_t)data], iot_knob_get_count_value(knob));
|
||||
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
|
||||
if (cause != ESP_SLEEP_WAKEUP_UNDEFINED) {
|
||||
ESP_LOGI(TAG, "Wake up from light sleep, reason %d", cause);
|
||||
}
|
||||
}
|
||||
|
||||
static void knob_init(uint32_t encoder_a, uint32_t encoder_b)
|
||||
{
|
||||
knob_config_t cfg = {
|
||||
.default_direction = 0,
|
||||
.gpio_encoder_a = encoder_a,
|
||||
.gpio_encoder_b = encoder_b,
|
||||
#if CONFIG_PM_ENABLE
|
||||
.enable_power_save = true,
|
||||
#endif
|
||||
};
|
||||
|
||||
knob = iot_knob_create(&cfg);
|
||||
assert(knob);
|
||||
esp_err_t err = iot_knob_register_cb(knob, KNOB_LEFT, knob_event_cb, (void *)KNOB_LEFT);
|
||||
err |= iot_knob_register_cb(knob, KNOB_RIGHT, knob_event_cb, (void *)KNOB_RIGHT);
|
||||
err |= iot_knob_register_cb(knob, KNOB_H_LIM, knob_event_cb, (void *)KNOB_H_LIM);
|
||||
err |= iot_knob_register_cb(knob, KNOB_L_LIM, knob_event_cb, (void *)KNOB_L_LIM);
|
||||
err |= iot_knob_register_cb(knob, KNOB_ZERO, knob_event_cb, (void *)KNOB_ZERO);
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
|
||||
void power_save_init(void)
|
||||
{
|
||||
esp_pm_config_t pm_config = {
|
||||
.max_freq_mhz = CONFIG_EXAMPLE_MAX_CPU_FREQ_MHZ,
|
||||
.min_freq_mhz = CONFIG_EXAMPLE_MIN_CPU_FREQ_MHZ,
|
||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
.light_sleep_enable = true
|
||||
#endif
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_pm_configure(&pm_config));
|
||||
}
|
||||
#else
|
||||
void power_save_init(void)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
esp_pm_config_esp32_t pm_config = {
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
esp_pm_config_esp32s2_t pm_config = {
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
esp_pm_config_esp32c3_t pm_config = {
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
esp_pm_config_esp32s3_t pm_config = {
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2
|
||||
esp_pm_config_esp32c2_t pm_config = {
|
||||
#endif
|
||||
.max_freq_mhz = CONFIG_EXAMPLE_MAX_CPU_FREQ_MHZ,
|
||||
.min_freq_mhz = CONFIG_EXAMPLE_MIN_CPU_FREQ_MHZ,
|
||||
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||
.light_sleep_enable = true
|
||||
#endif
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_pm_configure(&pm_config));
|
||||
}
|
||||
#endif
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
power_save_init();
|
||||
knob_init(ENCODER_A_GPIO, ENCODER_B_GPIO);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# Enable support for power management
|
||||
CONFIG_PM_ENABLE=y
|
||||
# Enable tickless idle mode
|
||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||
# Put related source code in IRAM
|
||||
CONFIG_PM_SLP_IRAM_OPT=y
|
||||
CONFIG_PM_RTOS_IDLE_OPT=y
|
||||
# Use 1000Hz freertos tick to lower sleep time threshold
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(usb_surface_dial)
|
||||
@@ -0,0 +1,49 @@
|
||||
## USB HID Surface Dial
|
||||
|
||||
This example shows how to use the ESP32-Sx USB function to emulate a Windows knob that allows volume control, page up and down, and more.
|
||||
|
||||
## Hardware Required
|
||||
|
||||

|
||||
|
||||
- Any ESP32-Sx development board with **knob** functionality.
|
||||
- The knob can be a series of rotary encoders with push function such as EC11
|
||||
- It is also possible to use three buttons that simulate: press, left turn, right turn
|
||||
|
||||
- Hardware Connection:
|
||||
- GPIO19 to USB_D-
|
||||
- GPIO20 to USB_D+
|
||||
- GPIO42 to EC11_E
|
||||
- GPIO1 to EC11_A
|
||||
- GPIO2 to EC11_C
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Build and Flash
|
||||
|
||||
1. Set up the `ESP-IDF` environment variables,you can refer [Set up the environment variables](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html#step-4-set-up-the-environment-variables), Linux can using:
|
||||
|
||||
```
|
||||
. $HOME/esp/esp-idf/export.sh
|
||||
```
|
||||
|
||||
2. Set ESP-IDF build target to `esp32s2` or `esp32s3`
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32s2
|
||||
```
|
||||
|
||||
3. Build, Flash, output log
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
## How To Use
|
||||
|
||||
* Connect the USB to the Windows USB port and wait for the USB device to finish installing
|
||||
* Press and hold the button to wake up the Windows wheel
|
||||
|
||||

|
||||
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 954 KiB |
@@ -0,0 +1,8 @@
|
||||
idf_component_register(
|
||||
SRCS "main.c" "usb_descriptors.c"
|
||||
INCLUDE_DIRS "."
|
||||
)
|
||||
|
||||
idf_component_get_property(tusb_lib leeebo__tinyusb_src COMPONENT_LIB)
|
||||
cmake_policy(SET CMP0079 NEW)
|
||||
target_link_libraries(${tusb_lib} PRIVATE ${COMPONENT_LIB})
|
||||
@@ -0,0 +1,24 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice DEVELOPMENT_BOARD_SELECTION
|
||||
prompt "Select the development board you are using"
|
||||
default ESP32_S3_USB_OTG if IDF_TARGET_ESP32S3
|
||||
default ESP32_S2_GENERIC if IDF_TARGET_ESP32S2
|
||||
help
|
||||
Select this option to choose the board for the example.
|
||||
|
||||
config ESP32_S3_USB_OTG
|
||||
bool "ESP32 S3 USB OTG"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
|
||||
config ESP32_S3_GENERIC
|
||||
bool "ESP32 S3 GENERIC"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
|
||||
config ESP32_S2_GENERIC
|
||||
bool "ESP32 S2 GENERIC"
|
||||
depends on IDF_TARGET_ESP32S2
|
||||
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,19 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf:
|
||||
version: ">=4.4.0"
|
||||
espressif/button:
|
||||
version: ">=2.3.0"
|
||||
override_path: "../../../../../components/button"
|
||||
leeebo/tinyusb_src:
|
||||
version: ">=0.0.4"
|
||||
espressif/knob:
|
||||
version: ">=0.1.0"
|
||||
override_path: "../../../../../components/knob"
|
||||
espressif/esp32_s3_usb_otg:
|
||||
version: "^1.5.1"
|
||||
rules:
|
||||
- if: "target in [esp32s3]"
|
||||
lvgl/lvgl: #temp to workaround bsp issue
|
||||
version: "9.2.0"
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_private/usb_phy.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "tusb.h"
|
||||
#include "tusb_config.h"
|
||||
#include "iot_button.h"
|
||||
#include "iot_knob.h"
|
||||
#ifdef CONFIG_ESP32_S3_USB_OTG
|
||||
#include "bsp/esp-bsp.h"
|
||||
#endif
|
||||
|
||||
#define TAG "DIAL"
|
||||
|
||||
#define GPIO_BUTTON 42
|
||||
#define GPIO_KNOB_A 1
|
||||
#define GPIO_KNOB_B 2
|
||||
|
||||
#define REPORT_ID 1
|
||||
#define DIAL_R 0xC8
|
||||
#define DIAL_L 0x38
|
||||
#define DIAL_PRESS 0x01
|
||||
#define DIAL_RELEASE 0x00
|
||||
#define DIAL_R_F 0x14
|
||||
#define DIAL_L_F 0xEC
|
||||
|
||||
static button_handle_t s_btn = 0;
|
||||
static knob_handle_t s_knob = 0;
|
||||
static usb_phy_handle_t s_phy_hdl;
|
||||
|
||||
static void usb_phy_init(void)
|
||||
{
|
||||
// Configure USB PHY
|
||||
usb_phy_config_t phy_conf = {
|
||||
.controller = USB_PHY_CTRL_OTG,
|
||||
.otg_mode = USB_OTG_MODE_DEVICE,
|
||||
.target = USB_PHY_TARGET_INT,
|
||||
};
|
||||
usb_new_phy(&phy_conf, &s_phy_hdl);
|
||||
}
|
||||
|
||||
static void surface_dial_report(uint8_t key)
|
||||
{
|
||||
uint8_t _dial_report[2];
|
||||
_dial_report[0] = key;
|
||||
_dial_report[1] = 0;
|
||||
if (key == DIAL_L || key == DIAL_L_F) {
|
||||
_dial_report[1] = 0xff;
|
||||
}
|
||||
tud_hid_report(REPORT_ID, _dial_report, 2);
|
||||
}
|
||||
|
||||
static void _button_press_down_cb(void *arg, void *data)
|
||||
{
|
||||
ESP_LOGI(TAG, "BTN: BUTTON_PRESS_DOWN");
|
||||
surface_dial_report(DIAL_PRESS);
|
||||
}
|
||||
|
||||
static void _button_press_up_cb(void *arg, void *data)
|
||||
{
|
||||
ESP_LOGI(TAG, "BTN: BUTTON_PRESS_UP[%"PRIu32"]", iot_button_get_ticks_time((button_handle_t)arg));
|
||||
surface_dial_report(DIAL_RELEASE);
|
||||
}
|
||||
|
||||
static void _knob_right_cb(void *arg, void *data)
|
||||
{
|
||||
ESP_LOGI(TAG, "KONB: KONB_RIGHT,count_value:%"PRId32"", iot_knob_get_count_value((button_handle_t)arg));
|
||||
surface_dial_report(DIAL_L);
|
||||
}
|
||||
|
||||
static void _knob_left_cb(void *arg, void *data)
|
||||
{
|
||||
ESP_LOGI(TAG, "KONB: KONB_LEFT,count_value:%"PRId32"", iot_knob_get_count_value((button_handle_t)arg));
|
||||
surface_dial_report(DIAL_R);
|
||||
}
|
||||
|
||||
static void _button_init(void)
|
||||
{
|
||||
button_config_t cfg = {
|
||||
.type = BUTTON_TYPE_GPIO,
|
||||
.long_press_time = 1000,
|
||||
.short_press_time = 200,
|
||||
.gpio_button_config = {
|
||||
.gpio_num = GPIO_BUTTON,
|
||||
.active_level = 0,
|
||||
},
|
||||
};
|
||||
s_btn = iot_button_create(&cfg);
|
||||
iot_button_register_cb(s_btn, BUTTON_PRESS_DOWN, _button_press_down_cb, NULL);
|
||||
iot_button_register_cb(s_btn, BUTTON_PRESS_UP, _button_press_up_cb, NULL);
|
||||
}
|
||||
|
||||
static void _knob_init(void)
|
||||
{
|
||||
knob_config_t cfg = {
|
||||
.default_direction = 0,
|
||||
.gpio_encoder_a = GPIO_KNOB_A,
|
||||
.gpio_encoder_b = GPIO_KNOB_B,
|
||||
};
|
||||
s_knob = iot_knob_create(&cfg);
|
||||
if (NULL == s_knob) {
|
||||
ESP_LOGE(TAG, "knob create failed");
|
||||
}
|
||||
|
||||
iot_knob_register_cb(s_knob, KNOB_LEFT, _knob_left_cb, NULL);
|
||||
iot_knob_register_cb(s_knob, KNOB_RIGHT, _knob_right_cb, NULL);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
#ifdef CONFIG_ESP32_S3_USB_OTG
|
||||
bsp_usb_mode_select_device();
|
||||
#endif
|
||||
usb_phy_init();
|
||||
_button_init();
|
||||
_knob_init();
|
||||
|
||||
tusb_init();
|
||||
|
||||
size_t timeout_tick = pdMS_TO_TICKS(10);
|
||||
while (1) {
|
||||
tud_task();
|
||||
vTaskDelay(timeout_tick);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
|
||||
{
|
||||
// TODO not Implemented
|
||||
(void) instance;
|
||||
(void) report_id;
|
||||
(void) report_type;
|
||||
(void) buffer;
|
||||
(void) reqlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize)
|
||||
{
|
||||
(void) instance;
|
||||
(void) report_id;
|
||||
(void) report_type;
|
||||
(void) buffer;
|
||||
(void) bufsize;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Board Specific Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// RHPort number used for device can be defined by board.mk, default to port 0
|
||||
#ifndef BOARD_TUD_RHPORT
|
||||
#define BOARD_TUD_RHPORT 0
|
||||
#endif
|
||||
|
||||
// RHPort max operational speed can defined by board.mk
|
||||
#ifndef BOARD_TUD_MAX_SPEED
|
||||
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// COMMON CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// defined by compiler flags for flexibility
|
||||
#ifndef CFG_TUSB_MCU
|
||||
#error CFG_TUSB_MCU must be defined
|
||||
#endif
|
||||
|
||||
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE
|
||||
|
||||
#ifndef CFG_TUSB_OS
|
||||
#define CFG_TUSB_OS OPT_OS_FREERTOS
|
||||
#endif
|
||||
|
||||
// Espressif IDF requires "freertos/" prefix in include path
|
||||
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
|
||||
#define CFG_TUSB_OS_INC_PATH freertos/
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_DEBUG
|
||||
#define CFG_TUSB_DEBUG 0
|
||||
#endif
|
||||
|
||||
// Enable Device stack
|
||||
#define CFG_TUD_ENABLED 1
|
||||
|
||||
// Default is max speed that hardware controller could support with on-chip PHY
|
||||
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
|
||||
|
||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
* into those specific section.
|
||||
* e.g
|
||||
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||
*/
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_HID 1
|
||||
#define CFG_TUD_CDC 0
|
||||
#define CFG_TUD_MSC 0
|
||||
#define CFG_TUD_MIDI 0
|
||||
#define CFG_TUD_VENDOR 0
|
||||
|
||||
// HID buffer size Should be sufficient to hold ID (if any) + Data
|
||||
#define CFG_TUD_HID_EP_BUFSIZE 8
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CONFIG_H_ */
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tusb.h"
|
||||
|
||||
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
|
||||
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
|
||||
*
|
||||
* Auto ProductID layout's Bitmap:
|
||||
* [MSB] HID | MSC | CDC [LSB]
|
||||
*/
|
||||
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
|
||||
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
|
||||
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_desc_device_t const desc_device = {
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = 0x00,
|
||||
.bDeviceSubClass = 0x00,
|
||||
.bDeviceProtocol = 0x00,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = 0xCafe,
|
||||
.idProduct = USB_PID,
|
||||
.bcdDevice = 0x0100,
|
||||
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
// Invoked when received GET DEVICE DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
uint8_t const *tud_descriptor_device_cb(void)
|
||||
{
|
||||
return (uint8_t const *) &desc_device;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HID Report Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Keyboard Report Descriptor Template
|
||||
#define TUD_HID_REPORT_DESC_DIAL(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( 0x0e ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DIGITIZER ) ,\
|
||||
HID_USAGE ( 0x21 ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
|
||||
HID_USAGE ( 1 ) ,\
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 1 ) ,\
|
||||
HID_LOGICAL_MIN ( 0 ) ,\
|
||||
HID_LOGICAL_MAX ( 1 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_DIAL ) ,\
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 15 ) ,\
|
||||
HID_UNIT_EXPONENT( 15 ) ,\
|
||||
HID_UNIT ( 0x14 ) ,\
|
||||
HID_PHYSICAL_MIN_N ( -3600, 2 ) ,\
|
||||
HID_PHYSICAL_MAX_N ( 3600, 2 ) ,\
|
||||
HID_LOGICAL_MIN_N ( -3600, 2 ) ,\
|
||||
HID_LOGICAL_MAX_N ( 3600, 2 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE) ,\
|
||||
HID_COLLECTION_END ,\
|
||||
HID_COLLECTION_END \
|
||||
|
||||
uint8_t const desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_DIAL(HID_REPORT_ID(1))
|
||||
};
|
||||
|
||||
// Invoked when received GET HID REPORT DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf)
|
||||
{
|
||||
if (itf == 0) {
|
||||
return desc_hid_report;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
enum {
|
||||
ITF_NUM_HID,
|
||||
ITF_NUM_TOTAL
|
||||
};
|
||||
|
||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN )
|
||||
|
||||
#define EPNUM_HID 0x81
|
||||
|
||||
uint8_t const desc_configuration[] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0, 100),
|
||||
|
||||
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
|
||||
TUD_HID_DESCRIPTOR(ITF_NUM_HID, 4, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10),
|
||||
};
|
||||
|
||||
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
|
||||
{
|
||||
(void) index; // for multiple configurations
|
||||
return desc_configuration;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// String Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// array of pointer to string descriptors
|
||||
char const *string_desc_arr [] = {
|
||||
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
|
||||
"TinyUSB", // 1: Manufacturer
|
||||
"TinyUSB Device", // 2: Product
|
||||
"123456", // 3: Serials, should use chip ID
|
||||
"Surface Dial", // 4: Interface 1 String
|
||||
};
|
||||
|
||||
static uint16_t _desc_str[32];
|
||||
|
||||
// Invoked when received GET STRING DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
||||
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||
{
|
||||
(void) langid;
|
||||
|
||||
uint8_t chr_count;
|
||||
|
||||
if (index == 0) {
|
||||
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||
chr_count = 1;
|
||||
} else {
|
||||
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
||||
|
||||
if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *str = string_desc_arr[index];
|
||||
|
||||
// Cap at max char
|
||||
chr_count = (uint8_t) strlen(str);
|
||||
if (chr_count > 31) {
|
||||
chr_count = 31;
|
||||
}
|
||||
|
||||
// Convert ASCII string into UTF-16
|
||||
for (uint8_t i = 0; i < chr_count; i++) {
|
||||
_desc_str[1 + i] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
// first byte is length (including header), second byte is string type
|
||||
_desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
|
||||
|
||||
return _desc_str;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
CONFIG_ESP32_S3_USB_OTG=y
|
||||
Reference in New Issue
Block a user