Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
version: 1.0.0
# Devices Configuration for Anyboard
devices:
- name: fake_camera # Just for invoking camera dependencies, no actual camera hardware connected
type: camera
version: default
sub_type: "dvp"
init_skip: true
peripherals:
- name: i2c_master
frequency: 100000

- name: camera
type: custom
version: default
dependencies:
espressif/usb_host_uvc: "2.4.2"

# PDM Microphone (bare PDM mic, no I2C codec IC).
# Lua audio reads the already-initialized i2s_audio_in peripheral directly.
- name: audio_adc
chip: internal
type: audio_codec
version: default
config:
adc_enabled: true
dac_enabled: false
adc_max_channel: 1
adc_channel_mask: "1"
adc_init_gain: 0
peripherals:
- name: i2s_audio_in

# SPI Display Device (ST7789 320x240 landscape, rotated right from portrait)
# SCLK=IO5, SDA=IO7, RST=IO6, DC=IO8, CS=IO4
- name: display_lcd
chip: st7789
type: display_lcd
sub_type: spi
version: default
config:
mirror_x: false
mirror_y: true
swap_xy: true
invert_color: true
x_max: 320
y_max: 200
io_spi_config:
cs_gpio_num: 4
dc_gpio_num: 8
spi_mode: 3
pclk_hz: 80000000

lcd_panel_config:
reset_gpio_num: 6
data_endian: "LCD_RGB_DATA_ENDIAN_BIG"
flags:
reset_active_high: false
vendor_config: NULL

peripherals:
- name: spi_display

# IMU Sensor (BMI270, I2C SCL=IO40 SDA=IO39, INT=IO18)
- name: imu_sensor
chip: bmi270
type: custom
version: 1.0.0
init_skip: true
config:
i2c_addr: 0x68
frequency: 400000
int_gpio_num: 18
peripherals:
- name: i2c_master

# Buttons (active low)
# enter=IO41, left=IO42, right=IO0
- name: buttons
chip: gpio_button
type: custom
version: 1.0.0
init_skip: true
config:
button_enter_gpio: 41
button_left_gpio: 42
button_right_gpio: 0
active_level: 0

# Buzzer (IO46)
- name: buzzer
chip: gpio_buzzer
type: custom
version: 1.0.0
init_skip: true
config:
gpio_num: 46
active_level: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
board: anyboard
chip: esp32s3
version: 1.0.0
description: "Anyboard Development Board"
manufacturer: "TEMP"
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
version: 1.0.0
# Peripherals Configuration for Anyboard
peripherals:
# I2C Configuration (SCL=IO40, SDA=IO39)
- name: i2c_master
type: i2c
role: master
config:
port: 0
pins:
sda: 39
scl: 40

# I2S PDM RX for microphone (CLK=IO9, DIN=IO17)
- name: i2s_audio_in
type: i2s
version: default
role: master
format: pdm-in
config:
port: 0
sample_rate_hz: 16000
clk_src: I2S_CLK_SRC_DEFAULT
mclk_multiple: 256
dn_sample_mode: I2S_PDM_DSR_8S
bclk_div: 8
data_bit_width: 16
slot_bit_width: I2S_SLOT_BIT_WIDTH_AUTO
slot_mode: I2S_SLOT_MODE_MONO
slot_mask: I2S_PDM_SLOT_LEFT
data_fmt: I2S_PDM_DATA_FMT_PCM
hp_en: true
hp_cut_off_freq_hz: 35.5
amplify_num: 1
pins:
clk: 9
din: 17
invert_flags:
clk_inv: false

# LCD SPI Configuration for ST7789 (SCLK=IO5, MOSI=IO7)
- name: spi_display
type: spi
role: master
config:
spi_bus_config:
spi_port: SPI2_HOST
data0_io_num: 7
sclk_io_num: 5
max_transfer_sz: 6400 # 320 * 2 * 10 (10 lines RGB565)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_ESP_VIDEO_ENABLE_USB_UVC_VIDEO_DEVICE=y
CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE=1024
CONFIG_USB_UVC_VIDEO_DEVICE_URB_SIZE=4096
CONFIG_APP_CLAW_LUA_MODULE_CAMERA=y
CONFIG_APP_CLAW_LUA_MODULE_VISION=y
CONFIG_APP_CLAW_LUA_MODULE_IMU=y
CONFIG_LUA_MODULE_IMU_CHIP_BMI270=y
CONFIG_ESP_BOARD_DEV_AUDIO_CODEC_SUPPORT=y
CONFIG_APP_CLAW_LUA_MODULE_AUDIO=y
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
CONFIG_ESP_CONSOLE_SECONDARY_NONE=y
156 changes: 156 additions & 0 deletions application/edge_agent/boards/community/anyboard/setup_device.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#include <string.h>
#include <stdlib.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_video_init.h"
#include "esp_video_device.h"
#include "esp_board_manager_includes.h"
#include "gen_board_device_custom.h"

static const char *TAG = "ANYBOARD_SETUP_DEVICE";

#define USB_UVC_DEV_NUM 1
#define USB_HOST_TASK_PRIORITY 5
#define USB_HOST_TASK_STACK_SIZE 4096
#define USB_UVC_TASK_PRIORITY configMAX_PRIORITIES - 2
#define USB_UVC_TASK_STACK_SIZE 4096

typedef struct {
dev_camera_handle_t handle;
} custom_usb_camera_handle_t;

static int usb_camera_init(void *config, int cfg_size, void **device_handle)
{
(void)config;
(void)cfg_size;
ESP_RETURN_ON_FALSE(device_handle != NULL, ESP_ERR_INVALID_ARG, TAG, "invalid camera handle");

#if CONFIG_ESP_VIDEO_ENABLE_USB_UVC_VIDEO_DEVICE
const esp_video_init_usb_uvc_config_t usb_uvc_config = {
.uvc = {
.uvc_dev_num = USB_UVC_DEV_NUM,
.task_stack = USB_UVC_TASK_STACK_SIZE,
.task_priority = USB_UVC_TASK_PRIORITY,
.task_affinity = 0,
},
.usb = {
.init_usb_host_lib = true,
.task_stack = USB_HOST_TASK_STACK_SIZE,
.task_priority = USB_HOST_TASK_PRIORITY,
.task_affinity = 0,
},
};
const esp_video_init_config_t video_config = {
.usb_uvc = &usb_uvc_config,
};

esp_err_t ret = esp_video_init(&video_config);
if (ret != ESP_OK) {
return ret;
}

custom_usb_camera_handle_t *handle = calloc(1, sizeof(*handle));
if (handle == NULL) {
(void)esp_video_deinit();
return ESP_ERR_NO_MEM;
}

handle->handle.dev_path = ESP_VIDEO_USB_UVC_NAME(0);
handle->handle.meta_path = "";
*device_handle = &handle->handle;
ESP_LOGI(TAG, "USB UVC camera initialized, dev_path: %s", handle->handle.dev_path);
return ESP_OK;
#else
ESP_LOGE(TAG, "USB UVC camera is disabled. Enable CONFIG_ESP_VIDEO_ENABLE_USB_UVC_VIDEO_DEVICE");
return ESP_ERR_NOT_SUPPORTED;
#endif
}

static int usb_camera_deinit(void *device_handle)
{
#if CONFIG_ESP_VIDEO_ENABLE_USB_UVC_VIDEO_DEVICE
free(device_handle);
ESP_RETURN_ON_ERROR(esp_video_deinit(), TAG, "failed to deinit USB UVC camera");
ESP_LOGI(TAG, "USB UVC camera deinitialized");
return ESP_OK;
#else
(void)device_handle;
return ESP_OK;
#endif
}

CUSTOM_DEVICE_IMPLEMENT(camera, usb_camera_init, usb_camera_deinit);

/*
* The AnyBoard LCD uses a cropped ST7789 glass. Without a panel gap, the
* top rows are addressed outside the visible window after landscape rotation.
*/
#define ANYBOARD_LCD_OFFSET_X 0
#define ANYBOARD_LCD_OFFSET_Y 16

typedef struct {
int cmd;
const void *data;
size_t data_bytes;
unsigned int delay_ms;
} st7789_lcd_init_cmd_t;

static const st7789_lcd_init_cmd_t vendor_specific_init[] = {
{0x11, (uint8_t []){0x00}, 1, 120},
{0xB2, (uint8_t []){0x0C, 0x0C, 0x00, 0x33, 0x33}, 5, 0},
{0x35, (uint8_t []){0x00}, 1, 0},
{0x36, (uint8_t []){0x00}, 1, 0},
{0x3A, (uint8_t []){0x05}, 1, 0},
{0xB7, (uint8_t []){0x35}, 1, 0},
{0xBB, (uint8_t []){0x2D}, 1, 0},
{0xC0, (uint8_t []){0x2C}, 1, 0},
{0xC2, (uint8_t []){0x01}, 1, 0},
{0xC3, (uint8_t []){0x15}, 1, 0},
{0xC4, (uint8_t []){0x20}, 1, 0},
{0xC6, (uint8_t []){0x0F}, 1, 0},
{0xD0, (uint8_t []){0xA4, 0xA1}, 2, 0},
{0xD6, (uint8_t []){0xA1}, 1, 0},
{0xE0, (uint8_t []){0x70, 0x05, 0x0A, 0x0B, 0x0A, 0x27, 0x2F, 0x44, 0x47, 0x37, 0x14, 0x14, 0x29, 0x2F}, 14, 0},
{0xE1, (uint8_t []){0x70, 0x07, 0x0C, 0x08, 0x08, 0x04, 0x2F, 0x33, 0x46, 0x18, 0x15, 0x15, 0x2B, 0x2D}, 14, 0},
{0x21, (uint8_t []){0x00}, 1, 0},
{0x29, (uint8_t []){0x00}, 1, 0},
{0x2C, (uint8_t []){0x00}, 1, 0},
};

esp_err_t lcd_panel_factory_entry_t(esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel)
{
esp_err_t ret = esp_lcd_new_panel_st7789(io, panel_dev_config, ret_panel);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to create ST7789 panel: %s", esp_err_to_name(ret));
return ret;
}

ret = esp_lcd_panel_set_gap(*ret_panel, ANYBOARD_LCD_OFFSET_X, ANYBOARD_LCD_OFFSET_Y);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "esp_lcd_panel_set_gap failed: %s", esp_err_to_name(ret));
}

for (size_t i = 0; i < sizeof(vendor_specific_init) / sizeof(vendor_specific_init[0]); i++) {
ret = esp_lcd_panel_io_tx_param(io, vendor_specific_init[i].cmd,
vendor_specific_init[i].data,
vendor_specific_init[i].data_bytes);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to send init cmd 0x%02x: %s", vendor_specific_init[i].cmd, esp_err_to_name(ret));
return ret;
}
if (vendor_specific_init[i].delay_ms > 0) {
vTaskDelay(pdMS_TO_TICKS(vendor_specific_init[i].delay_ms));
}
}

esp_lcd_panel_reset(*ret_panel);
esp_lcd_panel_init(*ret_panel);

return ESP_OK;
}